blob: 07b79b55308f124331fef818e16e5d5f964e9fe1 [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 Levillain1c1da432015-07-16 11:54:44 +010026#define ELEMENT_BYTE_OFFSET_AFTER(PreviousElement) \
27 k ## PreviousElement ## Offset + sizeof(PreviousElement ## Type)
28
29#define ELEMENT_BIT_OFFSET_AFTER(PreviousElement) \
30 k ## PreviousElement ## BitOffset + PreviousElement ## BitSize
31
Vladimir Marko8f1e08a2015-06-26 12:06:30 +010032class VariableIndentationOutputStream;
33
Roland Levillaina2d8ec62015-03-12 15:25:29 +000034// Size of a frame slot, in bytes. This constant is a signed value,
35// to please the compiler in arithmetic operations involving int32_t
36// (signed) values.
Roland Levillaina552e1c2015-03-26 15:01:03 +000037static constexpr ssize_t kFrameSlotSize = 4;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000038
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000039// Size of Dex virtual registers.
Roland Levillaina552e1c2015-03-26 15:01:03 +000040static constexpr size_t kVRegSize = 4;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000041
Roland Levillaind780c002015-07-15 14:30:26 +010042// We encode the number of bytes needed for writing a value on 3 bits
43// (i.e. up to 8 values), for values that we know are maximum 32-bit
44// long.
45static constexpr size_t kNumberOfBitForNumberOfBytesForEncoding = 3;
46
Nicolas Geoffray004c2302015-03-20 10:06:38 +000047class CodeInfo;
David Brazdilf677ebf2015-05-29 16:29:43 +010048class StackMapEncoding;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000049
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010050/**
51 * Classes in the following file are wrapper on stack map information backed
52 * by a MemoryRegion. As such they read and write to the region, they don't have
53 * their own fields.
54 */
55
Roland Levillaina2d8ec62015-03-12 15:25:29 +000056// Dex register location container used by DexRegisterMap and StackMapStream.
57class DexRegisterLocation {
58 public:
59 /*
60 * The location kind used to populate the Dex register information in a
61 * StackMapStream can either be:
David Brazdild9cb68e2015-08-25 13:52:43 +010062 * - kStack: vreg stored on the stack, value holds the stack offset;
63 * - kInRegister: vreg stored in low 32 bits of a core physical register,
64 * value holds the register number;
65 * - kInRegisterHigh: vreg stored in high 32 bits of a core physical register,
66 * value holds the register number;
67 * - kInFpuRegister: vreg stored in low 32 bits of an FPU register,
68 * value holds the register number;
69 * - kInFpuRegisterHigh: vreg stored in high 32 bits of an FPU register,
70 * value holds the register number;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000071 * - kConstant: value holds the constant;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000072 *
73 * In addition, DexRegisterMap also uses these values:
74 * - kInStackLargeOffset: value holds a "large" stack offset (greater than
Roland Levillaina552e1c2015-03-26 15:01:03 +000075 * or equal to 128 bytes);
76 * - kConstantLargeValue: value holds a "large" constant (lower than 0, or
David Brazdild9cb68e2015-08-25 13:52:43 +010077 * or greater than or equal to 32);
78 * - kNone: the register has no location, meaning it has not been set.
Roland Levillaina2d8ec62015-03-12 15:25:29 +000079 */
80 enum class Kind : uint8_t {
81 // Short location kinds, for entries fitting on one byte (3 bits
82 // for the kind, 5 bits for the value) in a DexRegisterMap.
David Brazdild9cb68e2015-08-25 13:52:43 +010083 kInStack = 0, // 0b000
84 kInRegister = 1, // 0b001
85 kInRegisterHigh = 2, // 0b010
Roland Levillaina2d8ec62015-03-12 15:25:29 +000086 kInFpuRegister = 3, // 0b011
David Brazdild9cb68e2015-08-25 13:52:43 +010087 kInFpuRegisterHigh = 4, // 0b100
88 kConstant = 5, // 0b101
Roland Levillaina2d8ec62015-03-12 15:25:29 +000089
90 // Large location kinds, requiring a 5-byte encoding (1 byte for the
91 // kind, 4 bytes for the value).
92
93 // Stack location at a large offset, meaning that the offset value
94 // divided by the stack frame slot size (4 bytes) cannot fit on a
95 // 5-bit unsigned integer (i.e., this offset value is greater than
96 // or equal to 2^5 * 4 = 128 bytes).
David Brazdild9cb68e2015-08-25 13:52:43 +010097 kInStackLargeOffset = 6, // 0b110
Roland Levillaina2d8ec62015-03-12 15:25:29 +000098
99 // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
Roland Levillaina552e1c2015-03-26 15:01:03 +0000100 // lower than 0, or greater than or equal to 2^5 = 32).
David Brazdild9cb68e2015-08-25 13:52:43 +0100101 kConstantLargeValue = 7, // 0b111
102
103 // Entries with no location are not stored and do not need own marker.
104 kNone = static_cast<uint8_t>(-1),
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000105
106 kLastLocationKind = kConstantLargeValue
107 };
108
109 static_assert(
110 sizeof(Kind) == 1u,
111 "art::DexRegisterLocation::Kind has a size different from one byte.");
112
113 static const char* PrettyDescriptor(Kind kind) {
114 switch (kind) {
115 case Kind::kNone:
116 return "none";
117 case Kind::kInStack:
118 return "in stack";
119 case Kind::kInRegister:
120 return "in register";
David Brazdild9cb68e2015-08-25 13:52:43 +0100121 case Kind::kInRegisterHigh:
122 return "in register high";
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000123 case Kind::kInFpuRegister:
124 return "in fpu register";
David Brazdild9cb68e2015-08-25 13:52:43 +0100125 case Kind::kInFpuRegisterHigh:
126 return "in fpu register high";
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000127 case Kind::kConstant:
128 return "as constant";
129 case Kind::kInStackLargeOffset:
130 return "in stack (large offset)";
131 case Kind::kConstantLargeValue:
132 return "as constant (large value)";
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000133 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100134 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000135 }
136
137 static bool IsShortLocationKind(Kind kind) {
138 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000139 case Kind::kInStack:
140 case Kind::kInRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100141 case Kind::kInRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000142 case Kind::kInFpuRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100143 case Kind::kInFpuRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000144 case Kind::kConstant:
145 return true;
146
147 case Kind::kInStackLargeOffset:
148 case Kind::kConstantLargeValue:
149 return false;
150
David Brazdild9cb68e2015-08-25 13:52:43 +0100151 case Kind::kNone:
152 LOG(FATAL) << "Unexpected location kind " << PrettyDescriptor(kind);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000153 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100154 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000155 }
156
157 // Convert `kind` to a "surface" kind, i.e. one that doesn't include
158 // any value with a "large" qualifier.
159 // TODO: Introduce another enum type for the surface kind?
160 static Kind ConvertToSurfaceKind(Kind kind) {
161 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000162 case Kind::kInStack:
163 case Kind::kInRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100164 case Kind::kInRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000165 case Kind::kInFpuRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100166 case Kind::kInFpuRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000167 case Kind::kConstant:
168 return kind;
169
170 case Kind::kInStackLargeOffset:
171 return Kind::kInStack;
172
173 case Kind::kConstantLargeValue:
174 return Kind::kConstant;
175
David Brazdild9cb68e2015-08-25 13:52:43 +0100176 case Kind::kNone:
177 return kind;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000178 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100179 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000180 }
181
Roland Levillaina552e1c2015-03-26 15:01:03 +0000182 // Required by art::StackMapStream::LocationCatalogEntriesIndices.
183 DexRegisterLocation() : kind_(Kind::kNone), value_(0) {}
184
185 DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {}
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000186
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000187 static DexRegisterLocation None() {
188 return DexRegisterLocation(Kind::kNone, 0);
189 }
190
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000191 // Get the "surface" kind of the location, i.e., the one that doesn't
192 // include any value with a "large" qualifier.
193 Kind GetKind() const {
194 return ConvertToSurfaceKind(kind_);
195 }
196
197 // Get the value of the location.
198 int32_t GetValue() const { return value_; }
199
200 // Get the actual kind of the location.
201 Kind GetInternalKind() const { return kind_; }
202
Calin Juravle6ae70962015-03-18 16:31:28 +0000203 bool operator==(DexRegisterLocation other) const {
204 return kind_ == other.kind_ && value_ == other.value_;
205 }
206
207 bool operator!=(DexRegisterLocation other) const {
208 return !(*this == other);
209 }
210
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000211 private:
212 Kind kind_;
213 int32_t value_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000214
215 friend class DexRegisterLocationHashFn;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000216};
217
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100218/**
Roland Levillaina552e1c2015-03-26 15:01:03 +0000219 * Store information on unique Dex register locations used in a method.
220 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100221 *
222 * [DexRegisterLocation+].
223 *
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000224 * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100225 */
Roland Levillaina552e1c2015-03-26 15:01:03 +0000226class DexRegisterLocationCatalog {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100227 public:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000228 explicit DexRegisterLocationCatalog(MemoryRegion region) : region_(region) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100229
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000230 // Short (compressed) location, fitting on one byte.
231 typedef uint8_t ShortLocation;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100232
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000233 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
234 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
235 int32_t value = dex_register_location.GetValue();
236 if (DexRegisterLocation::IsShortLocationKind(kind)) {
237 // Short location. Compress the kind and the value as a single byte.
238 if (kind == DexRegisterLocation::Kind::kInStack) {
239 // Instead of storing stack offsets expressed in bytes for
240 // short stack locations, store slot offsets. A stack offset
241 // is a multiple of 4 (kFrameSlotSize). This means that by
242 // dividing it by 4, we can fit values from the [0, 128)
243 // interval in a short stack location, and not just values
244 // from the [0, 32) interval.
245 DCHECK_EQ(value % kFrameSlotSize, 0);
246 value /= kFrameSlotSize;
247 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000248 DCHECK(IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000249 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
250 } else {
251 // Large location. Write the location on one byte and the value
252 // on 4 bytes.
Roland Levillaina552e1c2015-03-26 15:01:03 +0000253 DCHECK(!IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000254 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
255 // Also divide large stack offsets by 4 for the sake of consistency.
256 DCHECK_EQ(value % kFrameSlotSize, 0);
257 value /= kFrameSlotSize;
258 }
259 // Data can be unaligned as the written Dex register locations can
260 // either be 1-byte or 5-byte wide. Use
261 // art::MemoryRegion::StoreUnaligned instead of
262 // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
263 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
264 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
Roland Levillain442b46a2015-02-18 16:54:21 +0000265 }
266 }
267
Roland Levillaina552e1c2015-03-26 15:01:03 +0000268 // Find the offset of the location catalog entry number `location_catalog_entry_index`.
269 size_t FindLocationOffset(size_t location_catalog_entry_index) const {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000270 size_t offset = kFixedSize;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000271 // Skip the first `location_catalog_entry_index - 1` entries.
272 for (uint16_t i = 0; i < location_catalog_entry_index; ++i) {
273 // Read the first next byte and inspect its first 3 bits to decide
274 // whether it is a short or a large location.
275 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
276 if (DexRegisterLocation::IsShortLocationKind(kind)) {
277 // Short location. Skip the current byte.
278 offset += SingleShortEntrySize();
279 } else {
280 // Large location. Skip the 5 next bytes.
281 offset += SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000282 }
283 }
284 return offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100285 }
286
Roland Levillaina552e1c2015-03-26 15:01:03 +0000287 // Get the internal kind of entry at `location_catalog_entry_index`.
288 DexRegisterLocation::Kind GetLocationInternalKind(size_t location_catalog_entry_index) const {
289 if (location_catalog_entry_index == kNoLocationEntryIndex) {
290 return DexRegisterLocation::Kind::kNone;
291 }
292 return ExtractKindAtOffset(FindLocationOffset(location_catalog_entry_index));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100293 }
294
Roland Levillaina552e1c2015-03-26 15:01:03 +0000295 // Get the (surface) kind and value of entry at `location_catalog_entry_index`.
296 DexRegisterLocation GetDexRegisterLocation(size_t location_catalog_entry_index) const {
297 if (location_catalog_entry_index == kNoLocationEntryIndex) {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000298 return DexRegisterLocation::None();
299 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000300 size_t offset = FindLocationOffset(location_catalog_entry_index);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000301 // Read the first byte and inspect its first 3 bits to get the location.
302 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
303 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
304 if (DexRegisterLocation::IsShortLocationKind(kind)) {
305 // Short location. Extract the value from the remaining 5 bits.
306 int32_t value = ExtractValueFromShortLocation(first_byte);
307 if (kind == DexRegisterLocation::Kind::kInStack) {
308 // Convert the stack slot (short) offset to a byte offset value.
309 value *= kFrameSlotSize;
310 }
311 return DexRegisterLocation(kind, value);
312 } else {
313 // Large location. Read the four next bytes to get the value.
314 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
315 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
316 // Convert the stack slot (large) offset to a byte offset value.
317 value *= kFrameSlotSize;
318 }
319 return DexRegisterLocation(kind, value);
320 }
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100321 }
322
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000323 // Compute the compressed kind of `location`.
324 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
David Brazdild9cb68e2015-08-25 13:52:43 +0100325 DexRegisterLocation::Kind kind = location.GetInternalKind();
326 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000327 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000328 return IsShortStackOffsetValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000329 ? DexRegisterLocation::Kind::kInStack
330 : DexRegisterLocation::Kind::kInStackLargeOffset;
331
David Brazdild9cb68e2015-08-25 13:52:43 +0100332 case DexRegisterLocation::Kind::kInRegister:
333 case DexRegisterLocation::Kind::kInRegisterHigh:
334 DCHECK_GE(location.GetValue(), 0);
335 DCHECK_LT(location.GetValue(), 1 << kValueBits);
336 return kind;
337
338 case DexRegisterLocation::Kind::kInFpuRegister:
339 case DexRegisterLocation::Kind::kInFpuRegisterHigh:
340 DCHECK_GE(location.GetValue(), 0);
341 DCHECK_LT(location.GetValue(), 1 << kValueBits);
342 return kind;
343
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000344 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000345 return IsShortConstantValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000346 ? DexRegisterLocation::Kind::kConstant
347 : DexRegisterLocation::Kind::kConstantLargeValue;
348
David Brazdild9cb68e2015-08-25 13:52:43 +0100349 case DexRegisterLocation::Kind::kConstantLargeValue:
350 case DexRegisterLocation::Kind::kInStackLargeOffset:
351 case DexRegisterLocation::Kind::kNone:
352 LOG(FATAL) << "Unexpected location kind " << DexRegisterLocation::PrettyDescriptor(kind);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000353 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100354 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000355 }
356
357 // Can `location` be turned into a short location?
358 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
David Brazdild9cb68e2015-08-25 13:52:43 +0100359 DexRegisterLocation::Kind kind = location.GetInternalKind();
360 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000361 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000362 return IsShortStackOffsetValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000363
David Brazdild9cb68e2015-08-25 13:52:43 +0100364 case DexRegisterLocation::Kind::kInRegister:
365 case DexRegisterLocation::Kind::kInRegisterHigh:
366 case DexRegisterLocation::Kind::kInFpuRegister:
367 case DexRegisterLocation::Kind::kInFpuRegisterHigh:
368 return true;
369
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000370 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000371 return IsShortConstantValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000372
David Brazdild9cb68e2015-08-25 13:52:43 +0100373 case DexRegisterLocation::Kind::kConstantLargeValue:
374 case DexRegisterLocation::Kind::kInStackLargeOffset:
375 case DexRegisterLocation::Kind::kNone:
376 LOG(FATAL) << "Unexpected location kind " << DexRegisterLocation::PrettyDescriptor(kind);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000377 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100378 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000379 }
380
381 static size_t EntrySize(const DexRegisterLocation& location) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000382 return CanBeEncodedAsShortLocation(location) ? SingleShortEntrySize() : SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000383 }
384
385 static size_t SingleShortEntrySize() {
386 return sizeof(ShortLocation);
387 }
388
389 static size_t SingleLargeEntrySize() {
390 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100391 }
392
Roland Levillain12baf472015-03-05 12:41:42 +0000393 size_t Size() const {
394 return region_.size();
395 }
396
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100397 void Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info);
Roland Levillain0396ed72015-05-27 15:12:19 +0100398
Roland Levillaina552e1c2015-03-26 15:01:03 +0000399 // Special (invalid) Dex register location catalog entry index meaning
400 // that there is no location for a given Dex register (i.e., it is
401 // mapped to a DexRegisterLocation::Kind::kNone location).
402 static constexpr size_t kNoLocationEntryIndex = -1;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100403
Roland Levillain12baf472015-03-05 12:41:42 +0000404 private:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000405 static constexpr int kFixedSize = 0;
406
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000407 // Width of the kind "field" in a short location, in bits.
408 static constexpr size_t kKindBits = 3;
409 // Width of the value "field" in a short location, in bits.
410 static constexpr size_t kValueBits = 5;
411
412 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
413 static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
414 static constexpr size_t kKindOffset = 0;
415 static constexpr size_t kValueOffset = kKindBits;
416
Roland Levillaina552e1c2015-03-26 15:01:03 +0000417 static bool IsShortStackOffsetValue(int32_t value) {
418 DCHECK_EQ(value % kFrameSlotSize, 0);
419 return IsShortValue(value / kFrameSlotSize);
420 }
421
422 static bool IsShortConstantValue(int32_t value) {
423 return IsShortValue(value);
424 }
425
426 static bool IsShortValue(int32_t value) {
427 return IsUint<kValueBits>(value);
428 }
429
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000430 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000431 uint8_t kind_integer_value = static_cast<uint8_t>(kind);
432 DCHECK(IsUint<kKindBits>(kind_integer_value)) << kind_integer_value;
433 DCHECK(IsShortValue(value)) << value;
434 return (kind_integer_value & kKindMask) << kKindOffset
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000435 | (value & kValueMask) << kValueOffset;
436 }
437
438 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
439 uint8_t kind = (location >> kKindOffset) & kKindMask;
440 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000441 // We do not encode kNone locations in the stack map.
442 DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone));
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000443 return static_cast<DexRegisterLocation::Kind>(kind);
444 }
445
446 static int32_t ExtractValueFromShortLocation(ShortLocation location) {
447 return (location >> kValueOffset) & kValueMask;
448 }
449
450 // Extract a location kind from the byte at position `offset`.
451 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
452 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
453 return ExtractKindFromShortLocation(first_byte);
454 }
455
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100456 MemoryRegion region_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000457
458 friend class CodeInfo;
459 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100460};
461
Roland Levillaina552e1c2015-03-26 15:01:03 +0000462/* Information on Dex register locations for a specific PC, mapping a
463 * stack map's Dex register to a location entry in a DexRegisterLocationCatalog.
464 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100465 *
466 * [live_bit_mask, entries*]
467 *
Roland Levillaina552e1c2015-03-26 15:01:03 +0000468 * where entries are concatenated unsigned integer values encoded on a number
469 * of bits (fixed per DexRegisterMap instances of a CodeInfo object) depending
470 * on the number of entries in the Dex register location catalog
471 * (see DexRegisterMap::SingleEntrySizeInBits). The map is 1-byte aligned.
472 */
473class DexRegisterMap {
474 public:
475 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
476
477 // Get the surface kind of Dex register `dex_register_number`.
478 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number,
479 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100480 const CodeInfo& code_info,
481 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000482 return DexRegisterLocation::ConvertToSurfaceKind(
David Brazdilf677ebf2015-05-29 16:29:43 +0100483 GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info, enc));
Roland Levillaina552e1c2015-03-26 15:01:03 +0000484 }
485
486 // Get the internal kind of Dex register `dex_register_number`.
487 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number,
488 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100489 const CodeInfo& code_info,
490 const StackMapEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000491
492 // Get the Dex register location `dex_register_number`.
493 DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number,
494 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100495 const CodeInfo& code_info,
496 const StackMapEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000497
498 int32_t GetStackOffsetInBytes(uint16_t dex_register_number,
499 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100500 const CodeInfo& code_info,
501 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000502 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100503 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000504 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
505 // GetDexRegisterLocation returns the offset in bytes.
506 return location.GetValue();
507 }
508
509 int32_t GetConstant(uint16_t dex_register_number,
510 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100511 const CodeInfo& code_info,
512 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000513 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100514 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100515 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant)
516 << DexRegisterLocation::PrettyDescriptor(location.GetKind());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000517 return location.GetValue();
518 }
519
520 int32_t GetMachineRegister(uint16_t dex_register_number,
521 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100522 const CodeInfo& code_info,
523 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000524 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100525 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
David Brazdild9cb68e2015-08-25 13:52:43 +0100526 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister ||
527 location.GetInternalKind() == DexRegisterLocation::Kind::kInRegisterHigh ||
528 location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister ||
529 location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh)
Roland Levillaina552e1c2015-03-26 15:01:03 +0000530 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
531 return location.GetValue();
532 }
533
534 // Get the index of the entry in the Dex register location catalog
535 // corresponding to `dex_register_number`.
536 size_t GetLocationCatalogEntryIndex(uint16_t dex_register_number,
537 uint16_t number_of_dex_registers,
538 size_t number_of_location_catalog_entries) const {
539 if (!IsDexRegisterLive(dex_register_number)) {
540 return DexRegisterLocationCatalog::kNoLocationEntryIndex;
541 }
542
543 if (number_of_location_catalog_entries == 1) {
544 // We do not allocate space for location maps in the case of a
545 // single-entry location catalog, as it is useless. The only valid
546 // entry index is 0;
547 return 0;
548 }
549
550 // The bit offset of the beginning of the map locations.
551 size_t map_locations_offset_in_bits =
552 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
553 size_t index_in_dex_register_map = GetIndexInDexRegisterMap(dex_register_number);
554 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
555 // The bit size of an entry.
556 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
557 // The bit offset where `index_in_dex_register_map` is located.
558 size_t entry_offset_in_bits =
559 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
560 size_t location_catalog_entry_index =
561 region_.LoadBits(entry_offset_in_bits, map_entry_size_in_bits);
562 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
563 return location_catalog_entry_index;
564 }
565
566 // Map entry at `index_in_dex_register_map` to `location_catalog_entry_index`.
567 void SetLocationCatalogEntryIndex(size_t index_in_dex_register_map,
568 size_t location_catalog_entry_index,
569 uint16_t number_of_dex_registers,
570 size_t number_of_location_catalog_entries) {
571 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
572 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
573
574 if (number_of_location_catalog_entries == 1) {
575 // We do not allocate space for location maps in the case of a
576 // single-entry location catalog, as it is useless.
577 return;
578 }
579
580 // The bit offset of the beginning of the map locations.
581 size_t map_locations_offset_in_bits =
582 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
583 // The bit size of an entry.
584 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
585 // The bit offset where `index_in_dex_register_map` is located.
586 size_t entry_offset_in_bits =
587 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
588 region_.StoreBits(entry_offset_in_bits, location_catalog_entry_index, map_entry_size_in_bits);
589 }
590
591 void SetLiveBitMask(uint16_t number_of_dex_registers,
592 const BitVector& live_dex_registers_mask) {
593 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
594 for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
595 region_.StoreBit(live_bit_mask_offset_in_bits + i, live_dex_registers_mask.IsBitSet(i));
596 }
597 }
598
599 bool IsDexRegisterLive(uint16_t dex_register_number) const {
600 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
601 return region_.LoadBit(live_bit_mask_offset_in_bits + dex_register_number);
602 }
603
604 size_t GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers) const {
605 size_t number_of_live_dex_registers = 0;
606 for (size_t i = 0; i < number_of_dex_registers; ++i) {
607 if (IsDexRegisterLive(i)) {
608 ++number_of_live_dex_registers;
609 }
610 }
611 return number_of_live_dex_registers;
612 }
613
614 static size_t GetLiveBitMaskOffset() {
615 return kFixedSize;
616 }
617
618 // Compute the size of the live register bit mask (in bytes), for a
619 // method having `number_of_dex_registers` Dex registers.
620 static size_t GetLiveBitMaskSize(uint16_t number_of_dex_registers) {
621 return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte;
622 }
623
624 static size_t GetLocationMappingDataOffset(uint16_t number_of_dex_registers) {
625 return GetLiveBitMaskOffset() + GetLiveBitMaskSize(number_of_dex_registers);
626 }
627
628 size_t GetLocationMappingDataSize(uint16_t number_of_dex_registers,
629 size_t number_of_location_catalog_entries) const {
630 size_t location_mapping_data_size_in_bits =
631 GetNumberOfLiveDexRegisters(number_of_dex_registers)
632 * SingleEntrySizeInBits(number_of_location_catalog_entries);
633 return RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
634 }
635
636 // Return the size of a map entry in bits. Note that if
637 // `number_of_location_catalog_entries` equals 1, this function returns 0,
638 // which is fine, as there is no need to allocate a map for a
639 // single-entry location catalog; the only valid location catalog entry index
640 // for a live register in this case is 0 and there is no need to
641 // store it.
642 static size_t SingleEntrySizeInBits(size_t number_of_location_catalog_entries) {
643 // Handle the case of 0, as we cannot pass 0 to art::WhichPowerOf2.
644 return number_of_location_catalog_entries == 0
645 ? 0u
646 : WhichPowerOf2(RoundUpToPowerOfTwo(number_of_location_catalog_entries));
647 }
648
649 // Return the size of the DexRegisterMap object, in bytes.
650 size_t Size() const {
651 return region_.size();
652 }
653
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100654 void Dump(VariableIndentationOutputStream* vios,
655 const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100656
Roland Levillaina552e1c2015-03-26 15:01:03 +0000657 private:
658 // Return the index in the Dex register map corresponding to the Dex
659 // register number `dex_register_number`.
660 size_t GetIndexInDexRegisterMap(uint16_t dex_register_number) const {
661 if (!IsDexRegisterLive(dex_register_number)) {
662 return kInvalidIndexInDexRegisterMap;
663 }
664 return GetNumberOfLiveDexRegisters(dex_register_number);
665 }
666
667 // Special (invalid) Dex register map entry index meaning that there
668 // is no index in the map for a given Dex register (i.e., it must
669 // have been mapped to a DexRegisterLocation::Kind::kNone location).
670 static constexpr size_t kInvalidIndexInDexRegisterMap = -1;
671
672 static constexpr int kFixedSize = 0;
673
674 MemoryRegion region_;
675
676 friend class CodeInfo;
677 friend class StackMapStream;
678};
679
David Brazdilf677ebf2015-05-29 16:29:43 +0100680class StackMapEncoding {
681 public:
682 StackMapEncoding() {}
683
684 StackMapEncoding(size_t stack_mask_size,
685 size_t bytes_for_inline_info,
686 size_t bytes_for_dex_register_map,
687 size_t bytes_for_dex_pc,
688 size_t bytes_for_native_pc,
689 size_t bytes_for_register_mask)
690 : bytes_for_stack_mask_(stack_mask_size),
691 bytes_for_inline_info_(bytes_for_inline_info),
692 bytes_for_dex_register_map_(bytes_for_dex_register_map),
693 bytes_for_dex_pc_(bytes_for_dex_pc),
694 bytes_for_native_pc_(bytes_for_native_pc),
695 bytes_for_register_mask_(bytes_for_register_mask) {}
696
697 static StackMapEncoding CreateFromSizes(size_t stack_mask_size,
698 size_t inline_info_size,
699 size_t dex_register_map_size,
700 size_t dex_pc_max,
701 size_t native_pc_max,
702 size_t register_mask_max) {
703 return StackMapEncoding(
704 stack_mask_size,
705 // + 1 to also encode kNoInlineInfo: if an inline info offset
706 // is at 0xFF, we want to overflow to a larger encoding, because it will
707 // conflict with kNoInlineInfo.
708 // The offset is relative to the dex register map. TODO: Change this.
709 inline_info_size == 0
710 ? 0
711 : EncodingSizeInBytes(dex_register_map_size + inline_info_size + 1),
712 // + 1 to also encode kNoDexRegisterMap: if a dex register map offset
713 // is at 0xFF, we want to overflow to a larger encoding, because it will
714 // conflict with kNoDexRegisterMap.
715 EncodingSizeInBytes(dex_register_map_size + 1),
716 EncodingSizeInBytes(dex_pc_max),
717 EncodingSizeInBytes(native_pc_max),
718 EncodingSizeInBytes(register_mask_max));
719 }
720
721 // Get the size of one stack map of this CodeInfo object, in bytes.
722 // All stack maps of a CodeInfo have the same size.
723 size_t ComputeStackMapSize() const {
724 return bytes_for_register_mask_
725 + bytes_for_stack_mask_
726 + bytes_for_inline_info_
727 + bytes_for_dex_register_map_
728 + bytes_for_dex_pc_
729 + bytes_for_native_pc_;
730 }
731
732 bool HasInlineInfo() const { return bytes_for_inline_info_ > 0; }
733
734 size_t NumberOfBytesForStackMask() const { return bytes_for_stack_mask_; }
735 size_t NumberOfBytesForInlineInfo() const { return bytes_for_inline_info_; }
736 size_t NumberOfBytesForDexRegisterMap() const { return bytes_for_dex_register_map_; }
737 size_t NumberOfBytesForDexPc() const { return bytes_for_dex_pc_; }
738 size_t NumberOfBytesForNativePc() const { return bytes_for_native_pc_; }
739 size_t NumberOfBytesForRegisterMask() const { return bytes_for_register_mask_; }
740
741 size_t ComputeStackMapRegisterMaskOffset() const {
742 return kRegisterMaskOffset;
743 }
744
745 size_t ComputeStackMapStackMaskOffset() const {
746 return ComputeStackMapRegisterMaskOffset() + bytes_for_register_mask_;
747 }
748
749 size_t ComputeStackMapDexPcOffset() const {
750 return ComputeStackMapStackMaskOffset() + bytes_for_stack_mask_;
751 }
752
753 size_t ComputeStackMapNativePcOffset() const {
754 return ComputeStackMapDexPcOffset() + bytes_for_dex_pc_;
755 }
756
757 size_t ComputeStackMapDexRegisterMapOffset() const {
758 return ComputeStackMapNativePcOffset() + bytes_for_native_pc_;
759 }
760
761 size_t ComputeStackMapInlineInfoOffset() const {
762 return ComputeStackMapDexRegisterMapOffset() + bytes_for_dex_register_map_;
763 }
764
765 private:
766 static size_t EncodingSizeInBytes(size_t max_element) {
767 DCHECK(IsUint<32>(max_element));
768 return (max_element == 0) ? 0
769 : IsUint<8>(max_element) ? 1
770 : IsUint<16>(max_element) ? 2
771 : IsUint<24>(max_element) ? 3
772 : 4;
773 }
774
775 static constexpr int kRegisterMaskOffset = 0;
776
777 size_t bytes_for_stack_mask_;
778 size_t bytes_for_inline_info_;
779 size_t bytes_for_dex_register_map_;
780 size_t bytes_for_dex_pc_;
781 size_t bytes_for_native_pc_;
782 size_t bytes_for_register_mask_;
783};
784
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100785/**
786 * A Stack Map holds compilation information for a specific PC necessary for:
787 * - Mapping it to a dex PC,
788 * - Knowing which stack entries are objects,
789 * - Knowing which registers hold objects,
790 * - Knowing the inlining information,
791 * - Knowing the values of dex registers.
792 *
793 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100794 *
795 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask,
796 * stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100797 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100798class StackMap {
799 public:
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100800 StackMap() {}
David Brazdilf677ebf2015-05-29 16:29:43 +0100801 explicit StackMap(MemoryRegion region) : region_(region) {}
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100802
803 bool IsValid() const { return region_.pointer() != nullptr; }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100804
David Brazdilf677ebf2015-05-29 16:29:43 +0100805 uint32_t GetDexPc(const StackMapEncoding& encoding) const {
806 return LoadAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset());
807 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100808
David Brazdilf677ebf2015-05-29 16:29:43 +0100809 void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) {
810 StoreAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset(), dex_pc);
811 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100812
David Brazdilf677ebf2015-05-29 16:29:43 +0100813 uint32_t GetNativePcOffset(const StackMapEncoding& encoding) const {
814 return LoadAt(encoding.NumberOfBytesForNativePc(), encoding.ComputeStackMapNativePcOffset());
815 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100816
David Brazdilf677ebf2015-05-29 16:29:43 +0100817 void SetNativePcOffset(const StackMapEncoding& encoding, uint32_t native_pc_offset) {
818 StoreAt(encoding.NumberOfBytesForNativePc(),
819 encoding.ComputeStackMapNativePcOffset(),
820 native_pc_offset);
821 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100822
David Brazdilf677ebf2015-05-29 16:29:43 +0100823 uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const {
824 return LoadAt(encoding.NumberOfBytesForDexRegisterMap(),
825 encoding.ComputeStackMapDexRegisterMapOffset(),
826 /* check_max */ true);
827 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100828
David Brazdilf677ebf2015-05-29 16:29:43 +0100829 void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) {
830 StoreAt(encoding.NumberOfBytesForDexRegisterMap(),
831 encoding.ComputeStackMapDexRegisterMapOffset(),
832 offset);
833 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100834
David Brazdilf677ebf2015-05-29 16:29:43 +0100835 uint32_t GetInlineDescriptorOffset(const StackMapEncoding& encoding) const {
836 if (!encoding.HasInlineInfo()) return kNoInlineInfo;
837 return LoadAt(encoding.NumberOfBytesForInlineInfo(),
838 encoding.ComputeStackMapInlineInfoOffset(),
839 /* check_max */ true);
840 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100841
David Brazdilf677ebf2015-05-29 16:29:43 +0100842 void SetInlineDescriptorOffset(const StackMapEncoding& encoding, uint32_t offset) {
843 DCHECK(encoding.HasInlineInfo());
844 StoreAt(encoding.NumberOfBytesForInlineInfo(),
845 encoding.ComputeStackMapInlineInfoOffset(),
846 offset);
847 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100848
David Brazdilf677ebf2015-05-29 16:29:43 +0100849 uint32_t GetRegisterMask(const StackMapEncoding& encoding) const {
850 return LoadAt(encoding.NumberOfBytesForRegisterMask(),
851 encoding.ComputeStackMapRegisterMaskOffset());
852 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100853
David Brazdilf677ebf2015-05-29 16:29:43 +0100854 void SetRegisterMask(const StackMapEncoding& encoding, uint32_t mask) {
855 StoreAt(encoding.NumberOfBytesForRegisterMask(),
856 encoding.ComputeStackMapRegisterMaskOffset(),
857 mask);
858 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100859
David Brazdilf677ebf2015-05-29 16:29:43 +0100860 MemoryRegion GetStackMask(const StackMapEncoding& encoding) const {
861 return region_.Subregion(encoding.ComputeStackMapStackMaskOffset(),
862 encoding.NumberOfBytesForStackMask());
863 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100864
David Brazdilf677ebf2015-05-29 16:29:43 +0100865 void SetStackMask(const StackMapEncoding& encoding, const BitVector& sp_map) {
866 MemoryRegion region = GetStackMask(encoding);
David Brazdilf10a25f2015-06-02 14:29:52 +0100867 sp_map.CopyTo(region.start(), region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100868 }
869
David Brazdilf677ebf2015-05-29 16:29:43 +0100870 bool HasDexRegisterMap(const StackMapEncoding& encoding) const {
871 return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100872 }
873
David Brazdilf677ebf2015-05-29 16:29:43 +0100874 bool HasInlineInfo(const StackMapEncoding& encoding) const {
875 return GetInlineDescriptorOffset(encoding) != kNoInlineInfo;
Roland Levillain442b46a2015-02-18 16:54:21 +0000876 }
877
878 bool Equals(const StackMap& other) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100879 return region_.pointer() == other.region_.pointer()
880 && region_.size() == other.region_.size();
881 }
882
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100883 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100884 const CodeInfo& code_info,
David Brazdilf677ebf2015-05-29 16:29:43 +0100885 const StackMapEncoding& encoding,
Roland Levillainf2650d12015-05-28 14:53:28 +0100886 uint32_t code_offset,
887 uint16_t number_of_dex_registers,
888 const std::string& header_suffix = "") const;
889
Roland Levillain442b46a2015-02-18 16:54:21 +0000890 // Special (invalid) offset for the DexRegisterMapOffset field meaning
891 // that there is no Dex register map for this stack map.
892 static constexpr uint32_t kNoDexRegisterMap = -1;
893
894 // Special (invalid) offset for the InlineDescriptorOffset field meaning
895 // that there is no inline info for this stack map.
896 static constexpr uint32_t kNoInlineInfo = -1;
897
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100898 private:
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100899 static constexpr int kFixedSize = 0;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100900
David Brazdilf677ebf2015-05-29 16:29:43 +0100901 // Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true,
902 // this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF.
903 uint32_t LoadAt(size_t number_of_bytes, size_t offset, bool check_max = false) const;
904 void StoreAt(size_t number_of_bytes, size_t offset, uint32_t value) const;
905
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100906 MemoryRegion region_;
907
Nicolas Geoffray39468442014-09-02 15:17:15 +0100908 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100909};
910
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100911/**
912 * Inline information for a specific PC. The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100913 *
914 * [inlining_depth, entry+]
915 *
916 * where `entry` is of the form:
917 *
918 * [dex_pc, method_index, dex_register_map_offset].
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100919 */
920class InlineInfo {
921 public:
Roland Levillain1c1da432015-07-16 11:54:44 +0100922 // Memory layout: fixed contents.
923 typedef uint8_t DepthType;
924 // Memory layout: single entry contents.
925 typedef uint32_t MethodIndexType;
926 typedef uint32_t DexPcType;
927 typedef uint8_t InvokeTypeType;
928 typedef uint32_t DexRegisterMapType;
929
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100930 explicit InlineInfo(MemoryRegion region) : region_(region) {}
931
Roland Levillain1c1da432015-07-16 11:54:44 +0100932 DepthType GetDepth() const {
933 return region_.LoadUnaligned<DepthType>(kDepthOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100934 }
935
Roland Levillain1c1da432015-07-16 11:54:44 +0100936 void SetDepth(DepthType depth) {
937 region_.StoreUnaligned<DepthType>(kDepthOffset, depth);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100938 }
939
Roland Levillain1c1da432015-07-16 11:54:44 +0100940 MethodIndexType GetMethodIndexAtDepth(DepthType depth) const {
941 return region_.LoadUnaligned<MethodIndexType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100942 kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100943 }
944
Roland Levillain1c1da432015-07-16 11:54:44 +0100945 void SetMethodIndexAtDepth(DepthType depth, MethodIndexType index) {
946 region_.StoreUnaligned<MethodIndexType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100947 kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset, index);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100948 }
949
Roland Levillain1c1da432015-07-16 11:54:44 +0100950 DexPcType GetDexPcAtDepth(DepthType depth) const {
951 return region_.LoadUnaligned<DexPcType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100952 kFixedSize + depth * SingleEntrySize() + kDexPcOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100953 }
954
Roland Levillain1c1da432015-07-16 11:54:44 +0100955 void SetDexPcAtDepth(DepthType depth, DexPcType dex_pc) {
956 region_.StoreUnaligned<DexPcType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100957 kFixedSize + depth * SingleEntrySize() + kDexPcOffset, dex_pc);
958 }
959
Roland Levillain1c1da432015-07-16 11:54:44 +0100960 InvokeTypeType GetInvokeTypeAtDepth(DepthType depth) const {
961 return region_.LoadUnaligned<InvokeTypeType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100962 kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset);
963 }
964
Roland Levillain1c1da432015-07-16 11:54:44 +0100965 void SetInvokeTypeAtDepth(DepthType depth, InvokeTypeType invoke_type) {
966 region_.StoreUnaligned<InvokeTypeType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100967 kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset, invoke_type);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100968 }
969
Roland Levillain1c1da432015-07-16 11:54:44 +0100970 DexRegisterMapType GetDexRegisterMapOffsetAtDepth(DepthType depth) const {
971 return region_.LoadUnaligned<DexRegisterMapType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100972 kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100973 }
974
Roland Levillain1c1da432015-07-16 11:54:44 +0100975 void SetDexRegisterMapOffsetAtDepth(DepthType depth, DexRegisterMapType offset) {
976 region_.StoreUnaligned<DexRegisterMapType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100977 kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset, offset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100978 }
979
Roland Levillain1c1da432015-07-16 11:54:44 +0100980 bool HasDexRegisterMapAtDepth(DepthType depth) const {
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100981 return GetDexRegisterMapOffsetAtDepth(depth) != StackMap::kNoDexRegisterMap;
982 }
983
984 static size_t SingleEntrySize() {
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100985 return kFixedEntrySize;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100986 }
987
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100988 void Dump(VariableIndentationOutputStream* vios,
989 const CodeInfo& info, uint16_t* number_of_dex_registers) const;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100990
Roland Levillain1c1da432015-07-16 11:54:44 +0100991
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100992 private:
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100993 static constexpr int kDepthOffset = 0;
Roland Levillain1c1da432015-07-16 11:54:44 +0100994 static constexpr int kFixedSize = ELEMENT_BYTE_OFFSET_AFTER(Depth);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100995
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100996 static constexpr int kMethodIndexOffset = 0;
Roland Levillain1c1da432015-07-16 11:54:44 +0100997 static constexpr int kDexPcOffset = ELEMENT_BYTE_OFFSET_AFTER(MethodIndex);
998 static constexpr int kInvokeTypeOffset = ELEMENT_BYTE_OFFSET_AFTER(DexPc);
999 static constexpr int kDexRegisterMapOffset = ELEMENT_BYTE_OFFSET_AFTER(InvokeType);
1000 static constexpr int kFixedEntrySize = ELEMENT_BYTE_OFFSET_AFTER(DexRegisterMap);
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +01001001
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001002 MemoryRegion region_;
1003
1004 friend class CodeInfo;
1005 friend class StackMap;
1006 friend class StackMapStream;
1007};
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001008
1009/**
1010 * Wrapper around all compiler information collected for a method.
1011 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +01001012 *
1013 * [overall_size, encoding_info, number_of_location_catalog_entries, number_of_stack_maps,
1014 * stack_mask_size, DexRegisterLocationCatalog+, StackMap+, DexRegisterMap+, InlineInfo*]
1015 *
1016 * where `encoding_info` is of the form:
1017 *
1018 * [has_inline_info, inline_info_size_in_bytes, dex_register_map_size_in_bytes,
1019 * dex_pc_size_in_bytes, native_pc_size_in_bytes, register_mask_size_in_bytes].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001020 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001021class CodeInfo {
1022 public:
Roland Levillain1c1da432015-07-16 11:54:44 +01001023 // Memory layout: fixed contents.
1024 typedef uint32_t OverallSizeType;
1025 typedef uint16_t EncodingInfoType;
1026 typedef uint32_t NumberOfLocationCatalogEntriesType;
1027 typedef uint32_t NumberOfStackMapsType;
1028 typedef uint32_t StackMaskSizeType;
1029
1030 // Memory (bit) layout: encoding info.
1031 static constexpr int HasInlineInfoBitSize = 1;
1032 static constexpr int InlineInfoBitSize = kNumberOfBitForNumberOfBytesForEncoding;
1033 static constexpr int DexRegisterMapBitSize = kNumberOfBitForNumberOfBytesForEncoding;
1034 static constexpr int DexPcBitSize = kNumberOfBitForNumberOfBytesForEncoding;
1035 static constexpr int NativePcBitSize = kNumberOfBitForNumberOfBytesForEncoding;
1036 static constexpr int RegisterMaskBitSize = kNumberOfBitForNumberOfBytesForEncoding;
1037
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001038 explicit CodeInfo(MemoryRegion region) : region_(region) {}
1039
Nicolas Geoffray39468442014-09-02 15:17:15 +01001040 explicit CodeInfo(const void* data) {
1041 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
1042 region_ = MemoryRegion(const_cast<void*>(data), size);
1043 }
1044
David Brazdilf677ebf2015-05-29 16:29:43 +01001045 StackMapEncoding ExtractEncoding() const {
1046 return StackMapEncoding(region_.LoadUnaligned<uint32_t>(kStackMaskSizeOffset),
1047 GetNumberOfBytesForEncoding(kInlineInfoBitOffset),
1048 GetNumberOfBytesForEncoding(kDexRegisterMapBitOffset),
1049 GetNumberOfBytesForEncoding(kDexPcBitOffset),
1050 GetNumberOfBytesForEncoding(kNativePcBitOffset),
1051 GetNumberOfBytesForEncoding(kRegisterMaskBitOffset));
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001052 }
1053
David Brazdilf677ebf2015-05-29 16:29:43 +01001054 void SetEncoding(const StackMapEncoding& encoding) {
1055 region_.StoreUnaligned<uint32_t>(kStackMaskSizeOffset, encoding.NumberOfBytesForStackMask());
1056 region_.StoreBit(kHasInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo() != 0);
1057 SetEncodingAt(kInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo());
1058 SetEncodingAt(kDexRegisterMapBitOffset, encoding.NumberOfBytesForDexRegisterMap());
1059 SetEncodingAt(kDexPcBitOffset, encoding.NumberOfBytesForDexPc());
1060 SetEncodingAt(kNativePcBitOffset, encoding.NumberOfBytesForNativePc());
1061 SetEncodingAt(kRegisterMaskBitOffset, encoding.NumberOfBytesForRegisterMask());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001062 }
1063
1064 void SetEncodingAt(size_t bit_offset, size_t number_of_bytes) {
Roland Levillaind780c002015-07-15 14:30:26 +01001065 region_.StoreBits(bit_offset, number_of_bytes, kNumberOfBitForNumberOfBytesForEncoding);
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001066 }
1067
1068 size_t GetNumberOfBytesForEncoding(size_t bit_offset) const {
Roland Levillaind780c002015-07-15 14:30:26 +01001069 return region_.LoadBits(bit_offset, kNumberOfBitForNumberOfBytesForEncoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001070 }
1071
1072 bool HasInlineInfo() const {
1073 return region_.LoadBit(kHasInlineInfoBitOffset);
1074 }
1075
David Brazdilf677ebf2015-05-29 16:29:43 +01001076 DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const StackMapEncoding& encoding) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +00001077 return DexRegisterLocationCatalog(region_.Subregion(
David Brazdilf677ebf2015-05-29 16:29:43 +01001078 GetDexRegisterLocationCatalogOffset(encoding),
1079 GetDexRegisterLocationCatalogSize(encoding)));
Roland Levillaina552e1c2015-03-26 15:01:03 +00001080 }
1081
David Brazdilf677ebf2015-05-29 16:29:43 +01001082 StackMap GetStackMapAt(size_t i, const StackMapEncoding& encoding) const {
1083 size_t stack_map_size = encoding.ComputeStackMapSize();
1084 return StackMap(GetStackMaps(encoding).Subregion(i * stack_map_size, stack_map_size));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001085 }
1086
Roland Levillain1c1da432015-07-16 11:54:44 +01001087 OverallSizeType GetOverallSize() const {
1088 return region_.LoadUnaligned<OverallSizeType>(kOverallSizeOffset);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001089 }
1090
Roland Levillain1c1da432015-07-16 11:54:44 +01001091 void SetOverallSize(OverallSizeType size) {
1092 region_.StoreUnaligned<OverallSizeType>(kOverallSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001093 }
1094
Roland Levillain1c1da432015-07-16 11:54:44 +01001095 NumberOfLocationCatalogEntriesType GetNumberOfLocationCatalogEntries() const {
1096 return region_.LoadUnaligned<NumberOfLocationCatalogEntriesType>(
1097 kNumberOfLocationCatalogEntriesOffset);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001098 }
1099
Roland Levillain1c1da432015-07-16 11:54:44 +01001100 void SetNumberOfLocationCatalogEntries(NumberOfLocationCatalogEntriesType num_entries) {
1101 region_.StoreUnaligned<NumberOfLocationCatalogEntriesType>(
1102 kNumberOfLocationCatalogEntriesOffset, num_entries);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001103 }
1104
David Brazdilf677ebf2015-05-29 16:29:43 +01001105 uint32_t GetDexRegisterLocationCatalogSize(const StackMapEncoding& encoding) const {
1106 return ComputeDexRegisterLocationCatalogSize(GetDexRegisterLocationCatalogOffset(encoding),
Roland Levillain1c1da432015-07-16 11:54:44 +01001107 GetNumberOfLocationCatalogEntries());
Roland Levillaina552e1c2015-03-26 15:01:03 +00001108 }
1109
Roland Levillain1c1da432015-07-16 11:54:44 +01001110 NumberOfStackMapsType GetNumberOfStackMaps() const {
1111 return region_.LoadUnaligned<NumberOfStackMapsType>(kNumberOfStackMapsOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001112 }
1113
Roland Levillain1c1da432015-07-16 11:54:44 +01001114 void SetNumberOfStackMaps(NumberOfStackMapsType number_of_stack_maps) {
1115 region_.StoreUnaligned<NumberOfStackMapsType>(kNumberOfStackMapsOffset, number_of_stack_maps);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001116 }
1117
Roland Levillain29ba1b02015-03-13 11:45:07 +00001118 // Get the size all the stack maps of this CodeInfo object, in bytes.
David Brazdilf677ebf2015-05-29 16:29:43 +01001119 size_t GetStackMapsSize(const StackMapEncoding& encoding) const {
1120 return encoding.ComputeStackMapSize() * GetNumberOfStackMaps();
Roland Levillain29ba1b02015-03-13 11:45:07 +00001121 }
1122
David Brazdilf677ebf2015-05-29 16:29:43 +01001123 uint32_t GetDexRegisterLocationCatalogOffset(const StackMapEncoding& encoding) const {
1124 return GetStackMapsOffset() + GetStackMapsSize(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001125 }
1126
David Brazdilf677ebf2015-05-29 16:29:43 +01001127 size_t GetDexRegisterMapsOffset(const StackMapEncoding& encoding) const {
1128 return GetDexRegisterLocationCatalogOffset(encoding)
1129 + GetDexRegisterLocationCatalogSize(encoding);
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001130 }
1131
Nicolas Geoffray6530baf2015-05-26 15:22:58 +01001132 uint32_t GetStackMapsOffset() const {
1133 return kFixedSize;
1134 }
1135
David Brazdilf677ebf2015-05-29 16:29:43 +01001136 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
1137 const StackMapEncoding& encoding,
1138 uint32_t number_of_dex_registers) const {
1139 DCHECK(stack_map.HasDexRegisterMap(encoding));
1140 uint32_t offset = GetDexRegisterMapsOffset(encoding)
1141 + stack_map.GetDexRegisterMapOffset(encoding);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001142 size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001143 return DexRegisterMap(region_.Subregion(offset, size));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001144 }
1145
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001146 // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
1147 DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
1148 InlineInfo inline_info,
David Brazdilf677ebf2015-05-29 16:29:43 +01001149 const StackMapEncoding& encoding,
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001150 uint32_t number_of_dex_registers) const {
1151 DCHECK(inline_info.HasDexRegisterMapAtDepth(depth));
David Brazdilf677ebf2015-05-29 16:29:43 +01001152 uint32_t offset = GetDexRegisterMapsOffset(encoding)
1153 + inline_info.GetDexRegisterMapOffsetAtDepth(depth);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001154 size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
1155 return DexRegisterMap(region_.Subregion(offset, size));
1156 }
1157
David Brazdilf677ebf2015-05-29 16:29:43 +01001158 InlineInfo GetInlineInfoOf(StackMap stack_map, const StackMapEncoding& encoding) const {
1159 DCHECK(stack_map.HasInlineInfo(encoding));
1160 uint32_t offset = stack_map.GetInlineDescriptorOffset(encoding)
1161 + GetDexRegisterMapsOffset(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001162 uint8_t depth = region_.LoadUnaligned<uint8_t>(offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001163 return InlineInfo(region_.Subregion(offset,
1164 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
1165 }
1166
David Brazdilf677ebf2015-05-29 16:29:43 +01001167 StackMap GetStackMapForDexPc(uint32_t dex_pc, const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001168 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001169 StackMap stack_map = GetStackMapAt(i, encoding);
1170 if (stack_map.GetDexPc(encoding) == dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001171 return stack_map;
1172 }
1173 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001174 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001175 }
1176
David Brazdilf677ebf2015-05-29 16:29:43 +01001177 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset,
1178 const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001179 // TODO: stack maps are sorted by native pc, we can do a binary search.
1180 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001181 StackMap stack_map = GetStackMapAt(i, encoding);
1182 if (stack_map.GetNativePcOffset(encoding) == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001183 return stack_map;
1184 }
1185 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001186 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001187 }
1188
Roland Levillainf2650d12015-05-28 14:53:28 +01001189 // Dump this CodeInfo object on `os`. `code_offset` is the (absolute)
1190 // native PC of the compiled method and `number_of_dex_registers` the
1191 // number of Dex virtual registers used in this method. If
1192 // `dump_stack_maps` is true, also dump the stack maps and the
1193 // associated Dex register maps.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001194 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +01001195 uint32_t code_offset,
1196 uint16_t number_of_dex_registers,
1197 bool dump_stack_maps) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001198
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001199 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +01001200 static constexpr int kOverallSizeOffset = 0;
Roland Levillain1c1da432015-07-16 11:54:44 +01001201 static constexpr int kEncodingInfoOffset = ELEMENT_BYTE_OFFSET_AFTER(OverallSize);
1202 static constexpr int kNumberOfLocationCatalogEntriesOffset =
1203 ELEMENT_BYTE_OFFSET_AFTER(EncodingInfo);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001204 static constexpr int kNumberOfStackMapsOffset =
Roland Levillain1c1da432015-07-16 11:54:44 +01001205 ELEMENT_BYTE_OFFSET_AFTER(NumberOfLocationCatalogEntries);
1206 static constexpr int kStackMaskSizeOffset = ELEMENT_BYTE_OFFSET_AFTER(NumberOfStackMaps);
1207 static constexpr int kFixedSize = ELEMENT_BYTE_OFFSET_AFTER(StackMaskSize);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001208
Roland Levillain1c1da432015-07-16 11:54:44 +01001209 static constexpr int kHasInlineInfoBitOffset = kEncodingInfoOffset * kBitsPerByte;
1210 static constexpr int kInlineInfoBitOffset = ELEMENT_BIT_OFFSET_AFTER(HasInlineInfo);
1211 static constexpr int kDexRegisterMapBitOffset = ELEMENT_BIT_OFFSET_AFTER(InlineInfo);
1212 static constexpr int kDexPcBitOffset = ELEMENT_BIT_OFFSET_AFTER(DexRegisterMap);
1213 static constexpr int kNativePcBitOffset = ELEMENT_BIT_OFFSET_AFTER(DexPc);
1214 static constexpr int kRegisterMaskBitOffset = ELEMENT_BIT_OFFSET_AFTER(NativePc);
1215
1216 static constexpr int kEncodingInfoPastTheEndBitOffset = ELEMENT_BIT_OFFSET_AFTER(RegisterMask);
1217 static constexpr int kEncodingInfoOverallBitSize =
1218 kEncodingInfoPastTheEndBitOffset - kHasInlineInfoBitOffset;
1219
1220 static_assert(kEncodingInfoOverallBitSize <= (sizeof(EncodingInfoType) * kBitsPerByte),
1221 "art::CodeInfo::EncodingInfoType is too short to hold all encoding info elements.");
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001222
David Brazdilf677ebf2015-05-29 16:29:43 +01001223 MemoryRegion GetStackMaps(const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001224 return region_.size() == 0
1225 ? MemoryRegion()
David Brazdilf677ebf2015-05-29 16:29:43 +01001226 : region_.Subregion(GetStackMapsOffset(), GetStackMapsSize(encoding));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001227 }
1228
Roland Levillaina552e1c2015-03-26 15:01:03 +00001229 // Compute the size of the Dex register map associated to the stack map at
1230 // `dex_register_map_offset_in_code_info`.
1231 size_t ComputeDexRegisterMapSizeOf(uint32_t dex_register_map_offset_in_code_info,
1232 uint16_t number_of_dex_registers) const {
1233 // Offset where the actual mapping data starts within art::DexRegisterMap.
1234 size_t location_mapping_data_offset_in_dex_register_map =
1235 DexRegisterMap::GetLocationMappingDataOffset(number_of_dex_registers);
1236 // Create a temporary art::DexRegisterMap to be able to call
1237 // art::DexRegisterMap::GetNumberOfLiveDexRegisters and
1238 DexRegisterMap dex_register_map_without_locations(
1239 MemoryRegion(region_.Subregion(dex_register_map_offset_in_code_info,
1240 location_mapping_data_offset_in_dex_register_map)));
1241 size_t number_of_live_dex_registers =
1242 dex_register_map_without_locations.GetNumberOfLiveDexRegisters(number_of_dex_registers);
1243 size_t location_mapping_data_size_in_bits =
Roland Levillain1c1da432015-07-16 11:54:44 +01001244 DexRegisterMap::SingleEntrySizeInBits(GetNumberOfLocationCatalogEntries())
Roland Levillaina552e1c2015-03-26 15:01:03 +00001245 * number_of_live_dex_registers;
1246 size_t location_mapping_data_size_in_bytes =
1247 RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
1248 size_t dex_register_map_size =
1249 location_mapping_data_offset_in_dex_register_map + location_mapping_data_size_in_bytes;
1250 return dex_register_map_size;
1251 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001252
Roland Levillaina552e1c2015-03-26 15:01:03 +00001253 // Compute the size of a Dex register location catalog starting at offset `origin`
1254 // in `region_` and containing `number_of_dex_locations` entries.
1255 size_t ComputeDexRegisterLocationCatalogSize(uint32_t origin,
1256 uint32_t number_of_dex_locations) const {
1257 // TODO: Ideally, we would like to use art::DexRegisterLocationCatalog::Size or
1258 // art::DexRegisterLocationCatalog::FindLocationOffset, but the
1259 // DexRegisterLocationCatalog is not yet built. Try to factor common code.
1260 size_t offset = origin + DexRegisterLocationCatalog::kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001261
Roland Levillaina552e1c2015-03-26 15:01:03 +00001262 // Skip the first `number_of_dex_locations - 1` entries.
1263 for (uint16_t i = 0; i < number_of_dex_locations; ++i) {
1264 // Read the first next byte and inspect its first 3 bits to decide
1265 // whether it is a short or a large location.
1266 DexRegisterLocationCatalog::ShortLocation first_byte =
1267 region_.LoadUnaligned<DexRegisterLocationCatalog::ShortLocation>(offset);
1268 DexRegisterLocation::Kind kind =
1269 DexRegisterLocationCatalog::ExtractKindFromShortLocation(first_byte);
1270 if (DexRegisterLocation::IsShortLocationKind(kind)) {
1271 // Short location. Skip the current byte.
1272 offset += DexRegisterLocationCatalog::SingleShortEntrySize();
1273 } else {
1274 // Large location. Skip the 5 next bytes.
1275 offset += DexRegisterLocationCatalog::SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001276 }
1277 }
1278 size_t size = offset - origin;
1279 return size;
1280 }
1281
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001282 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +01001283 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001284};
1285
Roland Levillain1c1da432015-07-16 11:54:44 +01001286#undef ELEMENT_BYTE_OFFSET_AFTER
1287#undef ELEMENT_BIT_OFFSET_AFTER
1288
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001289} // namespace art
1290
1291#endif // ART_RUNTIME_STACK_MAP_H_