blob: e8769f97a6c1a2d9a20b0a0345786e5f553f22df [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
Vladimir Marko8f1e08a2015-06-26 12:06:30 +010026class VariableIndentationOutputStream;
27
Roland Levillaina2d8ec62015-03-12 15:25:29 +000028// Size of a frame slot, in bytes. This constant is a signed value,
29// to please the compiler in arithmetic operations involving int32_t
30// (signed) values.
Roland Levillaina552e1c2015-03-26 15:01:03 +000031static constexpr ssize_t kFrameSlotSize = 4;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000032
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000033// Size of Dex virtual registers.
Roland Levillaina552e1c2015-03-26 15:01:03 +000034static constexpr size_t kVRegSize = 4;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000035
Nicolas Geoffray004c2302015-03-20 10:06:38 +000036class CodeInfo;
David Brazdilf677ebf2015-05-29 16:29:43 +010037class StackMapEncoding;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000038
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
Roland Levillaina2d8ec62015-03-12 15:25:29 +000045// Dex register location container used by DexRegisterMap and StackMapStream.
46class DexRegisterLocation {
47 public:
48 /*
49 * The location kind used to populate the Dex register information in a
50 * StackMapStream can either be:
51 * - kNone: the register has no location yet, meaning it has not been set;
52 * - kConstant: value holds the constant;
53 * - kStack: value holds the stack offset;
54 * - kRegister: value holds the physical register number;
55 * - kFpuRegister: value holds the physical register number.
56 *
57 * In addition, DexRegisterMap also uses these values:
58 * - kInStackLargeOffset: value holds a "large" stack offset (greater than
Roland Levillaina552e1c2015-03-26 15:01:03 +000059 * or equal to 128 bytes);
60 * - kConstantLargeValue: value holds a "large" constant (lower than 0, or
61 * or greater than or equal to 32).
Roland Levillaina2d8ec62015-03-12 15:25:29 +000062 */
63 enum class Kind : uint8_t {
64 // Short location kinds, for entries fitting on one byte (3 bits
65 // for the kind, 5 bits for the value) in a DexRegisterMap.
66 kNone = 0, // 0b000
67 kInStack = 1, // 0b001
68 kInRegister = 2, // 0b010
69 kInFpuRegister = 3, // 0b011
70 kConstant = 4, // 0b100
71
72 // Large location kinds, requiring a 5-byte encoding (1 byte for the
73 // kind, 4 bytes for the value).
74
75 // Stack location at a large offset, meaning that the offset value
76 // divided by the stack frame slot size (4 bytes) cannot fit on a
77 // 5-bit unsigned integer (i.e., this offset value is greater than
78 // or equal to 2^5 * 4 = 128 bytes).
79 kInStackLargeOffset = 5, // 0b101
80
81 // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
Roland Levillaina552e1c2015-03-26 15:01:03 +000082 // lower than 0, or greater than or equal to 2^5 = 32).
Roland Levillaina2d8ec62015-03-12 15:25:29 +000083 kConstantLargeValue = 6, // 0b110
84
85 kLastLocationKind = kConstantLargeValue
86 };
87
88 static_assert(
89 sizeof(Kind) == 1u,
90 "art::DexRegisterLocation::Kind has a size different from one byte.");
91
92 static const char* PrettyDescriptor(Kind kind) {
93 switch (kind) {
94 case Kind::kNone:
95 return "none";
96 case Kind::kInStack:
97 return "in stack";
98 case Kind::kInRegister:
99 return "in register";
100 case Kind::kInFpuRegister:
101 return "in fpu register";
102 case Kind::kConstant:
103 return "as constant";
104 case Kind::kInStackLargeOffset:
105 return "in stack (large offset)";
106 case Kind::kConstantLargeValue:
107 return "as constant (large value)";
108 default:
109 UNREACHABLE();
110 }
111 }
112
113 static bool IsShortLocationKind(Kind kind) {
114 switch (kind) {
115 case Kind::kNone:
116 case Kind::kInStack:
117 case Kind::kInRegister:
118 case Kind::kInFpuRegister:
119 case Kind::kConstant:
120 return true;
121
122 case Kind::kInStackLargeOffset:
123 case Kind::kConstantLargeValue:
124 return false;
125
126 default:
127 UNREACHABLE();
128 }
129 }
130
131 // Convert `kind` to a "surface" kind, i.e. one that doesn't include
132 // any value with a "large" qualifier.
133 // TODO: Introduce another enum type for the surface kind?
134 static Kind ConvertToSurfaceKind(Kind kind) {
135 switch (kind) {
136 case Kind::kNone:
137 case Kind::kInStack:
138 case Kind::kInRegister:
139 case Kind::kInFpuRegister:
140 case Kind::kConstant:
141 return kind;
142
143 case Kind::kInStackLargeOffset:
144 return Kind::kInStack;
145
146 case Kind::kConstantLargeValue:
147 return Kind::kConstant;
148
149 default:
150 UNREACHABLE();
151 }
152 }
153
Roland Levillaina552e1c2015-03-26 15:01:03 +0000154 // Required by art::StackMapStream::LocationCatalogEntriesIndices.
155 DexRegisterLocation() : kind_(Kind::kNone), value_(0) {}
156
157 DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {}
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000158
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000159 static DexRegisterLocation None() {
160 return DexRegisterLocation(Kind::kNone, 0);
161 }
162
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000163 // Get the "surface" kind of the location, i.e., the one that doesn't
164 // include any value with a "large" qualifier.
165 Kind GetKind() const {
166 return ConvertToSurfaceKind(kind_);
167 }
168
169 // Get the value of the location.
170 int32_t GetValue() const { return value_; }
171
172 // Get the actual kind of the location.
173 Kind GetInternalKind() const { return kind_; }
174
Calin Juravle6ae70962015-03-18 16:31:28 +0000175 bool operator==(DexRegisterLocation other) const {
176 return kind_ == other.kind_ && value_ == other.value_;
177 }
178
179 bool operator!=(DexRegisterLocation other) const {
180 return !(*this == other);
181 }
182
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000183 private:
184 Kind kind_;
185 int32_t value_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000186
187 friend class DexRegisterLocationHashFn;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000188};
189
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100190/**
Roland Levillaina552e1c2015-03-26 15:01:03 +0000191 * Store information on unique Dex register locations used in a method.
192 * The information is of the form:
193 * [DexRegisterLocation+].
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000194 * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100195 */
Roland Levillaina552e1c2015-03-26 15:01:03 +0000196class DexRegisterLocationCatalog {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100197 public:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000198 explicit DexRegisterLocationCatalog(MemoryRegion region) : region_(region) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100199
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000200 // Short (compressed) location, fitting on one byte.
201 typedef uint8_t ShortLocation;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100202
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000203 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
204 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
205 int32_t value = dex_register_location.GetValue();
206 if (DexRegisterLocation::IsShortLocationKind(kind)) {
207 // Short location. Compress the kind and the value as a single byte.
208 if (kind == DexRegisterLocation::Kind::kInStack) {
209 // Instead of storing stack offsets expressed in bytes for
210 // short stack locations, store slot offsets. A stack offset
211 // is a multiple of 4 (kFrameSlotSize). This means that by
212 // dividing it by 4, we can fit values from the [0, 128)
213 // interval in a short stack location, and not just values
214 // from the [0, 32) interval.
215 DCHECK_EQ(value % kFrameSlotSize, 0);
216 value /= kFrameSlotSize;
217 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000218 DCHECK(IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000219 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
220 } else {
221 // Large location. Write the location on one byte and the value
222 // on 4 bytes.
Roland Levillaina552e1c2015-03-26 15:01:03 +0000223 DCHECK(!IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000224 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
225 // Also divide large stack offsets by 4 for the sake of consistency.
226 DCHECK_EQ(value % kFrameSlotSize, 0);
227 value /= kFrameSlotSize;
228 }
229 // Data can be unaligned as the written Dex register locations can
230 // either be 1-byte or 5-byte wide. Use
231 // art::MemoryRegion::StoreUnaligned instead of
232 // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
233 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
234 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
Roland Levillain442b46a2015-02-18 16:54:21 +0000235 }
236 }
237
Roland Levillaina552e1c2015-03-26 15:01:03 +0000238 // Find the offset of the location catalog entry number `location_catalog_entry_index`.
239 size_t FindLocationOffset(size_t location_catalog_entry_index) const {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000240 size_t offset = kFixedSize;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000241 // Skip the first `location_catalog_entry_index - 1` entries.
242 for (uint16_t i = 0; i < location_catalog_entry_index; ++i) {
243 // Read the first next byte and inspect its first 3 bits to decide
244 // whether it is a short or a large location.
245 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
246 if (DexRegisterLocation::IsShortLocationKind(kind)) {
247 // Short location. Skip the current byte.
248 offset += SingleShortEntrySize();
249 } else {
250 // Large location. Skip the 5 next bytes.
251 offset += SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000252 }
253 }
254 return offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100255 }
256
Roland Levillaina552e1c2015-03-26 15:01:03 +0000257 // Get the internal kind of entry at `location_catalog_entry_index`.
258 DexRegisterLocation::Kind GetLocationInternalKind(size_t location_catalog_entry_index) const {
259 if (location_catalog_entry_index == kNoLocationEntryIndex) {
260 return DexRegisterLocation::Kind::kNone;
261 }
262 return ExtractKindAtOffset(FindLocationOffset(location_catalog_entry_index));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100263 }
264
Roland Levillaina552e1c2015-03-26 15:01:03 +0000265 // Get the (surface) kind and value of entry at `location_catalog_entry_index`.
266 DexRegisterLocation GetDexRegisterLocation(size_t location_catalog_entry_index) const {
267 if (location_catalog_entry_index == kNoLocationEntryIndex) {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000268 return DexRegisterLocation::None();
269 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000270 size_t offset = FindLocationOffset(location_catalog_entry_index);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000271 // Read the first byte and inspect its first 3 bits to get the location.
272 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
273 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
274 if (DexRegisterLocation::IsShortLocationKind(kind)) {
275 // Short location. Extract the value from the remaining 5 bits.
276 int32_t value = ExtractValueFromShortLocation(first_byte);
277 if (kind == DexRegisterLocation::Kind::kInStack) {
278 // Convert the stack slot (short) offset to a byte offset value.
279 value *= kFrameSlotSize;
280 }
281 return DexRegisterLocation(kind, value);
282 } else {
283 // Large location. Read the four next bytes to get the value.
284 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
285 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
286 // Convert the stack slot (large) offset to a byte offset value.
287 value *= kFrameSlotSize;
288 }
289 return DexRegisterLocation(kind, value);
290 }
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100291 }
292
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000293 // Compute the compressed kind of `location`.
294 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
295 switch (location.GetInternalKind()) {
296 case DexRegisterLocation::Kind::kNone:
297 DCHECK_EQ(location.GetValue(), 0);
298 return DexRegisterLocation::Kind::kNone;
299
300 case DexRegisterLocation::Kind::kInRegister:
301 DCHECK_GE(location.GetValue(), 0);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000302 DCHECK_LT(location.GetValue(), 1 << kValueBits);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000303 return DexRegisterLocation::Kind::kInRegister;
304
305 case DexRegisterLocation::Kind::kInFpuRegister:
306 DCHECK_GE(location.GetValue(), 0);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000307 DCHECK_LT(location.GetValue(), 1 << kValueBits);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000308 return DexRegisterLocation::Kind::kInFpuRegister;
309
310 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000311 return IsShortStackOffsetValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000312 ? DexRegisterLocation::Kind::kInStack
313 : DexRegisterLocation::Kind::kInStackLargeOffset;
314
315 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000316 return IsShortConstantValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000317 ? DexRegisterLocation::Kind::kConstant
318 : DexRegisterLocation::Kind::kConstantLargeValue;
319
320 default:
321 LOG(FATAL) << "Unexpected location kind"
322 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
323 UNREACHABLE();
324 }
325 }
326
327 // Can `location` be turned into a short location?
328 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
329 switch (location.GetInternalKind()) {
330 case DexRegisterLocation::Kind::kNone:
331 case DexRegisterLocation::Kind::kInRegister:
332 case DexRegisterLocation::Kind::kInFpuRegister:
333 return true;
334
335 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000336 return IsShortStackOffsetValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000337
338 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000339 return IsShortConstantValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000340
341 default:
342 UNREACHABLE();
343 }
344 }
345
346 static size_t EntrySize(const DexRegisterLocation& location) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000347 return CanBeEncodedAsShortLocation(location) ? SingleShortEntrySize() : SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000348 }
349
350 static size_t SingleShortEntrySize() {
351 return sizeof(ShortLocation);
352 }
353
354 static size_t SingleLargeEntrySize() {
355 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100356 }
357
Roland Levillain12baf472015-03-05 12:41:42 +0000358 size_t Size() const {
359 return region_.size();
360 }
361
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100362 void Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info);
Roland Levillain0396ed72015-05-27 15:12:19 +0100363
Roland Levillaina552e1c2015-03-26 15:01:03 +0000364 // Special (invalid) Dex register location catalog entry index meaning
365 // that there is no location for a given Dex register (i.e., it is
366 // mapped to a DexRegisterLocation::Kind::kNone location).
367 static constexpr size_t kNoLocationEntryIndex = -1;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100368
Roland Levillain12baf472015-03-05 12:41:42 +0000369 private:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000370 static constexpr int kFixedSize = 0;
371
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000372 // Width of the kind "field" in a short location, in bits.
373 static constexpr size_t kKindBits = 3;
374 // Width of the value "field" in a short location, in bits.
375 static constexpr size_t kValueBits = 5;
376
377 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
378 static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
379 static constexpr size_t kKindOffset = 0;
380 static constexpr size_t kValueOffset = kKindBits;
381
Roland Levillaina552e1c2015-03-26 15:01:03 +0000382 static bool IsShortStackOffsetValue(int32_t value) {
383 DCHECK_EQ(value % kFrameSlotSize, 0);
384 return IsShortValue(value / kFrameSlotSize);
385 }
386
387 static bool IsShortConstantValue(int32_t value) {
388 return IsShortValue(value);
389 }
390
391 static bool IsShortValue(int32_t value) {
392 return IsUint<kValueBits>(value);
393 }
394
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000395 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000396 uint8_t kind_integer_value = static_cast<uint8_t>(kind);
397 DCHECK(IsUint<kKindBits>(kind_integer_value)) << kind_integer_value;
398 DCHECK(IsShortValue(value)) << value;
399 return (kind_integer_value & kKindMask) << kKindOffset
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000400 | (value & kValueMask) << kValueOffset;
401 }
402
403 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
404 uint8_t kind = (location >> kKindOffset) & kKindMask;
405 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000406 // We do not encode kNone locations in the stack map.
407 DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone));
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000408 return static_cast<DexRegisterLocation::Kind>(kind);
409 }
410
411 static int32_t ExtractValueFromShortLocation(ShortLocation location) {
412 return (location >> kValueOffset) & kValueMask;
413 }
414
415 // Extract a location kind from the byte at position `offset`.
416 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
417 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
418 return ExtractKindFromShortLocation(first_byte);
419 }
420
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100421 MemoryRegion region_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000422
423 friend class CodeInfo;
424 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100425};
426
Roland Levillaina552e1c2015-03-26 15:01:03 +0000427/* Information on Dex register locations for a specific PC, mapping a
428 * stack map's Dex register to a location entry in a DexRegisterLocationCatalog.
429 * The information is of the form:
430 * [live_bit_mask, entries*]
431 * where entries are concatenated unsigned integer values encoded on a number
432 * of bits (fixed per DexRegisterMap instances of a CodeInfo object) depending
433 * on the number of entries in the Dex register location catalog
434 * (see DexRegisterMap::SingleEntrySizeInBits). The map is 1-byte aligned.
435 */
436class DexRegisterMap {
437 public:
438 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
439
440 // Get the surface kind of Dex register `dex_register_number`.
441 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number,
442 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100443 const CodeInfo& code_info,
444 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000445 return DexRegisterLocation::ConvertToSurfaceKind(
David Brazdilf677ebf2015-05-29 16:29:43 +0100446 GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info, enc));
Roland Levillaina552e1c2015-03-26 15:01:03 +0000447 }
448
449 // Get the internal kind of Dex register `dex_register_number`.
450 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number,
451 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100452 const CodeInfo& code_info,
453 const StackMapEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000454
455 // Get the Dex register location `dex_register_number`.
456 DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number,
457 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100458 const CodeInfo& code_info,
459 const StackMapEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000460
461 int32_t GetStackOffsetInBytes(uint16_t dex_register_number,
462 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100463 const CodeInfo& code_info,
464 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000465 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100466 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000467 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
468 // GetDexRegisterLocation returns the offset in bytes.
469 return location.GetValue();
470 }
471
472 int32_t GetConstant(uint16_t dex_register_number,
473 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100474 const CodeInfo& code_info,
475 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000476 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100477 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100478 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant)
479 << DexRegisterLocation::PrettyDescriptor(location.GetKind());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000480 return location.GetValue();
481 }
482
483 int32_t GetMachineRegister(uint16_t dex_register_number,
484 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100485 const CodeInfo& code_info,
486 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000487 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100488 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000489 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister
490 || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister)
491 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
492 return location.GetValue();
493 }
494
495 // Get the index of the entry in the Dex register location catalog
496 // corresponding to `dex_register_number`.
497 size_t GetLocationCatalogEntryIndex(uint16_t dex_register_number,
498 uint16_t number_of_dex_registers,
499 size_t number_of_location_catalog_entries) const {
500 if (!IsDexRegisterLive(dex_register_number)) {
501 return DexRegisterLocationCatalog::kNoLocationEntryIndex;
502 }
503
504 if (number_of_location_catalog_entries == 1) {
505 // We do not allocate space for location maps in the case of a
506 // single-entry location catalog, as it is useless. The only valid
507 // entry index is 0;
508 return 0;
509 }
510
511 // The bit offset of the beginning of the map locations.
512 size_t map_locations_offset_in_bits =
513 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
514 size_t index_in_dex_register_map = GetIndexInDexRegisterMap(dex_register_number);
515 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
516 // The bit size of an entry.
517 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
518 // The bit offset where `index_in_dex_register_map` is located.
519 size_t entry_offset_in_bits =
520 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
521 size_t location_catalog_entry_index =
522 region_.LoadBits(entry_offset_in_bits, map_entry_size_in_bits);
523 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
524 return location_catalog_entry_index;
525 }
526
527 // Map entry at `index_in_dex_register_map` to `location_catalog_entry_index`.
528 void SetLocationCatalogEntryIndex(size_t index_in_dex_register_map,
529 size_t location_catalog_entry_index,
530 uint16_t number_of_dex_registers,
531 size_t number_of_location_catalog_entries) {
532 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
533 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
534
535 if (number_of_location_catalog_entries == 1) {
536 // We do not allocate space for location maps in the case of a
537 // single-entry location catalog, as it is useless.
538 return;
539 }
540
541 // The bit offset of the beginning of the map locations.
542 size_t map_locations_offset_in_bits =
543 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
544 // The bit size of an entry.
545 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
546 // The bit offset where `index_in_dex_register_map` is located.
547 size_t entry_offset_in_bits =
548 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
549 region_.StoreBits(entry_offset_in_bits, location_catalog_entry_index, map_entry_size_in_bits);
550 }
551
552 void SetLiveBitMask(uint16_t number_of_dex_registers,
553 const BitVector& live_dex_registers_mask) {
554 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
555 for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
556 region_.StoreBit(live_bit_mask_offset_in_bits + i, live_dex_registers_mask.IsBitSet(i));
557 }
558 }
559
560 bool IsDexRegisterLive(uint16_t dex_register_number) const {
561 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
562 return region_.LoadBit(live_bit_mask_offset_in_bits + dex_register_number);
563 }
564
565 size_t GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers) const {
566 size_t number_of_live_dex_registers = 0;
567 for (size_t i = 0; i < number_of_dex_registers; ++i) {
568 if (IsDexRegisterLive(i)) {
569 ++number_of_live_dex_registers;
570 }
571 }
572 return number_of_live_dex_registers;
573 }
574
575 static size_t GetLiveBitMaskOffset() {
576 return kFixedSize;
577 }
578
579 // Compute the size of the live register bit mask (in bytes), for a
580 // method having `number_of_dex_registers` Dex registers.
581 static size_t GetLiveBitMaskSize(uint16_t number_of_dex_registers) {
582 return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte;
583 }
584
585 static size_t GetLocationMappingDataOffset(uint16_t number_of_dex_registers) {
586 return GetLiveBitMaskOffset() + GetLiveBitMaskSize(number_of_dex_registers);
587 }
588
589 size_t GetLocationMappingDataSize(uint16_t number_of_dex_registers,
590 size_t number_of_location_catalog_entries) const {
591 size_t location_mapping_data_size_in_bits =
592 GetNumberOfLiveDexRegisters(number_of_dex_registers)
593 * SingleEntrySizeInBits(number_of_location_catalog_entries);
594 return RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
595 }
596
597 // Return the size of a map entry in bits. Note that if
598 // `number_of_location_catalog_entries` equals 1, this function returns 0,
599 // which is fine, as there is no need to allocate a map for a
600 // single-entry location catalog; the only valid location catalog entry index
601 // for a live register in this case is 0 and there is no need to
602 // store it.
603 static size_t SingleEntrySizeInBits(size_t number_of_location_catalog_entries) {
604 // Handle the case of 0, as we cannot pass 0 to art::WhichPowerOf2.
605 return number_of_location_catalog_entries == 0
606 ? 0u
607 : WhichPowerOf2(RoundUpToPowerOfTwo(number_of_location_catalog_entries));
608 }
609
610 // Return the size of the DexRegisterMap object, in bytes.
611 size_t Size() const {
612 return region_.size();
613 }
614
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100615 void Dump(VariableIndentationOutputStream* vios,
616 const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100617
Roland Levillaina552e1c2015-03-26 15:01:03 +0000618 private:
619 // Return the index in the Dex register map corresponding to the Dex
620 // register number `dex_register_number`.
621 size_t GetIndexInDexRegisterMap(uint16_t dex_register_number) const {
622 if (!IsDexRegisterLive(dex_register_number)) {
623 return kInvalidIndexInDexRegisterMap;
624 }
625 return GetNumberOfLiveDexRegisters(dex_register_number);
626 }
627
628 // Special (invalid) Dex register map entry index meaning that there
629 // is no index in the map for a given Dex register (i.e., it must
630 // have been mapped to a DexRegisterLocation::Kind::kNone location).
631 static constexpr size_t kInvalidIndexInDexRegisterMap = -1;
632
633 static constexpr int kFixedSize = 0;
634
635 MemoryRegion region_;
636
637 friend class CodeInfo;
638 friend class StackMapStream;
639};
640
David Brazdilf677ebf2015-05-29 16:29:43 +0100641class StackMapEncoding {
642 public:
643 StackMapEncoding() {}
644
645 StackMapEncoding(size_t stack_mask_size,
646 size_t bytes_for_inline_info,
647 size_t bytes_for_dex_register_map,
648 size_t bytes_for_dex_pc,
649 size_t bytes_for_native_pc,
650 size_t bytes_for_register_mask)
651 : bytes_for_stack_mask_(stack_mask_size),
652 bytes_for_inline_info_(bytes_for_inline_info),
653 bytes_for_dex_register_map_(bytes_for_dex_register_map),
654 bytes_for_dex_pc_(bytes_for_dex_pc),
655 bytes_for_native_pc_(bytes_for_native_pc),
656 bytes_for_register_mask_(bytes_for_register_mask) {}
657
658 static StackMapEncoding CreateFromSizes(size_t stack_mask_size,
659 size_t inline_info_size,
660 size_t dex_register_map_size,
661 size_t dex_pc_max,
662 size_t native_pc_max,
663 size_t register_mask_max) {
664 return StackMapEncoding(
665 stack_mask_size,
666 // + 1 to also encode kNoInlineInfo: if an inline info offset
667 // is at 0xFF, we want to overflow to a larger encoding, because it will
668 // conflict with kNoInlineInfo.
669 // The offset is relative to the dex register map. TODO: Change this.
670 inline_info_size == 0
671 ? 0
672 : EncodingSizeInBytes(dex_register_map_size + inline_info_size + 1),
673 // + 1 to also encode kNoDexRegisterMap: if a dex register map offset
674 // is at 0xFF, we want to overflow to a larger encoding, because it will
675 // conflict with kNoDexRegisterMap.
676 EncodingSizeInBytes(dex_register_map_size + 1),
677 EncodingSizeInBytes(dex_pc_max),
678 EncodingSizeInBytes(native_pc_max),
679 EncodingSizeInBytes(register_mask_max));
680 }
681
682 // Get the size of one stack map of this CodeInfo object, in bytes.
683 // All stack maps of a CodeInfo have the same size.
684 size_t ComputeStackMapSize() const {
685 return bytes_for_register_mask_
686 + bytes_for_stack_mask_
687 + bytes_for_inline_info_
688 + bytes_for_dex_register_map_
689 + bytes_for_dex_pc_
690 + bytes_for_native_pc_;
691 }
692
693 bool HasInlineInfo() const { return bytes_for_inline_info_ > 0; }
694
695 size_t NumberOfBytesForStackMask() const { return bytes_for_stack_mask_; }
696 size_t NumberOfBytesForInlineInfo() const { return bytes_for_inline_info_; }
697 size_t NumberOfBytesForDexRegisterMap() const { return bytes_for_dex_register_map_; }
698 size_t NumberOfBytesForDexPc() const { return bytes_for_dex_pc_; }
699 size_t NumberOfBytesForNativePc() const { return bytes_for_native_pc_; }
700 size_t NumberOfBytesForRegisterMask() const { return bytes_for_register_mask_; }
701
702 size_t ComputeStackMapRegisterMaskOffset() const {
703 return kRegisterMaskOffset;
704 }
705
706 size_t ComputeStackMapStackMaskOffset() const {
707 return ComputeStackMapRegisterMaskOffset() + bytes_for_register_mask_;
708 }
709
710 size_t ComputeStackMapDexPcOffset() const {
711 return ComputeStackMapStackMaskOffset() + bytes_for_stack_mask_;
712 }
713
714 size_t ComputeStackMapNativePcOffset() const {
715 return ComputeStackMapDexPcOffset() + bytes_for_dex_pc_;
716 }
717
718 size_t ComputeStackMapDexRegisterMapOffset() const {
719 return ComputeStackMapNativePcOffset() + bytes_for_native_pc_;
720 }
721
722 size_t ComputeStackMapInlineInfoOffset() const {
723 return ComputeStackMapDexRegisterMapOffset() + bytes_for_dex_register_map_;
724 }
725
726 private:
727 static size_t EncodingSizeInBytes(size_t max_element) {
728 DCHECK(IsUint<32>(max_element));
729 return (max_element == 0) ? 0
730 : IsUint<8>(max_element) ? 1
731 : IsUint<16>(max_element) ? 2
732 : IsUint<24>(max_element) ? 3
733 : 4;
734 }
735
736 static constexpr int kRegisterMaskOffset = 0;
737
738 size_t bytes_for_stack_mask_;
739 size_t bytes_for_inline_info_;
740 size_t bytes_for_dex_register_map_;
741 size_t bytes_for_dex_pc_;
742 size_t bytes_for_native_pc_;
743 size_t bytes_for_register_mask_;
744};
745
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100746/**
747 * A Stack Map holds compilation information for a specific PC necessary for:
748 * - Mapping it to a dex PC,
749 * - Knowing which stack entries are objects,
750 * - Knowing which registers hold objects,
751 * - Knowing the inlining information,
752 * - Knowing the values of dex registers.
753 *
754 * The information is of the form:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000755 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask,
756 * stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100757 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100758class StackMap {
759 public:
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100760 StackMap() {}
David Brazdilf677ebf2015-05-29 16:29:43 +0100761 explicit StackMap(MemoryRegion region) : region_(region) {}
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100762
763 bool IsValid() const { return region_.pointer() != nullptr; }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100764
David Brazdilf677ebf2015-05-29 16:29:43 +0100765 uint32_t GetDexPc(const StackMapEncoding& encoding) const {
766 return LoadAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset());
767 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100768
David Brazdilf677ebf2015-05-29 16:29:43 +0100769 void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) {
770 StoreAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset(), dex_pc);
771 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100772
David Brazdilf677ebf2015-05-29 16:29:43 +0100773 uint32_t GetNativePcOffset(const StackMapEncoding& encoding) const {
774 return LoadAt(encoding.NumberOfBytesForNativePc(), encoding.ComputeStackMapNativePcOffset());
775 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100776
David Brazdilf677ebf2015-05-29 16:29:43 +0100777 void SetNativePcOffset(const StackMapEncoding& encoding, uint32_t native_pc_offset) {
778 StoreAt(encoding.NumberOfBytesForNativePc(),
779 encoding.ComputeStackMapNativePcOffset(),
780 native_pc_offset);
781 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100782
David Brazdilf677ebf2015-05-29 16:29:43 +0100783 uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const {
784 return LoadAt(encoding.NumberOfBytesForDexRegisterMap(),
785 encoding.ComputeStackMapDexRegisterMapOffset(),
786 /* check_max */ true);
787 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100788
David Brazdilf677ebf2015-05-29 16:29:43 +0100789 void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) {
790 StoreAt(encoding.NumberOfBytesForDexRegisterMap(),
791 encoding.ComputeStackMapDexRegisterMapOffset(),
792 offset);
793 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100794
David Brazdilf677ebf2015-05-29 16:29:43 +0100795 uint32_t GetInlineDescriptorOffset(const StackMapEncoding& encoding) const {
796 if (!encoding.HasInlineInfo()) return kNoInlineInfo;
797 return LoadAt(encoding.NumberOfBytesForInlineInfo(),
798 encoding.ComputeStackMapInlineInfoOffset(),
799 /* check_max */ true);
800 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100801
David Brazdilf677ebf2015-05-29 16:29:43 +0100802 void SetInlineDescriptorOffset(const StackMapEncoding& encoding, uint32_t offset) {
803 DCHECK(encoding.HasInlineInfo());
804 StoreAt(encoding.NumberOfBytesForInlineInfo(),
805 encoding.ComputeStackMapInlineInfoOffset(),
806 offset);
807 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100808
David Brazdilf677ebf2015-05-29 16:29:43 +0100809 uint32_t GetRegisterMask(const StackMapEncoding& encoding) const {
810 return LoadAt(encoding.NumberOfBytesForRegisterMask(),
811 encoding.ComputeStackMapRegisterMaskOffset());
812 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100813
David Brazdilf677ebf2015-05-29 16:29:43 +0100814 void SetRegisterMask(const StackMapEncoding& encoding, uint32_t mask) {
815 StoreAt(encoding.NumberOfBytesForRegisterMask(),
816 encoding.ComputeStackMapRegisterMaskOffset(),
817 mask);
818 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100819
David Brazdilf677ebf2015-05-29 16:29:43 +0100820 MemoryRegion GetStackMask(const StackMapEncoding& encoding) const {
821 return region_.Subregion(encoding.ComputeStackMapStackMaskOffset(),
822 encoding.NumberOfBytesForStackMask());
823 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100824
David Brazdilf677ebf2015-05-29 16:29:43 +0100825 void SetStackMask(const StackMapEncoding& encoding, const BitVector& sp_map) {
826 MemoryRegion region = GetStackMask(encoding);
David Brazdilf10a25f2015-06-02 14:29:52 +0100827 sp_map.CopyTo(region.start(), region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100828 }
829
David Brazdilf677ebf2015-05-29 16:29:43 +0100830 bool HasDexRegisterMap(const StackMapEncoding& encoding) const {
831 return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100832 }
833
David Brazdilf677ebf2015-05-29 16:29:43 +0100834 bool HasInlineInfo(const StackMapEncoding& encoding) const {
835 return GetInlineDescriptorOffset(encoding) != kNoInlineInfo;
Roland Levillain442b46a2015-02-18 16:54:21 +0000836 }
837
838 bool Equals(const StackMap& other) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100839 return region_.pointer() == other.region_.pointer()
840 && region_.size() == other.region_.size();
841 }
842
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100843 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100844 const CodeInfo& code_info,
David Brazdilf677ebf2015-05-29 16:29:43 +0100845 const StackMapEncoding& encoding,
Roland Levillainf2650d12015-05-28 14:53:28 +0100846 uint32_t code_offset,
847 uint16_t number_of_dex_registers,
848 const std::string& header_suffix = "") const;
849
Roland Levillain442b46a2015-02-18 16:54:21 +0000850 // Special (invalid) offset for the DexRegisterMapOffset field meaning
851 // that there is no Dex register map for this stack map.
852 static constexpr uint32_t kNoDexRegisterMap = -1;
853
854 // Special (invalid) offset for the InlineDescriptorOffset field meaning
855 // that there is no inline info for this stack map.
856 static constexpr uint32_t kNoInlineInfo = -1;
857
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100858 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000859 // TODO: Instead of plain types such as "uint32_t", introduce
860 // typedefs (and document the memory layout of StackMap).
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100861 static constexpr int kFixedSize = 0;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100862
David Brazdilf677ebf2015-05-29 16:29:43 +0100863 // Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true,
864 // this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF.
865 uint32_t LoadAt(size_t number_of_bytes, size_t offset, bool check_max = false) const;
866 void StoreAt(size_t number_of_bytes, size_t offset, uint32_t value) const;
867
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100868 MemoryRegion region_;
869
Nicolas Geoffray39468442014-09-02 15:17:15 +0100870 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100871};
872
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100873/**
874 * Inline information for a specific PC. The information is of the form:
875 * [inlining_depth, [dex_pc, method_index, dex_register_map_offset]+]
876 */
877class InlineInfo {
878 public:
879 explicit InlineInfo(MemoryRegion region) : region_(region) {}
880
881 uint8_t GetDepth() const {
882 return region_.LoadUnaligned<uint8_t>(kDepthOffset);
883 }
884
885 void SetDepth(uint8_t depth) {
886 region_.StoreUnaligned<uint8_t>(kDepthOffset, depth);
887 }
888
889 uint32_t GetMethodIndexAtDepth(uint8_t depth) const {
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100890 return region_.LoadUnaligned<uint32_t>(
891 kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100892 }
893
894 void SetMethodIndexAtDepth(uint8_t depth, uint32_t index) {
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100895 region_.StoreUnaligned<uint32_t>(
896 kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset, index);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100897 }
898
899 uint32_t GetDexPcAtDepth(uint8_t depth) const {
900 return region_.LoadUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100901 kFixedSize + depth * SingleEntrySize() + kDexPcOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100902 }
903
904 void SetDexPcAtDepth(uint8_t depth, uint32_t dex_pc) {
905 region_.StoreUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100906 kFixedSize + depth * SingleEntrySize() + kDexPcOffset, dex_pc);
907 }
908
909 uint8_t GetInvokeTypeAtDepth(uint8_t depth) const {
910 return region_.LoadUnaligned<uint8_t>(
911 kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset);
912 }
913
914 void SetInvokeTypeAtDepth(uint8_t depth, uint8_t invoke_type) {
915 region_.StoreUnaligned<uint8_t>(
916 kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset, invoke_type);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100917 }
918
919 uint32_t GetDexRegisterMapOffsetAtDepth(uint8_t depth) const {
920 return region_.LoadUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100921 kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100922 }
923
924 void SetDexRegisterMapOffsetAtDepth(uint8_t depth, uint32_t offset) {
925 region_.StoreUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100926 kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset, offset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100927 }
928
929 bool HasDexRegisterMapAtDepth(uint8_t depth) const {
930 return GetDexRegisterMapOffsetAtDepth(depth) != StackMap::kNoDexRegisterMap;
931 }
932
933 static size_t SingleEntrySize() {
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100934 return kFixedEntrySize;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100935 }
936
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100937 void Dump(VariableIndentationOutputStream* vios,
938 const CodeInfo& info, uint16_t* number_of_dex_registers) const;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100939
940 private:
941 // TODO: Instead of plain types such as "uint8_t", introduce
942 // typedefs (and document the memory layout of InlineInfo).
943 static constexpr int kDepthOffset = 0;
944 static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
945
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100946 static constexpr int kMethodIndexOffset = 0;
947 static constexpr int kDexPcOffset = kMethodIndexOffset + sizeof(uint32_t);
948 static constexpr int kInvokeTypeOffset = kDexPcOffset + sizeof(uint32_t);
949 static constexpr int kDexRegisterMapOffset = kInvokeTypeOffset + sizeof(uint8_t);
950 static constexpr int kFixedEntrySize = kDexRegisterMapOffset + sizeof(uint32_t);
951
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100952 MemoryRegion region_;
953
954 friend class CodeInfo;
955 friend class StackMap;
956 friend class StackMapStream;
957};
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100958
959/**
960 * Wrapper around all compiler information collected for a method.
961 * The information is of the form:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000962 * [overall_size, number_of_location_catalog_entries, number_of_stack_maps, stack_mask_size,
963 * DexRegisterLocationCatalog+, StackMap+, DexRegisterMap+, InlineInfo*].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100964 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100965class CodeInfo {
966 public:
967 explicit CodeInfo(MemoryRegion region) : region_(region) {}
968
Nicolas Geoffray39468442014-09-02 15:17:15 +0100969 explicit CodeInfo(const void* data) {
970 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
971 region_ = MemoryRegion(const_cast<void*>(data), size);
972 }
973
David Brazdilf677ebf2015-05-29 16:29:43 +0100974 StackMapEncoding ExtractEncoding() const {
975 return StackMapEncoding(region_.LoadUnaligned<uint32_t>(kStackMaskSizeOffset),
976 GetNumberOfBytesForEncoding(kInlineInfoBitOffset),
977 GetNumberOfBytesForEncoding(kDexRegisterMapBitOffset),
978 GetNumberOfBytesForEncoding(kDexPcBitOffset),
979 GetNumberOfBytesForEncoding(kNativePcBitOffset),
980 GetNumberOfBytesForEncoding(kRegisterMaskBitOffset));
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100981 }
982
David Brazdilf677ebf2015-05-29 16:29:43 +0100983 void SetEncoding(const StackMapEncoding& encoding) {
984 region_.StoreUnaligned<uint32_t>(kStackMaskSizeOffset, encoding.NumberOfBytesForStackMask());
985 region_.StoreBit(kHasInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo() != 0);
986 SetEncodingAt(kInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo());
987 SetEncodingAt(kDexRegisterMapBitOffset, encoding.NumberOfBytesForDexRegisterMap());
988 SetEncodingAt(kDexPcBitOffset, encoding.NumberOfBytesForDexPc());
989 SetEncodingAt(kNativePcBitOffset, encoding.NumberOfBytesForNativePc());
990 SetEncodingAt(kRegisterMaskBitOffset, encoding.NumberOfBytesForRegisterMask());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100991 }
992
993 void SetEncodingAt(size_t bit_offset, size_t number_of_bytes) {
994 // We encode the number of bytes needed for writing a value on 3 bits,
995 // for values that we know are maximum 32bits.
996 region_.StoreBit(bit_offset, (number_of_bytes & 1));
997 region_.StoreBit(bit_offset + 1, (number_of_bytes & 2));
998 region_.StoreBit(bit_offset + 2, (number_of_bytes & 4));
999 }
1000
1001 size_t GetNumberOfBytesForEncoding(size_t bit_offset) const {
1002 return region_.LoadBit(bit_offset)
1003 + (region_.LoadBit(bit_offset + 1) << 1)
1004 + (region_.LoadBit(bit_offset + 2) << 2);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001005 }
1006
1007 bool HasInlineInfo() const {
1008 return region_.LoadBit(kHasInlineInfoBitOffset);
1009 }
1010
David Brazdilf677ebf2015-05-29 16:29:43 +01001011 DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const StackMapEncoding& encoding) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +00001012 return DexRegisterLocationCatalog(region_.Subregion(
David Brazdilf677ebf2015-05-29 16:29:43 +01001013 GetDexRegisterLocationCatalogOffset(encoding),
1014 GetDexRegisterLocationCatalogSize(encoding)));
Roland Levillaina552e1c2015-03-26 15:01:03 +00001015 }
1016
David Brazdilf677ebf2015-05-29 16:29:43 +01001017 StackMap GetStackMapAt(size_t i, const StackMapEncoding& encoding) const {
1018 size_t stack_map_size = encoding.ComputeStackMapSize();
1019 return StackMap(GetStackMaps(encoding).Subregion(i * stack_map_size, stack_map_size));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001020 }
1021
1022 uint32_t GetOverallSize() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001023 return region_.LoadUnaligned<uint32_t>(kOverallSizeOffset);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001024 }
1025
1026 void SetOverallSize(uint32_t size) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001027 region_.StoreUnaligned<uint32_t>(kOverallSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001028 }
1029
Roland Levillaina552e1c2015-03-26 15:01:03 +00001030 uint32_t GetNumberOfDexRegisterLocationCatalogEntries() const {
1031 return region_.LoadUnaligned<uint32_t>(kNumberOfDexRegisterLocationCatalogEntriesOffset);
1032 }
1033
1034 void SetNumberOfDexRegisterLocationCatalogEntries(uint32_t num_entries) {
1035 region_.StoreUnaligned<uint32_t>(kNumberOfDexRegisterLocationCatalogEntriesOffset, num_entries);
1036 }
1037
David Brazdilf677ebf2015-05-29 16:29:43 +01001038 uint32_t GetDexRegisterLocationCatalogSize(const StackMapEncoding& encoding) const {
1039 return ComputeDexRegisterLocationCatalogSize(GetDexRegisterLocationCatalogOffset(encoding),
Roland Levillaina552e1c2015-03-26 15:01:03 +00001040 GetNumberOfDexRegisterLocationCatalogEntries());
1041 }
1042
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001043 size_t GetNumberOfStackMaps() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001044 return region_.LoadUnaligned<uint32_t>(kNumberOfStackMapsOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001045 }
1046
1047 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001048 region_.StoreUnaligned<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001049 }
1050
Roland Levillain29ba1b02015-03-13 11:45:07 +00001051 // Get the size all the stack maps of this CodeInfo object, in bytes.
David Brazdilf677ebf2015-05-29 16:29:43 +01001052 size_t GetStackMapsSize(const StackMapEncoding& encoding) const {
1053 return encoding.ComputeStackMapSize() * GetNumberOfStackMaps();
Roland Levillain29ba1b02015-03-13 11:45:07 +00001054 }
1055
David Brazdilf677ebf2015-05-29 16:29:43 +01001056 uint32_t GetDexRegisterLocationCatalogOffset(const StackMapEncoding& encoding) const {
1057 return GetStackMapsOffset() + GetStackMapsSize(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001058 }
1059
David Brazdilf677ebf2015-05-29 16:29:43 +01001060 size_t GetDexRegisterMapsOffset(const StackMapEncoding& encoding) const {
1061 return GetDexRegisterLocationCatalogOffset(encoding)
1062 + GetDexRegisterLocationCatalogSize(encoding);
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001063 }
1064
Nicolas Geoffray6530baf2015-05-26 15:22:58 +01001065 uint32_t GetStackMapsOffset() const {
1066 return kFixedSize;
1067 }
1068
David Brazdilf677ebf2015-05-29 16:29:43 +01001069 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
1070 const StackMapEncoding& encoding,
1071 uint32_t number_of_dex_registers) const {
1072 DCHECK(stack_map.HasDexRegisterMap(encoding));
1073 uint32_t offset = GetDexRegisterMapsOffset(encoding)
1074 + stack_map.GetDexRegisterMapOffset(encoding);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001075 size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001076 return DexRegisterMap(region_.Subregion(offset, size));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001077 }
1078
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001079 // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
1080 DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
1081 InlineInfo inline_info,
David Brazdilf677ebf2015-05-29 16:29:43 +01001082 const StackMapEncoding& encoding,
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001083 uint32_t number_of_dex_registers) const {
1084 DCHECK(inline_info.HasDexRegisterMapAtDepth(depth));
David Brazdilf677ebf2015-05-29 16:29:43 +01001085 uint32_t offset = GetDexRegisterMapsOffset(encoding)
1086 + inline_info.GetDexRegisterMapOffsetAtDepth(depth);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001087 size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
1088 return DexRegisterMap(region_.Subregion(offset, size));
1089 }
1090
David Brazdilf677ebf2015-05-29 16:29:43 +01001091 InlineInfo GetInlineInfoOf(StackMap stack_map, const StackMapEncoding& encoding) const {
1092 DCHECK(stack_map.HasInlineInfo(encoding));
1093 uint32_t offset = stack_map.GetInlineDescriptorOffset(encoding)
1094 + GetDexRegisterMapsOffset(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001095 uint8_t depth = region_.LoadUnaligned<uint8_t>(offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001096 return InlineInfo(region_.Subregion(offset,
1097 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
1098 }
1099
David Brazdilf677ebf2015-05-29 16:29:43 +01001100 StackMap GetStackMapForDexPc(uint32_t dex_pc, const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001101 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001102 StackMap stack_map = GetStackMapAt(i, encoding);
1103 if (stack_map.GetDexPc(encoding) == dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001104 return stack_map;
1105 }
1106 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001107 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001108 }
1109
David Brazdilf677ebf2015-05-29 16:29:43 +01001110 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset,
1111 const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001112 // TODO: stack maps are sorted by native pc, we can do a binary search.
1113 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001114 StackMap stack_map = GetStackMapAt(i, encoding);
1115 if (stack_map.GetNativePcOffset(encoding) == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001116 return stack_map;
1117 }
1118 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001119 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001120 }
1121
Roland Levillainf2650d12015-05-28 14:53:28 +01001122 // Dump this CodeInfo object on `os`. `code_offset` is the (absolute)
1123 // native PC of the compiled method and `number_of_dex_registers` the
1124 // number of Dex virtual registers used in this method. If
1125 // `dump_stack_maps` is true, also dump the stack maps and the
1126 // associated Dex register maps.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001127 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +01001128 uint32_t code_offset,
1129 uint16_t number_of_dex_registers,
1130 bool dump_stack_maps) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001131
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001132 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001133 // TODO: Instead of plain types such as "uint32_t", introduce
1134 // typedefs (and document the memory layout of CodeInfo).
Nicolas Geoffray39468442014-09-02 15:17:15 +01001135 static constexpr int kOverallSizeOffset = 0;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001136 static constexpr int kEncodingInfoOffset = kOverallSizeOffset + sizeof(uint32_t);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001137 static constexpr int kNumberOfDexRegisterLocationCatalogEntriesOffset =
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001138 kEncodingInfoOffset + sizeof(uint16_t);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001139 static constexpr int kNumberOfStackMapsOffset =
1140 kNumberOfDexRegisterLocationCatalogEntriesOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001141 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
1142 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
1143
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001144 static constexpr int kHasInlineInfoBitOffset = (kEncodingInfoOffset * kBitsPerByte);
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001145 static constexpr int kInlineInfoBitOffset = kHasInlineInfoBitOffset + 1;
1146 static constexpr int kDexRegisterMapBitOffset = kInlineInfoBitOffset + 3;
1147 static constexpr int kDexPcBitOffset = kDexRegisterMapBitOffset + 3;
1148 static constexpr int kNativePcBitOffset = kDexPcBitOffset + 3;
1149 static constexpr int kRegisterMaskBitOffset = kNativePcBitOffset + 3;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001150
David Brazdilf677ebf2015-05-29 16:29:43 +01001151 MemoryRegion GetStackMaps(const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001152 return region_.size() == 0
1153 ? MemoryRegion()
David Brazdilf677ebf2015-05-29 16:29:43 +01001154 : region_.Subregion(GetStackMapsOffset(), GetStackMapsSize(encoding));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001155 }
1156
Roland Levillaina552e1c2015-03-26 15:01:03 +00001157 // Compute the size of the Dex register map associated to the stack map at
1158 // `dex_register_map_offset_in_code_info`.
1159 size_t ComputeDexRegisterMapSizeOf(uint32_t dex_register_map_offset_in_code_info,
1160 uint16_t number_of_dex_registers) const {
1161 // Offset where the actual mapping data starts within art::DexRegisterMap.
1162 size_t location_mapping_data_offset_in_dex_register_map =
1163 DexRegisterMap::GetLocationMappingDataOffset(number_of_dex_registers);
1164 // Create a temporary art::DexRegisterMap to be able to call
1165 // art::DexRegisterMap::GetNumberOfLiveDexRegisters and
1166 DexRegisterMap dex_register_map_without_locations(
1167 MemoryRegion(region_.Subregion(dex_register_map_offset_in_code_info,
1168 location_mapping_data_offset_in_dex_register_map)));
1169 size_t number_of_live_dex_registers =
1170 dex_register_map_without_locations.GetNumberOfLiveDexRegisters(number_of_dex_registers);
1171 size_t location_mapping_data_size_in_bits =
1172 DexRegisterMap::SingleEntrySizeInBits(GetNumberOfDexRegisterLocationCatalogEntries())
1173 * number_of_live_dex_registers;
1174 size_t location_mapping_data_size_in_bytes =
1175 RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
1176 size_t dex_register_map_size =
1177 location_mapping_data_offset_in_dex_register_map + location_mapping_data_size_in_bytes;
1178 return dex_register_map_size;
1179 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001180
Roland Levillaina552e1c2015-03-26 15:01:03 +00001181 // Compute the size of a Dex register location catalog starting at offset `origin`
1182 // in `region_` and containing `number_of_dex_locations` entries.
1183 size_t ComputeDexRegisterLocationCatalogSize(uint32_t origin,
1184 uint32_t number_of_dex_locations) const {
1185 // TODO: Ideally, we would like to use art::DexRegisterLocationCatalog::Size or
1186 // art::DexRegisterLocationCatalog::FindLocationOffset, but the
1187 // DexRegisterLocationCatalog is not yet built. Try to factor common code.
1188 size_t offset = origin + DexRegisterLocationCatalog::kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001189
Roland Levillaina552e1c2015-03-26 15:01:03 +00001190 // Skip the first `number_of_dex_locations - 1` entries.
1191 for (uint16_t i = 0; i < number_of_dex_locations; ++i) {
1192 // Read the first next byte and inspect its first 3 bits to decide
1193 // whether it is a short or a large location.
1194 DexRegisterLocationCatalog::ShortLocation first_byte =
1195 region_.LoadUnaligned<DexRegisterLocationCatalog::ShortLocation>(offset);
1196 DexRegisterLocation::Kind kind =
1197 DexRegisterLocationCatalog::ExtractKindFromShortLocation(first_byte);
1198 if (DexRegisterLocation::IsShortLocationKind(kind)) {
1199 // Short location. Skip the current byte.
1200 offset += DexRegisterLocationCatalog::SingleShortEntrySize();
1201 } else {
1202 // Large location. Skip the 5 next bytes.
1203 offset += DexRegisterLocationCatalog::SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001204 }
1205 }
1206 size_t size = offset - origin;
1207 return size;
1208 }
1209
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001210 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +01001211 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001212};
1213
1214} // namespace art
1215
1216#endif // ART_RUNTIME_STACK_MAP_H_