blob: 9e8884efd4558c13ad0fcb76883342df79d8b670 [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"
David Srbecky09ed0982016-02-12 21:58:43 +000023#include "leb128.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010024
25namespace art {
26
Roland Levillain1c1da432015-07-16 11:54:44 +010027#define ELEMENT_BYTE_OFFSET_AFTER(PreviousElement) \
28 k ## PreviousElement ## Offset + sizeof(PreviousElement ## Type)
29
30#define ELEMENT_BIT_OFFSET_AFTER(PreviousElement) \
31 k ## PreviousElement ## BitOffset + PreviousElement ## BitSize
32
Vladimir Marko8f1e08a2015-06-26 12:06:30 +010033class VariableIndentationOutputStream;
34
Roland Levillaina2d8ec62015-03-12 15:25:29 +000035// Size of a frame slot, in bytes. This constant is a signed value,
36// to please the compiler in arithmetic operations involving int32_t
37// (signed) values.
Roland Levillaina552e1c2015-03-26 15:01:03 +000038static constexpr ssize_t kFrameSlotSize = 4;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000039
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000040// Size of Dex virtual registers.
Roland Levillaina552e1c2015-03-26 15:01:03 +000041static constexpr size_t kVRegSize = 4;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000042
Nicolas Geoffray004c2302015-03-20 10:06:38 +000043class CodeInfo;
David Brazdilf677ebf2015-05-29 16:29:43 +010044class StackMapEncoding;
David Srbecky09ed0982016-02-12 21:58:43 +000045struct CodeInfoEncoding;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000046
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010047/**
48 * Classes in the following file are wrapper on stack map information backed
49 * by a MemoryRegion. As such they read and write to the region, they don't have
50 * their own fields.
51 */
52
Roland Levillaina2d8ec62015-03-12 15:25:29 +000053// Dex register location container used by DexRegisterMap and StackMapStream.
54class DexRegisterLocation {
55 public:
56 /*
57 * The location kind used to populate the Dex register information in a
58 * StackMapStream can either be:
David Brazdild9cb68e2015-08-25 13:52:43 +010059 * - kStack: vreg stored on the stack, value holds the stack offset;
60 * - kInRegister: vreg stored in low 32 bits of a core physical register,
61 * value holds the register number;
62 * - kInRegisterHigh: vreg stored in high 32 bits of a core physical register,
63 * value holds the register number;
64 * - kInFpuRegister: vreg stored in low 32 bits of an FPU register,
65 * value holds the register number;
66 * - kInFpuRegisterHigh: vreg stored in high 32 bits of an FPU register,
67 * value holds the register number;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000068 * - kConstant: value holds the constant;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000069 *
70 * In addition, DexRegisterMap also uses these values:
71 * - kInStackLargeOffset: value holds a "large" stack offset (greater than
Roland Levillaina552e1c2015-03-26 15:01:03 +000072 * or equal to 128 bytes);
73 * - kConstantLargeValue: value holds a "large" constant (lower than 0, or
David Brazdild9cb68e2015-08-25 13:52:43 +010074 * or greater than or equal to 32);
75 * - kNone: the register has no location, meaning it has not been set.
Roland Levillaina2d8ec62015-03-12 15:25:29 +000076 */
77 enum class Kind : uint8_t {
78 // Short location kinds, for entries fitting on one byte (3 bits
79 // for the kind, 5 bits for the value) in a DexRegisterMap.
David Brazdild9cb68e2015-08-25 13:52:43 +010080 kInStack = 0, // 0b000
81 kInRegister = 1, // 0b001
82 kInRegisterHigh = 2, // 0b010
Roland Levillaina2d8ec62015-03-12 15:25:29 +000083 kInFpuRegister = 3, // 0b011
David Brazdild9cb68e2015-08-25 13:52:43 +010084 kInFpuRegisterHigh = 4, // 0b100
85 kConstant = 5, // 0b101
Roland Levillaina2d8ec62015-03-12 15:25:29 +000086
87 // Large location kinds, requiring a 5-byte encoding (1 byte for the
88 // kind, 4 bytes for the value).
89
90 // Stack location at a large offset, meaning that the offset value
91 // divided by the stack frame slot size (4 bytes) cannot fit on a
92 // 5-bit unsigned integer (i.e., this offset value is greater than
93 // or equal to 2^5 * 4 = 128 bytes).
David Brazdild9cb68e2015-08-25 13:52:43 +010094 kInStackLargeOffset = 6, // 0b110
Roland Levillaina2d8ec62015-03-12 15:25:29 +000095
96 // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
Roland Levillaina552e1c2015-03-26 15:01:03 +000097 // lower than 0, or greater than or equal to 2^5 = 32).
David Brazdild9cb68e2015-08-25 13:52:43 +010098 kConstantLargeValue = 7, // 0b111
99
100 // Entries with no location are not stored and do not need own marker.
101 kNone = static_cast<uint8_t>(-1),
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000102
103 kLastLocationKind = kConstantLargeValue
104 };
105
106 static_assert(
107 sizeof(Kind) == 1u,
108 "art::DexRegisterLocation::Kind has a size different from one byte.");
109
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000110 static bool IsShortLocationKind(Kind kind) {
111 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000112 case Kind::kInStack:
113 case Kind::kInRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100114 case Kind::kInRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000115 case Kind::kInFpuRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100116 case Kind::kInFpuRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000117 case Kind::kConstant:
118 return true;
119
120 case Kind::kInStackLargeOffset:
121 case Kind::kConstantLargeValue:
122 return false;
123
David Brazdild9cb68e2015-08-25 13:52:43 +0100124 case Kind::kNone:
David Srbecky7dc11782016-02-25 13:23:56 +0000125 LOG(FATAL) << "Unexpected location kind";
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000126 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100127 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000128 }
129
130 // Convert `kind` to a "surface" kind, i.e. one that doesn't include
131 // any value with a "large" qualifier.
132 // TODO: Introduce another enum type for the surface kind?
133 static Kind ConvertToSurfaceKind(Kind kind) {
134 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000135 case Kind::kInStack:
136 case Kind::kInRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100137 case Kind::kInRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000138 case Kind::kInFpuRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100139 case Kind::kInFpuRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000140 case Kind::kConstant:
141 return kind;
142
143 case Kind::kInStackLargeOffset:
144 return Kind::kInStack;
145
146 case Kind::kConstantLargeValue:
147 return Kind::kConstant;
148
David Brazdild9cb68e2015-08-25 13:52:43 +0100149 case Kind::kNone:
150 return kind;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000151 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100152 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000153 }
154
Roland Levillaina552e1c2015-03-26 15:01:03 +0000155 // Required by art::StackMapStream::LocationCatalogEntriesIndices.
156 DexRegisterLocation() : kind_(Kind::kNone), value_(0) {}
157
158 DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {}
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000159
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000160 static DexRegisterLocation None() {
161 return DexRegisterLocation(Kind::kNone, 0);
162 }
163
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000164 // Get the "surface" kind of the location, i.e., the one that doesn't
165 // include any value with a "large" qualifier.
166 Kind GetKind() const {
167 return ConvertToSurfaceKind(kind_);
168 }
169
170 // Get the value of the location.
171 int32_t GetValue() const { return value_; }
172
173 // Get the actual kind of the location.
174 Kind GetInternalKind() const { return kind_; }
175
Calin Juravle6ae70962015-03-18 16:31:28 +0000176 bool operator==(DexRegisterLocation other) const {
177 return kind_ == other.kind_ && value_ == other.value_;
178 }
179
180 bool operator!=(DexRegisterLocation other) const {
181 return !(*this == other);
182 }
183
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000184 private:
185 Kind kind_;
186 int32_t value_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000187
188 friend class DexRegisterLocationHashFn;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000189};
190
David Srbecky7dc11782016-02-25 13:23:56 +0000191std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind);
192
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100193/**
Roland Levillaina552e1c2015-03-26 15:01:03 +0000194 * Store information on unique Dex register locations used in a method.
195 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100196 *
197 * [DexRegisterLocation+].
198 *
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000199 * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100200 */
Roland Levillaina552e1c2015-03-26 15:01:03 +0000201class DexRegisterLocationCatalog {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100202 public:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000203 explicit DexRegisterLocationCatalog(MemoryRegion region) : region_(region) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100204
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000205 // Short (compressed) location, fitting on one byte.
206 typedef uint8_t ShortLocation;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100207
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000208 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
209 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
210 int32_t value = dex_register_location.GetValue();
211 if (DexRegisterLocation::IsShortLocationKind(kind)) {
212 // Short location. Compress the kind and the value as a single byte.
213 if (kind == DexRegisterLocation::Kind::kInStack) {
214 // Instead of storing stack offsets expressed in bytes for
215 // short stack locations, store slot offsets. A stack offset
216 // is a multiple of 4 (kFrameSlotSize). This means that by
217 // dividing it by 4, we can fit values from the [0, 128)
218 // interval in a short stack location, and not just values
219 // from the [0, 32) interval.
220 DCHECK_EQ(value % kFrameSlotSize, 0);
221 value /= kFrameSlotSize;
222 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000223 DCHECK(IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000224 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
225 } else {
226 // Large location. Write the location on one byte and the value
227 // on 4 bytes.
Roland Levillaina552e1c2015-03-26 15:01:03 +0000228 DCHECK(!IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000229 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
230 // Also divide large stack offsets by 4 for the sake of consistency.
231 DCHECK_EQ(value % kFrameSlotSize, 0);
232 value /= kFrameSlotSize;
233 }
234 // Data can be unaligned as the written Dex register locations can
235 // either be 1-byte or 5-byte wide. Use
236 // art::MemoryRegion::StoreUnaligned instead of
237 // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
238 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
239 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
Roland Levillain442b46a2015-02-18 16:54:21 +0000240 }
241 }
242
Roland Levillaina552e1c2015-03-26 15:01:03 +0000243 // Find the offset of the location catalog entry number `location_catalog_entry_index`.
244 size_t FindLocationOffset(size_t location_catalog_entry_index) const {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000245 size_t offset = kFixedSize;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000246 // Skip the first `location_catalog_entry_index - 1` entries.
247 for (uint16_t i = 0; i < location_catalog_entry_index; ++i) {
248 // Read the first next byte and inspect its first 3 bits to decide
249 // whether it is a short or a large location.
250 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
251 if (DexRegisterLocation::IsShortLocationKind(kind)) {
252 // Short location. Skip the current byte.
253 offset += SingleShortEntrySize();
254 } else {
255 // Large location. Skip the 5 next bytes.
256 offset += SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000257 }
258 }
259 return offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100260 }
261
Roland Levillaina552e1c2015-03-26 15:01:03 +0000262 // Get the internal kind of entry at `location_catalog_entry_index`.
263 DexRegisterLocation::Kind GetLocationInternalKind(size_t location_catalog_entry_index) const {
264 if (location_catalog_entry_index == kNoLocationEntryIndex) {
265 return DexRegisterLocation::Kind::kNone;
266 }
267 return ExtractKindAtOffset(FindLocationOffset(location_catalog_entry_index));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100268 }
269
Roland Levillaina552e1c2015-03-26 15:01:03 +0000270 // Get the (surface) kind and value of entry at `location_catalog_entry_index`.
271 DexRegisterLocation GetDexRegisterLocation(size_t location_catalog_entry_index) const {
272 if (location_catalog_entry_index == kNoLocationEntryIndex) {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000273 return DexRegisterLocation::None();
274 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000275 size_t offset = FindLocationOffset(location_catalog_entry_index);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000276 // Read the first byte and inspect its first 3 bits to get the location.
277 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
278 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
279 if (DexRegisterLocation::IsShortLocationKind(kind)) {
280 // Short location. Extract the value from the remaining 5 bits.
281 int32_t value = ExtractValueFromShortLocation(first_byte);
282 if (kind == DexRegisterLocation::Kind::kInStack) {
283 // Convert the stack slot (short) offset to a byte offset value.
284 value *= kFrameSlotSize;
285 }
286 return DexRegisterLocation(kind, value);
287 } else {
288 // Large location. Read the four next bytes to get the value.
289 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
290 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
291 // Convert the stack slot (large) offset to a byte offset value.
292 value *= kFrameSlotSize;
293 }
294 return DexRegisterLocation(kind, value);
295 }
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100296 }
297
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000298 // Compute the compressed kind of `location`.
299 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
David Brazdild9cb68e2015-08-25 13:52:43 +0100300 DexRegisterLocation::Kind kind = location.GetInternalKind();
301 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000302 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000303 return IsShortStackOffsetValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000304 ? DexRegisterLocation::Kind::kInStack
305 : DexRegisterLocation::Kind::kInStackLargeOffset;
306
David Brazdild9cb68e2015-08-25 13:52:43 +0100307 case DexRegisterLocation::Kind::kInRegister:
308 case DexRegisterLocation::Kind::kInRegisterHigh:
309 DCHECK_GE(location.GetValue(), 0);
310 DCHECK_LT(location.GetValue(), 1 << kValueBits);
311 return kind;
312
313 case DexRegisterLocation::Kind::kInFpuRegister:
314 case DexRegisterLocation::Kind::kInFpuRegisterHigh:
315 DCHECK_GE(location.GetValue(), 0);
316 DCHECK_LT(location.GetValue(), 1 << kValueBits);
317 return kind;
318
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000319 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000320 return IsShortConstantValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000321 ? DexRegisterLocation::Kind::kConstant
322 : DexRegisterLocation::Kind::kConstantLargeValue;
323
David Brazdild9cb68e2015-08-25 13:52:43 +0100324 case DexRegisterLocation::Kind::kConstantLargeValue:
325 case DexRegisterLocation::Kind::kInStackLargeOffset:
326 case DexRegisterLocation::Kind::kNone:
David Srbecky7dc11782016-02-25 13:23:56 +0000327 LOG(FATAL) << "Unexpected location kind " << kind;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000328 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100329 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000330 }
331
332 // Can `location` be turned into a short location?
333 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
David Brazdild9cb68e2015-08-25 13:52:43 +0100334 DexRegisterLocation::Kind kind = location.GetInternalKind();
335 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000336 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000337 return IsShortStackOffsetValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000338
David Brazdild9cb68e2015-08-25 13:52:43 +0100339 case DexRegisterLocation::Kind::kInRegister:
340 case DexRegisterLocation::Kind::kInRegisterHigh:
341 case DexRegisterLocation::Kind::kInFpuRegister:
342 case DexRegisterLocation::Kind::kInFpuRegisterHigh:
343 return true;
344
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000345 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000346 return IsShortConstantValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000347
David Brazdild9cb68e2015-08-25 13:52:43 +0100348 case DexRegisterLocation::Kind::kConstantLargeValue:
349 case DexRegisterLocation::Kind::kInStackLargeOffset:
350 case DexRegisterLocation::Kind::kNone:
David Srbecky7dc11782016-02-25 13:23:56 +0000351 LOG(FATAL) << "Unexpected location kind " << kind;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000352 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100353 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000354 }
355
356 static size_t EntrySize(const DexRegisterLocation& location) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000357 return CanBeEncodedAsShortLocation(location) ? SingleShortEntrySize() : SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000358 }
359
360 static size_t SingleShortEntrySize() {
361 return sizeof(ShortLocation);
362 }
363
364 static size_t SingleLargeEntrySize() {
365 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100366 }
367
Roland Levillain12baf472015-03-05 12:41:42 +0000368 size_t Size() const {
369 return region_.size();
370 }
371
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100372 void Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info);
Roland Levillain0396ed72015-05-27 15:12:19 +0100373
Roland Levillaina552e1c2015-03-26 15:01:03 +0000374 // Special (invalid) Dex register location catalog entry index meaning
375 // that there is no location for a given Dex register (i.e., it is
376 // mapped to a DexRegisterLocation::Kind::kNone location).
377 static constexpr size_t kNoLocationEntryIndex = -1;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100378
Roland Levillain12baf472015-03-05 12:41:42 +0000379 private:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000380 static constexpr int kFixedSize = 0;
381
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000382 // Width of the kind "field" in a short location, in bits.
383 static constexpr size_t kKindBits = 3;
384 // Width of the value "field" in a short location, in bits.
385 static constexpr size_t kValueBits = 5;
386
387 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
388 static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
389 static constexpr size_t kKindOffset = 0;
390 static constexpr size_t kValueOffset = kKindBits;
391
Roland Levillaina552e1c2015-03-26 15:01:03 +0000392 static bool IsShortStackOffsetValue(int32_t value) {
393 DCHECK_EQ(value % kFrameSlotSize, 0);
394 return IsShortValue(value / kFrameSlotSize);
395 }
396
397 static bool IsShortConstantValue(int32_t value) {
398 return IsShortValue(value);
399 }
400
401 static bool IsShortValue(int32_t value) {
402 return IsUint<kValueBits>(value);
403 }
404
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000405 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000406 uint8_t kind_integer_value = static_cast<uint8_t>(kind);
407 DCHECK(IsUint<kKindBits>(kind_integer_value)) << kind_integer_value;
408 DCHECK(IsShortValue(value)) << value;
409 return (kind_integer_value & kKindMask) << kKindOffset
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000410 | (value & kValueMask) << kValueOffset;
411 }
412
413 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
414 uint8_t kind = (location >> kKindOffset) & kKindMask;
415 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000416 // We do not encode kNone locations in the stack map.
417 DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone));
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000418 return static_cast<DexRegisterLocation::Kind>(kind);
419 }
420
421 static int32_t ExtractValueFromShortLocation(ShortLocation location) {
422 return (location >> kValueOffset) & kValueMask;
423 }
424
425 // Extract a location kind from the byte at position `offset`.
426 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
427 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
428 return ExtractKindFromShortLocation(first_byte);
429 }
430
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100431 MemoryRegion region_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000432
433 friend class CodeInfo;
434 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100435};
436
Roland Levillaina552e1c2015-03-26 15:01:03 +0000437/* Information on Dex register locations for a specific PC, mapping a
438 * stack map's Dex register to a location entry in a DexRegisterLocationCatalog.
439 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100440 *
441 * [live_bit_mask, entries*]
442 *
Roland Levillaina552e1c2015-03-26 15:01:03 +0000443 * where entries are concatenated unsigned integer values encoded on a number
444 * of bits (fixed per DexRegisterMap instances of a CodeInfo object) depending
445 * on the number of entries in the Dex register location catalog
446 * (see DexRegisterMap::SingleEntrySizeInBits). The map is 1-byte aligned.
447 */
448class DexRegisterMap {
449 public:
450 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +0000451 DexRegisterMap() {}
452
453 bool IsValid() const { return region_.pointer() != nullptr; }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000454
455 // Get the surface kind of Dex register `dex_register_number`.
456 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number,
457 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100458 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000459 const CodeInfoEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000460 return DexRegisterLocation::ConvertToSurfaceKind(
David Brazdilf677ebf2015-05-29 16:29:43 +0100461 GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info, enc));
Roland Levillaina552e1c2015-03-26 15:01:03 +0000462 }
463
464 // Get the internal kind of Dex register `dex_register_number`.
465 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number,
466 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100467 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000468 const CodeInfoEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000469
470 // Get the Dex register location `dex_register_number`.
471 DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number,
472 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100473 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000474 const CodeInfoEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000475
476 int32_t GetStackOffsetInBytes(uint16_t dex_register_number,
477 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100478 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000479 const CodeInfoEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000480 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100481 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000482 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
483 // GetDexRegisterLocation returns the offset in bytes.
484 return location.GetValue();
485 }
486
487 int32_t GetConstant(uint16_t dex_register_number,
488 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100489 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000490 const CodeInfoEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000491 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100492 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
David Srbecky7dc11782016-02-25 13:23:56 +0000493 DCHECK_EQ(location.GetKind(), DexRegisterLocation::Kind::kConstant);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000494 return location.GetValue();
495 }
496
497 int32_t GetMachineRegister(uint16_t dex_register_number,
498 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100499 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000500 const CodeInfoEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000501 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100502 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
David Brazdild9cb68e2015-08-25 13:52:43 +0100503 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister ||
504 location.GetInternalKind() == DexRegisterLocation::Kind::kInRegisterHigh ||
505 location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister ||
506 location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh)
David Srbecky7dc11782016-02-25 13:23:56 +0000507 << location.GetInternalKind();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000508 return location.GetValue();
509 }
510
511 // Get the index of the entry in the Dex register location catalog
512 // corresponding to `dex_register_number`.
513 size_t GetLocationCatalogEntryIndex(uint16_t dex_register_number,
514 uint16_t number_of_dex_registers,
515 size_t number_of_location_catalog_entries) const {
516 if (!IsDexRegisterLive(dex_register_number)) {
517 return DexRegisterLocationCatalog::kNoLocationEntryIndex;
518 }
519
520 if (number_of_location_catalog_entries == 1) {
521 // We do not allocate space for location maps in the case of a
522 // single-entry location catalog, as it is useless. The only valid
523 // entry index is 0;
524 return 0;
525 }
526
527 // The bit offset of the beginning of the map locations.
528 size_t map_locations_offset_in_bits =
529 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
530 size_t index_in_dex_register_map = GetIndexInDexRegisterMap(dex_register_number);
531 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
532 // The bit size of an entry.
533 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
534 // The bit offset where `index_in_dex_register_map` is located.
535 size_t entry_offset_in_bits =
536 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
537 size_t location_catalog_entry_index =
538 region_.LoadBits(entry_offset_in_bits, map_entry_size_in_bits);
539 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
540 return location_catalog_entry_index;
541 }
542
543 // Map entry at `index_in_dex_register_map` to `location_catalog_entry_index`.
544 void SetLocationCatalogEntryIndex(size_t index_in_dex_register_map,
545 size_t location_catalog_entry_index,
546 uint16_t number_of_dex_registers,
547 size_t number_of_location_catalog_entries) {
548 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
549 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
550
551 if (number_of_location_catalog_entries == 1) {
552 // We do not allocate space for location maps in the case of a
553 // single-entry location catalog, as it is useless.
554 return;
555 }
556
557 // The bit offset of the beginning of the map locations.
558 size_t map_locations_offset_in_bits =
559 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
560 // The bit size of an entry.
561 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
562 // The bit offset where `index_in_dex_register_map` is located.
563 size_t entry_offset_in_bits =
564 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
565 region_.StoreBits(entry_offset_in_bits, location_catalog_entry_index, map_entry_size_in_bits);
566 }
567
568 void SetLiveBitMask(uint16_t number_of_dex_registers,
569 const BitVector& live_dex_registers_mask) {
570 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
571 for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
572 region_.StoreBit(live_bit_mask_offset_in_bits + i, live_dex_registers_mask.IsBitSet(i));
573 }
574 }
575
576 bool IsDexRegisterLive(uint16_t dex_register_number) const {
577 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
578 return region_.LoadBit(live_bit_mask_offset_in_bits + dex_register_number);
579 }
580
581 size_t GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers) const {
582 size_t number_of_live_dex_registers = 0;
583 for (size_t i = 0; i < number_of_dex_registers; ++i) {
584 if (IsDexRegisterLive(i)) {
585 ++number_of_live_dex_registers;
586 }
587 }
588 return number_of_live_dex_registers;
589 }
590
591 static size_t GetLiveBitMaskOffset() {
592 return kFixedSize;
593 }
594
595 // Compute the size of the live register bit mask (in bytes), for a
596 // method having `number_of_dex_registers` Dex registers.
597 static size_t GetLiveBitMaskSize(uint16_t number_of_dex_registers) {
598 return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte;
599 }
600
601 static size_t GetLocationMappingDataOffset(uint16_t number_of_dex_registers) {
602 return GetLiveBitMaskOffset() + GetLiveBitMaskSize(number_of_dex_registers);
603 }
604
605 size_t GetLocationMappingDataSize(uint16_t number_of_dex_registers,
606 size_t number_of_location_catalog_entries) const {
607 size_t location_mapping_data_size_in_bits =
608 GetNumberOfLiveDexRegisters(number_of_dex_registers)
609 * SingleEntrySizeInBits(number_of_location_catalog_entries);
610 return RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
611 }
612
613 // Return the size of a map entry in bits. Note that if
614 // `number_of_location_catalog_entries` equals 1, this function returns 0,
615 // which is fine, as there is no need to allocate a map for a
616 // single-entry location catalog; the only valid location catalog entry index
617 // for a live register in this case is 0 and there is no need to
618 // store it.
619 static size_t SingleEntrySizeInBits(size_t number_of_location_catalog_entries) {
620 // Handle the case of 0, as we cannot pass 0 to art::WhichPowerOf2.
621 return number_of_location_catalog_entries == 0
622 ? 0u
623 : WhichPowerOf2(RoundUpToPowerOfTwo(number_of_location_catalog_entries));
624 }
625
626 // Return the size of the DexRegisterMap object, in bytes.
627 size_t Size() const {
628 return region_.size();
629 }
630
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100631 void Dump(VariableIndentationOutputStream* vios,
632 const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100633
Roland Levillaina552e1c2015-03-26 15:01:03 +0000634 private:
635 // Return the index in the Dex register map corresponding to the Dex
636 // register number `dex_register_number`.
637 size_t GetIndexInDexRegisterMap(uint16_t dex_register_number) const {
638 if (!IsDexRegisterLive(dex_register_number)) {
639 return kInvalidIndexInDexRegisterMap;
640 }
641 return GetNumberOfLiveDexRegisters(dex_register_number);
642 }
643
644 // Special (invalid) Dex register map entry index meaning that there
645 // is no index in the map for a given Dex register (i.e., it must
646 // have been mapped to a DexRegisterLocation::Kind::kNone location).
647 static constexpr size_t kInvalidIndexInDexRegisterMap = -1;
648
649 static constexpr int kFixedSize = 0;
650
651 MemoryRegion region_;
652
653 friend class CodeInfo;
654 friend class StackMapStream;
655};
656
David Srbecky09ed0982016-02-12 21:58:43 +0000657// Represents bit range of bit-packed integer field.
658// We reuse the idea from ULEB128p1 to support encoding of -1 (aka 0xFFFFFFFF).
659// If min_value is set to -1, we implicitly subtract one from any loaded value,
660// and add one to any stored value. This is generalized to any negative values.
661// In other words, min_value acts as a base and the stored value is added to it.
662struct FieldEncoding {
663 FieldEncoding(size_t start_offset, size_t end_offset, int32_t min_value = 0)
664 : start_offset_(start_offset), end_offset_(end_offset), min_value_(min_value) {
665 DCHECK_LE(start_offset_, end_offset_);
666 DCHECK_LE(BitSize(), 32u);
667 }
668
669 ALWAYS_INLINE size_t BitSize() const { return end_offset_ - start_offset_; }
670
671 ALWAYS_INLINE int32_t Load(const MemoryRegion& region) const {
672 DCHECK_LE(end_offset_, region.size_in_bits());
673 const size_t bit_count = BitSize();
674 if (bit_count == 0) {
675 // Do not touch any memory if the range is empty.
676 return min_value_;
677 }
678 uint8_t* address = region.start() + start_offset_ / kBitsPerByte;
679 const uint32_t shift = start_offset_ & (kBitsPerByte - 1);
680 // Load the value (reading only the strictly needed bytes).
681 const uint32_t load_bit_count = shift + bit_count;
682 uint32_t value = *address++ >> shift;
683 if (load_bit_count > 8) {
684 value |= static_cast<uint32_t>(*address++) << (8 - shift);
685 if (load_bit_count > 16) {
686 value |= static_cast<uint32_t>(*address++) << (16 - shift);
687 if (load_bit_count > 24) {
688 value |= static_cast<uint32_t>(*address++) << (24 - shift);
689 if (load_bit_count > 32) {
690 value |= static_cast<uint32_t>(*address++) << (32 - shift);
691 }
692 }
693 }
694 }
695 // Clear unwanted most significant bits.
696 uint32_t clear_bit_count = 32 - bit_count;
697 value = (value << clear_bit_count) >> clear_bit_count;
698 return value + min_value_;
699 }
700
701 ALWAYS_INLINE void Store(MemoryRegion region, int32_t value) const {
702 region.StoreBits(start_offset_, value - min_value_, BitSize());
703 DCHECK_EQ(Load(region), value);
704 }
705
706 private:
707 size_t start_offset_;
708 size_t end_offset_;
709 int32_t min_value_;
710};
711
David Brazdilf677ebf2015-05-29 16:29:43 +0100712class StackMapEncoding {
713 public:
714 StackMapEncoding() {}
715
David Srbecky09ed0982016-02-12 21:58:43 +0000716 // Set stack map bit layout based on given sizes.
717 // Returns the size of stack map in bytes.
718 size_t SetFromSizes(size_t native_pc_max,
719 size_t dex_pc_max,
720 size_t dex_register_map_size,
721 size_t inline_info_size,
722 size_t register_mask_max,
723 size_t stack_mask_bit_size) {
724 size_t bit_offset = 0;
725 DCHECK_EQ(kNativePcBitOffset, bit_offset);
726 bit_offset += MinimumBitsToStore(native_pc_max);
David Brazdilf677ebf2015-05-29 16:29:43 +0100727
David Srbecky09ed0982016-02-12 21:58:43 +0000728 dex_pc_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
729 bit_offset += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max);
730
731 // We also need +1 for kNoDexRegisterMap, but since the size is strictly
732 // greater than any offset we might try to encode, we already implicitly have it.
733 dex_register_map_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
734 bit_offset += MinimumBitsToStore(dex_register_map_size);
735
736 // We also need +1 for kNoInlineInfo, but since the inline_info_size is strictly
737 // greater than the offset we might try to encode, we already implicitly have it.
738 // If inline_info_size is zero, we can encode only kNoInlineInfo (in zero bits).
739 inline_info_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
740 if (inline_info_size != 0) {
741 bit_offset += MinimumBitsToStore(dex_register_map_size + inline_info_size);
742 }
743
744 register_mask_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
745 bit_offset += MinimumBitsToStore(register_mask_max);
746
747 stack_mask_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
748 bit_offset += stack_mask_bit_size;
749
750 return RoundUp(bit_offset, kBitsPerByte) / kBitsPerByte;
David Brazdilf677ebf2015-05-29 16:29:43 +0100751 }
752
David Srbecky09ed0982016-02-12 21:58:43 +0000753 ALWAYS_INLINE FieldEncoding GetNativePcEncoding() const {
754 return FieldEncoding(kNativePcBitOffset, dex_pc_bit_offset_);
755 }
756 ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const {
757 return FieldEncoding(dex_pc_bit_offset_, dex_register_map_bit_offset_, -1 /* min_value */);
758 }
759 ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const {
760 return FieldEncoding(dex_register_map_bit_offset_, inline_info_bit_offset_, -1 /* min_value */);
761 }
762 ALWAYS_INLINE FieldEncoding GetInlineInfoEncoding() const {
763 return FieldEncoding(inline_info_bit_offset_, register_mask_bit_offset_, -1 /* min_value */);
764 }
765 ALWAYS_INLINE FieldEncoding GetRegisterMaskEncoding() const {
766 return FieldEncoding(register_mask_bit_offset_, stack_mask_bit_offset_);
767 }
768 ALWAYS_INLINE size_t GetStackMaskBitOffset() const {
769 // The end offset is not encoded. It is implicitly the end of stack map entry.
770 return stack_mask_bit_offset_;
David Brazdilf677ebf2015-05-29 16:29:43 +0100771 }
772
David Srbecky09ed0982016-02-12 21:58:43 +0000773 void Dump(VariableIndentationOutputStream* vios) const;
David Brazdilf677ebf2015-05-29 16:29:43 +0100774
775 private:
David Srbecky09ed0982016-02-12 21:58:43 +0000776 static constexpr size_t kNativePcBitOffset = 0;
777 uint8_t dex_pc_bit_offset_;
778 uint8_t dex_register_map_bit_offset_;
779 uint8_t inline_info_bit_offset_;
780 uint8_t register_mask_bit_offset_;
781 uint8_t stack_mask_bit_offset_;
David Brazdilf677ebf2015-05-29 16:29:43 +0100782};
783
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100784/**
785 * A Stack Map holds compilation information for a specific PC necessary for:
786 * - Mapping it to a dex PC,
787 * - Knowing which stack entries are objects,
788 * - Knowing which registers hold objects,
789 * - Knowing the inlining information,
790 * - Knowing the values of dex registers.
791 *
792 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100793 *
David Srbecky09ed0982016-02-12 21:58:43 +0000794 * [native_pc_offset, dex_pc, dex_register_map_offset, inlining_info_offset, register_mask,
Roland Levillain1c1da432015-07-16 11:54:44 +0100795 * stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100796 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100797class StackMap {
798 public:
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100799 StackMap() {}
David Brazdilf677ebf2015-05-29 16:29:43 +0100800 explicit StackMap(MemoryRegion region) : region_(region) {}
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100801
David Srbecky09ed0982016-02-12 21:58:43 +0000802 ALWAYS_INLINE bool IsValid() const { return region_.pointer() != nullptr; }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100803
David Srbecky09ed0982016-02-12 21:58:43 +0000804 ALWAYS_INLINE uint32_t GetDexPc(const StackMapEncoding& encoding) const {
805 return encoding.GetDexPcEncoding().Load(region_);
David Brazdilf677ebf2015-05-29 16:29:43 +0100806 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100807
David Srbecky09ed0982016-02-12 21:58:43 +0000808 ALWAYS_INLINE void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) {
809 encoding.GetDexPcEncoding().Store(region_, dex_pc);
David Brazdilf677ebf2015-05-29 16:29:43 +0100810 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100811
David Srbecky09ed0982016-02-12 21:58:43 +0000812 ALWAYS_INLINE uint32_t GetNativePcOffset(const StackMapEncoding& encoding) const {
813 return encoding.GetNativePcEncoding().Load(region_);
David Brazdilf677ebf2015-05-29 16:29:43 +0100814 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100815
David Srbecky09ed0982016-02-12 21:58:43 +0000816 ALWAYS_INLINE void SetNativePcOffset(const StackMapEncoding& encoding, uint32_t native_pc_offset) {
817 encoding.GetNativePcEncoding().Store(region_, native_pc_offset);
David Brazdilf677ebf2015-05-29 16:29:43 +0100818 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100819
David Srbecky09ed0982016-02-12 21:58:43 +0000820 ALWAYS_INLINE uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const {
821 return encoding.GetDexRegisterMapEncoding().Load(region_);
David Brazdilf677ebf2015-05-29 16:29:43 +0100822 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100823
David Srbecky09ed0982016-02-12 21:58:43 +0000824 ALWAYS_INLINE void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) {
825 encoding.GetDexRegisterMapEncoding().Store(region_, offset);
David Brazdilf677ebf2015-05-29 16:29:43 +0100826 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100827
David Srbecky09ed0982016-02-12 21:58:43 +0000828 ALWAYS_INLINE uint32_t GetInlineDescriptorOffset(const StackMapEncoding& encoding) const {
829 return encoding.GetInlineInfoEncoding().Load(region_);
David Brazdilf677ebf2015-05-29 16:29:43 +0100830 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100831
David Srbecky09ed0982016-02-12 21:58:43 +0000832 ALWAYS_INLINE void SetInlineDescriptorOffset(const StackMapEncoding& encoding, uint32_t offset) {
833 encoding.GetInlineInfoEncoding().Store(region_, offset);
David Brazdilf677ebf2015-05-29 16:29:43 +0100834 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100835
David Srbecky09ed0982016-02-12 21:58:43 +0000836 ALWAYS_INLINE uint32_t GetRegisterMask(const StackMapEncoding& encoding) const {
837 return encoding.GetRegisterMaskEncoding().Load(region_);
David Brazdilf677ebf2015-05-29 16:29:43 +0100838 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100839
David Srbecky09ed0982016-02-12 21:58:43 +0000840 ALWAYS_INLINE void SetRegisterMask(const StackMapEncoding& encoding, uint32_t mask) {
841 encoding.GetRegisterMaskEncoding().Store(region_, mask);
David Brazdilf677ebf2015-05-29 16:29:43 +0100842 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100843
David Srbecky09ed0982016-02-12 21:58:43 +0000844 ALWAYS_INLINE size_t GetNumberOfStackMaskBits(const StackMapEncoding& encoding) const {
845 return region_.size_in_bits() - encoding.GetStackMaskBitOffset();
David Brazdilf677ebf2015-05-29 16:29:43 +0100846 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100847
David Srbecky09ed0982016-02-12 21:58:43 +0000848 ALWAYS_INLINE bool GetStackMaskBit(const StackMapEncoding& encoding, size_t index) const {
849 return region_.LoadBit(encoding.GetStackMaskBitOffset() + index);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100850 }
851
David Srbecky09ed0982016-02-12 21:58:43 +0000852 ALWAYS_INLINE void SetStackMaskBit(const StackMapEncoding& encoding, size_t index, bool value) {
853 region_.StoreBit(encoding.GetStackMaskBitOffset() + index, value);
854 }
855
856 ALWAYS_INLINE bool HasDexRegisterMap(const StackMapEncoding& encoding) const {
David Brazdilf677ebf2015-05-29 16:29:43 +0100857 return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100858 }
859
David Srbecky09ed0982016-02-12 21:58:43 +0000860 ALWAYS_INLINE bool HasInlineInfo(const StackMapEncoding& encoding) const {
David Brazdilf677ebf2015-05-29 16:29:43 +0100861 return GetInlineDescriptorOffset(encoding) != kNoInlineInfo;
Roland Levillain442b46a2015-02-18 16:54:21 +0000862 }
863
David Srbecky09ed0982016-02-12 21:58:43 +0000864 ALWAYS_INLINE bool Equals(const StackMap& other) const {
865 return region_.pointer() == other.region_.pointer() && region_.size() == other.region_.size();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100866 }
867
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100868 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100869 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000870 const CodeInfoEncoding& encoding,
Roland Levillainf2650d12015-05-28 14:53:28 +0100871 uint32_t code_offset,
872 uint16_t number_of_dex_registers,
873 const std::string& header_suffix = "") const;
874
Roland Levillain442b46a2015-02-18 16:54:21 +0000875 // Special (invalid) offset for the DexRegisterMapOffset field meaning
876 // that there is no Dex register map for this stack map.
877 static constexpr uint32_t kNoDexRegisterMap = -1;
878
879 // Special (invalid) offset for the InlineDescriptorOffset field meaning
880 // that there is no inline info for this stack map.
881 static constexpr uint32_t kNoInlineInfo = -1;
882
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100883 private:
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100884 static constexpr int kFixedSize = 0;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100885
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
David Srbecky09ed0982016-02-12 21:58:43 +0000989// Most of the fields are encoded as ULEB128 to save space.
990struct CodeInfoEncoding {
991 uint32_t non_header_size;
992 uint32_t number_of_stack_maps;
993 uint32_t stack_map_size_in_bytes;
994 uint32_t number_of_location_catalog_entries;
995 StackMapEncoding stack_map_encoding;
996 uint8_t header_size;
997
998 CodeInfoEncoding() { }
999
1000 explicit CodeInfoEncoding(const void* data) {
1001 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
1002 non_header_size = DecodeUnsignedLeb128(&ptr);
1003 number_of_stack_maps = DecodeUnsignedLeb128(&ptr);
1004 stack_map_size_in_bytes = DecodeUnsignedLeb128(&ptr);
1005 number_of_location_catalog_entries = DecodeUnsignedLeb128(&ptr);
1006 static_assert(alignof(StackMapEncoding) == 1, "StackMapEncoding should not require alignment");
1007 stack_map_encoding = *reinterpret_cast<const StackMapEncoding*>(ptr);
1008 ptr += sizeof(StackMapEncoding);
1009 header_size = dchecked_integral_cast<uint8_t>(ptr - reinterpret_cast<const uint8_t*>(data));
1010 }
1011
1012 template<typename Vector>
1013 void Compress(Vector* dest) const {
1014 EncodeUnsignedLeb128(dest, non_header_size);
1015 EncodeUnsignedLeb128(dest, number_of_stack_maps);
1016 EncodeUnsignedLeb128(dest, stack_map_size_in_bytes);
1017 EncodeUnsignedLeb128(dest, number_of_location_catalog_entries);
1018 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&stack_map_encoding);
1019 dest->insert(dest->end(), ptr, ptr + sizeof(stack_map_encoding));
1020 }
1021};
1022
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001023/**
1024 * Wrapper around all compiler information collected for a method.
1025 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +01001026 *
David Srbecky09ed0982016-02-12 21:58:43 +00001027 * [CodeInfoEncoding, StackMap+, DexRegisterLocationCatalog+, DexRegisterMap+, InlineInfo*]
Roland Levillain1c1da432015-07-16 11:54:44 +01001028 *
David Srbecky09ed0982016-02-12 21:58:43 +00001029 * where CodeInfoEncoding is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +01001030 *
David Srbecky09ed0982016-02-12 21:58:43 +00001031 * [non_header_size, number_of_stack_maps, stack_map_size_in_bytes,
1032 * number_of_location_catalog_entries, StackMapEncoding]
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001033 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001034class CodeInfo {
1035 public:
David Srbecky09ed0982016-02-12 21:58:43 +00001036 explicit CodeInfo(MemoryRegion region) : region_(region) {
1037 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001038
Nicolas Geoffray39468442014-09-02 15:17:15 +01001039 explicit CodeInfo(const void* data) {
David Srbecky09ed0982016-02-12 21:58:43 +00001040 CodeInfoEncoding encoding = CodeInfoEncoding(data);
1041 region_ = MemoryRegion(const_cast<void*>(data),
1042 encoding.header_size + encoding.non_header_size);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001043 }
1044
David Srbecky09ed0982016-02-12 21:58:43 +00001045 CodeInfoEncoding ExtractEncoding() const {
1046 return CodeInfoEncoding(region_.start());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001047 }
1048
David Srbecky09ed0982016-02-12 21:58:43 +00001049 bool HasInlineInfo(const CodeInfoEncoding& encoding) const {
1050 return encoding.stack_map_encoding.GetInlineInfoEncoding().BitSize() > 0;
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001051 }
1052
David Srbecky09ed0982016-02-12 21:58:43 +00001053 DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const CodeInfoEncoding& encoding) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +00001054 return DexRegisterLocationCatalog(region_.Subregion(
David Brazdilf677ebf2015-05-29 16:29:43 +01001055 GetDexRegisterLocationCatalogOffset(encoding),
1056 GetDexRegisterLocationCatalogSize(encoding)));
Roland Levillaina552e1c2015-03-26 15:01:03 +00001057 }
1058
David Srbecky09ed0982016-02-12 21:58:43 +00001059 StackMap GetStackMapAt(size_t i, const CodeInfoEncoding& encoding) const {
1060 size_t stack_map_size = encoding.stack_map_size_in_bytes;
David Brazdilf677ebf2015-05-29 16:29:43 +01001061 return StackMap(GetStackMaps(encoding).Subregion(i * stack_map_size, stack_map_size));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001062 }
1063
David Srbecky09ed0982016-02-12 21:58:43 +00001064 uint32_t GetNumberOfLocationCatalogEntries(const CodeInfoEncoding& encoding) const {
1065 return encoding.number_of_location_catalog_entries;
Nicolas Geoffray39468442014-09-02 15:17:15 +01001066 }
1067
David Srbecky09ed0982016-02-12 21:58:43 +00001068 uint32_t GetDexRegisterLocationCatalogSize(const CodeInfoEncoding& encoding) const {
David Brazdilf677ebf2015-05-29 16:29:43 +01001069 return ComputeDexRegisterLocationCatalogSize(GetDexRegisterLocationCatalogOffset(encoding),
David Srbecky09ed0982016-02-12 21:58:43 +00001070 GetNumberOfLocationCatalogEntries(encoding));
Roland Levillaina552e1c2015-03-26 15:01:03 +00001071 }
1072
David Srbecky09ed0982016-02-12 21:58:43 +00001073 uint32_t GetNumberOfStackMaps(const CodeInfoEncoding& encoding) const {
1074 return encoding.number_of_stack_maps;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001075 }
1076
David Brazdil77a48ae2015-09-15 12:34:04 +00001077 // Get the size of all the stack maps of this CodeInfo object, in bytes.
David Srbecky09ed0982016-02-12 21:58:43 +00001078 size_t GetStackMapsSize(const CodeInfoEncoding& encoding) const {
1079 return encoding.stack_map_size_in_bytes * GetNumberOfStackMaps(encoding);
Roland Levillain29ba1b02015-03-13 11:45:07 +00001080 }
1081
David Srbecky09ed0982016-02-12 21:58:43 +00001082 uint32_t GetDexRegisterLocationCatalogOffset(const CodeInfoEncoding& encoding) const {
1083 return GetStackMapsOffset(encoding) + GetStackMapsSize(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001084 }
1085
David Srbecky09ed0982016-02-12 21:58:43 +00001086 size_t GetDexRegisterMapsOffset(const CodeInfoEncoding& encoding) const {
David Brazdilf677ebf2015-05-29 16:29:43 +01001087 return GetDexRegisterLocationCatalogOffset(encoding)
1088 + GetDexRegisterLocationCatalogSize(encoding);
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001089 }
1090
David Srbecky09ed0982016-02-12 21:58:43 +00001091 uint32_t GetStackMapsOffset(const CodeInfoEncoding& encoding) const {
1092 return encoding.header_size;
Nicolas Geoffray6530baf2015-05-26 15:22:58 +01001093 }
1094
David Brazdilf677ebf2015-05-29 16:29:43 +01001095 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
David Srbecky09ed0982016-02-12 21:58:43 +00001096 const CodeInfoEncoding& encoding,
David Brazdilf677ebf2015-05-29 16:29:43 +01001097 uint32_t number_of_dex_registers) const {
David Srbecky09ed0982016-02-12 21:58:43 +00001098 if (!stack_map.HasDexRegisterMap(encoding.stack_map_encoding)) {
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +00001099 return DexRegisterMap();
1100 } else {
1101 uint32_t offset = GetDexRegisterMapsOffset(encoding)
David Srbecky09ed0982016-02-12 21:58:43 +00001102 + stack_map.GetDexRegisterMapOffset(encoding.stack_map_encoding);
1103 size_t size = ComputeDexRegisterMapSizeOf(encoding, offset, number_of_dex_registers);
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +00001104 return DexRegisterMap(region_.Subregion(offset, size));
1105 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001106 }
1107
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001108 // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
1109 DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
1110 InlineInfo inline_info,
David Srbecky09ed0982016-02-12 21:58:43 +00001111 const CodeInfoEncoding& encoding,
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001112 uint32_t number_of_dex_registers) const {
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +00001113 if (!inline_info.HasDexRegisterMapAtDepth(depth)) {
1114 return DexRegisterMap();
1115 } else {
1116 uint32_t offset = GetDexRegisterMapsOffset(encoding)
1117 + inline_info.GetDexRegisterMapOffsetAtDepth(depth);
David Srbecky09ed0982016-02-12 21:58:43 +00001118 size_t size = ComputeDexRegisterMapSizeOf(encoding, offset, number_of_dex_registers);
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +00001119 return DexRegisterMap(region_.Subregion(offset, size));
1120 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001121 }
1122
David Srbecky09ed0982016-02-12 21:58:43 +00001123 InlineInfo GetInlineInfoOf(StackMap stack_map, const CodeInfoEncoding& encoding) const {
1124 DCHECK(stack_map.HasInlineInfo(encoding.stack_map_encoding));
1125 uint32_t offset = stack_map.GetInlineDescriptorOffset(encoding.stack_map_encoding)
David Brazdilf677ebf2015-05-29 16:29:43 +01001126 + GetDexRegisterMapsOffset(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001127 uint8_t depth = region_.LoadUnaligned<uint8_t>(offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001128 return InlineInfo(region_.Subregion(offset,
1129 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
1130 }
1131
David Srbecky09ed0982016-02-12 21:58:43 +00001132 StackMap GetStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const {
1133 for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001134 StackMap stack_map = GetStackMapAt(i, encoding);
David Srbecky09ed0982016-02-12 21:58:43 +00001135 if (stack_map.GetDexPc(encoding.stack_map_encoding) == dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001136 return stack_map;
1137 }
1138 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001139 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001140 }
1141
David Brazdil77a48ae2015-09-15 12:34:04 +00001142 // Searches the stack map list backwards because catch stack maps are stored
1143 // at the end.
David Srbecky09ed0982016-02-12 21:58:43 +00001144 StackMap GetCatchStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const {
1145 for (size_t i = GetNumberOfStackMaps(encoding); i > 0; --i) {
David Brazdil77a48ae2015-09-15 12:34:04 +00001146 StackMap stack_map = GetStackMapAt(i - 1, encoding);
David Srbecky09ed0982016-02-12 21:58:43 +00001147 if (stack_map.GetDexPc(encoding.stack_map_encoding) == dex_pc) {
David Brazdil77a48ae2015-09-15 12:34:04 +00001148 return stack_map;
1149 }
1150 }
1151 return StackMap();
1152 }
1153
David Srbecky09ed0982016-02-12 21:58:43 +00001154 StackMap GetOsrStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const {
1155 size_t e = GetNumberOfStackMaps(encoding);
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001156 if (e == 0) {
1157 // There cannot be OSR stack map if there is no stack map.
1158 return StackMap();
1159 }
1160 // Walk over all stack maps. If two consecutive stack maps are identical, then we
1161 // have found a stack map suitable for OSR.
David Srbecky09ed0982016-02-12 21:58:43 +00001162 const StackMapEncoding& stack_map_encoding = encoding.stack_map_encoding;
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001163 for (size_t i = 0; i < e - 1; ++i) {
1164 StackMap stack_map = GetStackMapAt(i, encoding);
David Srbecky09ed0982016-02-12 21:58:43 +00001165 if (stack_map.GetDexPc(stack_map_encoding) == dex_pc) {
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001166 StackMap other = GetStackMapAt(i + 1, encoding);
David Srbecky09ed0982016-02-12 21:58:43 +00001167 if (other.GetDexPc(stack_map_encoding) == dex_pc &&
1168 other.GetNativePcOffset(stack_map_encoding) ==
1169 stack_map.GetNativePcOffset(stack_map_encoding)) {
1170 DCHECK_EQ(other.GetDexRegisterMapOffset(stack_map_encoding),
1171 stack_map.GetDexRegisterMapOffset(stack_map_encoding));
1172 DCHECK(!stack_map.HasInlineInfo(stack_map_encoding));
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001173 if (i < e - 2) {
1174 // Make sure there are not three identical stack maps following each other.
David Srbecky09ed0982016-02-12 21:58:43 +00001175 DCHECK_NE(stack_map.GetNativePcOffset(stack_map_encoding),
1176 GetStackMapAt(i + 2, encoding).GetNativePcOffset(stack_map_encoding));
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001177 }
1178 return stack_map;
1179 }
1180 }
1181 }
1182 return StackMap();
1183 }
1184
David Brazdilf677ebf2015-05-29 16:29:43 +01001185 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset,
David Srbecky09ed0982016-02-12 21:58:43 +00001186 const CodeInfoEncoding& encoding) const {
David Brazdil77a48ae2015-09-15 12:34:04 +00001187 // TODO: Safepoint stack maps are sorted by native_pc_offset but catch stack
1188 // maps are not. If we knew that the method does not have try/catch,
1189 // we could do binary search.
David Srbecky09ed0982016-02-12 21:58:43 +00001190 for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001191 StackMap stack_map = GetStackMapAt(i, encoding);
David Srbecky09ed0982016-02-12 21:58:43 +00001192 if (stack_map.GetNativePcOffset(encoding.stack_map_encoding) == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001193 return stack_map;
1194 }
1195 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001196 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001197 }
1198
Roland Levillainf2650d12015-05-28 14:53:28 +01001199 // Dump this CodeInfo object on `os`. `code_offset` is the (absolute)
1200 // native PC of the compiled method and `number_of_dex_registers` the
1201 // number of Dex virtual registers used in this method. If
1202 // `dump_stack_maps` is true, also dump the stack maps and the
1203 // associated Dex register maps.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001204 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +01001205 uint32_t code_offset,
1206 uint16_t number_of_dex_registers,
1207 bool dump_stack_maps) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001208
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001209 private:
David Srbecky09ed0982016-02-12 21:58:43 +00001210 MemoryRegion GetStackMaps(const CodeInfoEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001211 return region_.size() == 0
1212 ? MemoryRegion()
David Srbecky09ed0982016-02-12 21:58:43 +00001213 : region_.Subregion(GetStackMapsOffset(encoding), GetStackMapsSize(encoding));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001214 }
1215
Roland Levillaina552e1c2015-03-26 15:01:03 +00001216 // Compute the size of the Dex register map associated to the stack map at
1217 // `dex_register_map_offset_in_code_info`.
David Srbecky09ed0982016-02-12 21:58:43 +00001218 size_t ComputeDexRegisterMapSizeOf(const CodeInfoEncoding& encoding,
1219 uint32_t dex_register_map_offset_in_code_info,
Roland Levillaina552e1c2015-03-26 15:01:03 +00001220 uint16_t number_of_dex_registers) const {
1221 // Offset where the actual mapping data starts within art::DexRegisterMap.
1222 size_t location_mapping_data_offset_in_dex_register_map =
1223 DexRegisterMap::GetLocationMappingDataOffset(number_of_dex_registers);
1224 // Create a temporary art::DexRegisterMap to be able to call
1225 // art::DexRegisterMap::GetNumberOfLiveDexRegisters and
1226 DexRegisterMap dex_register_map_without_locations(
1227 MemoryRegion(region_.Subregion(dex_register_map_offset_in_code_info,
1228 location_mapping_data_offset_in_dex_register_map)));
1229 size_t number_of_live_dex_registers =
1230 dex_register_map_without_locations.GetNumberOfLiveDexRegisters(number_of_dex_registers);
1231 size_t location_mapping_data_size_in_bits =
David Srbecky09ed0982016-02-12 21:58:43 +00001232 DexRegisterMap::SingleEntrySizeInBits(GetNumberOfLocationCatalogEntries(encoding))
Roland Levillaina552e1c2015-03-26 15:01:03 +00001233 * number_of_live_dex_registers;
1234 size_t location_mapping_data_size_in_bytes =
1235 RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
1236 size_t dex_register_map_size =
1237 location_mapping_data_offset_in_dex_register_map + location_mapping_data_size_in_bytes;
1238 return dex_register_map_size;
1239 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001240
Roland Levillaina552e1c2015-03-26 15:01:03 +00001241 // Compute the size of a Dex register location catalog starting at offset `origin`
1242 // in `region_` and containing `number_of_dex_locations` entries.
1243 size_t ComputeDexRegisterLocationCatalogSize(uint32_t origin,
1244 uint32_t number_of_dex_locations) const {
1245 // TODO: Ideally, we would like to use art::DexRegisterLocationCatalog::Size or
1246 // art::DexRegisterLocationCatalog::FindLocationOffset, but the
1247 // DexRegisterLocationCatalog is not yet built. Try to factor common code.
1248 size_t offset = origin + DexRegisterLocationCatalog::kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001249
Roland Levillaina552e1c2015-03-26 15:01:03 +00001250 // Skip the first `number_of_dex_locations - 1` entries.
1251 for (uint16_t i = 0; i < number_of_dex_locations; ++i) {
1252 // Read the first next byte and inspect its first 3 bits to decide
1253 // whether it is a short or a large location.
1254 DexRegisterLocationCatalog::ShortLocation first_byte =
1255 region_.LoadUnaligned<DexRegisterLocationCatalog::ShortLocation>(offset);
1256 DexRegisterLocation::Kind kind =
1257 DexRegisterLocationCatalog::ExtractKindFromShortLocation(first_byte);
1258 if (DexRegisterLocation::IsShortLocationKind(kind)) {
1259 // Short location. Skip the current byte.
1260 offset += DexRegisterLocationCatalog::SingleShortEntrySize();
1261 } else {
1262 // Large location. Skip the 5 next bytes.
1263 offset += DexRegisterLocationCatalog::SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001264 }
1265 }
1266 size_t size = offset - origin;
1267 return size;
1268 }
1269
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001270 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +01001271 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001272};
1273
Roland Levillain1c1da432015-07-16 11:54:44 +01001274#undef ELEMENT_BYTE_OFFSET_AFTER
1275#undef ELEMENT_BIT_OFFSET_AFTER
1276
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001277} // namespace art
1278
1279#endif // ART_RUNTIME_STACK_MAP_H_