blob: 4e420084d17f6582c7bb5e185b485d90f5f15663 [file] [log] [blame]
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_STACK_MAP_H_
18#define ART_RUNTIME_STACK_MAP_H_
19
20#include "base/bit_vector.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010021#include "base/bit_utils.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010022#include "memory_region.h"
23
24namespace art {
25
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.
Roland Levillaina552e1c2015-03-26 15:01:03 +000029static constexpr ssize_t kFrameSlotSize = 4;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000030
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000031// Size of Dex virtual registers.
Roland Levillaina552e1c2015-03-26 15:01:03 +000032static constexpr size_t kVRegSize = 4;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000033
Nicolas Geoffray004c2302015-03-20 10:06:38 +000034class CodeInfo;
David Brazdilf677ebf2015-05-29 16:29:43 +010035class StackMapEncoding;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000036
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
Roland Levillaina2d8ec62015-03-12 15:25:29 +000043// Dex register location container used by DexRegisterMap and StackMapStream.
44class DexRegisterLocation {
45 public:
46 /*
47 * The location kind used to populate the Dex register information in a
48 * StackMapStream can either be:
49 * - kNone: the register has no location yet, meaning it has not been set;
50 * - kConstant: value holds the constant;
51 * - kStack: value holds the stack offset;
52 * - kRegister: value holds the physical register number;
53 * - kFpuRegister: value holds the physical register number.
54 *
55 * In addition, DexRegisterMap also uses these values:
56 * - kInStackLargeOffset: value holds a "large" stack offset (greater than
Roland Levillaina552e1c2015-03-26 15:01:03 +000057 * or equal to 128 bytes);
58 * - kConstantLargeValue: value holds a "large" constant (lower than 0, or
59 * or greater than or equal to 32).
Roland Levillaina2d8ec62015-03-12 15:25:29 +000060 */
61 enum class Kind : uint8_t {
62 // Short location kinds, for entries fitting on one byte (3 bits
63 // for the kind, 5 bits for the value) in a DexRegisterMap.
64 kNone = 0, // 0b000
65 kInStack = 1, // 0b001
66 kInRegister = 2, // 0b010
67 kInFpuRegister = 3, // 0b011
68 kConstant = 4, // 0b100
69
70 // Large location kinds, requiring a 5-byte encoding (1 byte for the
71 // kind, 4 bytes for the value).
72
73 // Stack location at a large offset, meaning that the offset value
74 // divided by the stack frame slot size (4 bytes) cannot fit on a
75 // 5-bit unsigned integer (i.e., this offset value is greater than
76 // or equal to 2^5 * 4 = 128 bytes).
77 kInStackLargeOffset = 5, // 0b101
78
79 // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
Roland Levillaina552e1c2015-03-26 15:01:03 +000080 // lower than 0, or greater than or equal to 2^5 = 32).
Roland Levillaina2d8ec62015-03-12 15:25:29 +000081 kConstantLargeValue = 6, // 0b110
82
83 kLastLocationKind = kConstantLargeValue
84 };
85
86 static_assert(
87 sizeof(Kind) == 1u,
88 "art::DexRegisterLocation::Kind has a size different from one byte.");
89
90 static const char* PrettyDescriptor(Kind kind) {
91 switch (kind) {
92 case Kind::kNone:
93 return "none";
94 case Kind::kInStack:
95 return "in stack";
96 case Kind::kInRegister:
97 return "in register";
98 case Kind::kInFpuRegister:
99 return "in fpu register";
100 case Kind::kConstant:
101 return "as constant";
102 case Kind::kInStackLargeOffset:
103 return "in stack (large offset)";
104 case Kind::kConstantLargeValue:
105 return "as constant (large value)";
106 default:
107 UNREACHABLE();
108 }
109 }
110
111 static bool IsShortLocationKind(Kind kind) {
112 switch (kind) {
113 case Kind::kNone:
114 case Kind::kInStack:
115 case Kind::kInRegister:
116 case Kind::kInFpuRegister:
117 case Kind::kConstant:
118 return true;
119
120 case Kind::kInStackLargeOffset:
121 case Kind::kConstantLargeValue:
122 return false;
123
124 default:
125 UNREACHABLE();
126 }
127 }
128
129 // Convert `kind` to a "surface" kind, i.e. one that doesn't include
130 // any value with a "large" qualifier.
131 // TODO: Introduce another enum type for the surface kind?
132 static Kind ConvertToSurfaceKind(Kind kind) {
133 switch (kind) {
134 case Kind::kNone:
135 case Kind::kInStack:
136 case Kind::kInRegister:
137 case Kind::kInFpuRegister:
138 case Kind::kConstant:
139 return kind;
140
141 case Kind::kInStackLargeOffset:
142 return Kind::kInStack;
143
144 case Kind::kConstantLargeValue:
145 return Kind::kConstant;
146
147 default:
148 UNREACHABLE();
149 }
150 }
151
Roland Levillaina552e1c2015-03-26 15:01:03 +0000152 // Required by art::StackMapStream::LocationCatalogEntriesIndices.
153 DexRegisterLocation() : kind_(Kind::kNone), value_(0) {}
154
155 DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {}
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000156
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000157 static DexRegisterLocation None() {
158 return DexRegisterLocation(Kind::kNone, 0);
159 }
160
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000161 // Get the "surface" kind of the location, i.e., the one that doesn't
162 // include any value with a "large" qualifier.
163 Kind GetKind() const {
164 return ConvertToSurfaceKind(kind_);
165 }
166
167 // Get the value of the location.
168 int32_t GetValue() const { return value_; }
169
170 // Get the actual kind of the location.
171 Kind GetInternalKind() const { return kind_; }
172
Calin Juravle6ae70962015-03-18 16:31:28 +0000173 bool operator==(DexRegisterLocation other) const {
174 return kind_ == other.kind_ && value_ == other.value_;
175 }
176
177 bool operator!=(DexRegisterLocation other) const {
178 return !(*this == other);
179 }
180
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000181 private:
182 Kind kind_;
183 int32_t value_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000184
185 friend class DexRegisterLocationHashFn;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000186};
187
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100188/**
Roland Levillaina552e1c2015-03-26 15:01:03 +0000189 * Store information on unique Dex register locations used in a method.
190 * The information is of the form:
191 * [DexRegisterLocation+].
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000192 * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100193 */
Roland Levillaina552e1c2015-03-26 15:01:03 +0000194class DexRegisterLocationCatalog {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100195 public:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000196 explicit DexRegisterLocationCatalog(MemoryRegion region) : region_(region) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100197
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000198 // Short (compressed) location, fitting on one byte.
199 typedef uint8_t ShortLocation;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100200
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000201 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
202 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
203 int32_t value = dex_register_location.GetValue();
204 if (DexRegisterLocation::IsShortLocationKind(kind)) {
205 // Short location. Compress the kind and the value as a single byte.
206 if (kind == DexRegisterLocation::Kind::kInStack) {
207 // Instead of storing stack offsets expressed in bytes for
208 // short stack locations, store slot offsets. A stack offset
209 // is a multiple of 4 (kFrameSlotSize). This means that by
210 // dividing it by 4, we can fit values from the [0, 128)
211 // interval in a short stack location, and not just values
212 // from the [0, 32) interval.
213 DCHECK_EQ(value % kFrameSlotSize, 0);
214 value /= kFrameSlotSize;
215 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000216 DCHECK(IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000217 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
218 } else {
219 // Large location. Write the location on one byte and the value
220 // on 4 bytes.
Roland Levillaina552e1c2015-03-26 15:01:03 +0000221 DCHECK(!IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000222 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
223 // Also divide large stack offsets by 4 for the sake of consistency.
224 DCHECK_EQ(value % kFrameSlotSize, 0);
225 value /= kFrameSlotSize;
226 }
227 // Data can be unaligned as the written Dex register locations can
228 // either be 1-byte or 5-byte wide. Use
229 // art::MemoryRegion::StoreUnaligned instead of
230 // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
231 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
232 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
Roland Levillain442b46a2015-02-18 16:54:21 +0000233 }
234 }
235
Roland Levillaina552e1c2015-03-26 15:01:03 +0000236 // Find the offset of the location catalog entry number `location_catalog_entry_index`.
237 size_t FindLocationOffset(size_t location_catalog_entry_index) const {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000238 size_t offset = kFixedSize;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000239 // Skip the first `location_catalog_entry_index - 1` entries.
240 for (uint16_t i = 0; i < location_catalog_entry_index; ++i) {
241 // Read the first next byte and inspect its first 3 bits to decide
242 // whether it is a short or a large location.
243 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
244 if (DexRegisterLocation::IsShortLocationKind(kind)) {
245 // Short location. Skip the current byte.
246 offset += SingleShortEntrySize();
247 } else {
248 // Large location. Skip the 5 next bytes.
249 offset += SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000250 }
251 }
252 return offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100253 }
254
Roland Levillaina552e1c2015-03-26 15:01:03 +0000255 // Get the internal kind of entry at `location_catalog_entry_index`.
256 DexRegisterLocation::Kind GetLocationInternalKind(size_t location_catalog_entry_index) const {
257 if (location_catalog_entry_index == kNoLocationEntryIndex) {
258 return DexRegisterLocation::Kind::kNone;
259 }
260 return ExtractKindAtOffset(FindLocationOffset(location_catalog_entry_index));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100261 }
262
Roland Levillaina552e1c2015-03-26 15:01:03 +0000263 // Get the (surface) kind and value of entry at `location_catalog_entry_index`.
264 DexRegisterLocation GetDexRegisterLocation(size_t location_catalog_entry_index) const {
265 if (location_catalog_entry_index == kNoLocationEntryIndex) {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000266 return DexRegisterLocation::None();
267 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000268 size_t offset = FindLocationOffset(location_catalog_entry_index);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000269 // Read the first byte and inspect its first 3 bits to get the location.
270 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
271 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
272 if (DexRegisterLocation::IsShortLocationKind(kind)) {
273 // Short location. Extract the value from the remaining 5 bits.
274 int32_t value = ExtractValueFromShortLocation(first_byte);
275 if (kind == DexRegisterLocation::Kind::kInStack) {
276 // Convert the stack slot (short) offset to a byte offset value.
277 value *= kFrameSlotSize;
278 }
279 return DexRegisterLocation(kind, value);
280 } else {
281 // Large location. Read the four next bytes to get the value.
282 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
283 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
284 // Convert the stack slot (large) offset to a byte offset value.
285 value *= kFrameSlotSize;
286 }
287 return DexRegisterLocation(kind, value);
288 }
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100289 }
290
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000291 // Compute the compressed kind of `location`.
292 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
293 switch (location.GetInternalKind()) {
294 case DexRegisterLocation::Kind::kNone:
295 DCHECK_EQ(location.GetValue(), 0);
296 return DexRegisterLocation::Kind::kNone;
297
298 case DexRegisterLocation::Kind::kInRegister:
299 DCHECK_GE(location.GetValue(), 0);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000300 DCHECK_LT(location.GetValue(), 1 << kValueBits);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000301 return DexRegisterLocation::Kind::kInRegister;
302
303 case DexRegisterLocation::Kind::kInFpuRegister:
304 DCHECK_GE(location.GetValue(), 0);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000305 DCHECK_LT(location.GetValue(), 1 << kValueBits);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000306 return DexRegisterLocation::Kind::kInFpuRegister;
307
308 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000309 return IsShortStackOffsetValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000310 ? DexRegisterLocation::Kind::kInStack
311 : DexRegisterLocation::Kind::kInStackLargeOffset;
312
313 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000314 return IsShortConstantValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000315 ? DexRegisterLocation::Kind::kConstant
316 : DexRegisterLocation::Kind::kConstantLargeValue;
317
318 default:
319 LOG(FATAL) << "Unexpected location kind"
320 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
321 UNREACHABLE();
322 }
323 }
324
325 // Can `location` be turned into a short location?
326 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
327 switch (location.GetInternalKind()) {
328 case DexRegisterLocation::Kind::kNone:
329 case DexRegisterLocation::Kind::kInRegister:
330 case DexRegisterLocation::Kind::kInFpuRegister:
331 return true;
332
333 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000334 return IsShortStackOffsetValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000335
336 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000337 return IsShortConstantValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000338
339 default:
340 UNREACHABLE();
341 }
342 }
343
344 static size_t EntrySize(const DexRegisterLocation& location) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000345 return CanBeEncodedAsShortLocation(location) ? SingleShortEntrySize() : SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000346 }
347
348 static size_t SingleShortEntrySize() {
349 return sizeof(ShortLocation);
350 }
351
352 static size_t SingleLargeEntrySize() {
353 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100354 }
355
Roland Levillain12baf472015-03-05 12:41:42 +0000356 size_t Size() const {
357 return region_.size();
358 }
359
Roland Levillain0396ed72015-05-27 15:12:19 +0100360 void Dump(std::ostream& os, const CodeInfo& code_info);
361
Roland Levillaina552e1c2015-03-26 15:01:03 +0000362 // Special (invalid) Dex register location catalog entry index meaning
363 // that there is no location for a given Dex register (i.e., it is
364 // mapped to a DexRegisterLocation::Kind::kNone location).
365 static constexpr size_t kNoLocationEntryIndex = -1;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100366
Roland Levillain12baf472015-03-05 12:41:42 +0000367 private:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000368 static constexpr int kFixedSize = 0;
369
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000370 // Width of the kind "field" in a short location, in bits.
371 static constexpr size_t kKindBits = 3;
372 // Width of the value "field" in a short location, in bits.
373 static constexpr size_t kValueBits = 5;
374
375 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
376 static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
377 static constexpr size_t kKindOffset = 0;
378 static constexpr size_t kValueOffset = kKindBits;
379
Roland Levillaina552e1c2015-03-26 15:01:03 +0000380 static bool IsShortStackOffsetValue(int32_t value) {
381 DCHECK_EQ(value % kFrameSlotSize, 0);
382 return IsShortValue(value / kFrameSlotSize);
383 }
384
385 static bool IsShortConstantValue(int32_t value) {
386 return IsShortValue(value);
387 }
388
389 static bool IsShortValue(int32_t value) {
390 return IsUint<kValueBits>(value);
391 }
392
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000393 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000394 uint8_t kind_integer_value = static_cast<uint8_t>(kind);
395 DCHECK(IsUint<kKindBits>(kind_integer_value)) << kind_integer_value;
396 DCHECK(IsShortValue(value)) << value;
397 return (kind_integer_value & kKindMask) << kKindOffset
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000398 | (value & kValueMask) << kValueOffset;
399 }
400
401 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
402 uint8_t kind = (location >> kKindOffset) & kKindMask;
403 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000404 // We do not encode kNone locations in the stack map.
405 DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone));
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000406 return static_cast<DexRegisterLocation::Kind>(kind);
407 }
408
409 static int32_t ExtractValueFromShortLocation(ShortLocation location) {
410 return (location >> kValueOffset) & kValueMask;
411 }
412
413 // Extract a location kind from the byte at position `offset`.
414 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
415 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
416 return ExtractKindFromShortLocation(first_byte);
417 }
418
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100419 MemoryRegion region_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000420
421 friend class CodeInfo;
422 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100423};
424
Roland Levillaina552e1c2015-03-26 15:01:03 +0000425/* Information on Dex register locations for a specific PC, mapping a
426 * stack map's Dex register to a location entry in a DexRegisterLocationCatalog.
427 * The information is of the form:
428 * [live_bit_mask, entries*]
429 * where entries are concatenated unsigned integer values encoded on a number
430 * of bits (fixed per DexRegisterMap instances of a CodeInfo object) depending
431 * on the number of entries in the Dex register location catalog
432 * (see DexRegisterMap::SingleEntrySizeInBits). The map is 1-byte aligned.
433 */
434class DexRegisterMap {
435 public:
436 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
437
438 // Get the surface kind of Dex register `dex_register_number`.
439 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number,
440 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100441 const CodeInfo& code_info,
442 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000443 return DexRegisterLocation::ConvertToSurfaceKind(
David Brazdilf677ebf2015-05-29 16:29:43 +0100444 GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info, enc));
Roland Levillaina552e1c2015-03-26 15:01:03 +0000445 }
446
447 // Get the internal kind of Dex register `dex_register_number`.
448 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number,
449 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100450 const CodeInfo& code_info,
451 const StackMapEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000452
453 // Get the Dex register location `dex_register_number`.
454 DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number,
455 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100456 const CodeInfo& code_info,
457 const StackMapEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000458
459 int32_t GetStackOffsetInBytes(uint16_t dex_register_number,
460 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100461 const CodeInfo& code_info,
462 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000463 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100464 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000465 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
466 // GetDexRegisterLocation returns the offset in bytes.
467 return location.GetValue();
468 }
469
470 int32_t GetConstant(uint16_t dex_register_number,
471 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100472 const CodeInfo& code_info,
473 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000474 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100475 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100476 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant)
477 << DexRegisterLocation::PrettyDescriptor(location.GetKind());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000478 return location.GetValue();
479 }
480
481 int32_t GetMachineRegister(uint16_t dex_register_number,
482 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100483 const CodeInfo& code_info,
484 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000485 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100486 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000487 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister
488 || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister)
489 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
490 return location.GetValue();
491 }
492
493 // Get the index of the entry in the Dex register location catalog
494 // corresponding to `dex_register_number`.
495 size_t GetLocationCatalogEntryIndex(uint16_t dex_register_number,
496 uint16_t number_of_dex_registers,
497 size_t number_of_location_catalog_entries) const {
498 if (!IsDexRegisterLive(dex_register_number)) {
499 return DexRegisterLocationCatalog::kNoLocationEntryIndex;
500 }
501
502 if (number_of_location_catalog_entries == 1) {
503 // We do not allocate space for location maps in the case of a
504 // single-entry location catalog, as it is useless. The only valid
505 // entry index is 0;
506 return 0;
507 }
508
509 // The bit offset of the beginning of the map locations.
510 size_t map_locations_offset_in_bits =
511 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
512 size_t index_in_dex_register_map = GetIndexInDexRegisterMap(dex_register_number);
513 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
514 // The bit size of an entry.
515 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
516 // The bit offset where `index_in_dex_register_map` is located.
517 size_t entry_offset_in_bits =
518 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
519 size_t location_catalog_entry_index =
520 region_.LoadBits(entry_offset_in_bits, map_entry_size_in_bits);
521 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
522 return location_catalog_entry_index;
523 }
524
525 // Map entry at `index_in_dex_register_map` to `location_catalog_entry_index`.
526 void SetLocationCatalogEntryIndex(size_t index_in_dex_register_map,
527 size_t location_catalog_entry_index,
528 uint16_t number_of_dex_registers,
529 size_t number_of_location_catalog_entries) {
530 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
531 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
532
533 if (number_of_location_catalog_entries == 1) {
534 // We do not allocate space for location maps in the case of a
535 // single-entry location catalog, as it is useless.
536 return;
537 }
538
539 // The bit offset of the beginning of the map locations.
540 size_t map_locations_offset_in_bits =
541 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
542 // The bit size of an entry.
543 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
544 // The bit offset where `index_in_dex_register_map` is located.
545 size_t entry_offset_in_bits =
546 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
547 region_.StoreBits(entry_offset_in_bits, location_catalog_entry_index, map_entry_size_in_bits);
548 }
549
550 void SetLiveBitMask(uint16_t number_of_dex_registers,
551 const BitVector& live_dex_registers_mask) {
552 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
553 for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
554 region_.StoreBit(live_bit_mask_offset_in_bits + i, live_dex_registers_mask.IsBitSet(i));
555 }
556 }
557
558 bool IsDexRegisterLive(uint16_t dex_register_number) const {
559 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
560 return region_.LoadBit(live_bit_mask_offset_in_bits + dex_register_number);
561 }
562
563 size_t GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers) const {
564 size_t number_of_live_dex_registers = 0;
565 for (size_t i = 0; i < number_of_dex_registers; ++i) {
566 if (IsDexRegisterLive(i)) {
567 ++number_of_live_dex_registers;
568 }
569 }
570 return number_of_live_dex_registers;
571 }
572
573 static size_t GetLiveBitMaskOffset() {
574 return kFixedSize;
575 }
576
577 // Compute the size of the live register bit mask (in bytes), for a
578 // method having `number_of_dex_registers` Dex registers.
579 static size_t GetLiveBitMaskSize(uint16_t number_of_dex_registers) {
580 return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte;
581 }
582
583 static size_t GetLocationMappingDataOffset(uint16_t number_of_dex_registers) {
584 return GetLiveBitMaskOffset() + GetLiveBitMaskSize(number_of_dex_registers);
585 }
586
587 size_t GetLocationMappingDataSize(uint16_t number_of_dex_registers,
588 size_t number_of_location_catalog_entries) const {
589 size_t location_mapping_data_size_in_bits =
590 GetNumberOfLiveDexRegisters(number_of_dex_registers)
591 * SingleEntrySizeInBits(number_of_location_catalog_entries);
592 return RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
593 }
594
595 // Return the size of a map entry in bits. Note that if
596 // `number_of_location_catalog_entries` equals 1, this function returns 0,
597 // which is fine, as there is no need to allocate a map for a
598 // single-entry location catalog; the only valid location catalog entry index
599 // for a live register in this case is 0 and there is no need to
600 // store it.
601 static size_t SingleEntrySizeInBits(size_t number_of_location_catalog_entries) {
602 // Handle the case of 0, as we cannot pass 0 to art::WhichPowerOf2.
603 return number_of_location_catalog_entries == 0
604 ? 0u
605 : WhichPowerOf2(RoundUpToPowerOfTwo(number_of_location_catalog_entries));
606 }
607
608 // Return the size of the DexRegisterMap object, in bytes.
609 size_t Size() const {
610 return region_.size();
611 }
612
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100613 void Dump(std::ostream& o, const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
614
Roland Levillaina552e1c2015-03-26 15:01:03 +0000615 private:
616 // Return the index in the Dex register map corresponding to the Dex
617 // register number `dex_register_number`.
618 size_t GetIndexInDexRegisterMap(uint16_t dex_register_number) const {
619 if (!IsDexRegisterLive(dex_register_number)) {
620 return kInvalidIndexInDexRegisterMap;
621 }
622 return GetNumberOfLiveDexRegisters(dex_register_number);
623 }
624
625 // Special (invalid) Dex register map entry index meaning that there
626 // is no index in the map for a given Dex register (i.e., it must
627 // have been mapped to a DexRegisterLocation::Kind::kNone location).
628 static constexpr size_t kInvalidIndexInDexRegisterMap = -1;
629
630 static constexpr int kFixedSize = 0;
631
632 MemoryRegion region_;
633
634 friend class CodeInfo;
635 friend class StackMapStream;
636};
637
David Brazdilf677ebf2015-05-29 16:29:43 +0100638class StackMapEncoding {
639 public:
640 StackMapEncoding() {}
641
642 StackMapEncoding(size_t stack_mask_size,
643 size_t bytes_for_inline_info,
644 size_t bytes_for_dex_register_map,
645 size_t bytes_for_dex_pc,
646 size_t bytes_for_native_pc,
647 size_t bytes_for_register_mask)
648 : bytes_for_stack_mask_(stack_mask_size),
649 bytes_for_inline_info_(bytes_for_inline_info),
650 bytes_for_dex_register_map_(bytes_for_dex_register_map),
651 bytes_for_dex_pc_(bytes_for_dex_pc),
652 bytes_for_native_pc_(bytes_for_native_pc),
653 bytes_for_register_mask_(bytes_for_register_mask) {}
654
655 static StackMapEncoding CreateFromSizes(size_t stack_mask_size,
656 size_t inline_info_size,
657 size_t dex_register_map_size,
658 size_t dex_pc_max,
659 size_t native_pc_max,
660 size_t register_mask_max) {
661 return StackMapEncoding(
662 stack_mask_size,
663 // + 1 to also encode kNoInlineInfo: if an inline info offset
664 // is at 0xFF, we want to overflow to a larger encoding, because it will
665 // conflict with kNoInlineInfo.
666 // The offset is relative to the dex register map. TODO: Change this.
667 inline_info_size == 0
668 ? 0
669 : EncodingSizeInBytes(dex_register_map_size + inline_info_size + 1),
670 // + 1 to also encode kNoDexRegisterMap: if a dex register map offset
671 // is at 0xFF, we want to overflow to a larger encoding, because it will
672 // conflict with kNoDexRegisterMap.
673 EncodingSizeInBytes(dex_register_map_size + 1),
674 EncodingSizeInBytes(dex_pc_max),
675 EncodingSizeInBytes(native_pc_max),
676 EncodingSizeInBytes(register_mask_max));
677 }
678
679 // Get the size of one stack map of this CodeInfo object, in bytes.
680 // All stack maps of a CodeInfo have the same size.
681 size_t ComputeStackMapSize() const {
682 return bytes_for_register_mask_
683 + bytes_for_stack_mask_
684 + bytes_for_inline_info_
685 + bytes_for_dex_register_map_
686 + bytes_for_dex_pc_
687 + bytes_for_native_pc_;
688 }
689
690 bool HasInlineInfo() const { return bytes_for_inline_info_ > 0; }
691
692 size_t NumberOfBytesForStackMask() const { return bytes_for_stack_mask_; }
693 size_t NumberOfBytesForInlineInfo() const { return bytes_for_inline_info_; }
694 size_t NumberOfBytesForDexRegisterMap() const { return bytes_for_dex_register_map_; }
695 size_t NumberOfBytesForDexPc() const { return bytes_for_dex_pc_; }
696 size_t NumberOfBytesForNativePc() const { return bytes_for_native_pc_; }
697 size_t NumberOfBytesForRegisterMask() const { return bytes_for_register_mask_; }
698
699 size_t ComputeStackMapRegisterMaskOffset() const {
700 return kRegisterMaskOffset;
701 }
702
703 size_t ComputeStackMapStackMaskOffset() const {
704 return ComputeStackMapRegisterMaskOffset() + bytes_for_register_mask_;
705 }
706
707 size_t ComputeStackMapDexPcOffset() const {
708 return ComputeStackMapStackMaskOffset() + bytes_for_stack_mask_;
709 }
710
711 size_t ComputeStackMapNativePcOffset() const {
712 return ComputeStackMapDexPcOffset() + bytes_for_dex_pc_;
713 }
714
715 size_t ComputeStackMapDexRegisterMapOffset() const {
716 return ComputeStackMapNativePcOffset() + bytes_for_native_pc_;
717 }
718
719 size_t ComputeStackMapInlineInfoOffset() const {
720 return ComputeStackMapDexRegisterMapOffset() + bytes_for_dex_register_map_;
721 }
722
723 private:
724 static size_t EncodingSizeInBytes(size_t max_element) {
725 DCHECK(IsUint<32>(max_element));
726 return (max_element == 0) ? 0
727 : IsUint<8>(max_element) ? 1
728 : IsUint<16>(max_element) ? 2
729 : IsUint<24>(max_element) ? 3
730 : 4;
731 }
732
733 static constexpr int kRegisterMaskOffset = 0;
734
735 size_t bytes_for_stack_mask_;
736 size_t bytes_for_inline_info_;
737 size_t bytes_for_dex_register_map_;
738 size_t bytes_for_dex_pc_;
739 size_t bytes_for_native_pc_;
740 size_t bytes_for_register_mask_;
741};
742
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100743/**
744 * A Stack Map holds compilation information for a specific PC necessary for:
745 * - Mapping it to a dex PC,
746 * - Knowing which stack entries are objects,
747 * - Knowing which registers hold objects,
748 * - Knowing the inlining information,
749 * - Knowing the values of dex registers.
750 *
751 * The information is of the form:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000752 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask,
753 * stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100754 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100755class StackMap {
756 public:
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100757 StackMap() {}
David Brazdilf677ebf2015-05-29 16:29:43 +0100758 explicit StackMap(MemoryRegion region) : region_(region) {}
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100759
760 bool IsValid() const { return region_.pointer() != nullptr; }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100761
David Brazdilf677ebf2015-05-29 16:29:43 +0100762 uint32_t GetDexPc(const StackMapEncoding& encoding) const {
763 return LoadAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset());
764 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100765
David Brazdilf677ebf2015-05-29 16:29:43 +0100766 void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) {
767 StoreAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset(), dex_pc);
768 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100769
David Brazdilf677ebf2015-05-29 16:29:43 +0100770 uint32_t GetNativePcOffset(const StackMapEncoding& encoding) const {
771 return LoadAt(encoding.NumberOfBytesForNativePc(), encoding.ComputeStackMapNativePcOffset());
772 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100773
David Brazdilf677ebf2015-05-29 16:29:43 +0100774 void SetNativePcOffset(const StackMapEncoding& encoding, uint32_t native_pc_offset) {
775 StoreAt(encoding.NumberOfBytesForNativePc(),
776 encoding.ComputeStackMapNativePcOffset(),
777 native_pc_offset);
778 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100779
David Brazdilf677ebf2015-05-29 16:29:43 +0100780 uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const {
781 return LoadAt(encoding.NumberOfBytesForDexRegisterMap(),
782 encoding.ComputeStackMapDexRegisterMapOffset(),
783 /* check_max */ true);
784 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100785
David Brazdilf677ebf2015-05-29 16:29:43 +0100786 void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) {
787 StoreAt(encoding.NumberOfBytesForDexRegisterMap(),
788 encoding.ComputeStackMapDexRegisterMapOffset(),
789 offset);
790 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100791
David Brazdilf677ebf2015-05-29 16:29:43 +0100792 uint32_t GetInlineDescriptorOffset(const StackMapEncoding& encoding) const {
793 if (!encoding.HasInlineInfo()) return kNoInlineInfo;
794 return LoadAt(encoding.NumberOfBytesForInlineInfo(),
795 encoding.ComputeStackMapInlineInfoOffset(),
796 /* check_max */ true);
797 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100798
David Brazdilf677ebf2015-05-29 16:29:43 +0100799 void SetInlineDescriptorOffset(const StackMapEncoding& encoding, uint32_t offset) {
800 DCHECK(encoding.HasInlineInfo());
801 StoreAt(encoding.NumberOfBytesForInlineInfo(),
802 encoding.ComputeStackMapInlineInfoOffset(),
803 offset);
804 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100805
David Brazdilf677ebf2015-05-29 16:29:43 +0100806 uint32_t GetRegisterMask(const StackMapEncoding& encoding) const {
807 return LoadAt(encoding.NumberOfBytesForRegisterMask(),
808 encoding.ComputeStackMapRegisterMaskOffset());
809 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100810
David Brazdilf677ebf2015-05-29 16:29:43 +0100811 void SetRegisterMask(const StackMapEncoding& encoding, uint32_t mask) {
812 StoreAt(encoding.NumberOfBytesForRegisterMask(),
813 encoding.ComputeStackMapRegisterMaskOffset(),
814 mask);
815 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100816
David Brazdilf677ebf2015-05-29 16:29:43 +0100817 MemoryRegion GetStackMask(const StackMapEncoding& encoding) const {
818 return region_.Subregion(encoding.ComputeStackMapStackMaskOffset(),
819 encoding.NumberOfBytesForStackMask());
820 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100821
David Brazdilf677ebf2015-05-29 16:29:43 +0100822 void SetStackMask(const StackMapEncoding& encoding, const BitVector& sp_map) {
823 MemoryRegion region = GetStackMask(encoding);
David Brazdilf10a25f2015-06-02 14:29:52 +0100824 sp_map.CopyTo(region.start(), region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100825 }
826
David Brazdilf677ebf2015-05-29 16:29:43 +0100827 bool HasDexRegisterMap(const StackMapEncoding& encoding) const {
828 return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100829 }
830
David Brazdilf677ebf2015-05-29 16:29:43 +0100831 bool HasInlineInfo(const StackMapEncoding& encoding) const {
832 return GetInlineDescriptorOffset(encoding) != kNoInlineInfo;
Roland Levillain442b46a2015-02-18 16:54:21 +0000833 }
834
835 bool Equals(const StackMap& other) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100836 return region_.pointer() == other.region_.pointer()
837 && region_.size() == other.region_.size();
838 }
839
Roland Levillainf2650d12015-05-28 14:53:28 +0100840 void Dump(std::ostream& os,
841 const CodeInfo& code_info,
David Brazdilf677ebf2015-05-29 16:29:43 +0100842 const StackMapEncoding& encoding,
Roland Levillainf2650d12015-05-28 14:53:28 +0100843 uint32_t code_offset,
844 uint16_t number_of_dex_registers,
845 const std::string& header_suffix = "") const;
846
Roland Levillain442b46a2015-02-18 16:54:21 +0000847 // Special (invalid) offset for the DexRegisterMapOffset field meaning
848 // that there is no Dex register map for this stack map.
849 static constexpr uint32_t kNoDexRegisterMap = -1;
850
851 // Special (invalid) offset for the InlineDescriptorOffset field meaning
852 // that there is no inline info for this stack map.
853 static constexpr uint32_t kNoInlineInfo = -1;
854
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100855 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000856 // TODO: Instead of plain types such as "uint32_t", introduce
857 // typedefs (and document the memory layout of StackMap).
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100858 static constexpr int kFixedSize = 0;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100859
David Brazdilf677ebf2015-05-29 16:29:43 +0100860 // Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true,
861 // this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF.
862 uint32_t LoadAt(size_t number_of_bytes, size_t offset, bool check_max = false) const;
863 void StoreAt(size_t number_of_bytes, size_t offset, uint32_t value) const;
864
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100865 MemoryRegion region_;
866
Nicolas Geoffray39468442014-09-02 15:17:15 +0100867 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100868};
869
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100870/**
871 * Inline information for a specific PC. The information is of the form:
872 * [inlining_depth, [dex_pc, method_index, dex_register_map_offset]+]
873 */
874class InlineInfo {
875 public:
876 explicit InlineInfo(MemoryRegion region) : region_(region) {}
877
878 uint8_t GetDepth() const {
879 return region_.LoadUnaligned<uint8_t>(kDepthOffset);
880 }
881
882 void SetDepth(uint8_t depth) {
883 region_.StoreUnaligned<uint8_t>(kDepthOffset, depth);
884 }
885
886 uint32_t GetMethodIndexAtDepth(uint8_t depth) const {
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100887 return region_.LoadUnaligned<uint32_t>(
888 kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100889 }
890
891 void SetMethodIndexAtDepth(uint8_t depth, uint32_t index) {
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100892 region_.StoreUnaligned<uint32_t>(
893 kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset, index);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100894 }
895
896 uint32_t GetDexPcAtDepth(uint8_t depth) const {
897 return region_.LoadUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100898 kFixedSize + depth * SingleEntrySize() + kDexPcOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100899 }
900
901 void SetDexPcAtDepth(uint8_t depth, uint32_t dex_pc) {
902 region_.StoreUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100903 kFixedSize + depth * SingleEntrySize() + kDexPcOffset, dex_pc);
904 }
905
906 uint8_t GetInvokeTypeAtDepth(uint8_t depth) const {
907 return region_.LoadUnaligned<uint8_t>(
908 kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset);
909 }
910
911 void SetInvokeTypeAtDepth(uint8_t depth, uint8_t invoke_type) {
912 region_.StoreUnaligned<uint8_t>(
913 kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset, invoke_type);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100914 }
915
916 uint32_t GetDexRegisterMapOffsetAtDepth(uint8_t depth) const {
917 return region_.LoadUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100918 kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100919 }
920
921 void SetDexRegisterMapOffsetAtDepth(uint8_t depth, uint32_t offset) {
922 region_.StoreUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100923 kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset, offset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100924 }
925
926 bool HasDexRegisterMapAtDepth(uint8_t depth) const {
927 return GetDexRegisterMapOffsetAtDepth(depth) != StackMap::kNoDexRegisterMap;
928 }
929
930 static size_t SingleEntrySize() {
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100931 return kFixedEntrySize;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100932 }
933
934 void Dump(std::ostream& os, const CodeInfo& info, uint16_t* number_of_dex_registers) const;
935
936 private:
937 // TODO: Instead of plain types such as "uint8_t", introduce
938 // typedefs (and document the memory layout of InlineInfo).
939 static constexpr int kDepthOffset = 0;
940 static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
941
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100942 static constexpr int kMethodIndexOffset = 0;
943 static constexpr int kDexPcOffset = kMethodIndexOffset + sizeof(uint32_t);
944 static constexpr int kInvokeTypeOffset = kDexPcOffset + sizeof(uint32_t);
945 static constexpr int kDexRegisterMapOffset = kInvokeTypeOffset + sizeof(uint8_t);
946 static constexpr int kFixedEntrySize = kDexRegisterMapOffset + sizeof(uint32_t);
947
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100948 MemoryRegion region_;
949
950 friend class CodeInfo;
951 friend class StackMap;
952 friend class StackMapStream;
953};
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100954
955/**
956 * Wrapper around all compiler information collected for a method.
957 * The information is of the form:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000958 * [overall_size, number_of_location_catalog_entries, number_of_stack_maps, stack_mask_size,
959 * DexRegisterLocationCatalog+, StackMap+, DexRegisterMap+, InlineInfo*].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100960 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100961class CodeInfo {
962 public:
963 explicit CodeInfo(MemoryRegion region) : region_(region) {}
964
Nicolas Geoffray39468442014-09-02 15:17:15 +0100965 explicit CodeInfo(const void* data) {
966 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
967 region_ = MemoryRegion(const_cast<void*>(data), size);
968 }
969
David Brazdilf677ebf2015-05-29 16:29:43 +0100970 StackMapEncoding ExtractEncoding() const {
971 return StackMapEncoding(region_.LoadUnaligned<uint32_t>(kStackMaskSizeOffset),
972 GetNumberOfBytesForEncoding(kInlineInfoBitOffset),
973 GetNumberOfBytesForEncoding(kDexRegisterMapBitOffset),
974 GetNumberOfBytesForEncoding(kDexPcBitOffset),
975 GetNumberOfBytesForEncoding(kNativePcBitOffset),
976 GetNumberOfBytesForEncoding(kRegisterMaskBitOffset));
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100977 }
978
David Brazdilf677ebf2015-05-29 16:29:43 +0100979 void SetEncoding(const StackMapEncoding& encoding) {
980 region_.StoreUnaligned<uint32_t>(kStackMaskSizeOffset, encoding.NumberOfBytesForStackMask());
981 region_.StoreBit(kHasInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo() != 0);
982 SetEncodingAt(kInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo());
983 SetEncodingAt(kDexRegisterMapBitOffset, encoding.NumberOfBytesForDexRegisterMap());
984 SetEncodingAt(kDexPcBitOffset, encoding.NumberOfBytesForDexPc());
985 SetEncodingAt(kNativePcBitOffset, encoding.NumberOfBytesForNativePc());
986 SetEncodingAt(kRegisterMaskBitOffset, encoding.NumberOfBytesForRegisterMask());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100987 }
988
989 void SetEncodingAt(size_t bit_offset, size_t number_of_bytes) {
990 // We encode the number of bytes needed for writing a value on 3 bits,
991 // for values that we know are maximum 32bits.
992 region_.StoreBit(bit_offset, (number_of_bytes & 1));
993 region_.StoreBit(bit_offset + 1, (number_of_bytes & 2));
994 region_.StoreBit(bit_offset + 2, (number_of_bytes & 4));
995 }
996
997 size_t GetNumberOfBytesForEncoding(size_t bit_offset) const {
998 return region_.LoadBit(bit_offset)
999 + (region_.LoadBit(bit_offset + 1) << 1)
1000 + (region_.LoadBit(bit_offset + 2) << 2);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001001 }
1002
1003 bool HasInlineInfo() const {
1004 return region_.LoadBit(kHasInlineInfoBitOffset);
1005 }
1006
David Brazdilf677ebf2015-05-29 16:29:43 +01001007 DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const StackMapEncoding& encoding) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +00001008 return DexRegisterLocationCatalog(region_.Subregion(
David Brazdilf677ebf2015-05-29 16:29:43 +01001009 GetDexRegisterLocationCatalogOffset(encoding),
1010 GetDexRegisterLocationCatalogSize(encoding)));
Roland Levillaina552e1c2015-03-26 15:01:03 +00001011 }
1012
David Brazdilf677ebf2015-05-29 16:29:43 +01001013 StackMap GetStackMapAt(size_t i, const StackMapEncoding& encoding) const {
1014 size_t stack_map_size = encoding.ComputeStackMapSize();
1015 return StackMap(GetStackMaps(encoding).Subregion(i * stack_map_size, stack_map_size));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001016 }
1017
1018 uint32_t GetOverallSize() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001019 return region_.LoadUnaligned<uint32_t>(kOverallSizeOffset);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001020 }
1021
1022 void SetOverallSize(uint32_t size) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001023 region_.StoreUnaligned<uint32_t>(kOverallSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001024 }
1025
Roland Levillaina552e1c2015-03-26 15:01:03 +00001026 uint32_t GetNumberOfDexRegisterLocationCatalogEntries() const {
1027 return region_.LoadUnaligned<uint32_t>(kNumberOfDexRegisterLocationCatalogEntriesOffset);
1028 }
1029
1030 void SetNumberOfDexRegisterLocationCatalogEntries(uint32_t num_entries) {
1031 region_.StoreUnaligned<uint32_t>(kNumberOfDexRegisterLocationCatalogEntriesOffset, num_entries);
1032 }
1033
David Brazdilf677ebf2015-05-29 16:29:43 +01001034 uint32_t GetDexRegisterLocationCatalogSize(const StackMapEncoding& encoding) const {
1035 return ComputeDexRegisterLocationCatalogSize(GetDexRegisterLocationCatalogOffset(encoding),
Roland Levillaina552e1c2015-03-26 15:01:03 +00001036 GetNumberOfDexRegisterLocationCatalogEntries());
1037 }
1038
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001039 size_t GetNumberOfStackMaps() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001040 return region_.LoadUnaligned<uint32_t>(kNumberOfStackMapsOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001041 }
1042
1043 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001044 region_.StoreUnaligned<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001045 }
1046
Roland Levillain29ba1b02015-03-13 11:45:07 +00001047 // Get the size all the stack maps of this CodeInfo object, in bytes.
David Brazdilf677ebf2015-05-29 16:29:43 +01001048 size_t GetStackMapsSize(const StackMapEncoding& encoding) const {
1049 return encoding.ComputeStackMapSize() * GetNumberOfStackMaps();
Roland Levillain29ba1b02015-03-13 11:45:07 +00001050 }
1051
David Brazdilf677ebf2015-05-29 16:29:43 +01001052 uint32_t GetDexRegisterLocationCatalogOffset(const StackMapEncoding& encoding) const {
1053 return GetStackMapsOffset() + GetStackMapsSize(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001054 }
1055
David Brazdilf677ebf2015-05-29 16:29:43 +01001056 size_t GetDexRegisterMapsOffset(const StackMapEncoding& encoding) const {
1057 return GetDexRegisterLocationCatalogOffset(encoding)
1058 + GetDexRegisterLocationCatalogSize(encoding);
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001059 }
1060
Nicolas Geoffray6530baf2015-05-26 15:22:58 +01001061 uint32_t GetStackMapsOffset() const {
1062 return kFixedSize;
1063 }
1064
David Brazdilf677ebf2015-05-29 16:29:43 +01001065 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
1066 const StackMapEncoding& encoding,
1067 uint32_t number_of_dex_registers) const {
1068 DCHECK(stack_map.HasDexRegisterMap(encoding));
1069 uint32_t offset = GetDexRegisterMapsOffset(encoding)
1070 + stack_map.GetDexRegisterMapOffset(encoding);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001071 size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001072 return DexRegisterMap(region_.Subregion(offset, size));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001073 }
1074
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001075 // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
1076 DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
1077 InlineInfo inline_info,
David Brazdilf677ebf2015-05-29 16:29:43 +01001078 const StackMapEncoding& encoding,
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001079 uint32_t number_of_dex_registers) const {
1080 DCHECK(inline_info.HasDexRegisterMapAtDepth(depth));
David Brazdilf677ebf2015-05-29 16:29:43 +01001081 uint32_t offset = GetDexRegisterMapsOffset(encoding)
1082 + inline_info.GetDexRegisterMapOffsetAtDepth(depth);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001083 size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
1084 return DexRegisterMap(region_.Subregion(offset, size));
1085 }
1086
David Brazdilf677ebf2015-05-29 16:29:43 +01001087 InlineInfo GetInlineInfoOf(StackMap stack_map, const StackMapEncoding& encoding) const {
1088 DCHECK(stack_map.HasInlineInfo(encoding));
1089 uint32_t offset = stack_map.GetInlineDescriptorOffset(encoding)
1090 + GetDexRegisterMapsOffset(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001091 uint8_t depth = region_.LoadUnaligned<uint8_t>(offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001092 return InlineInfo(region_.Subregion(offset,
1093 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
1094 }
1095
David Brazdilf677ebf2015-05-29 16:29:43 +01001096 StackMap GetStackMapForDexPc(uint32_t dex_pc, const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001097 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001098 StackMap stack_map = GetStackMapAt(i, encoding);
1099 if (stack_map.GetDexPc(encoding) == dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001100 return stack_map;
1101 }
1102 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001103 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001104 }
1105
David Brazdilf677ebf2015-05-29 16:29:43 +01001106 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset,
1107 const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001108 // TODO: stack maps are sorted by native pc, we can do a binary search.
1109 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001110 StackMap stack_map = GetStackMapAt(i, encoding);
1111 if (stack_map.GetNativePcOffset(encoding) == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001112 return stack_map;
1113 }
1114 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001115 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001116 }
1117
Roland Levillainf2650d12015-05-28 14:53:28 +01001118 // Dump this CodeInfo object on `os`. `code_offset` is the (absolute)
1119 // native PC of the compiled method and `number_of_dex_registers` the
1120 // number of Dex virtual registers used in this method. If
1121 // `dump_stack_maps` is true, also dump the stack maps and the
1122 // associated Dex register maps.
1123 void Dump(std::ostream& os,
1124 uint32_t code_offset,
1125 uint16_t number_of_dex_registers,
1126 bool dump_stack_maps) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001127
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001128 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001129 // TODO: Instead of plain types such as "uint32_t", introduce
1130 // typedefs (and document the memory layout of CodeInfo).
Nicolas Geoffray39468442014-09-02 15:17:15 +01001131 static constexpr int kOverallSizeOffset = 0;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001132 static constexpr int kEncodingInfoOffset = kOverallSizeOffset + sizeof(uint32_t);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001133 static constexpr int kNumberOfDexRegisterLocationCatalogEntriesOffset =
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001134 kEncodingInfoOffset + sizeof(uint16_t);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001135 static constexpr int kNumberOfStackMapsOffset =
1136 kNumberOfDexRegisterLocationCatalogEntriesOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001137 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
1138 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
1139
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001140 static constexpr int kHasInlineInfoBitOffset = (kEncodingInfoOffset * kBitsPerByte);
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001141 static constexpr int kInlineInfoBitOffset = kHasInlineInfoBitOffset + 1;
1142 static constexpr int kDexRegisterMapBitOffset = kInlineInfoBitOffset + 3;
1143 static constexpr int kDexPcBitOffset = kDexRegisterMapBitOffset + 3;
1144 static constexpr int kNativePcBitOffset = kDexPcBitOffset + 3;
1145 static constexpr int kRegisterMaskBitOffset = kNativePcBitOffset + 3;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001146
David Brazdilf677ebf2015-05-29 16:29:43 +01001147 MemoryRegion GetStackMaps(const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001148 return region_.size() == 0
1149 ? MemoryRegion()
David Brazdilf677ebf2015-05-29 16:29:43 +01001150 : region_.Subregion(GetStackMapsOffset(), GetStackMapsSize(encoding));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001151 }
1152
Roland Levillaina552e1c2015-03-26 15:01:03 +00001153 // Compute the size of the Dex register map associated to the stack map at
1154 // `dex_register_map_offset_in_code_info`.
1155 size_t ComputeDexRegisterMapSizeOf(uint32_t dex_register_map_offset_in_code_info,
1156 uint16_t number_of_dex_registers) const {
1157 // Offset where the actual mapping data starts within art::DexRegisterMap.
1158 size_t location_mapping_data_offset_in_dex_register_map =
1159 DexRegisterMap::GetLocationMappingDataOffset(number_of_dex_registers);
1160 // Create a temporary art::DexRegisterMap to be able to call
1161 // art::DexRegisterMap::GetNumberOfLiveDexRegisters and
1162 DexRegisterMap dex_register_map_without_locations(
1163 MemoryRegion(region_.Subregion(dex_register_map_offset_in_code_info,
1164 location_mapping_data_offset_in_dex_register_map)));
1165 size_t number_of_live_dex_registers =
1166 dex_register_map_without_locations.GetNumberOfLiveDexRegisters(number_of_dex_registers);
1167 size_t location_mapping_data_size_in_bits =
1168 DexRegisterMap::SingleEntrySizeInBits(GetNumberOfDexRegisterLocationCatalogEntries())
1169 * number_of_live_dex_registers;
1170 size_t location_mapping_data_size_in_bytes =
1171 RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
1172 size_t dex_register_map_size =
1173 location_mapping_data_offset_in_dex_register_map + location_mapping_data_size_in_bytes;
1174 return dex_register_map_size;
1175 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001176
Roland Levillaina552e1c2015-03-26 15:01:03 +00001177 // Compute the size of a Dex register location catalog starting at offset `origin`
1178 // in `region_` and containing `number_of_dex_locations` entries.
1179 size_t ComputeDexRegisterLocationCatalogSize(uint32_t origin,
1180 uint32_t number_of_dex_locations) const {
1181 // TODO: Ideally, we would like to use art::DexRegisterLocationCatalog::Size or
1182 // art::DexRegisterLocationCatalog::FindLocationOffset, but the
1183 // DexRegisterLocationCatalog is not yet built. Try to factor common code.
1184 size_t offset = origin + DexRegisterLocationCatalog::kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001185
Roland Levillaina552e1c2015-03-26 15:01:03 +00001186 // Skip the first `number_of_dex_locations - 1` entries.
1187 for (uint16_t i = 0; i < number_of_dex_locations; ++i) {
1188 // Read the first next byte and inspect its first 3 bits to decide
1189 // whether it is a short or a large location.
1190 DexRegisterLocationCatalog::ShortLocation first_byte =
1191 region_.LoadUnaligned<DexRegisterLocationCatalog::ShortLocation>(offset);
1192 DexRegisterLocation::Kind kind =
1193 DexRegisterLocationCatalog::ExtractKindFromShortLocation(first_byte);
1194 if (DexRegisterLocation::IsShortLocationKind(kind)) {
1195 // Short location. Skip the current byte.
1196 offset += DexRegisterLocationCatalog::SingleShortEntrySize();
1197 } else {
1198 // Large location. Skip the 5 next bytes.
1199 offset += DexRegisterLocationCatalog::SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001200 }
1201 }
1202 size_t size = offset - origin;
1203 return size;
1204 }
1205
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001206 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +01001207 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001208};
1209
1210} // namespace art
1211
1212#endif // ART_RUNTIME_STACK_MAP_H_