blob: 629fc9a347a9abde55d28e12680dea54d751306f [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 Geoffray004c2302015-03-20 10:06:38 +000037class CodeInfo;
38
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010039/**
40 * Classes in the following file are wrapper on stack map information backed
41 * by a MemoryRegion. As such they read and write to the region, they don't have
42 * their own fields.
43 */
44
45/**
46 * Inline information for a specific PC. The information is of the form:
47 * [inlining_depth, [method_dex reference]+]
48 */
49class InlineInfo {
50 public:
51 explicit InlineInfo(MemoryRegion region) : region_(region) {}
52
53 uint8_t GetDepth() const {
Roland Levillainede7bf82015-03-13 12:23:04 +000054 return region_.LoadUnaligned<uint8_t>(kDepthOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010055 }
56
57 void SetDepth(uint8_t depth) {
Roland Levillainede7bf82015-03-13 12:23:04 +000058 region_.StoreUnaligned<uint8_t>(kDepthOffset, depth);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010059 }
60
61 uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
Roland Levillainede7bf82015-03-13 12:23:04 +000062 return region_.LoadUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010063 }
64
65 void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
Roland Levillainede7bf82015-03-13 12:23:04 +000066 region_.StoreUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010067 }
68
69 static size_t SingleEntrySize() {
70 return sizeof(uint32_t);
71 }
72
73 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +000074 // TODO: Instead of plain types such as "uint8_t", introduce
75 // typedefs (and document the memory layout of InlineInfo).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010076 static constexpr int kDepthOffset = 0;
77 static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
78
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010079 MemoryRegion region_;
80
Nicolas Geoffray39468442014-09-02 15:17:15 +010081 friend class CodeInfo;
82 friend class StackMap;
83 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010084};
85
Roland Levillaina2d8ec62015-03-12 15:25:29 +000086// Dex register location container used by DexRegisterMap and StackMapStream.
87class DexRegisterLocation {
88 public:
89 /*
90 * The location kind used to populate the Dex register information in a
91 * StackMapStream can either be:
92 * - kNone: the register has no location yet, meaning it has not been set;
93 * - kConstant: value holds the constant;
94 * - kStack: value holds the stack offset;
95 * - kRegister: value holds the physical register number;
96 * - kFpuRegister: value holds the physical register number.
97 *
98 * In addition, DexRegisterMap also uses these values:
99 * - kInStackLargeOffset: value holds a "large" stack offset (greater than
100 * 128 bytes);
101 * - kConstantLargeValue: value holds a "large" constant (lower than or
102 * equal to -16, or greater than 16).
103 */
104 enum class Kind : uint8_t {
105 // Short location kinds, for entries fitting on one byte (3 bits
106 // for the kind, 5 bits for the value) in a DexRegisterMap.
107 kNone = 0, // 0b000
108 kInStack = 1, // 0b001
109 kInRegister = 2, // 0b010
110 kInFpuRegister = 3, // 0b011
111 kConstant = 4, // 0b100
112
113 // Large location kinds, requiring a 5-byte encoding (1 byte for the
114 // kind, 4 bytes for the value).
115
116 // Stack location at a large offset, meaning that the offset value
117 // divided by the stack frame slot size (4 bytes) cannot fit on a
118 // 5-bit unsigned integer (i.e., this offset value is greater than
119 // or equal to 2^5 * 4 = 128 bytes).
120 kInStackLargeOffset = 5, // 0b101
121
122 // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
123 // lower than -2^(5-1) = -16, or greater than or equal to
124 // 2^(5-1) - 1 = 15).
125 kConstantLargeValue = 6, // 0b110
126
127 kLastLocationKind = kConstantLargeValue
128 };
129
130 static_assert(
131 sizeof(Kind) == 1u,
132 "art::DexRegisterLocation::Kind has a size different from one byte.");
133
134 static const char* PrettyDescriptor(Kind kind) {
135 switch (kind) {
136 case Kind::kNone:
137 return "none";
138 case Kind::kInStack:
139 return "in stack";
140 case Kind::kInRegister:
141 return "in register";
142 case Kind::kInFpuRegister:
143 return "in fpu register";
144 case Kind::kConstant:
145 return "as constant";
146 case Kind::kInStackLargeOffset:
147 return "in stack (large offset)";
148 case Kind::kConstantLargeValue:
149 return "as constant (large value)";
150 default:
151 UNREACHABLE();
152 }
153 }
154
155 static bool IsShortLocationKind(Kind kind) {
156 switch (kind) {
157 case Kind::kNone:
158 case Kind::kInStack:
159 case Kind::kInRegister:
160 case Kind::kInFpuRegister:
161 case Kind::kConstant:
162 return true;
163
164 case Kind::kInStackLargeOffset:
165 case Kind::kConstantLargeValue:
166 return false;
167
168 default:
169 UNREACHABLE();
170 }
171 }
172
173 // Convert `kind` to a "surface" kind, i.e. one that doesn't include
174 // any value with a "large" qualifier.
175 // TODO: Introduce another enum type for the surface kind?
176 static Kind ConvertToSurfaceKind(Kind kind) {
177 switch (kind) {
178 case Kind::kNone:
179 case Kind::kInStack:
180 case Kind::kInRegister:
181 case Kind::kInFpuRegister:
182 case Kind::kConstant:
183 return kind;
184
185 case Kind::kInStackLargeOffset:
186 return Kind::kInStack;
187
188 case Kind::kConstantLargeValue:
189 return Kind::kConstant;
190
191 default:
192 UNREACHABLE();
193 }
194 }
195
196 DexRegisterLocation(Kind kind, int32_t value)
197 : kind_(kind), value_(value) {}
198
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000199 static DexRegisterLocation None() {
200 return DexRegisterLocation(Kind::kNone, 0);
201 }
202
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000203 // Get the "surface" kind of the location, i.e., the one that doesn't
204 // include any value with a "large" qualifier.
205 Kind GetKind() const {
206 return ConvertToSurfaceKind(kind_);
207 }
208
209 // Get the value of the location.
210 int32_t GetValue() const { return value_; }
211
212 // Get the actual kind of the location.
213 Kind GetInternalKind() const { return kind_; }
214
215 private:
216 Kind kind_;
217 int32_t value_;
218};
219
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100220/**
221 * Information on dex register values for a specific PC. The information is
222 * of the form:
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000223 * [live_bit_mask, DexRegisterLocation+].
224 * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100225 */
226class DexRegisterMap {
227 public:
228 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
229
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000230 // Short (compressed) location, fitting on one byte.
231 typedef uint8_t ShortLocation;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100232
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000233 static size_t LiveBitMaskSize(uint16_t number_of_dex_registers) {
234 return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte;
235 }
236
237 void SetLiveBitMask(size_t offset,
238 uint16_t number_of_dex_registers,
239 const BitVector& live_dex_registers_mask) {
240 for (uint16_t i = 0; i < number_of_dex_registers; i++) {
241 region_.StoreBit(offset + i, live_dex_registers_mask.IsBitSet(i));
242 }
243 }
244
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000245 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
246 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
247 int32_t value = dex_register_location.GetValue();
248 if (DexRegisterLocation::IsShortLocationKind(kind)) {
249 // Short location. Compress the kind and the value as a single byte.
250 if (kind == DexRegisterLocation::Kind::kInStack) {
251 // Instead of storing stack offsets expressed in bytes for
252 // short stack locations, store slot offsets. A stack offset
253 // is a multiple of 4 (kFrameSlotSize). This means that by
254 // dividing it by 4, we can fit values from the [0, 128)
255 // interval in a short stack location, and not just values
256 // from the [0, 32) interval.
257 DCHECK_EQ(value % kFrameSlotSize, 0);
258 value /= kFrameSlotSize;
259 }
260 DCHECK(IsUint<kValueBits>(value)) << value;
261 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
262 } else {
263 // Large location. Write the location on one byte and the value
264 // on 4 bytes.
265 DCHECK(!IsUint<kValueBits>(value)) << value;
266 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
267 // Also divide large stack offsets by 4 for the sake of consistency.
268 DCHECK_EQ(value % kFrameSlotSize, 0);
269 value /= kFrameSlotSize;
270 }
271 // Data can be unaligned as the written Dex register locations can
272 // either be 1-byte or 5-byte wide. Use
273 // art::MemoryRegion::StoreUnaligned instead of
274 // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
275 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
276 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
Roland Levillain442b46a2015-02-18 16:54:21 +0000277 }
278 }
279
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000280 bool IsDexRegisterLive(uint16_t dex_register_index) const {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000281 size_t offset = kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000282 return region_.LoadBit(offset + dex_register_index);
283 }
284
285 static constexpr size_t kNoDexRegisterLocationOffset = -1;
286
287 static size_t GetDexRegisterMapLocationsOffset(uint16_t number_of_dex_registers) {
288 return kLiveBitMaskOffset + LiveBitMaskSize(number_of_dex_registers);
289 }
290
291 // Find the offset of the Dex register location number `dex_register_index`.
292 size_t FindLocationOffset(uint16_t dex_register_index, uint16_t number_of_dex_registers) const {
293 if (!IsDexRegisterLive(dex_register_index)) return kNoDexRegisterLocationOffset;
294 size_t offset = GetDexRegisterMapLocationsOffset(number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000295 // Skip the first `dex_register_index - 1` entries.
296 for (uint16_t i = 0; i < dex_register_index; ++i) {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000297 if (IsDexRegisterLive(i)) {
298 // Read the first next byte and inspect its first 3 bits to decide
299 // whether it is a short or a large location.
300 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
301 if (DexRegisterLocation::IsShortLocationKind(kind)) {
302 // Short location. Skip the current byte.
303 offset += SingleShortEntrySize();
304 } else {
305 // Large location. Skip the 5 next bytes.
306 offset += SingleLargeEntrySize();
307 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000308 }
309 }
310 return offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100311 }
312
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000313 // Get the surface kind.
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000314 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_index,
315 uint16_t number_of_dex_registers) const {
316 return IsDexRegisterLive(dex_register_index)
317 ? DexRegisterLocation::ConvertToSurfaceKind(
318 GetLocationInternalKind(dex_register_index, number_of_dex_registers))
319 : DexRegisterLocation::Kind::kNone;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100320 }
321
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000322 // Get the internal kind.
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000323 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_index,
324 uint16_t number_of_dex_registers) const {
325 return IsDexRegisterLive(dex_register_index)
326 ? ExtractKindAtOffset(FindLocationOffset(dex_register_index, number_of_dex_registers))
327 : DexRegisterLocation::Kind::kNone;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100328 }
329
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000330 // TODO: Rename as GetDexRegisterLocation?
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000331 DexRegisterLocation GetLocationKindAndValue(uint16_t dex_register_index,
332 uint16_t number_of_dex_registers) const {
333 if (!IsDexRegisterLive(dex_register_index)) {
334 return DexRegisterLocation::None();
335 }
336 size_t offset = FindLocationOffset(dex_register_index, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000337 // Read the first byte and inspect its first 3 bits to get the location.
338 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
339 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
340 if (DexRegisterLocation::IsShortLocationKind(kind)) {
341 // Short location. Extract the value from the remaining 5 bits.
342 int32_t value = ExtractValueFromShortLocation(first_byte);
343 if (kind == DexRegisterLocation::Kind::kInStack) {
344 // Convert the stack slot (short) offset to a byte offset value.
345 value *= kFrameSlotSize;
346 }
347 return DexRegisterLocation(kind, value);
348 } else {
349 // Large location. Read the four next bytes to get the value.
350 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
351 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
352 // Convert the stack slot (large) offset to a byte offset value.
353 value *= kFrameSlotSize;
354 }
355 return DexRegisterLocation(kind, value);
356 }
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100357 }
358
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000359 int32_t GetStackOffsetInBytes(uint16_t dex_register_index,
360 uint16_t number_of_dex_registers) const {
361 DexRegisterLocation location =
362 GetLocationKindAndValue(dex_register_index, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000363 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
364 // GetLocationKindAndValue returns the offset in bytes.
365 return location.GetValue();
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100366 }
367
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000368 int32_t GetConstant(uint16_t dex_register_index, uint16_t number_of_dex_registers) const {
369 DexRegisterLocation location =
370 GetLocationKindAndValue(dex_register_index, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000371 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
372 return location.GetValue();
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100373 }
374
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000375 int32_t GetMachineRegister(uint16_t dex_register_index, uint16_t number_of_dex_registers) const {
376 DexRegisterLocation location =
377 GetLocationKindAndValue(dex_register_index, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000378 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister
379 || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister)
380 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
381 return location.GetValue();
382 }
383
384 // Compute the compressed kind of `location`.
385 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
386 switch (location.GetInternalKind()) {
387 case DexRegisterLocation::Kind::kNone:
388 DCHECK_EQ(location.GetValue(), 0);
389 return DexRegisterLocation::Kind::kNone;
390
391 case DexRegisterLocation::Kind::kInRegister:
392 DCHECK_GE(location.GetValue(), 0);
393 DCHECK_LT(location.GetValue(), 1 << DexRegisterMap::kValueBits);
394 return DexRegisterLocation::Kind::kInRegister;
395
396 case DexRegisterLocation::Kind::kInFpuRegister:
397 DCHECK_GE(location.GetValue(), 0);
398 DCHECK_LT(location.GetValue(), 1 << DexRegisterMap::kValueBits);
399 return DexRegisterLocation::Kind::kInFpuRegister;
400
401 case DexRegisterLocation::Kind::kInStack:
402 DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
403 return IsUint<DexRegisterMap::kValueBits>(location.GetValue() / kFrameSlotSize)
404 ? DexRegisterLocation::Kind::kInStack
405 : DexRegisterLocation::Kind::kInStackLargeOffset;
406
407 case DexRegisterLocation::Kind::kConstant:
408 return IsUint<DexRegisterMap::kValueBits>(location.GetValue())
409 ? DexRegisterLocation::Kind::kConstant
410 : DexRegisterLocation::Kind::kConstantLargeValue;
411
412 default:
413 LOG(FATAL) << "Unexpected location kind"
414 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
415 UNREACHABLE();
416 }
417 }
418
419 // Can `location` be turned into a short location?
420 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
421 switch (location.GetInternalKind()) {
422 case DexRegisterLocation::Kind::kNone:
423 case DexRegisterLocation::Kind::kInRegister:
424 case DexRegisterLocation::Kind::kInFpuRegister:
425 return true;
426
427 case DexRegisterLocation::Kind::kInStack:
428 DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
429 return IsUint<kValueBits>(location.GetValue() / kFrameSlotSize);
430
431 case DexRegisterLocation::Kind::kConstant:
432 return IsUint<kValueBits>(location.GetValue());
433
434 default:
435 UNREACHABLE();
436 }
437 }
438
439 static size_t EntrySize(const DexRegisterLocation& location) {
440 return CanBeEncodedAsShortLocation(location)
441 ? DexRegisterMap::SingleShortEntrySize()
442 : DexRegisterMap::SingleLargeEntrySize();
443 }
444
445 static size_t SingleShortEntrySize() {
446 return sizeof(ShortLocation);
447 }
448
449 static size_t SingleLargeEntrySize() {
450 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100451 }
452
Roland Levillain12baf472015-03-05 12:41:42 +0000453 size_t Size() const {
454 return region_.size();
455 }
456
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000457 static constexpr int kLiveBitMaskOffset = 0;
458 static constexpr int kFixedSize = kLiveBitMaskOffset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100459
Roland Levillain12baf472015-03-05 12:41:42 +0000460 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000461 // Width of the kind "field" in a short location, in bits.
462 static constexpr size_t kKindBits = 3;
463 // Width of the value "field" in a short location, in bits.
464 static constexpr size_t kValueBits = 5;
465
466 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
467 static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
468 static constexpr size_t kKindOffset = 0;
469 static constexpr size_t kValueOffset = kKindBits;
470
471 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
472 DCHECK(IsUint<kKindBits>(static_cast<uint8_t>(kind))) << static_cast<uint8_t>(kind);
473 DCHECK(IsUint<kValueBits>(value)) << value;
474 return (static_cast<uint8_t>(kind) & kKindMask) << kKindOffset
475 | (value & kValueMask) << kValueOffset;
476 }
477
478 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
479 uint8_t kind = (location >> kKindOffset) & kKindMask;
480 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000481 // We do not encode kNone locations in the stack map.
482 DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone));
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000483 return static_cast<DexRegisterLocation::Kind>(kind);
484 }
485
486 static int32_t ExtractValueFromShortLocation(ShortLocation location) {
487 return (location >> kValueOffset) & kValueMask;
488 }
489
490 // Extract a location kind from the byte at position `offset`.
491 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
492 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
493 return ExtractKindFromShortLocation(first_byte);
494 }
495
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100496 MemoryRegion region_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000497
498 friend class CodeInfo;
499 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100500};
501
502/**
503 * A Stack Map holds compilation information for a specific PC necessary for:
504 * - Mapping it to a dex PC,
505 * - Knowing which stack entries are objects,
506 * - Knowing which registers hold objects,
507 * - Knowing the inlining information,
508 * - Knowing the values of dex registers.
509 *
510 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100511 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100512 *
513 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
514 * stack size of a method.
515 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100516class StackMap {
517 public:
518 explicit StackMap(MemoryRegion region) : region_(region) {}
519
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000520 uint32_t GetDexPc(const CodeInfo& info) const;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100521
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000522 void SetDexPc(const CodeInfo& info, uint32_t dex_pc);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100523
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000524 uint32_t GetNativePcOffset(const CodeInfo& info) const;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100525
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000526 void SetNativePcOffset(const CodeInfo& info, uint32_t native_pc_offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100527
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000528 uint32_t GetDexRegisterMapOffset(const CodeInfo& info) const;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100529
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000530 void SetDexRegisterMapOffset(const CodeInfo& info, uint32_t offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100531
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000532 uint32_t GetInlineDescriptorOffset(const CodeInfo& info) const;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100533
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000534 void SetInlineDescriptorOffset(const CodeInfo& info, uint32_t offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100535
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000536 uint32_t GetRegisterMask(const CodeInfo& info) const;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100537
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000538 void SetRegisterMask(const CodeInfo& info, uint32_t mask);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100539
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000540 MemoryRegion GetStackMask(const CodeInfo& info) const;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100541
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000542 void SetStackMask(const CodeInfo& info, const BitVector& sp_map) {
543 MemoryRegion region = GetStackMask(info);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100544 for (size_t i = 0; i < region.size_in_bits(); i++) {
545 region.StoreBit(i, sp_map.IsBitSet(i));
546 }
547 }
548
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000549 bool HasDexRegisterMap(const CodeInfo& info) const {
550 return GetDexRegisterMapOffset(info) != kNoDexRegisterMap;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100551 }
552
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000553 bool HasInlineInfo(const CodeInfo& info) const {
554 return GetInlineDescriptorOffset(info) != kNoInlineInfo;
Roland Levillain442b46a2015-02-18 16:54:21 +0000555 }
556
557 bool Equals(const StackMap& other) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100558 return region_.pointer() == other.region_.pointer()
559 && region_.size() == other.region_.size();
560 }
561
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000562 static size_t ComputeStackMapSize(size_t stack_mask_size,
563 bool has_inline_info,
564 bool is_small_inline_info,
565 bool is_small_dex_map,
566 bool is_small_dex_pc,
567 bool is_small_native_pc);
568
569 static size_t ComputeStackMapSize(size_t stack_mask_size,
570 size_t inline_info_size,
571 size_t dex_register_map_size,
572 size_t dex_pc_max,
573 size_t native_pc_max);
574
575 // TODO: Revisit this abstraction if we allow 3 bytes encoding.
576 typedef uint8_t kSmallEncoding;
577 typedef uint32_t kLargeEncoding;
578 static constexpr size_t kBytesForSmallEncoding = sizeof(kSmallEncoding);
579 static constexpr size_t kBitsForSmallEncoding = kBitsPerByte * kBytesForSmallEncoding;
580 static constexpr size_t kBytesForLargeEncoding = sizeof(kLargeEncoding);
581 static constexpr size_t kBitsForLargeEncoding = kBitsPerByte * kBytesForLargeEncoding;
Nicolas Geoffray376b2bb2014-12-09 14:26:32 +0000582
Roland Levillain442b46a2015-02-18 16:54:21 +0000583 // Special (invalid) offset for the DexRegisterMapOffset field meaning
584 // that there is no Dex register map for this stack map.
585 static constexpr uint32_t kNoDexRegisterMap = -1;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000586 static constexpr uint32_t kNoDexRegisterMapSmallEncoding =
587 std::numeric_limits<kSmallEncoding>::max();
Roland Levillain442b46a2015-02-18 16:54:21 +0000588
589 // Special (invalid) offset for the InlineDescriptorOffset field meaning
590 // that there is no inline info for this stack map.
591 static constexpr uint32_t kNoInlineInfo = -1;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000592 static constexpr uint32_t kNoInlineInfoSmallEncoding =
593 std::numeric_limits<kSmallEncoding>::max();
594
595 // Returns the number of bytes needed for an entry in the StackMap.
596 static size_t NumberOfBytesForEntry(bool small_encoding) {
597 return small_encoding ? kBytesForSmallEncoding : kBytesForLargeEncoding;
598 }
Roland Levillain442b46a2015-02-18 16:54:21 +0000599
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100600 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000601 // TODO: Instead of plain types such as "uint32_t", introduce
602 // typedefs (and document the memory layout of StackMap).
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000603 static constexpr int kRegisterMaskOffset = 0;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100604 static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
605 static constexpr int kStackMaskOffset = kFixedSize;
606
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100607 MemoryRegion region_;
608
Nicolas Geoffray39468442014-09-02 15:17:15 +0100609 friend class CodeInfo;
610 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100611};
612
613
614/**
615 * Wrapper around all compiler information collected for a method.
616 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100617 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100618 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100619class CodeInfo {
620 public:
621 explicit CodeInfo(MemoryRegion region) : region_(region) {}
622
Nicolas Geoffray39468442014-09-02 15:17:15 +0100623 explicit CodeInfo(const void* data) {
624 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
625 region_ = MemoryRegion(const_cast<void*>(data), size);
626 }
627
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000628 void SetEncoding(size_t inline_info_size,
629 size_t dex_register_map_size,
630 size_t dex_pc_max,
631 size_t native_pc_max) {
632 if (inline_info_size != 0) {
633 region_.StoreBit(kHasInlineInfoBitOffset, 1);
634 region_.StoreBit(kHasSmallInlineInfoBitOffset, IsUint<StackMap::kBitsForSmallEncoding>(
635 // + 1 to also encode kNoInlineInfo: if an inline info offset
636 // is at 0xFF, we want to overflow to a larger encoding, because it will
637 // conflict with kNoInlineInfo.
638 // The offset is relative to the dex register map. TODO: Change this.
639 inline_info_size + dex_register_map_size + 1));
640 } else {
641 region_.StoreBit(kHasInlineInfoBitOffset, 0);
642 region_.StoreBit(kHasSmallInlineInfoBitOffset, 0);
643 }
644 region_.StoreBit(kHasSmallDexRegisterMapBitOffset,
645 // + 1 to also encode kNoDexRegisterMap: if a dex register map offset
646 // is at 0xFF, we want to overflow to a larger encoding, because it will
647 // conflict with kNoDexRegisterMap.
648 IsUint<StackMap::kBitsForSmallEncoding>(dex_register_map_size + 1));
649 region_.StoreBit(kHasSmallDexPcBitOffset, IsUint<StackMap::kBitsForSmallEncoding>(dex_pc_max));
650 region_.StoreBit(kHasSmallNativePcBitOffset,
651 IsUint<StackMap::kBitsForSmallEncoding>(native_pc_max));
652 }
653
654 bool HasInlineInfo() const {
655 return region_.LoadBit(kHasInlineInfoBitOffset);
656 }
657
658 bool HasSmallInlineInfo() const {
659 return region_.LoadBit(kHasSmallInlineInfoBitOffset);
660 }
661
662 bool HasSmallDexRegisterMap() const {
663 return region_.LoadBit(kHasSmallDexRegisterMapBitOffset);
664 }
665
666 bool HasSmallNativePc() const {
667 return region_.LoadBit(kHasSmallNativePcBitOffset);
668 }
669
670 bool HasSmallDexPc() const {
671 return region_.LoadBit(kHasSmallDexPcBitOffset);
672 }
673
674 size_t ComputeStackMapRegisterMaskOffset() const {
675 return StackMap::kRegisterMaskOffset;
676 }
677
678 size_t ComputeStackMapStackMaskOffset() const {
679 return StackMap::kStackMaskOffset;
680 }
681
682 size_t ComputeStackMapDexPcOffset() const {
683 return ComputeStackMapStackMaskOffset() + GetStackMaskSize();
684 }
685
686 size_t ComputeStackMapNativePcOffset() const {
687 return ComputeStackMapDexPcOffset()
688 + (HasSmallDexPc() ? sizeof(uint8_t) : sizeof(uint32_t));
689 }
690
691 size_t ComputeStackMapDexRegisterMapOffset() const {
692 return ComputeStackMapNativePcOffset()
693 + (HasSmallNativePc() ? sizeof(uint8_t) : sizeof(uint32_t));
694 }
695
696 size_t ComputeStackMapInlineInfoOffset() const {
697 CHECK(HasInlineInfo());
698 return ComputeStackMapDexRegisterMapOffset()
699 + (HasSmallDexRegisterMap() ? sizeof(uint8_t) : sizeof(uint32_t));
700 }
701
Nicolas Geoffray39468442014-09-02 15:17:15 +0100702 StackMap GetStackMapAt(size_t i) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100703 size_t size = StackMapSize();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100704 return StackMap(GetStackMaps().Subregion(i * size, size));
705 }
706
707 uint32_t GetOverallSize() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000708 return region_.LoadUnaligned<uint32_t>(kOverallSizeOffset);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100709 }
710
711 void SetOverallSize(uint32_t size) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000712 region_.StoreUnaligned<uint32_t>(kOverallSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100713 }
714
715 uint32_t GetStackMaskSize() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000716 return region_.LoadUnaligned<uint32_t>(kStackMaskSizeOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100717 }
718
719 void SetStackMaskSize(uint32_t size) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000720 region_.StoreUnaligned<uint32_t>(kStackMaskSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100721 }
722
723 size_t GetNumberOfStackMaps() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000724 return region_.LoadUnaligned<uint32_t>(kNumberOfStackMapsOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100725 }
726
727 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000728 region_.StoreUnaligned<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100729 }
730
Roland Levillain29ba1b02015-03-13 11:45:07 +0000731 // Get the size of one stack map of this CodeInfo object, in bytes.
732 // All stack maps of a CodeInfo have the same size.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100733 size_t StackMapSize() const {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000734 return StackMap::ComputeStackMapSize(GetStackMaskSize(),
735 HasInlineInfo(),
736 HasSmallInlineInfo(),
737 HasSmallDexRegisterMap(),
738 HasSmallDexPc(),
739 HasSmallNativePc());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100740 }
741
Roland Levillain29ba1b02015-03-13 11:45:07 +0000742 // Get the size all the stack maps of this CodeInfo object, in bytes.
743 size_t StackMapsSize() const {
744 return StackMapSize() * GetNumberOfStackMaps();
745 }
746
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000747 size_t GetDexRegisterMapsOffset() const {
748 return CodeInfo::kFixedSize + StackMapsSize();
749 }
750
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000751 uint32_t GetStackMapsOffset() const {
752 return kFixedSize;
753 }
754
Roland Levillain442b46a2015-02-18 16:54:21 +0000755 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) const {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000756 DCHECK(stack_map.HasDexRegisterMap(*this));
757 uint32_t offset = stack_map.GetDexRegisterMapOffset(*this) + GetDexRegisterMapsOffset();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000758 size_t size = ComputeDexRegisterMapSize(offset, number_of_dex_registers);
759 return DexRegisterMap(region_.Subregion(offset, size));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100760 }
761
Roland Levillain442b46a2015-02-18 16:54:21 +0000762 InlineInfo GetInlineInfoOf(StackMap stack_map) const {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000763 DCHECK(stack_map.HasInlineInfo(*this));
764 uint32_t offset = stack_map.GetInlineDescriptorOffset(*this) + GetDexRegisterMapsOffset();
765 uint8_t depth = region_.LoadUnaligned<uint8_t>(offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100766 return InlineInfo(region_.Subregion(offset,
767 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
768 }
769
Roland Levillain442b46a2015-02-18 16:54:21 +0000770 StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100771 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100772 StackMap stack_map = GetStackMapAt(i);
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000773 if (stack_map.GetDexPc(*this) == dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100774 return stack_map;
775 }
776 }
777 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700778 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100779 }
780
Roland Levillain442b46a2015-02-18 16:54:21 +0000781 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100782 // TODO: stack maps are sorted by native pc, we can do a binary search.
783 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100784 StackMap stack_map = GetStackMapAt(i);
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000785 if (stack_map.GetNativePcOffset(*this) == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100786 return stack_map;
787 }
788 }
789 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700790 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100791 }
792
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000793 void Dump(std::ostream& os, uint16_t number_of_dex_registers) const;
794 void DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const;
795
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100796 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000797 // TODO: Instead of plain types such as "uint32_t", introduce
798 // typedefs (and document the memory layout of CodeInfo).
Nicolas Geoffray39468442014-09-02 15:17:15 +0100799 static constexpr int kOverallSizeOffset = 0;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000800 static constexpr int kEncodingInfoOffset = kOverallSizeOffset + sizeof(uint32_t);
801 static constexpr int kNumberOfStackMapsOffset = kEncodingInfoOffset + sizeof(uint8_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100802 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
803 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
804
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000805 static constexpr int kHasInlineInfoBitOffset = (kEncodingInfoOffset * kBitsPerByte);
806 static constexpr int kHasSmallInlineInfoBitOffset = kHasInlineInfoBitOffset + 1;
807 static constexpr int kHasSmallDexRegisterMapBitOffset = kHasSmallInlineInfoBitOffset + 1;
808 static constexpr int kHasSmallDexPcBitOffset = kHasSmallDexRegisterMapBitOffset + 1;
809 static constexpr int kHasSmallNativePcBitOffset = kHasSmallDexPcBitOffset + 1;
810
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100811 MemoryRegion GetStackMaps() const {
812 return region_.size() == 0
813 ? MemoryRegion()
Roland Levillain29ba1b02015-03-13 11:45:07 +0000814 : region_.Subregion(kFixedSize, StackMapsSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100815 }
816
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000817 // Compute the size of a Dex register map starting at offset `origin` in
818 // `region_` and containing `number_of_dex_registers` locations.
819 size_t ComputeDexRegisterMapSize(uint32_t origin, uint32_t number_of_dex_registers) const {
820 // TODO: Ideally, we would like to use art::DexRegisterMap::Size or
821 // art::DexRegisterMap::FindLocationOffset, but the DexRegisterMap is not
822 // yet built. Try to factor common code.
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000823 size_t offset =
824 origin + DexRegisterMap::GetDexRegisterMapLocationsOffset(number_of_dex_registers);
825
826 // Create a temporary DexRegisterMap to be able to call DexRegisterMap.IsDexRegisterLive.
827 DexRegisterMap only_live_mask(MemoryRegion(region_.Subregion(origin, offset - origin)));
828
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000829 // Skip the first `number_of_dex_registers - 1` entries.
830 for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000831 if (only_live_mask.IsDexRegisterLive(i)) {
832 // Read the first next byte and inspect its first 3 bits to decide
833 // whether it is a short or a large location.
834 DexRegisterMap::ShortLocation first_byte =
835 region_.LoadUnaligned<DexRegisterMap::ShortLocation>(offset);
836 DexRegisterLocation::Kind kind =
837 DexRegisterMap::ExtractKindFromShortLocation(first_byte);
838 if (DexRegisterLocation::IsShortLocationKind(kind)) {
839 // Short location. Skip the current byte.
840 offset += DexRegisterMap::SingleShortEntrySize();
841 } else {
842 // Large location. Skip the 5 next bytes.
843 offset += DexRegisterMap::SingleLargeEntrySize();
844 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000845 }
846 }
847 size_t size = offset - origin;
848 return size;
849 }
850
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100851 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100852 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100853};
854
855} // namespace art
856
857#endif // ART_RUNTIME_STACK_MAP_H_