blob: dbf23aafc3eea1a707cdddaa674bb92696181709 [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
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000113 static bool IsShortLocationKind(Kind kind) {
114 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000115 case Kind::kInStack:
116 case Kind::kInRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100117 case Kind::kInRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000118 case Kind::kInFpuRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100119 case Kind::kInFpuRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000120 case Kind::kConstant:
121 return true;
122
123 case Kind::kInStackLargeOffset:
124 case Kind::kConstantLargeValue:
125 return false;
126
David Brazdild9cb68e2015-08-25 13:52:43 +0100127 case Kind::kNone:
David Srbecky7dc11782016-02-25 13:23:56 +0000128 LOG(FATAL) << "Unexpected location kind";
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000129 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100130 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000131 }
132
133 // Convert `kind` to a "surface" kind, i.e. one that doesn't include
134 // any value with a "large" qualifier.
135 // TODO: Introduce another enum type for the surface kind?
136 static Kind ConvertToSurfaceKind(Kind kind) {
137 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000138 case Kind::kInStack:
139 case Kind::kInRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100140 case Kind::kInRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000141 case Kind::kInFpuRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100142 case Kind::kInFpuRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000143 case Kind::kConstant:
144 return kind;
145
146 case Kind::kInStackLargeOffset:
147 return Kind::kInStack;
148
149 case Kind::kConstantLargeValue:
150 return Kind::kConstant;
151
David Brazdild9cb68e2015-08-25 13:52:43 +0100152 case Kind::kNone:
153 return kind;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000154 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100155 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000156 }
157
Roland Levillaina552e1c2015-03-26 15:01:03 +0000158 // Required by art::StackMapStream::LocationCatalogEntriesIndices.
159 DexRegisterLocation() : kind_(Kind::kNone), value_(0) {}
160
161 DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {}
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000162
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000163 static DexRegisterLocation None() {
164 return DexRegisterLocation(Kind::kNone, 0);
165 }
166
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000167 // Get the "surface" kind of the location, i.e., the one that doesn't
168 // include any value with a "large" qualifier.
169 Kind GetKind() const {
170 return ConvertToSurfaceKind(kind_);
171 }
172
173 // Get the value of the location.
174 int32_t GetValue() const { return value_; }
175
176 // Get the actual kind of the location.
177 Kind GetInternalKind() const { return kind_; }
178
Calin Juravle6ae70962015-03-18 16:31:28 +0000179 bool operator==(DexRegisterLocation other) const {
180 return kind_ == other.kind_ && value_ == other.value_;
181 }
182
183 bool operator!=(DexRegisterLocation other) const {
184 return !(*this == other);
185 }
186
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000187 private:
188 Kind kind_;
189 int32_t value_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000190
191 friend class DexRegisterLocationHashFn;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000192};
193
David Srbecky7dc11782016-02-25 13:23:56 +0000194std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind);
195
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100196/**
Roland Levillaina552e1c2015-03-26 15:01:03 +0000197 * Store information on unique Dex register locations used in a method.
198 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100199 *
200 * [DexRegisterLocation+].
201 *
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000202 * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100203 */
Roland Levillaina552e1c2015-03-26 15:01:03 +0000204class DexRegisterLocationCatalog {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100205 public:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000206 explicit DexRegisterLocationCatalog(MemoryRegion region) : region_(region) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100207
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000208 // Short (compressed) location, fitting on one byte.
209 typedef uint8_t ShortLocation;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100210
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000211 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
212 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
213 int32_t value = dex_register_location.GetValue();
214 if (DexRegisterLocation::IsShortLocationKind(kind)) {
215 // Short location. Compress the kind and the value as a single byte.
216 if (kind == DexRegisterLocation::Kind::kInStack) {
217 // Instead of storing stack offsets expressed in bytes for
218 // short stack locations, store slot offsets. A stack offset
219 // is a multiple of 4 (kFrameSlotSize). This means that by
220 // dividing it by 4, we can fit values from the [0, 128)
221 // interval in a short stack location, and not just values
222 // from the [0, 32) interval.
223 DCHECK_EQ(value % kFrameSlotSize, 0);
224 value /= kFrameSlotSize;
225 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000226 DCHECK(IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000227 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
228 } else {
229 // Large location. Write the location on one byte and the value
230 // on 4 bytes.
Roland Levillaina552e1c2015-03-26 15:01:03 +0000231 DCHECK(!IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000232 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
233 // Also divide large stack offsets by 4 for the sake of consistency.
234 DCHECK_EQ(value % kFrameSlotSize, 0);
235 value /= kFrameSlotSize;
236 }
237 // Data can be unaligned as the written Dex register locations can
238 // either be 1-byte or 5-byte wide. Use
239 // art::MemoryRegion::StoreUnaligned instead of
240 // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
241 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
242 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
Roland Levillain442b46a2015-02-18 16:54:21 +0000243 }
244 }
245
Roland Levillaina552e1c2015-03-26 15:01:03 +0000246 // Find the offset of the location catalog entry number `location_catalog_entry_index`.
247 size_t FindLocationOffset(size_t location_catalog_entry_index) const {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000248 size_t offset = kFixedSize;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000249 // Skip the first `location_catalog_entry_index - 1` entries.
250 for (uint16_t i = 0; i < location_catalog_entry_index; ++i) {
251 // Read the first next byte and inspect its first 3 bits to decide
252 // whether it is a short or a large location.
253 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
254 if (DexRegisterLocation::IsShortLocationKind(kind)) {
255 // Short location. Skip the current byte.
256 offset += SingleShortEntrySize();
257 } else {
258 // Large location. Skip the 5 next bytes.
259 offset += SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000260 }
261 }
262 return offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100263 }
264
Roland Levillaina552e1c2015-03-26 15:01:03 +0000265 // Get the internal kind of entry at `location_catalog_entry_index`.
266 DexRegisterLocation::Kind GetLocationInternalKind(size_t location_catalog_entry_index) const {
267 if (location_catalog_entry_index == kNoLocationEntryIndex) {
268 return DexRegisterLocation::Kind::kNone;
269 }
270 return ExtractKindAtOffset(FindLocationOffset(location_catalog_entry_index));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100271 }
272
Roland Levillaina552e1c2015-03-26 15:01:03 +0000273 // Get the (surface) kind and value of entry at `location_catalog_entry_index`.
274 DexRegisterLocation GetDexRegisterLocation(size_t location_catalog_entry_index) const {
275 if (location_catalog_entry_index == kNoLocationEntryIndex) {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000276 return DexRegisterLocation::None();
277 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000278 size_t offset = FindLocationOffset(location_catalog_entry_index);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000279 // Read the first byte and inspect its first 3 bits to get the location.
280 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
281 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
282 if (DexRegisterLocation::IsShortLocationKind(kind)) {
283 // Short location. Extract the value from the remaining 5 bits.
284 int32_t value = ExtractValueFromShortLocation(first_byte);
285 if (kind == DexRegisterLocation::Kind::kInStack) {
286 // Convert the stack slot (short) offset to a byte offset value.
287 value *= kFrameSlotSize;
288 }
289 return DexRegisterLocation(kind, value);
290 } else {
291 // Large location. Read the four next bytes to get the value.
292 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
293 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
294 // Convert the stack slot (large) offset to a byte offset value.
295 value *= kFrameSlotSize;
296 }
297 return DexRegisterLocation(kind, value);
298 }
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100299 }
300
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000301 // Compute the compressed kind of `location`.
302 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
David Brazdild9cb68e2015-08-25 13:52:43 +0100303 DexRegisterLocation::Kind kind = location.GetInternalKind();
304 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000305 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000306 return IsShortStackOffsetValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000307 ? DexRegisterLocation::Kind::kInStack
308 : DexRegisterLocation::Kind::kInStackLargeOffset;
309
David Brazdild9cb68e2015-08-25 13:52:43 +0100310 case DexRegisterLocation::Kind::kInRegister:
311 case DexRegisterLocation::Kind::kInRegisterHigh:
312 DCHECK_GE(location.GetValue(), 0);
313 DCHECK_LT(location.GetValue(), 1 << kValueBits);
314 return kind;
315
316 case DexRegisterLocation::Kind::kInFpuRegister:
317 case DexRegisterLocation::Kind::kInFpuRegisterHigh:
318 DCHECK_GE(location.GetValue(), 0);
319 DCHECK_LT(location.GetValue(), 1 << kValueBits);
320 return kind;
321
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000322 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000323 return IsShortConstantValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000324 ? DexRegisterLocation::Kind::kConstant
325 : DexRegisterLocation::Kind::kConstantLargeValue;
326
David Brazdild9cb68e2015-08-25 13:52:43 +0100327 case DexRegisterLocation::Kind::kConstantLargeValue:
328 case DexRegisterLocation::Kind::kInStackLargeOffset:
329 case DexRegisterLocation::Kind::kNone:
David Srbecky7dc11782016-02-25 13:23:56 +0000330 LOG(FATAL) << "Unexpected location kind " << kind;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000331 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100332 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000333 }
334
335 // Can `location` be turned into a short location?
336 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
David Brazdild9cb68e2015-08-25 13:52:43 +0100337 DexRegisterLocation::Kind kind = location.GetInternalKind();
338 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000339 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000340 return IsShortStackOffsetValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000341
David Brazdild9cb68e2015-08-25 13:52:43 +0100342 case DexRegisterLocation::Kind::kInRegister:
343 case DexRegisterLocation::Kind::kInRegisterHigh:
344 case DexRegisterLocation::Kind::kInFpuRegister:
345 case DexRegisterLocation::Kind::kInFpuRegisterHigh:
346 return true;
347
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000348 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000349 return IsShortConstantValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000350
David Brazdild9cb68e2015-08-25 13:52:43 +0100351 case DexRegisterLocation::Kind::kConstantLargeValue:
352 case DexRegisterLocation::Kind::kInStackLargeOffset:
353 case DexRegisterLocation::Kind::kNone:
David Srbecky7dc11782016-02-25 13:23:56 +0000354 LOG(FATAL) << "Unexpected location kind " << kind;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000355 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100356 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000357 }
358
359 static size_t EntrySize(const DexRegisterLocation& location) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000360 return CanBeEncodedAsShortLocation(location) ? SingleShortEntrySize() : SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000361 }
362
363 static size_t SingleShortEntrySize() {
364 return sizeof(ShortLocation);
365 }
366
367 static size_t SingleLargeEntrySize() {
368 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100369 }
370
Roland Levillain12baf472015-03-05 12:41:42 +0000371 size_t Size() const {
372 return region_.size();
373 }
374
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100375 void Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info);
Roland Levillain0396ed72015-05-27 15:12:19 +0100376
Roland Levillaina552e1c2015-03-26 15:01:03 +0000377 // Special (invalid) Dex register location catalog entry index meaning
378 // that there is no location for a given Dex register (i.e., it is
379 // mapped to a DexRegisterLocation::Kind::kNone location).
380 static constexpr size_t kNoLocationEntryIndex = -1;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100381
Roland Levillain12baf472015-03-05 12:41:42 +0000382 private:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000383 static constexpr int kFixedSize = 0;
384
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000385 // Width of the kind "field" in a short location, in bits.
386 static constexpr size_t kKindBits = 3;
387 // Width of the value "field" in a short location, in bits.
388 static constexpr size_t kValueBits = 5;
389
390 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
391 static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
392 static constexpr size_t kKindOffset = 0;
393 static constexpr size_t kValueOffset = kKindBits;
394
Roland Levillaina552e1c2015-03-26 15:01:03 +0000395 static bool IsShortStackOffsetValue(int32_t value) {
396 DCHECK_EQ(value % kFrameSlotSize, 0);
397 return IsShortValue(value / kFrameSlotSize);
398 }
399
400 static bool IsShortConstantValue(int32_t value) {
401 return IsShortValue(value);
402 }
403
404 static bool IsShortValue(int32_t value) {
405 return IsUint<kValueBits>(value);
406 }
407
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000408 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000409 uint8_t kind_integer_value = static_cast<uint8_t>(kind);
410 DCHECK(IsUint<kKindBits>(kind_integer_value)) << kind_integer_value;
411 DCHECK(IsShortValue(value)) << value;
412 return (kind_integer_value & kKindMask) << kKindOffset
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000413 | (value & kValueMask) << kValueOffset;
414 }
415
416 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
417 uint8_t kind = (location >> kKindOffset) & kKindMask;
418 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000419 // We do not encode kNone locations in the stack map.
420 DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone));
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000421 return static_cast<DexRegisterLocation::Kind>(kind);
422 }
423
424 static int32_t ExtractValueFromShortLocation(ShortLocation location) {
425 return (location >> kValueOffset) & kValueMask;
426 }
427
428 // Extract a location kind from the byte at position `offset`.
429 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
430 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
431 return ExtractKindFromShortLocation(first_byte);
432 }
433
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100434 MemoryRegion region_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000435
436 friend class CodeInfo;
437 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100438};
439
Roland Levillaina552e1c2015-03-26 15:01:03 +0000440/* Information on Dex register locations for a specific PC, mapping a
441 * stack map's Dex register to a location entry in a DexRegisterLocationCatalog.
442 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100443 *
444 * [live_bit_mask, entries*]
445 *
Roland Levillaina552e1c2015-03-26 15:01:03 +0000446 * where entries are concatenated unsigned integer values encoded on a number
447 * of bits (fixed per DexRegisterMap instances of a CodeInfo object) depending
448 * on the number of entries in the Dex register location catalog
449 * (see DexRegisterMap::SingleEntrySizeInBits). The map is 1-byte aligned.
450 */
451class DexRegisterMap {
452 public:
453 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +0000454 DexRegisterMap() {}
455
456 bool IsValid() const { return region_.pointer() != nullptr; }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000457
458 // Get the surface kind of Dex register `dex_register_number`.
459 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number,
460 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100461 const CodeInfo& code_info,
462 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000463 return DexRegisterLocation::ConvertToSurfaceKind(
David Brazdilf677ebf2015-05-29 16:29:43 +0100464 GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info, enc));
Roland Levillaina552e1c2015-03-26 15:01:03 +0000465 }
466
467 // Get the internal kind of Dex register `dex_register_number`.
468 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number,
469 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100470 const CodeInfo& code_info,
471 const StackMapEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000472
473 // Get the Dex register location `dex_register_number`.
474 DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number,
475 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100476 const CodeInfo& code_info,
477 const StackMapEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000478
479 int32_t GetStackOffsetInBytes(uint16_t dex_register_number,
480 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100481 const CodeInfo& code_info,
482 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000483 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100484 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000485 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
486 // GetDexRegisterLocation returns the offset in bytes.
487 return location.GetValue();
488 }
489
490 int32_t GetConstant(uint16_t dex_register_number,
491 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100492 const CodeInfo& code_info,
493 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000494 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100495 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
David Srbecky7dc11782016-02-25 13:23:56 +0000496 DCHECK_EQ(location.GetKind(), DexRegisterLocation::Kind::kConstant);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000497 return location.GetValue();
498 }
499
500 int32_t GetMachineRegister(uint16_t dex_register_number,
501 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100502 const CodeInfo& code_info,
503 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000504 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100505 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
David Brazdild9cb68e2015-08-25 13:52:43 +0100506 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister ||
507 location.GetInternalKind() == DexRegisterLocation::Kind::kInRegisterHigh ||
508 location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister ||
509 location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh)
David Srbecky7dc11782016-02-25 13:23:56 +0000510 << location.GetInternalKind();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000511 return location.GetValue();
512 }
513
514 // Get the index of the entry in the Dex register location catalog
515 // corresponding to `dex_register_number`.
516 size_t GetLocationCatalogEntryIndex(uint16_t dex_register_number,
517 uint16_t number_of_dex_registers,
518 size_t number_of_location_catalog_entries) const {
519 if (!IsDexRegisterLive(dex_register_number)) {
520 return DexRegisterLocationCatalog::kNoLocationEntryIndex;
521 }
522
523 if (number_of_location_catalog_entries == 1) {
524 // We do not allocate space for location maps in the case of a
525 // single-entry location catalog, as it is useless. The only valid
526 // entry index is 0;
527 return 0;
528 }
529
530 // The bit offset of the beginning of the map locations.
531 size_t map_locations_offset_in_bits =
532 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
533 size_t index_in_dex_register_map = GetIndexInDexRegisterMap(dex_register_number);
534 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
535 // The bit size of an entry.
536 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
537 // The bit offset where `index_in_dex_register_map` is located.
538 size_t entry_offset_in_bits =
539 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
540 size_t location_catalog_entry_index =
541 region_.LoadBits(entry_offset_in_bits, map_entry_size_in_bits);
542 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
543 return location_catalog_entry_index;
544 }
545
546 // Map entry at `index_in_dex_register_map` to `location_catalog_entry_index`.
547 void SetLocationCatalogEntryIndex(size_t index_in_dex_register_map,
548 size_t location_catalog_entry_index,
549 uint16_t number_of_dex_registers,
550 size_t number_of_location_catalog_entries) {
551 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
552 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
553
554 if (number_of_location_catalog_entries == 1) {
555 // We do not allocate space for location maps in the case of a
556 // single-entry location catalog, as it is useless.
557 return;
558 }
559
560 // The bit offset of the beginning of the map locations.
561 size_t map_locations_offset_in_bits =
562 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
563 // The bit size of an entry.
564 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
565 // The bit offset where `index_in_dex_register_map` is located.
566 size_t entry_offset_in_bits =
567 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
568 region_.StoreBits(entry_offset_in_bits, location_catalog_entry_index, map_entry_size_in_bits);
569 }
570
571 void SetLiveBitMask(uint16_t number_of_dex_registers,
572 const BitVector& live_dex_registers_mask) {
573 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
574 for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
575 region_.StoreBit(live_bit_mask_offset_in_bits + i, live_dex_registers_mask.IsBitSet(i));
576 }
577 }
578
579 bool IsDexRegisterLive(uint16_t dex_register_number) const {
580 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
581 return region_.LoadBit(live_bit_mask_offset_in_bits + dex_register_number);
582 }
583
584 size_t GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers) const {
585 size_t number_of_live_dex_registers = 0;
586 for (size_t i = 0; i < number_of_dex_registers; ++i) {
587 if (IsDexRegisterLive(i)) {
588 ++number_of_live_dex_registers;
589 }
590 }
591 return number_of_live_dex_registers;
592 }
593
594 static size_t GetLiveBitMaskOffset() {
595 return kFixedSize;
596 }
597
598 // Compute the size of the live register bit mask (in bytes), for a
599 // method having `number_of_dex_registers` Dex registers.
600 static size_t GetLiveBitMaskSize(uint16_t number_of_dex_registers) {
601 return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte;
602 }
603
604 static size_t GetLocationMappingDataOffset(uint16_t number_of_dex_registers) {
605 return GetLiveBitMaskOffset() + GetLiveBitMaskSize(number_of_dex_registers);
606 }
607
608 size_t GetLocationMappingDataSize(uint16_t number_of_dex_registers,
609 size_t number_of_location_catalog_entries) const {
610 size_t location_mapping_data_size_in_bits =
611 GetNumberOfLiveDexRegisters(number_of_dex_registers)
612 * SingleEntrySizeInBits(number_of_location_catalog_entries);
613 return RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
614 }
615
616 // Return the size of a map entry in bits. Note that if
617 // `number_of_location_catalog_entries` equals 1, this function returns 0,
618 // which is fine, as there is no need to allocate a map for a
619 // single-entry location catalog; the only valid location catalog entry index
620 // for a live register in this case is 0 and there is no need to
621 // store it.
622 static size_t SingleEntrySizeInBits(size_t number_of_location_catalog_entries) {
623 // Handle the case of 0, as we cannot pass 0 to art::WhichPowerOf2.
624 return number_of_location_catalog_entries == 0
625 ? 0u
626 : WhichPowerOf2(RoundUpToPowerOfTwo(number_of_location_catalog_entries));
627 }
628
629 // Return the size of the DexRegisterMap object, in bytes.
630 size_t Size() const {
631 return region_.size();
632 }
633
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100634 void Dump(VariableIndentationOutputStream* vios,
635 const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100636
Roland Levillaina552e1c2015-03-26 15:01:03 +0000637 private:
638 // Return the index in the Dex register map corresponding to the Dex
639 // register number `dex_register_number`.
640 size_t GetIndexInDexRegisterMap(uint16_t dex_register_number) const {
641 if (!IsDexRegisterLive(dex_register_number)) {
642 return kInvalidIndexInDexRegisterMap;
643 }
644 return GetNumberOfLiveDexRegisters(dex_register_number);
645 }
646
647 // Special (invalid) Dex register map entry index meaning that there
648 // is no index in the map for a given Dex register (i.e., it must
649 // have been mapped to a DexRegisterLocation::Kind::kNone location).
650 static constexpr size_t kInvalidIndexInDexRegisterMap = -1;
651
652 static constexpr int kFixedSize = 0;
653
654 MemoryRegion region_;
655
656 friend class CodeInfo;
657 friend class StackMapStream;
658};
659
David Brazdilf677ebf2015-05-29 16:29:43 +0100660class StackMapEncoding {
661 public:
662 StackMapEncoding() {}
663
664 StackMapEncoding(size_t stack_mask_size,
665 size_t bytes_for_inline_info,
666 size_t bytes_for_dex_register_map,
667 size_t bytes_for_dex_pc,
668 size_t bytes_for_native_pc,
669 size_t bytes_for_register_mask)
670 : bytes_for_stack_mask_(stack_mask_size),
671 bytes_for_inline_info_(bytes_for_inline_info),
672 bytes_for_dex_register_map_(bytes_for_dex_register_map),
673 bytes_for_dex_pc_(bytes_for_dex_pc),
674 bytes_for_native_pc_(bytes_for_native_pc),
675 bytes_for_register_mask_(bytes_for_register_mask) {}
676
677 static StackMapEncoding CreateFromSizes(size_t stack_mask_size,
678 size_t inline_info_size,
679 size_t dex_register_map_size,
680 size_t dex_pc_max,
681 size_t native_pc_max,
682 size_t register_mask_max) {
683 return StackMapEncoding(
684 stack_mask_size,
685 // + 1 to also encode kNoInlineInfo: if an inline info offset
686 // is at 0xFF, we want to overflow to a larger encoding, because it will
687 // conflict with kNoInlineInfo.
688 // The offset is relative to the dex register map. TODO: Change this.
689 inline_info_size == 0
690 ? 0
691 : EncodingSizeInBytes(dex_register_map_size + inline_info_size + 1),
692 // + 1 to also encode kNoDexRegisterMap: if a dex register map offset
693 // is at 0xFF, we want to overflow to a larger encoding, because it will
694 // conflict with kNoDexRegisterMap.
695 EncodingSizeInBytes(dex_register_map_size + 1),
696 EncodingSizeInBytes(dex_pc_max),
697 EncodingSizeInBytes(native_pc_max),
698 EncodingSizeInBytes(register_mask_max));
699 }
700
701 // Get the size of one stack map of this CodeInfo object, in bytes.
702 // All stack maps of a CodeInfo have the same size.
703 size_t ComputeStackMapSize() const {
704 return bytes_for_register_mask_
705 + bytes_for_stack_mask_
706 + bytes_for_inline_info_
707 + bytes_for_dex_register_map_
708 + bytes_for_dex_pc_
709 + bytes_for_native_pc_;
710 }
711
712 bool HasInlineInfo() const { return bytes_for_inline_info_ > 0; }
713
714 size_t NumberOfBytesForStackMask() const { return bytes_for_stack_mask_; }
715 size_t NumberOfBytesForInlineInfo() const { return bytes_for_inline_info_; }
716 size_t NumberOfBytesForDexRegisterMap() const { return bytes_for_dex_register_map_; }
717 size_t NumberOfBytesForDexPc() const { return bytes_for_dex_pc_; }
718 size_t NumberOfBytesForNativePc() const { return bytes_for_native_pc_; }
719 size_t NumberOfBytesForRegisterMask() const { return bytes_for_register_mask_; }
720
721 size_t ComputeStackMapRegisterMaskOffset() const {
722 return kRegisterMaskOffset;
723 }
724
725 size_t ComputeStackMapStackMaskOffset() const {
726 return ComputeStackMapRegisterMaskOffset() + bytes_for_register_mask_;
727 }
728
729 size_t ComputeStackMapDexPcOffset() const {
730 return ComputeStackMapStackMaskOffset() + bytes_for_stack_mask_;
731 }
732
733 size_t ComputeStackMapNativePcOffset() const {
734 return ComputeStackMapDexPcOffset() + bytes_for_dex_pc_;
735 }
736
737 size_t ComputeStackMapDexRegisterMapOffset() const {
738 return ComputeStackMapNativePcOffset() + bytes_for_native_pc_;
739 }
740
741 size_t ComputeStackMapInlineInfoOffset() const {
742 return ComputeStackMapDexRegisterMapOffset() + bytes_for_dex_register_map_;
743 }
744
745 private:
746 static size_t EncodingSizeInBytes(size_t max_element) {
747 DCHECK(IsUint<32>(max_element));
748 return (max_element == 0) ? 0
749 : IsUint<8>(max_element) ? 1
750 : IsUint<16>(max_element) ? 2
751 : IsUint<24>(max_element) ? 3
752 : 4;
753 }
754
755 static constexpr int kRegisterMaskOffset = 0;
756
757 size_t bytes_for_stack_mask_;
758 size_t bytes_for_inline_info_;
759 size_t bytes_for_dex_register_map_;
760 size_t bytes_for_dex_pc_;
761 size_t bytes_for_native_pc_;
762 size_t bytes_for_register_mask_;
763};
764
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100765/**
766 * A Stack Map holds compilation information for a specific PC necessary for:
767 * - Mapping it to a dex PC,
768 * - Knowing which stack entries are objects,
769 * - Knowing which registers hold objects,
770 * - Knowing the inlining information,
771 * - Knowing the values of dex registers.
772 *
773 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100774 *
775 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask,
776 * stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100777 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100778class StackMap {
779 public:
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100780 StackMap() {}
David Brazdilf677ebf2015-05-29 16:29:43 +0100781 explicit StackMap(MemoryRegion region) : region_(region) {}
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100782
783 bool IsValid() const { return region_.pointer() != nullptr; }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100784
David Brazdilf677ebf2015-05-29 16:29:43 +0100785 uint32_t GetDexPc(const StackMapEncoding& encoding) const {
786 return LoadAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset());
787 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100788
David Brazdilf677ebf2015-05-29 16:29:43 +0100789 void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) {
790 StoreAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset(), dex_pc);
791 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100792
David Brazdilf677ebf2015-05-29 16:29:43 +0100793 uint32_t GetNativePcOffset(const StackMapEncoding& encoding) const {
794 return LoadAt(encoding.NumberOfBytesForNativePc(), encoding.ComputeStackMapNativePcOffset());
795 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100796
David Brazdilf677ebf2015-05-29 16:29:43 +0100797 void SetNativePcOffset(const StackMapEncoding& encoding, uint32_t native_pc_offset) {
798 StoreAt(encoding.NumberOfBytesForNativePc(),
799 encoding.ComputeStackMapNativePcOffset(),
800 native_pc_offset);
801 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100802
David Brazdilf677ebf2015-05-29 16:29:43 +0100803 uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const {
804 return LoadAt(encoding.NumberOfBytesForDexRegisterMap(),
805 encoding.ComputeStackMapDexRegisterMapOffset(),
806 /* check_max */ true);
807 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100808
David Brazdilf677ebf2015-05-29 16:29:43 +0100809 void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) {
810 StoreAt(encoding.NumberOfBytesForDexRegisterMap(),
811 encoding.ComputeStackMapDexRegisterMapOffset(),
812 offset);
813 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100814
David Brazdilf677ebf2015-05-29 16:29:43 +0100815 uint32_t GetInlineDescriptorOffset(const StackMapEncoding& encoding) const {
816 if (!encoding.HasInlineInfo()) return kNoInlineInfo;
817 return LoadAt(encoding.NumberOfBytesForInlineInfo(),
818 encoding.ComputeStackMapInlineInfoOffset(),
819 /* check_max */ true);
820 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100821
David Brazdilf677ebf2015-05-29 16:29:43 +0100822 void SetInlineDescriptorOffset(const StackMapEncoding& encoding, uint32_t offset) {
823 DCHECK(encoding.HasInlineInfo());
824 StoreAt(encoding.NumberOfBytesForInlineInfo(),
825 encoding.ComputeStackMapInlineInfoOffset(),
826 offset);
827 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100828
David Brazdilf677ebf2015-05-29 16:29:43 +0100829 uint32_t GetRegisterMask(const StackMapEncoding& encoding) const {
830 return LoadAt(encoding.NumberOfBytesForRegisterMask(),
831 encoding.ComputeStackMapRegisterMaskOffset());
832 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100833
David Brazdilf677ebf2015-05-29 16:29:43 +0100834 void SetRegisterMask(const StackMapEncoding& encoding, uint32_t mask) {
835 StoreAt(encoding.NumberOfBytesForRegisterMask(),
836 encoding.ComputeStackMapRegisterMaskOffset(),
837 mask);
838 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100839
David Brazdilf677ebf2015-05-29 16:29:43 +0100840 MemoryRegion GetStackMask(const StackMapEncoding& encoding) const {
841 return region_.Subregion(encoding.ComputeStackMapStackMaskOffset(),
842 encoding.NumberOfBytesForStackMask());
843 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100844
David Brazdilf677ebf2015-05-29 16:29:43 +0100845 void SetStackMask(const StackMapEncoding& encoding, const BitVector& sp_map) {
846 MemoryRegion region = GetStackMask(encoding);
David Brazdilf10a25f2015-06-02 14:29:52 +0100847 sp_map.CopyTo(region.start(), region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100848 }
849
David Brazdilf677ebf2015-05-29 16:29:43 +0100850 bool HasDexRegisterMap(const StackMapEncoding& encoding) const {
851 return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100852 }
853
David Brazdilf677ebf2015-05-29 16:29:43 +0100854 bool HasInlineInfo(const StackMapEncoding& encoding) const {
855 return GetInlineDescriptorOffset(encoding) != kNoInlineInfo;
Roland Levillain442b46a2015-02-18 16:54:21 +0000856 }
857
858 bool Equals(const StackMap& other) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100859 return region_.pointer() == other.region_.pointer()
860 && region_.size() == other.region_.size();
861 }
862
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100863 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100864 const CodeInfo& code_info,
David Brazdilf677ebf2015-05-29 16:29:43 +0100865 const StackMapEncoding& encoding,
Roland Levillainf2650d12015-05-28 14:53:28 +0100866 uint32_t code_offset,
867 uint16_t number_of_dex_registers,
868 const std::string& header_suffix = "") const;
869
Roland Levillain442b46a2015-02-18 16:54:21 +0000870 // Special (invalid) offset for the DexRegisterMapOffset field meaning
871 // that there is no Dex register map for this stack map.
872 static constexpr uint32_t kNoDexRegisterMap = -1;
873
874 // Special (invalid) offset for the InlineDescriptorOffset field meaning
875 // that there is no inline info for this stack map.
876 static constexpr uint32_t kNoInlineInfo = -1;
877
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100878 private:
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100879 static constexpr int kFixedSize = 0;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100880
David Brazdilf677ebf2015-05-29 16:29:43 +0100881 // Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true,
882 // this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF.
883 uint32_t LoadAt(size_t number_of_bytes, size_t offset, bool check_max = false) const;
884 void StoreAt(size_t number_of_bytes, size_t offset, uint32_t value) const;
885
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100886 MemoryRegion region_;
887
Nicolas Geoffray39468442014-09-02 15:17:15 +0100888 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100889};
890
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100891/**
892 * Inline information for a specific PC. The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100893 *
894 * [inlining_depth, entry+]
895 *
896 * where `entry` is of the form:
897 *
898 * [dex_pc, method_index, dex_register_map_offset].
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100899 */
900class InlineInfo {
901 public:
Roland Levillain1c1da432015-07-16 11:54:44 +0100902 // Memory layout: fixed contents.
903 typedef uint8_t DepthType;
904 // Memory layout: single entry contents.
905 typedef uint32_t MethodIndexType;
906 typedef uint32_t DexPcType;
907 typedef uint8_t InvokeTypeType;
908 typedef uint32_t DexRegisterMapType;
909
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100910 explicit InlineInfo(MemoryRegion region) : region_(region) {}
911
Roland Levillain1c1da432015-07-16 11:54:44 +0100912 DepthType GetDepth() const {
913 return region_.LoadUnaligned<DepthType>(kDepthOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100914 }
915
Roland Levillain1c1da432015-07-16 11:54:44 +0100916 void SetDepth(DepthType depth) {
917 region_.StoreUnaligned<DepthType>(kDepthOffset, depth);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100918 }
919
Roland Levillain1c1da432015-07-16 11:54:44 +0100920 MethodIndexType GetMethodIndexAtDepth(DepthType depth) const {
921 return region_.LoadUnaligned<MethodIndexType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100922 kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100923 }
924
Roland Levillain1c1da432015-07-16 11:54:44 +0100925 void SetMethodIndexAtDepth(DepthType depth, MethodIndexType index) {
926 region_.StoreUnaligned<MethodIndexType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100927 kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset, index);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100928 }
929
Roland Levillain1c1da432015-07-16 11:54:44 +0100930 DexPcType GetDexPcAtDepth(DepthType depth) const {
931 return region_.LoadUnaligned<DexPcType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100932 kFixedSize + depth * SingleEntrySize() + kDexPcOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100933 }
934
Roland Levillain1c1da432015-07-16 11:54:44 +0100935 void SetDexPcAtDepth(DepthType depth, DexPcType dex_pc) {
936 region_.StoreUnaligned<DexPcType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100937 kFixedSize + depth * SingleEntrySize() + kDexPcOffset, dex_pc);
938 }
939
Roland Levillain1c1da432015-07-16 11:54:44 +0100940 InvokeTypeType GetInvokeTypeAtDepth(DepthType depth) const {
941 return region_.LoadUnaligned<InvokeTypeType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100942 kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset);
943 }
944
Roland Levillain1c1da432015-07-16 11:54:44 +0100945 void SetInvokeTypeAtDepth(DepthType depth, InvokeTypeType invoke_type) {
946 region_.StoreUnaligned<InvokeTypeType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100947 kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset, invoke_type);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100948 }
949
Roland Levillain1c1da432015-07-16 11:54:44 +0100950 DexRegisterMapType GetDexRegisterMapOffsetAtDepth(DepthType depth) const {
951 return region_.LoadUnaligned<DexRegisterMapType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100952 kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100953 }
954
Roland Levillain1c1da432015-07-16 11:54:44 +0100955 void SetDexRegisterMapOffsetAtDepth(DepthType depth, DexRegisterMapType offset) {
956 region_.StoreUnaligned<DexRegisterMapType>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100957 kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset, offset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100958 }
959
Roland Levillain1c1da432015-07-16 11:54:44 +0100960 bool HasDexRegisterMapAtDepth(DepthType depth) const {
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100961 return GetDexRegisterMapOffsetAtDepth(depth) != StackMap::kNoDexRegisterMap;
962 }
963
964 static size_t SingleEntrySize() {
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100965 return kFixedEntrySize;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100966 }
967
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100968 void Dump(VariableIndentationOutputStream* vios,
969 const CodeInfo& info, uint16_t* number_of_dex_registers) const;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100970
Roland Levillain1c1da432015-07-16 11:54:44 +0100971
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100972 private:
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100973 static constexpr int kDepthOffset = 0;
Roland Levillain1c1da432015-07-16 11:54:44 +0100974 static constexpr int kFixedSize = ELEMENT_BYTE_OFFSET_AFTER(Depth);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100975
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100976 static constexpr int kMethodIndexOffset = 0;
Roland Levillain1c1da432015-07-16 11:54:44 +0100977 static constexpr int kDexPcOffset = ELEMENT_BYTE_OFFSET_AFTER(MethodIndex);
978 static constexpr int kInvokeTypeOffset = ELEMENT_BYTE_OFFSET_AFTER(DexPc);
979 static constexpr int kDexRegisterMapOffset = ELEMENT_BYTE_OFFSET_AFTER(InvokeType);
980 static constexpr int kFixedEntrySize = ELEMENT_BYTE_OFFSET_AFTER(DexRegisterMap);
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100981
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100982 MemoryRegion region_;
983
984 friend class CodeInfo;
985 friend class StackMap;
986 friend class StackMapStream;
987};
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100988
989/**
990 * Wrapper around all compiler information collected for a method.
991 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100992 *
993 * [overall_size, encoding_info, number_of_location_catalog_entries, number_of_stack_maps,
994 * stack_mask_size, DexRegisterLocationCatalog+, StackMap+, DexRegisterMap+, InlineInfo*]
995 *
996 * where `encoding_info` is of the form:
997 *
998 * [has_inline_info, inline_info_size_in_bytes, dex_register_map_size_in_bytes,
999 * dex_pc_size_in_bytes, native_pc_size_in_bytes, register_mask_size_in_bytes].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001000 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001001class CodeInfo {
1002 public:
Roland Levillain1c1da432015-07-16 11:54:44 +01001003 // Memory layout: fixed contents.
1004 typedef uint32_t OverallSizeType;
1005 typedef uint16_t EncodingInfoType;
1006 typedef uint32_t NumberOfLocationCatalogEntriesType;
1007 typedef uint32_t NumberOfStackMapsType;
1008 typedef uint32_t StackMaskSizeType;
1009
1010 // Memory (bit) layout: encoding info.
1011 static constexpr int HasInlineInfoBitSize = 1;
1012 static constexpr int InlineInfoBitSize = kNumberOfBitForNumberOfBytesForEncoding;
1013 static constexpr int DexRegisterMapBitSize = kNumberOfBitForNumberOfBytesForEncoding;
1014 static constexpr int DexPcBitSize = kNumberOfBitForNumberOfBytesForEncoding;
1015 static constexpr int NativePcBitSize = kNumberOfBitForNumberOfBytesForEncoding;
1016 static constexpr int RegisterMaskBitSize = kNumberOfBitForNumberOfBytesForEncoding;
1017
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001018 explicit CodeInfo(MemoryRegion region) : region_(region) {}
1019
Nicolas Geoffray39468442014-09-02 15:17:15 +01001020 explicit CodeInfo(const void* data) {
1021 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
1022 region_ = MemoryRegion(const_cast<void*>(data), size);
1023 }
1024
David Brazdilf677ebf2015-05-29 16:29:43 +01001025 StackMapEncoding ExtractEncoding() const {
1026 return StackMapEncoding(region_.LoadUnaligned<uint32_t>(kStackMaskSizeOffset),
1027 GetNumberOfBytesForEncoding(kInlineInfoBitOffset),
1028 GetNumberOfBytesForEncoding(kDexRegisterMapBitOffset),
1029 GetNumberOfBytesForEncoding(kDexPcBitOffset),
1030 GetNumberOfBytesForEncoding(kNativePcBitOffset),
1031 GetNumberOfBytesForEncoding(kRegisterMaskBitOffset));
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001032 }
1033
David Brazdilf677ebf2015-05-29 16:29:43 +01001034 void SetEncoding(const StackMapEncoding& encoding) {
1035 region_.StoreUnaligned<uint32_t>(kStackMaskSizeOffset, encoding.NumberOfBytesForStackMask());
1036 region_.StoreBit(kHasInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo() != 0);
1037 SetEncodingAt(kInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo());
1038 SetEncodingAt(kDexRegisterMapBitOffset, encoding.NumberOfBytesForDexRegisterMap());
1039 SetEncodingAt(kDexPcBitOffset, encoding.NumberOfBytesForDexPc());
1040 SetEncodingAt(kNativePcBitOffset, encoding.NumberOfBytesForNativePc());
1041 SetEncodingAt(kRegisterMaskBitOffset, encoding.NumberOfBytesForRegisterMask());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001042 }
1043
1044 void SetEncodingAt(size_t bit_offset, size_t number_of_bytes) {
Roland Levillaind780c002015-07-15 14:30:26 +01001045 region_.StoreBits(bit_offset, number_of_bytes, kNumberOfBitForNumberOfBytesForEncoding);
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001046 }
1047
1048 size_t GetNumberOfBytesForEncoding(size_t bit_offset) const {
Roland Levillaind780c002015-07-15 14:30:26 +01001049 return region_.LoadBits(bit_offset, kNumberOfBitForNumberOfBytesForEncoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001050 }
1051
1052 bool HasInlineInfo() const {
1053 return region_.LoadBit(kHasInlineInfoBitOffset);
1054 }
1055
David Brazdilf677ebf2015-05-29 16:29:43 +01001056 DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const StackMapEncoding& encoding) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +00001057 return DexRegisterLocationCatalog(region_.Subregion(
David Brazdilf677ebf2015-05-29 16:29:43 +01001058 GetDexRegisterLocationCatalogOffset(encoding),
1059 GetDexRegisterLocationCatalogSize(encoding)));
Roland Levillaina552e1c2015-03-26 15:01:03 +00001060 }
1061
David Brazdilf677ebf2015-05-29 16:29:43 +01001062 StackMap GetStackMapAt(size_t i, const StackMapEncoding& encoding) const {
1063 size_t stack_map_size = encoding.ComputeStackMapSize();
1064 return StackMap(GetStackMaps(encoding).Subregion(i * stack_map_size, stack_map_size));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001065 }
1066
Roland Levillain1c1da432015-07-16 11:54:44 +01001067 OverallSizeType GetOverallSize() const {
1068 return region_.LoadUnaligned<OverallSizeType>(kOverallSizeOffset);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001069 }
1070
Roland Levillain1c1da432015-07-16 11:54:44 +01001071 void SetOverallSize(OverallSizeType size) {
1072 region_.StoreUnaligned<OverallSizeType>(kOverallSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001073 }
1074
Roland Levillain1c1da432015-07-16 11:54:44 +01001075 NumberOfLocationCatalogEntriesType GetNumberOfLocationCatalogEntries() const {
1076 return region_.LoadUnaligned<NumberOfLocationCatalogEntriesType>(
1077 kNumberOfLocationCatalogEntriesOffset);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001078 }
1079
Roland Levillain1c1da432015-07-16 11:54:44 +01001080 void SetNumberOfLocationCatalogEntries(NumberOfLocationCatalogEntriesType num_entries) {
1081 region_.StoreUnaligned<NumberOfLocationCatalogEntriesType>(
1082 kNumberOfLocationCatalogEntriesOffset, num_entries);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001083 }
1084
David Brazdilf677ebf2015-05-29 16:29:43 +01001085 uint32_t GetDexRegisterLocationCatalogSize(const StackMapEncoding& encoding) const {
1086 return ComputeDexRegisterLocationCatalogSize(GetDexRegisterLocationCatalogOffset(encoding),
Roland Levillain1c1da432015-07-16 11:54:44 +01001087 GetNumberOfLocationCatalogEntries());
Roland Levillaina552e1c2015-03-26 15:01:03 +00001088 }
1089
Roland Levillain1c1da432015-07-16 11:54:44 +01001090 NumberOfStackMapsType GetNumberOfStackMaps() const {
1091 return region_.LoadUnaligned<NumberOfStackMapsType>(kNumberOfStackMapsOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001092 }
1093
Roland Levillain1c1da432015-07-16 11:54:44 +01001094 void SetNumberOfStackMaps(NumberOfStackMapsType number_of_stack_maps) {
1095 region_.StoreUnaligned<NumberOfStackMapsType>(kNumberOfStackMapsOffset, number_of_stack_maps);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001096 }
1097
David Brazdil77a48ae2015-09-15 12:34:04 +00001098 // Get the size of all the stack maps of this CodeInfo object, in bytes.
David Brazdilf677ebf2015-05-29 16:29:43 +01001099 size_t GetStackMapsSize(const StackMapEncoding& encoding) const {
1100 return encoding.ComputeStackMapSize() * GetNumberOfStackMaps();
Roland Levillain29ba1b02015-03-13 11:45:07 +00001101 }
1102
David Brazdilf677ebf2015-05-29 16:29:43 +01001103 uint32_t GetDexRegisterLocationCatalogOffset(const StackMapEncoding& encoding) const {
1104 return GetStackMapsOffset() + GetStackMapsSize(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001105 }
1106
David Brazdilf677ebf2015-05-29 16:29:43 +01001107 size_t GetDexRegisterMapsOffset(const StackMapEncoding& encoding) const {
1108 return GetDexRegisterLocationCatalogOffset(encoding)
1109 + GetDexRegisterLocationCatalogSize(encoding);
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001110 }
1111
Nicolas Geoffray6530baf2015-05-26 15:22:58 +01001112 uint32_t GetStackMapsOffset() const {
1113 return kFixedSize;
1114 }
1115
David Brazdilf677ebf2015-05-29 16:29:43 +01001116 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
1117 const StackMapEncoding& encoding,
1118 uint32_t number_of_dex_registers) const {
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +00001119 if (!stack_map.HasDexRegisterMap(encoding)) {
1120 return DexRegisterMap();
1121 } else {
1122 uint32_t offset = GetDexRegisterMapsOffset(encoding)
1123 + stack_map.GetDexRegisterMapOffset(encoding);
1124 size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
1125 return DexRegisterMap(region_.Subregion(offset, size));
1126 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001127 }
1128
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001129 // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
1130 DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
1131 InlineInfo inline_info,
David Brazdilf677ebf2015-05-29 16:29:43 +01001132 const StackMapEncoding& encoding,
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001133 uint32_t number_of_dex_registers) const {
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +00001134 if (!inline_info.HasDexRegisterMapAtDepth(depth)) {
1135 return DexRegisterMap();
1136 } else {
1137 uint32_t offset = GetDexRegisterMapsOffset(encoding)
1138 + inline_info.GetDexRegisterMapOffsetAtDepth(depth);
1139 size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
1140 return DexRegisterMap(region_.Subregion(offset, size));
1141 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001142 }
1143
David Brazdilf677ebf2015-05-29 16:29:43 +01001144 InlineInfo GetInlineInfoOf(StackMap stack_map, const StackMapEncoding& encoding) const {
1145 DCHECK(stack_map.HasInlineInfo(encoding));
1146 uint32_t offset = stack_map.GetInlineDescriptorOffset(encoding)
1147 + GetDexRegisterMapsOffset(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001148 uint8_t depth = region_.LoadUnaligned<uint8_t>(offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001149 return InlineInfo(region_.Subregion(offset,
1150 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
1151 }
1152
David Brazdilf677ebf2015-05-29 16:29:43 +01001153 StackMap GetStackMapForDexPc(uint32_t dex_pc, const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001154 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001155 StackMap stack_map = GetStackMapAt(i, encoding);
1156 if (stack_map.GetDexPc(encoding) == dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001157 return stack_map;
1158 }
1159 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001160 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001161 }
1162
David Brazdil77a48ae2015-09-15 12:34:04 +00001163 // Searches the stack map list backwards because catch stack maps are stored
1164 // at the end.
1165 StackMap GetCatchStackMapForDexPc(uint32_t dex_pc, const StackMapEncoding& encoding) const {
1166 for (size_t i = GetNumberOfStackMaps(); i > 0; --i) {
1167 StackMap stack_map = GetStackMapAt(i - 1, encoding);
1168 if (stack_map.GetDexPc(encoding) == dex_pc) {
1169 return stack_map;
1170 }
1171 }
1172 return StackMap();
1173 }
1174
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001175 StackMap GetOsrStackMapForDexPc(uint32_t dex_pc, const StackMapEncoding& encoding) const {
1176 size_t e = GetNumberOfStackMaps();
1177 if (e == 0) {
1178 // There cannot be OSR stack map if there is no stack map.
1179 return StackMap();
1180 }
1181 // Walk over all stack maps. If two consecutive stack maps are identical, then we
1182 // have found a stack map suitable for OSR.
1183 for (size_t i = 0; i < e - 1; ++i) {
1184 StackMap stack_map = GetStackMapAt(i, encoding);
1185 if (stack_map.GetDexPc(encoding) == dex_pc) {
1186 StackMap other = GetStackMapAt(i + 1, encoding);
1187 if (other.GetDexPc(encoding) == dex_pc &&
1188 other.GetNativePcOffset(encoding) == stack_map.GetNativePcOffset(encoding)) {
1189 DCHECK_EQ(other.GetDexRegisterMapOffset(encoding),
1190 stack_map.GetDexRegisterMapOffset(encoding));
1191 DCHECK(!stack_map.HasInlineInfo(encoding));
1192 if (i < e - 2) {
1193 // Make sure there are not three identical stack maps following each other.
1194 DCHECK_NE(stack_map.GetNativePcOffset(encoding),
1195 GetStackMapAt(i + 2, encoding).GetNativePcOffset(encoding));
1196 }
1197 return stack_map;
1198 }
1199 }
1200 }
1201 return StackMap();
1202 }
1203
David Brazdilf677ebf2015-05-29 16:29:43 +01001204 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset,
1205 const StackMapEncoding& encoding) const {
David Brazdil77a48ae2015-09-15 12:34:04 +00001206 // TODO: Safepoint stack maps are sorted by native_pc_offset but catch stack
1207 // maps are not. If we knew that the method does not have try/catch,
1208 // we could do binary search.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001209 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001210 StackMap stack_map = GetStackMapAt(i, encoding);
1211 if (stack_map.GetNativePcOffset(encoding) == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001212 return stack_map;
1213 }
1214 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001215 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001216 }
1217
Roland Levillainf2650d12015-05-28 14:53:28 +01001218 // Dump this CodeInfo object on `os`. `code_offset` is the (absolute)
1219 // native PC of the compiled method and `number_of_dex_registers` the
1220 // number of Dex virtual registers used in this method. If
1221 // `dump_stack_maps` is true, also dump the stack maps and the
1222 // associated Dex register maps.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001223 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +01001224 uint32_t code_offset,
1225 uint16_t number_of_dex_registers,
1226 bool dump_stack_maps) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001227
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001228 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +01001229 static constexpr int kOverallSizeOffset = 0;
Roland Levillain1c1da432015-07-16 11:54:44 +01001230 static constexpr int kEncodingInfoOffset = ELEMENT_BYTE_OFFSET_AFTER(OverallSize);
1231 static constexpr int kNumberOfLocationCatalogEntriesOffset =
1232 ELEMENT_BYTE_OFFSET_AFTER(EncodingInfo);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001233 static constexpr int kNumberOfStackMapsOffset =
Roland Levillain1c1da432015-07-16 11:54:44 +01001234 ELEMENT_BYTE_OFFSET_AFTER(NumberOfLocationCatalogEntries);
1235 static constexpr int kStackMaskSizeOffset = ELEMENT_BYTE_OFFSET_AFTER(NumberOfStackMaps);
1236 static constexpr int kFixedSize = ELEMENT_BYTE_OFFSET_AFTER(StackMaskSize);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001237
Roland Levillain1c1da432015-07-16 11:54:44 +01001238 static constexpr int kHasInlineInfoBitOffset = kEncodingInfoOffset * kBitsPerByte;
1239 static constexpr int kInlineInfoBitOffset = ELEMENT_BIT_OFFSET_AFTER(HasInlineInfo);
1240 static constexpr int kDexRegisterMapBitOffset = ELEMENT_BIT_OFFSET_AFTER(InlineInfo);
1241 static constexpr int kDexPcBitOffset = ELEMENT_BIT_OFFSET_AFTER(DexRegisterMap);
1242 static constexpr int kNativePcBitOffset = ELEMENT_BIT_OFFSET_AFTER(DexPc);
1243 static constexpr int kRegisterMaskBitOffset = ELEMENT_BIT_OFFSET_AFTER(NativePc);
1244
1245 static constexpr int kEncodingInfoPastTheEndBitOffset = ELEMENT_BIT_OFFSET_AFTER(RegisterMask);
1246 static constexpr int kEncodingInfoOverallBitSize =
1247 kEncodingInfoPastTheEndBitOffset - kHasInlineInfoBitOffset;
1248
1249 static_assert(kEncodingInfoOverallBitSize <= (sizeof(EncodingInfoType) * kBitsPerByte),
1250 "art::CodeInfo::EncodingInfoType is too short to hold all encoding info elements.");
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001251
David Brazdilf677ebf2015-05-29 16:29:43 +01001252 MemoryRegion GetStackMaps(const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001253 return region_.size() == 0
1254 ? MemoryRegion()
David Brazdilf677ebf2015-05-29 16:29:43 +01001255 : region_.Subregion(GetStackMapsOffset(), GetStackMapsSize(encoding));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001256 }
1257
Roland Levillaina552e1c2015-03-26 15:01:03 +00001258 // Compute the size of the Dex register map associated to the stack map at
1259 // `dex_register_map_offset_in_code_info`.
1260 size_t ComputeDexRegisterMapSizeOf(uint32_t dex_register_map_offset_in_code_info,
1261 uint16_t number_of_dex_registers) const {
1262 // Offset where the actual mapping data starts within art::DexRegisterMap.
1263 size_t location_mapping_data_offset_in_dex_register_map =
1264 DexRegisterMap::GetLocationMappingDataOffset(number_of_dex_registers);
1265 // Create a temporary art::DexRegisterMap to be able to call
1266 // art::DexRegisterMap::GetNumberOfLiveDexRegisters and
1267 DexRegisterMap dex_register_map_without_locations(
1268 MemoryRegion(region_.Subregion(dex_register_map_offset_in_code_info,
1269 location_mapping_data_offset_in_dex_register_map)));
1270 size_t number_of_live_dex_registers =
1271 dex_register_map_without_locations.GetNumberOfLiveDexRegisters(number_of_dex_registers);
1272 size_t location_mapping_data_size_in_bits =
Roland Levillain1c1da432015-07-16 11:54:44 +01001273 DexRegisterMap::SingleEntrySizeInBits(GetNumberOfLocationCatalogEntries())
Roland Levillaina552e1c2015-03-26 15:01:03 +00001274 * number_of_live_dex_registers;
1275 size_t location_mapping_data_size_in_bytes =
1276 RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
1277 size_t dex_register_map_size =
1278 location_mapping_data_offset_in_dex_register_map + location_mapping_data_size_in_bytes;
1279 return dex_register_map_size;
1280 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001281
Roland Levillaina552e1c2015-03-26 15:01:03 +00001282 // Compute the size of a Dex register location catalog starting at offset `origin`
1283 // in `region_` and containing `number_of_dex_locations` entries.
1284 size_t ComputeDexRegisterLocationCatalogSize(uint32_t origin,
1285 uint32_t number_of_dex_locations) const {
1286 // TODO: Ideally, we would like to use art::DexRegisterLocationCatalog::Size or
1287 // art::DexRegisterLocationCatalog::FindLocationOffset, but the
1288 // DexRegisterLocationCatalog is not yet built. Try to factor common code.
1289 size_t offset = origin + DexRegisterLocationCatalog::kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001290
Roland Levillaina552e1c2015-03-26 15:01:03 +00001291 // Skip the first `number_of_dex_locations - 1` entries.
1292 for (uint16_t i = 0; i < number_of_dex_locations; ++i) {
1293 // Read the first next byte and inspect its first 3 bits to decide
1294 // whether it is a short or a large location.
1295 DexRegisterLocationCatalog::ShortLocation first_byte =
1296 region_.LoadUnaligned<DexRegisterLocationCatalog::ShortLocation>(offset);
1297 DexRegisterLocation::Kind kind =
1298 DexRegisterLocationCatalog::ExtractKindFromShortLocation(first_byte);
1299 if (DexRegisterLocation::IsShortLocationKind(kind)) {
1300 // Short location. Skip the current byte.
1301 offset += DexRegisterLocationCatalog::SingleShortEntrySize();
1302 } else {
1303 // Large location. Skip the 5 next bytes.
1304 offset += DexRegisterLocationCatalog::SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001305 }
1306 }
1307 size_t size = offset - origin;
1308 return size;
1309 }
1310
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001311 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +01001312 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001313};
1314
Roland Levillain1c1da432015-07-16 11:54:44 +01001315#undef ELEMENT_BYTE_OFFSET_AFTER
1316#undef ELEMENT_BIT_OFFSET_AFTER
1317
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001318} // namespace art
1319
1320#endif // ART_RUNTIME_STACK_MAP_H_