blob: 4647d676999a24613585fe661ab28f2cc65bcde7 [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"
Vladimir Marko87f3fcb2016-04-28 15:52:11 +010022#include "dex_file.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010023#include "memory_region.h"
David Srbecky09ed0982016-02-12 21:58:43 +000024#include "leb128.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010025
26namespace art {
27
Vladimir Marko8f1e08a2015-06-26 12:06:30 +010028class VariableIndentationOutputStream;
29
Roland Levillaina2d8ec62015-03-12 15:25:29 +000030// Size of a frame slot, in bytes. This constant is a signed value,
31// to please the compiler in arithmetic operations involving int32_t
32// (signed) values.
Roland Levillaina552e1c2015-03-26 15:01:03 +000033static constexpr ssize_t kFrameSlotSize = 4;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000034
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000035// Size of Dex virtual registers.
Roland Levillaina552e1c2015-03-26 15:01:03 +000036static constexpr size_t kVRegSize = 4;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000037
Nicolas Geoffray004c2302015-03-20 10:06:38 +000038class CodeInfo;
David Brazdilf677ebf2015-05-29 16:29:43 +010039class StackMapEncoding;
David Srbecky09ed0982016-02-12 21:58:43 +000040struct CodeInfoEncoding;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000041
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010042/**
43 * Classes in the following file are wrapper on stack map information backed
44 * by a MemoryRegion. As such they read and write to the region, they don't have
45 * their own fields.
46 */
47
Roland Levillaina2d8ec62015-03-12 15:25:29 +000048// Dex register location container used by DexRegisterMap and StackMapStream.
49class DexRegisterLocation {
50 public:
51 /*
52 * The location kind used to populate the Dex register information in a
53 * StackMapStream can either be:
David Brazdild9cb68e2015-08-25 13:52:43 +010054 * - kStack: vreg stored on the stack, value holds the stack offset;
55 * - kInRegister: vreg stored in low 32 bits of a core physical register,
56 * value holds the register number;
57 * - kInRegisterHigh: vreg stored in high 32 bits of a core physical register,
58 * value holds the register number;
59 * - kInFpuRegister: vreg stored in low 32 bits of an FPU register,
60 * value holds the register number;
61 * - kInFpuRegisterHigh: vreg stored in high 32 bits of an FPU register,
62 * value holds the register number;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000063 * - kConstant: value holds the constant;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000064 *
65 * In addition, DexRegisterMap also uses these values:
66 * - kInStackLargeOffset: value holds a "large" stack offset (greater than
Roland Levillaina552e1c2015-03-26 15:01:03 +000067 * or equal to 128 bytes);
68 * - kConstantLargeValue: value holds a "large" constant (lower than 0, or
David Brazdild9cb68e2015-08-25 13:52:43 +010069 * or greater than or equal to 32);
70 * - kNone: the register has no location, meaning it has not been set.
Roland Levillaina2d8ec62015-03-12 15:25:29 +000071 */
72 enum class Kind : uint8_t {
73 // Short location kinds, for entries fitting on one byte (3 bits
74 // for the kind, 5 bits for the value) in a DexRegisterMap.
David Brazdild9cb68e2015-08-25 13:52:43 +010075 kInStack = 0, // 0b000
76 kInRegister = 1, // 0b001
77 kInRegisterHigh = 2, // 0b010
Roland Levillaina2d8ec62015-03-12 15:25:29 +000078 kInFpuRegister = 3, // 0b011
David Brazdild9cb68e2015-08-25 13:52:43 +010079 kInFpuRegisterHigh = 4, // 0b100
80 kConstant = 5, // 0b101
Roland Levillaina2d8ec62015-03-12 15:25:29 +000081
82 // Large location kinds, requiring a 5-byte encoding (1 byte for the
83 // kind, 4 bytes for the value).
84
85 // Stack location at a large offset, meaning that the offset value
86 // divided by the stack frame slot size (4 bytes) cannot fit on a
87 // 5-bit unsigned integer (i.e., this offset value is greater than
88 // or equal to 2^5 * 4 = 128 bytes).
David Brazdild9cb68e2015-08-25 13:52:43 +010089 kInStackLargeOffset = 6, // 0b110
Roland Levillaina2d8ec62015-03-12 15:25:29 +000090
91 // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
Roland Levillaina552e1c2015-03-26 15:01:03 +000092 // lower than 0, or greater than or equal to 2^5 = 32).
David Brazdild9cb68e2015-08-25 13:52:43 +010093 kConstantLargeValue = 7, // 0b111
94
95 // Entries with no location are not stored and do not need own marker.
96 kNone = static_cast<uint8_t>(-1),
Roland Levillaina2d8ec62015-03-12 15:25:29 +000097
98 kLastLocationKind = kConstantLargeValue
99 };
100
101 static_assert(
102 sizeof(Kind) == 1u,
103 "art::DexRegisterLocation::Kind has a size different from one byte.");
104
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000105 static bool IsShortLocationKind(Kind kind) {
106 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000107 case Kind::kInStack:
108 case Kind::kInRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100109 case Kind::kInRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000110 case Kind::kInFpuRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100111 case Kind::kInFpuRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000112 case Kind::kConstant:
113 return true;
114
115 case Kind::kInStackLargeOffset:
116 case Kind::kConstantLargeValue:
117 return false;
118
David Brazdild9cb68e2015-08-25 13:52:43 +0100119 case Kind::kNone:
David Srbecky7dc11782016-02-25 13:23:56 +0000120 LOG(FATAL) << "Unexpected location kind";
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000121 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100122 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000123 }
124
125 // Convert `kind` to a "surface" kind, i.e. one that doesn't include
126 // any value with a "large" qualifier.
127 // TODO: Introduce another enum type for the surface kind?
128 static Kind ConvertToSurfaceKind(Kind kind) {
129 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000130 case Kind::kInStack:
131 case Kind::kInRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100132 case Kind::kInRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000133 case Kind::kInFpuRegister:
David Brazdild9cb68e2015-08-25 13:52:43 +0100134 case Kind::kInFpuRegisterHigh:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000135 case Kind::kConstant:
136 return kind;
137
138 case Kind::kInStackLargeOffset:
139 return Kind::kInStack;
140
141 case Kind::kConstantLargeValue:
142 return Kind::kConstant;
143
David Brazdild9cb68e2015-08-25 13:52:43 +0100144 case Kind::kNone:
145 return kind;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000146 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100147 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000148 }
149
Roland Levillaina552e1c2015-03-26 15:01:03 +0000150 // Required by art::StackMapStream::LocationCatalogEntriesIndices.
151 DexRegisterLocation() : kind_(Kind::kNone), value_(0) {}
152
153 DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {}
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000154
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000155 static DexRegisterLocation None() {
156 return DexRegisterLocation(Kind::kNone, 0);
157 }
158
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000159 // Get the "surface" kind of the location, i.e., the one that doesn't
160 // include any value with a "large" qualifier.
161 Kind GetKind() const {
162 return ConvertToSurfaceKind(kind_);
163 }
164
165 // Get the value of the location.
166 int32_t GetValue() const { return value_; }
167
168 // Get the actual kind of the location.
169 Kind GetInternalKind() const { return kind_; }
170
Calin Juravle6ae70962015-03-18 16:31:28 +0000171 bool operator==(DexRegisterLocation other) const {
172 return kind_ == other.kind_ && value_ == other.value_;
173 }
174
175 bool operator!=(DexRegisterLocation other) const {
176 return !(*this == other);
177 }
178
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000179 private:
180 Kind kind_;
181 int32_t value_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000182
183 friend class DexRegisterLocationHashFn;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000184};
185
David Srbecky7dc11782016-02-25 13:23:56 +0000186std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind);
187
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100188/**
Roland Levillaina552e1c2015-03-26 15:01:03 +0000189 * Store information on unique Dex register locations used in a method.
190 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100191 *
192 * [DexRegisterLocation+].
193 *
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000194 * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100195 */
Roland Levillaina552e1c2015-03-26 15:01:03 +0000196class DexRegisterLocationCatalog {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100197 public:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000198 explicit DexRegisterLocationCatalog(MemoryRegion region) : region_(region) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100199
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000200 // Short (compressed) location, fitting on one byte.
201 typedef uint8_t ShortLocation;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100202
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000203 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
204 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
205 int32_t value = dex_register_location.GetValue();
206 if (DexRegisterLocation::IsShortLocationKind(kind)) {
207 // Short location. Compress the kind and the value as a single byte.
208 if (kind == DexRegisterLocation::Kind::kInStack) {
209 // Instead of storing stack offsets expressed in bytes for
210 // short stack locations, store slot offsets. A stack offset
211 // is a multiple of 4 (kFrameSlotSize). This means that by
212 // dividing it by 4, we can fit values from the [0, 128)
213 // interval in a short stack location, and not just values
214 // from the [0, 32) interval.
215 DCHECK_EQ(value % kFrameSlotSize, 0);
216 value /= kFrameSlotSize;
217 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000218 DCHECK(IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000219 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
220 } else {
221 // Large location. Write the location on one byte and the value
222 // on 4 bytes.
Roland Levillaina552e1c2015-03-26 15:01:03 +0000223 DCHECK(!IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000224 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
225 // Also divide large stack offsets by 4 for the sake of consistency.
226 DCHECK_EQ(value % kFrameSlotSize, 0);
227 value /= kFrameSlotSize;
228 }
229 // Data can be unaligned as the written Dex register locations can
230 // either be 1-byte or 5-byte wide. Use
231 // art::MemoryRegion::StoreUnaligned instead of
232 // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
233 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
234 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
Roland Levillain442b46a2015-02-18 16:54:21 +0000235 }
236 }
237
Roland Levillaina552e1c2015-03-26 15:01:03 +0000238 // Find the offset of the location catalog entry number `location_catalog_entry_index`.
239 size_t FindLocationOffset(size_t location_catalog_entry_index) const {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000240 size_t offset = kFixedSize;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000241 // Skip the first `location_catalog_entry_index - 1` entries.
242 for (uint16_t i = 0; i < location_catalog_entry_index; ++i) {
243 // Read the first next byte and inspect its first 3 bits to decide
244 // whether it is a short or a large location.
245 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
246 if (DexRegisterLocation::IsShortLocationKind(kind)) {
247 // Short location. Skip the current byte.
248 offset += SingleShortEntrySize();
249 } else {
250 // Large location. Skip the 5 next bytes.
251 offset += SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000252 }
253 }
254 return offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100255 }
256
Roland Levillaina552e1c2015-03-26 15:01:03 +0000257 // Get the internal kind of entry at `location_catalog_entry_index`.
258 DexRegisterLocation::Kind GetLocationInternalKind(size_t location_catalog_entry_index) const {
259 if (location_catalog_entry_index == kNoLocationEntryIndex) {
260 return DexRegisterLocation::Kind::kNone;
261 }
262 return ExtractKindAtOffset(FindLocationOffset(location_catalog_entry_index));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100263 }
264
Roland Levillaina552e1c2015-03-26 15:01:03 +0000265 // Get the (surface) kind and value of entry at `location_catalog_entry_index`.
266 DexRegisterLocation GetDexRegisterLocation(size_t location_catalog_entry_index) const {
267 if (location_catalog_entry_index == kNoLocationEntryIndex) {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000268 return DexRegisterLocation::None();
269 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000270 size_t offset = FindLocationOffset(location_catalog_entry_index);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000271 // Read the first byte and inspect its first 3 bits to get the location.
272 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
273 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
274 if (DexRegisterLocation::IsShortLocationKind(kind)) {
275 // Short location. Extract the value from the remaining 5 bits.
276 int32_t value = ExtractValueFromShortLocation(first_byte);
277 if (kind == DexRegisterLocation::Kind::kInStack) {
278 // Convert the stack slot (short) offset to a byte offset value.
279 value *= kFrameSlotSize;
280 }
281 return DexRegisterLocation(kind, value);
282 } else {
283 // Large location. Read the four next bytes to get the value.
284 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
285 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
286 // Convert the stack slot (large) offset to a byte offset value.
287 value *= kFrameSlotSize;
288 }
289 return DexRegisterLocation(kind, value);
290 }
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100291 }
292
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000293 // Compute the compressed kind of `location`.
294 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
David Brazdild9cb68e2015-08-25 13:52:43 +0100295 DexRegisterLocation::Kind kind = location.GetInternalKind();
296 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000297 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000298 return IsShortStackOffsetValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000299 ? DexRegisterLocation::Kind::kInStack
300 : DexRegisterLocation::Kind::kInStackLargeOffset;
301
David Brazdild9cb68e2015-08-25 13:52:43 +0100302 case DexRegisterLocation::Kind::kInRegister:
303 case DexRegisterLocation::Kind::kInRegisterHigh:
304 DCHECK_GE(location.GetValue(), 0);
305 DCHECK_LT(location.GetValue(), 1 << kValueBits);
306 return kind;
307
308 case DexRegisterLocation::Kind::kInFpuRegister:
309 case DexRegisterLocation::Kind::kInFpuRegisterHigh:
310 DCHECK_GE(location.GetValue(), 0);
311 DCHECK_LT(location.GetValue(), 1 << kValueBits);
312 return kind;
313
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000314 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000315 return IsShortConstantValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000316 ? DexRegisterLocation::Kind::kConstant
317 : DexRegisterLocation::Kind::kConstantLargeValue;
318
David Brazdild9cb68e2015-08-25 13:52:43 +0100319 case DexRegisterLocation::Kind::kConstantLargeValue:
320 case DexRegisterLocation::Kind::kInStackLargeOffset:
321 case DexRegisterLocation::Kind::kNone:
David Srbecky7dc11782016-02-25 13:23:56 +0000322 LOG(FATAL) << "Unexpected location kind " << kind;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000323 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100324 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000325 }
326
327 // Can `location` be turned into a short location?
328 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
David Brazdild9cb68e2015-08-25 13:52:43 +0100329 DexRegisterLocation::Kind kind = location.GetInternalKind();
330 switch (kind) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000331 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000332 return IsShortStackOffsetValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000333
David Brazdild9cb68e2015-08-25 13:52:43 +0100334 case DexRegisterLocation::Kind::kInRegister:
335 case DexRegisterLocation::Kind::kInRegisterHigh:
336 case DexRegisterLocation::Kind::kInFpuRegister:
337 case DexRegisterLocation::Kind::kInFpuRegisterHigh:
338 return true;
339
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000340 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000341 return IsShortConstantValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000342
David Brazdild9cb68e2015-08-25 13:52:43 +0100343 case DexRegisterLocation::Kind::kConstantLargeValue:
344 case DexRegisterLocation::Kind::kInStackLargeOffset:
345 case DexRegisterLocation::Kind::kNone:
David Srbecky7dc11782016-02-25 13:23:56 +0000346 LOG(FATAL) << "Unexpected location kind " << kind;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000347 }
David Brazdild9cb68e2015-08-25 13:52:43 +0100348 UNREACHABLE();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000349 }
350
351 static size_t EntrySize(const DexRegisterLocation& location) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000352 return CanBeEncodedAsShortLocation(location) ? SingleShortEntrySize() : SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000353 }
354
355 static size_t SingleShortEntrySize() {
356 return sizeof(ShortLocation);
357 }
358
359 static size_t SingleLargeEntrySize() {
360 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100361 }
362
Roland Levillain12baf472015-03-05 12:41:42 +0000363 size_t Size() const {
364 return region_.size();
365 }
366
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100367 void Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info);
Roland Levillain0396ed72015-05-27 15:12:19 +0100368
Roland Levillaina552e1c2015-03-26 15:01:03 +0000369 // Special (invalid) Dex register location catalog entry index meaning
370 // that there is no location for a given Dex register (i.e., it is
371 // mapped to a DexRegisterLocation::Kind::kNone location).
372 static constexpr size_t kNoLocationEntryIndex = -1;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100373
Roland Levillain12baf472015-03-05 12:41:42 +0000374 private:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000375 static constexpr int kFixedSize = 0;
376
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000377 // Width of the kind "field" in a short location, in bits.
378 static constexpr size_t kKindBits = 3;
379 // Width of the value "field" in a short location, in bits.
380 static constexpr size_t kValueBits = 5;
381
382 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
383 static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
384 static constexpr size_t kKindOffset = 0;
385 static constexpr size_t kValueOffset = kKindBits;
386
Roland Levillaina552e1c2015-03-26 15:01:03 +0000387 static bool IsShortStackOffsetValue(int32_t value) {
388 DCHECK_EQ(value % kFrameSlotSize, 0);
389 return IsShortValue(value / kFrameSlotSize);
390 }
391
392 static bool IsShortConstantValue(int32_t value) {
393 return IsShortValue(value);
394 }
395
396 static bool IsShortValue(int32_t value) {
397 return IsUint<kValueBits>(value);
398 }
399
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000400 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000401 uint8_t kind_integer_value = static_cast<uint8_t>(kind);
402 DCHECK(IsUint<kKindBits>(kind_integer_value)) << kind_integer_value;
403 DCHECK(IsShortValue(value)) << value;
404 return (kind_integer_value & kKindMask) << kKindOffset
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000405 | (value & kValueMask) << kValueOffset;
406 }
407
408 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
409 uint8_t kind = (location >> kKindOffset) & kKindMask;
410 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000411 // We do not encode kNone locations in the stack map.
412 DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone));
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000413 return static_cast<DexRegisterLocation::Kind>(kind);
414 }
415
416 static int32_t ExtractValueFromShortLocation(ShortLocation location) {
417 return (location >> kValueOffset) & kValueMask;
418 }
419
420 // Extract a location kind from the byte at position `offset`.
421 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
422 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
423 return ExtractKindFromShortLocation(first_byte);
424 }
425
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100426 MemoryRegion region_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000427
428 friend class CodeInfo;
429 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100430};
431
Roland Levillaina552e1c2015-03-26 15:01:03 +0000432/* Information on Dex register locations for a specific PC, mapping a
433 * stack map's Dex register to a location entry in a DexRegisterLocationCatalog.
434 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100435 *
436 * [live_bit_mask, entries*]
437 *
Roland Levillaina552e1c2015-03-26 15:01:03 +0000438 * where entries are concatenated unsigned integer values encoded on a number
439 * of bits (fixed per DexRegisterMap instances of a CodeInfo object) depending
440 * on the number of entries in the Dex register location catalog
441 * (see DexRegisterMap::SingleEntrySizeInBits). The map is 1-byte aligned.
442 */
443class DexRegisterMap {
444 public:
445 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +0000446 DexRegisterMap() {}
447
448 bool IsValid() const { return region_.pointer() != nullptr; }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000449
450 // Get the surface kind of Dex register `dex_register_number`.
451 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number,
452 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100453 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000454 const CodeInfoEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000455 return DexRegisterLocation::ConvertToSurfaceKind(
David Brazdilf677ebf2015-05-29 16:29:43 +0100456 GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info, enc));
Roland Levillaina552e1c2015-03-26 15:01:03 +0000457 }
458
459 // Get the internal kind of Dex register `dex_register_number`.
460 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number,
461 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100462 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000463 const CodeInfoEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000464
465 // Get the Dex register location `dex_register_number`.
466 DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number,
467 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100468 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000469 const CodeInfoEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000470
471 int32_t GetStackOffsetInBytes(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 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100476 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000477 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
478 // GetDexRegisterLocation returns the offset in bytes.
479 return location.GetValue();
480 }
481
482 int32_t GetConstant(uint16_t dex_register_number,
483 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100484 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000485 const CodeInfoEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000486 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100487 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
David Srbecky7dc11782016-02-25 13:23:56 +0000488 DCHECK_EQ(location.GetKind(), DexRegisterLocation::Kind::kConstant);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000489 return location.GetValue();
490 }
491
492 int32_t GetMachineRegister(uint16_t dex_register_number,
493 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100494 const CodeInfo& code_info,
David Srbecky09ed0982016-02-12 21:58:43 +0000495 const CodeInfoEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000496 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100497 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
David Brazdild9cb68e2015-08-25 13:52:43 +0100498 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister ||
499 location.GetInternalKind() == DexRegisterLocation::Kind::kInRegisterHigh ||
500 location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister ||
501 location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh)
David Srbecky7dc11782016-02-25 13:23:56 +0000502 << location.GetInternalKind();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000503 return location.GetValue();
504 }
505
506 // Get the index of the entry in the Dex register location catalog
507 // corresponding to `dex_register_number`.
508 size_t GetLocationCatalogEntryIndex(uint16_t dex_register_number,
509 uint16_t number_of_dex_registers,
510 size_t number_of_location_catalog_entries) const {
511 if (!IsDexRegisterLive(dex_register_number)) {
512 return DexRegisterLocationCatalog::kNoLocationEntryIndex;
513 }
514
515 if (number_of_location_catalog_entries == 1) {
516 // We do not allocate space for location maps in the case of a
517 // single-entry location catalog, as it is useless. The only valid
518 // entry index is 0;
519 return 0;
520 }
521
522 // The bit offset of the beginning of the map locations.
523 size_t map_locations_offset_in_bits =
524 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
525 size_t index_in_dex_register_map = GetIndexInDexRegisterMap(dex_register_number);
526 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
527 // The bit size of an entry.
528 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
529 // The bit offset where `index_in_dex_register_map` is located.
530 size_t entry_offset_in_bits =
531 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
532 size_t location_catalog_entry_index =
533 region_.LoadBits(entry_offset_in_bits, map_entry_size_in_bits);
534 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
535 return location_catalog_entry_index;
536 }
537
538 // Map entry at `index_in_dex_register_map` to `location_catalog_entry_index`.
539 void SetLocationCatalogEntryIndex(size_t index_in_dex_register_map,
540 size_t location_catalog_entry_index,
541 uint16_t number_of_dex_registers,
542 size_t number_of_location_catalog_entries) {
543 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
544 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
545
546 if (number_of_location_catalog_entries == 1) {
547 // We do not allocate space for location maps in the case of a
548 // single-entry location catalog, as it is useless.
549 return;
550 }
551
552 // The bit offset of the beginning of the map locations.
553 size_t map_locations_offset_in_bits =
554 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
555 // The bit size of an entry.
556 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
557 // The bit offset where `index_in_dex_register_map` is located.
558 size_t entry_offset_in_bits =
559 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
560 region_.StoreBits(entry_offset_in_bits, location_catalog_entry_index, map_entry_size_in_bits);
561 }
562
563 void SetLiveBitMask(uint16_t number_of_dex_registers,
564 const BitVector& live_dex_registers_mask) {
565 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
566 for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
567 region_.StoreBit(live_bit_mask_offset_in_bits + i, live_dex_registers_mask.IsBitSet(i));
568 }
569 }
570
571 bool IsDexRegisterLive(uint16_t dex_register_number) const {
572 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
573 return region_.LoadBit(live_bit_mask_offset_in_bits + dex_register_number);
574 }
575
576 size_t GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers) const {
577 size_t number_of_live_dex_registers = 0;
578 for (size_t i = 0; i < number_of_dex_registers; ++i) {
579 if (IsDexRegisterLive(i)) {
580 ++number_of_live_dex_registers;
581 }
582 }
583 return number_of_live_dex_registers;
584 }
585
586 static size_t GetLiveBitMaskOffset() {
587 return kFixedSize;
588 }
589
590 // Compute the size of the live register bit mask (in bytes), for a
591 // method having `number_of_dex_registers` Dex registers.
592 static size_t GetLiveBitMaskSize(uint16_t number_of_dex_registers) {
593 return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte;
594 }
595
596 static size_t GetLocationMappingDataOffset(uint16_t number_of_dex_registers) {
597 return GetLiveBitMaskOffset() + GetLiveBitMaskSize(number_of_dex_registers);
598 }
599
600 size_t GetLocationMappingDataSize(uint16_t number_of_dex_registers,
601 size_t number_of_location_catalog_entries) const {
602 size_t location_mapping_data_size_in_bits =
603 GetNumberOfLiveDexRegisters(number_of_dex_registers)
604 * SingleEntrySizeInBits(number_of_location_catalog_entries);
605 return RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
606 }
607
608 // Return the size of a map entry in bits. Note that if
609 // `number_of_location_catalog_entries` equals 1, this function returns 0,
610 // which is fine, as there is no need to allocate a map for a
611 // single-entry location catalog; the only valid location catalog entry index
612 // for a live register in this case is 0 and there is no need to
613 // store it.
614 static size_t SingleEntrySizeInBits(size_t number_of_location_catalog_entries) {
615 // Handle the case of 0, as we cannot pass 0 to art::WhichPowerOf2.
616 return number_of_location_catalog_entries == 0
617 ? 0u
618 : WhichPowerOf2(RoundUpToPowerOfTwo(number_of_location_catalog_entries));
619 }
620
621 // Return the size of the DexRegisterMap object, in bytes.
622 size_t Size() const {
623 return region_.size();
624 }
625
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100626 void Dump(VariableIndentationOutputStream* vios,
627 const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100628
Roland Levillaina552e1c2015-03-26 15:01:03 +0000629 private:
630 // Return the index in the Dex register map corresponding to the Dex
631 // register number `dex_register_number`.
632 size_t GetIndexInDexRegisterMap(uint16_t dex_register_number) const {
633 if (!IsDexRegisterLive(dex_register_number)) {
634 return kInvalidIndexInDexRegisterMap;
635 }
636 return GetNumberOfLiveDexRegisters(dex_register_number);
637 }
638
639 // Special (invalid) Dex register map entry index meaning that there
640 // is no index in the map for a given Dex register (i.e., it must
641 // have been mapped to a DexRegisterLocation::Kind::kNone location).
642 static constexpr size_t kInvalidIndexInDexRegisterMap = -1;
643
644 static constexpr int kFixedSize = 0;
645
646 MemoryRegion region_;
647
648 friend class CodeInfo;
649 friend class StackMapStream;
650};
651
David Srbecky09ed0982016-02-12 21:58:43 +0000652// Represents bit range of bit-packed integer field.
653// We reuse the idea from ULEB128p1 to support encoding of -1 (aka 0xFFFFFFFF).
654// If min_value is set to -1, we implicitly subtract one from any loaded value,
655// and add one to any stored value. This is generalized to any negative values.
656// In other words, min_value acts as a base and the stored value is added to it.
657struct FieldEncoding {
658 FieldEncoding(size_t start_offset, size_t end_offset, int32_t min_value = 0)
659 : start_offset_(start_offset), end_offset_(end_offset), min_value_(min_value) {
660 DCHECK_LE(start_offset_, end_offset_);
661 DCHECK_LE(BitSize(), 32u);
662 }
663
664 ALWAYS_INLINE size_t BitSize() const { return end_offset_ - start_offset_; }
665
666 ALWAYS_INLINE int32_t Load(const MemoryRegion& region) const {
667 DCHECK_LE(end_offset_, region.size_in_bits());
668 const size_t bit_count = BitSize();
669 if (bit_count == 0) {
670 // Do not touch any memory if the range is empty.
671 return min_value_;
672 }
673 uint8_t* address = region.start() + start_offset_ / kBitsPerByte;
674 const uint32_t shift = start_offset_ & (kBitsPerByte - 1);
675 // Load the value (reading only the strictly needed bytes).
676 const uint32_t load_bit_count = shift + bit_count;
677 uint32_t value = *address++ >> shift;
678 if (load_bit_count > 8) {
679 value |= static_cast<uint32_t>(*address++) << (8 - shift);
680 if (load_bit_count > 16) {
681 value |= static_cast<uint32_t>(*address++) << (16 - shift);
682 if (load_bit_count > 24) {
683 value |= static_cast<uint32_t>(*address++) << (24 - shift);
684 if (load_bit_count > 32) {
685 value |= static_cast<uint32_t>(*address++) << (32 - shift);
686 }
687 }
688 }
689 }
690 // Clear unwanted most significant bits.
691 uint32_t clear_bit_count = 32 - bit_count;
692 value = (value << clear_bit_count) >> clear_bit_count;
693 return value + min_value_;
694 }
695
696 ALWAYS_INLINE void Store(MemoryRegion region, int32_t value) const {
697 region.StoreBits(start_offset_, value - min_value_, BitSize());
698 DCHECK_EQ(Load(region), value);
699 }
700
701 private:
702 size_t start_offset_;
703 size_t end_offset_;
704 int32_t min_value_;
705};
706
David Brazdilf677ebf2015-05-29 16:29:43 +0100707class StackMapEncoding {
708 public:
709 StackMapEncoding() {}
710
David Srbecky09ed0982016-02-12 21:58:43 +0000711 // Set stack map bit layout based on given sizes.
712 // Returns the size of stack map in bytes.
713 size_t SetFromSizes(size_t native_pc_max,
714 size_t dex_pc_max,
715 size_t dex_register_map_size,
716 size_t inline_info_size,
717 size_t register_mask_max,
718 size_t stack_mask_bit_size) {
719 size_t bit_offset = 0;
720 DCHECK_EQ(kNativePcBitOffset, bit_offset);
721 bit_offset += MinimumBitsToStore(native_pc_max);
David Brazdilf677ebf2015-05-29 16:29:43 +0100722
David Srbecky09ed0982016-02-12 21:58:43 +0000723 dex_pc_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
724 bit_offset += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max);
725
726 // We also need +1 for kNoDexRegisterMap, but since the size is strictly
727 // greater than any offset we might try to encode, we already implicitly have it.
728 dex_register_map_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
729 bit_offset += MinimumBitsToStore(dex_register_map_size);
730
731 // We also need +1 for kNoInlineInfo, but since the inline_info_size is strictly
732 // greater than the offset we might try to encode, we already implicitly have it.
733 // If inline_info_size is zero, we can encode only kNoInlineInfo (in zero bits).
734 inline_info_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
735 if (inline_info_size != 0) {
736 bit_offset += MinimumBitsToStore(dex_register_map_size + inline_info_size);
737 }
738
739 register_mask_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
740 bit_offset += MinimumBitsToStore(register_mask_max);
741
742 stack_mask_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
743 bit_offset += stack_mask_bit_size;
744
745 return RoundUp(bit_offset, kBitsPerByte) / kBitsPerByte;
David Brazdilf677ebf2015-05-29 16:29:43 +0100746 }
747
David Srbecky09ed0982016-02-12 21:58:43 +0000748 ALWAYS_INLINE FieldEncoding GetNativePcEncoding() const {
749 return FieldEncoding(kNativePcBitOffset, dex_pc_bit_offset_);
750 }
751 ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const {
752 return FieldEncoding(dex_pc_bit_offset_, dex_register_map_bit_offset_, -1 /* min_value */);
753 }
754 ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const {
755 return FieldEncoding(dex_register_map_bit_offset_, inline_info_bit_offset_, -1 /* min_value */);
756 }
757 ALWAYS_INLINE FieldEncoding GetInlineInfoEncoding() const {
758 return FieldEncoding(inline_info_bit_offset_, register_mask_bit_offset_, -1 /* min_value */);
759 }
760 ALWAYS_INLINE FieldEncoding GetRegisterMaskEncoding() const {
761 return FieldEncoding(register_mask_bit_offset_, stack_mask_bit_offset_);
762 }
763 ALWAYS_INLINE size_t GetStackMaskBitOffset() const {
764 // The end offset is not encoded. It is implicitly the end of stack map entry.
765 return stack_mask_bit_offset_;
David Brazdilf677ebf2015-05-29 16:29:43 +0100766 }
767
David Srbecky09ed0982016-02-12 21:58:43 +0000768 void Dump(VariableIndentationOutputStream* vios) const;
David Brazdilf677ebf2015-05-29 16:29:43 +0100769
770 private:
David Srbecky09ed0982016-02-12 21:58:43 +0000771 static constexpr size_t kNativePcBitOffset = 0;
772 uint8_t dex_pc_bit_offset_;
773 uint8_t dex_register_map_bit_offset_;
774 uint8_t inline_info_bit_offset_;
775 uint8_t register_mask_bit_offset_;
776 uint8_t stack_mask_bit_offset_;
David Brazdilf677ebf2015-05-29 16:29:43 +0100777};
778
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100779/**
780 * A Stack Map holds compilation information for a specific PC necessary for:
781 * - Mapping it to a dex PC,
782 * - Knowing which stack entries are objects,
783 * - Knowing which registers hold objects,
784 * - Knowing the inlining information,
785 * - Knowing the values of dex registers.
786 *
787 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100788 *
David Srbecky09ed0982016-02-12 21:58:43 +0000789 * [native_pc_offset, dex_pc, dex_register_map_offset, inlining_info_offset, register_mask,
Roland Levillain1c1da432015-07-16 11:54:44 +0100790 * stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100791 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100792class StackMap {
793 public:
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100794 StackMap() {}
David Brazdilf677ebf2015-05-29 16:29:43 +0100795 explicit StackMap(MemoryRegion region) : region_(region) {}
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100796
David Srbecky09ed0982016-02-12 21:58:43 +0000797 ALWAYS_INLINE bool IsValid() const { return region_.pointer() != nullptr; }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100798
David Srbecky09ed0982016-02-12 21:58:43 +0000799 ALWAYS_INLINE uint32_t GetDexPc(const StackMapEncoding& encoding) const {
800 return encoding.GetDexPcEncoding().Load(region_);
David Brazdilf677ebf2015-05-29 16:29:43 +0100801 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100802
David Srbecky09ed0982016-02-12 21:58:43 +0000803 ALWAYS_INLINE void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) {
804 encoding.GetDexPcEncoding().Store(region_, dex_pc);
David Brazdilf677ebf2015-05-29 16:29:43 +0100805 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100806
David Srbecky09ed0982016-02-12 21:58:43 +0000807 ALWAYS_INLINE uint32_t GetNativePcOffset(const StackMapEncoding& encoding) const {
808 return encoding.GetNativePcEncoding().Load(region_);
David Brazdilf677ebf2015-05-29 16:29:43 +0100809 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100810
David Srbecky09ed0982016-02-12 21:58:43 +0000811 ALWAYS_INLINE void SetNativePcOffset(const StackMapEncoding& encoding, uint32_t native_pc_offset) {
812 encoding.GetNativePcEncoding().Store(region_, native_pc_offset);
David Brazdilf677ebf2015-05-29 16:29:43 +0100813 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100814
David Srbecky09ed0982016-02-12 21:58:43 +0000815 ALWAYS_INLINE uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const {
816 return encoding.GetDexRegisterMapEncoding().Load(region_);
David Brazdilf677ebf2015-05-29 16:29:43 +0100817 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100818
David Srbecky09ed0982016-02-12 21:58:43 +0000819 ALWAYS_INLINE void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) {
820 encoding.GetDexRegisterMapEncoding().Store(region_, offset);
David Brazdilf677ebf2015-05-29 16:29:43 +0100821 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100822
David Srbecky09ed0982016-02-12 21:58:43 +0000823 ALWAYS_INLINE uint32_t GetInlineDescriptorOffset(const StackMapEncoding& encoding) const {
824 return encoding.GetInlineInfoEncoding().Load(region_);
David Brazdilf677ebf2015-05-29 16:29:43 +0100825 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100826
David Srbecky09ed0982016-02-12 21:58:43 +0000827 ALWAYS_INLINE void SetInlineDescriptorOffset(const StackMapEncoding& encoding, uint32_t offset) {
828 encoding.GetInlineInfoEncoding().Store(region_, offset);
David Brazdilf677ebf2015-05-29 16:29:43 +0100829 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100830
David Srbecky09ed0982016-02-12 21:58:43 +0000831 ALWAYS_INLINE uint32_t GetRegisterMask(const StackMapEncoding& encoding) const {
832 return encoding.GetRegisterMaskEncoding().Load(region_);
David Brazdilf677ebf2015-05-29 16:29:43 +0100833 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100834
David Srbecky09ed0982016-02-12 21:58:43 +0000835 ALWAYS_INLINE void SetRegisterMask(const StackMapEncoding& encoding, uint32_t mask) {
836 encoding.GetRegisterMaskEncoding().Store(region_, mask);
David Brazdilf677ebf2015-05-29 16:29:43 +0100837 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100838
David Srbecky09ed0982016-02-12 21:58:43 +0000839 ALWAYS_INLINE size_t GetNumberOfStackMaskBits(const StackMapEncoding& encoding) const {
840 return region_.size_in_bits() - encoding.GetStackMaskBitOffset();
David Brazdilf677ebf2015-05-29 16:29:43 +0100841 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100842
David Srbecky09ed0982016-02-12 21:58:43 +0000843 ALWAYS_INLINE bool GetStackMaskBit(const StackMapEncoding& encoding, size_t index) const {
844 return region_.LoadBit(encoding.GetStackMaskBitOffset() + index);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100845 }
846
David Srbecky09ed0982016-02-12 21:58:43 +0000847 ALWAYS_INLINE void SetStackMaskBit(const StackMapEncoding& encoding, size_t index, bool value) {
848 region_.StoreBit(encoding.GetStackMaskBitOffset() + index, value);
849 }
850
851 ALWAYS_INLINE bool HasDexRegisterMap(const StackMapEncoding& encoding) const {
David Brazdilf677ebf2015-05-29 16:29:43 +0100852 return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100853 }
854
David Srbecky09ed0982016-02-12 21:58:43 +0000855 ALWAYS_INLINE bool HasInlineInfo(const StackMapEncoding& encoding) const {
David Brazdilf677ebf2015-05-29 16:29:43 +0100856 return GetInlineDescriptorOffset(encoding) != kNoInlineInfo;
Roland Levillain442b46a2015-02-18 16:54:21 +0000857 }
858
David Srbecky09ed0982016-02-12 21:58:43 +0000859 ALWAYS_INLINE bool Equals(const StackMap& other) const {
860 return region_.pointer() == other.region_.pointer() && region_.size() == other.region_.size();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100861 }
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 Srbecky09ed0982016-02-12 21:58:43 +0000865 const CodeInfoEncoding& 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
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100881 MemoryRegion region_;
882
Nicolas Geoffray39468442014-09-02 15:17:15 +0100883 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100884};
885
David Srbecky61b28a12016-02-25 21:55:03 +0000886class InlineInfoEncoding {
887 public:
888 void SetFromSizes(size_t method_index_max,
889 size_t dex_pc_max,
890 size_t invoke_type_max,
891 size_t dex_register_map_size) {
892 total_bit_size_ = kMethodIndexBitOffset;
893 total_bit_size_ += MinimumBitsToStore(method_index_max);
894
895 dex_pc_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100896 // Note: We're not encoding the dex pc if there is none. That's the case
897 // for an intrinsified native method, such as String.charAt().
898 if (dex_pc_max != DexFile::kDexNoIndex) {
899 total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max);
900 }
David Srbecky61b28a12016-02-25 21:55:03 +0000901
902 invoke_type_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
903 total_bit_size_ += MinimumBitsToStore(invoke_type_max);
904
905 // We also need +1 for kNoDexRegisterMap, but since the size is strictly
906 // greater than any offset we might try to encode, we already implicitly have it.
907 dex_register_map_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
908 total_bit_size_ += MinimumBitsToStore(dex_register_map_size);
909 }
910
911 ALWAYS_INLINE FieldEncoding GetMethodIndexEncoding() const {
912 return FieldEncoding(kMethodIndexBitOffset, dex_pc_bit_offset_);
913 }
914 ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const {
915 return FieldEncoding(dex_pc_bit_offset_, invoke_type_bit_offset_, -1 /* min_value */);
916 }
917 ALWAYS_INLINE FieldEncoding GetInvokeTypeEncoding() const {
918 return FieldEncoding(invoke_type_bit_offset_, dex_register_map_bit_offset_);
919 }
920 ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const {
921 return FieldEncoding(dex_register_map_bit_offset_, total_bit_size_, -1 /* min_value */);
922 }
923 ALWAYS_INLINE size_t GetEntrySize() const {
924 return RoundUp(total_bit_size_, kBitsPerByte) / kBitsPerByte;
925 }
926
927 void Dump(VariableIndentationOutputStream* vios) const;
928
929 private:
930 static constexpr uint8_t kIsLastBitOffset = 0;
931 static constexpr uint8_t kMethodIndexBitOffset = 1;
932 uint8_t dex_pc_bit_offset_;
933 uint8_t invoke_type_bit_offset_;
934 uint8_t dex_register_map_bit_offset_;
935 uint8_t total_bit_size_;
936};
937
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100938/**
939 * Inline information for a specific PC. The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +0100940 *
David Srbecky61b28a12016-02-25 21:55:03 +0000941 * [is_last, method_index, dex_pc, invoke_type, dex_register_map_offset]+.
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100942 */
943class InlineInfo {
944 public:
David Srbecky61b28a12016-02-25 21:55:03 +0000945 explicit InlineInfo(MemoryRegion region) : region_(region) {
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100946 }
947
David Srbecky61b28a12016-02-25 21:55:03 +0000948 ALWAYS_INLINE uint32_t GetDepth(const InlineInfoEncoding& encoding) const {
949 size_t depth = 0;
950 while (!GetRegionAtDepth(encoding, depth++).LoadBit(0)) { } // Check is_last bit.
951 return depth;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100952 }
953
David Srbecky61b28a12016-02-25 21:55:03 +0000954 ALWAYS_INLINE void SetDepth(const InlineInfoEncoding& encoding, uint32_t depth) {
955 DCHECK_GT(depth, 0u);
956 for (size_t d = 0; d < depth; ++d) {
957 GetRegionAtDepth(encoding, d).StoreBit(0, d == depth - 1); // Set is_last bit.
958 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100959 }
960
David Srbecky61b28a12016-02-25 21:55:03 +0000961 ALWAYS_INLINE uint32_t GetMethodIndexAtDepth(const InlineInfoEncoding& encoding,
962 uint32_t depth) const {
963 return encoding.GetMethodIndexEncoding().Load(GetRegionAtDepth(encoding, depth));
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100964 }
965
David Srbecky61b28a12016-02-25 21:55:03 +0000966 ALWAYS_INLINE void SetMethodIndexAtDepth(const InlineInfoEncoding& encoding,
967 uint32_t depth,
968 uint32_t index) {
969 encoding.GetMethodIndexEncoding().Store(GetRegionAtDepth(encoding, depth), index);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100970 }
971
David Srbecky61b28a12016-02-25 21:55:03 +0000972 ALWAYS_INLINE uint32_t GetDexPcAtDepth(const InlineInfoEncoding& encoding,
973 uint32_t depth) const {
974 return encoding.GetDexPcEncoding().Load(GetRegionAtDepth(encoding, depth));
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100975 }
976
David Srbecky61b28a12016-02-25 21:55:03 +0000977 ALWAYS_INLINE void SetDexPcAtDepth(const InlineInfoEncoding& encoding,
978 uint32_t depth,
979 uint32_t dex_pc) {
980 encoding.GetDexPcEncoding().Store(GetRegionAtDepth(encoding, depth), dex_pc);
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100981 }
982
David Srbecky61b28a12016-02-25 21:55:03 +0000983 ALWAYS_INLINE uint32_t GetInvokeTypeAtDepth(const InlineInfoEncoding& encoding,
984 uint32_t depth) const {
985 return encoding.GetInvokeTypeEncoding().Load(GetRegionAtDepth(encoding, depth));
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100986 }
987
David Srbecky61b28a12016-02-25 21:55:03 +0000988 ALWAYS_INLINE void SetInvokeTypeAtDepth(const InlineInfoEncoding& encoding,
989 uint32_t depth,
990 uint32_t invoke_type) {
991 encoding.GetInvokeTypeEncoding().Store(GetRegionAtDepth(encoding, depth), invoke_type);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100992 }
993
David Srbecky61b28a12016-02-25 21:55:03 +0000994 ALWAYS_INLINE uint32_t GetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding,
995 uint32_t depth) const {
996 return encoding.GetDexRegisterMapEncoding().Load(GetRegionAtDepth(encoding, depth));
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100997 }
998
David Srbecky61b28a12016-02-25 21:55:03 +0000999 ALWAYS_INLINE void SetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding,
1000 uint32_t depth,
1001 uint32_t offset) {
1002 encoding.GetDexRegisterMapEncoding().Store(GetRegionAtDepth(encoding, depth), offset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001003 }
1004
David Srbecky61b28a12016-02-25 21:55:03 +00001005 ALWAYS_INLINE bool HasDexRegisterMapAtDepth(const InlineInfoEncoding& encoding,
1006 uint32_t depth) const {
1007 return GetDexRegisterMapOffsetAtDepth(encoding, depth) != StackMap::kNoDexRegisterMap;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001008 }
1009
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001010 void Dump(VariableIndentationOutputStream* vios,
David Srbecky61b28a12016-02-25 21:55:03 +00001011 const CodeInfo& info,
1012 uint16_t* number_of_dex_registers) const;
Roland Levillain1c1da432015-07-16 11:54:44 +01001013
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001014 private:
David Srbecky61b28a12016-02-25 21:55:03 +00001015 ALWAYS_INLINE MemoryRegion GetRegionAtDepth(const InlineInfoEncoding& encoding,
1016 uint32_t depth) const {
1017 size_t entry_size = encoding.GetEntrySize();
1018 DCHECK_GT(entry_size, 0u);
1019 return region_.Subregion(depth * entry_size, entry_size);
1020 }
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +01001021
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001022 MemoryRegion region_;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001023};
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001024
David Srbecky09ed0982016-02-12 21:58:43 +00001025// Most of the fields are encoded as ULEB128 to save space.
1026struct CodeInfoEncoding {
1027 uint32_t non_header_size;
1028 uint32_t number_of_stack_maps;
1029 uint32_t stack_map_size_in_bytes;
1030 uint32_t number_of_location_catalog_entries;
1031 StackMapEncoding stack_map_encoding;
David Srbecky61b28a12016-02-25 21:55:03 +00001032 InlineInfoEncoding inline_info_encoding;
David Srbecky09ed0982016-02-12 21:58:43 +00001033 uint8_t header_size;
1034
1035 CodeInfoEncoding() { }
1036
1037 explicit CodeInfoEncoding(const void* data) {
1038 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
1039 non_header_size = DecodeUnsignedLeb128(&ptr);
1040 number_of_stack_maps = DecodeUnsignedLeb128(&ptr);
1041 stack_map_size_in_bytes = DecodeUnsignedLeb128(&ptr);
1042 number_of_location_catalog_entries = DecodeUnsignedLeb128(&ptr);
David Srbecky61b28a12016-02-25 21:55:03 +00001043 static_assert(alignof(StackMapEncoding) == 1,
1044 "StackMapEncoding should not require alignment");
David Srbecky09ed0982016-02-12 21:58:43 +00001045 stack_map_encoding = *reinterpret_cast<const StackMapEncoding*>(ptr);
1046 ptr += sizeof(StackMapEncoding);
David Srbecky61b28a12016-02-25 21:55:03 +00001047 if (stack_map_encoding.GetInlineInfoEncoding().BitSize() > 0) {
1048 static_assert(alignof(InlineInfoEncoding) == 1,
1049 "InlineInfoEncoding should not require alignment");
1050 inline_info_encoding = *reinterpret_cast<const InlineInfoEncoding*>(ptr);
1051 ptr += sizeof(InlineInfoEncoding);
1052 } else {
1053 inline_info_encoding = InlineInfoEncoding{}; // NOLINT.
1054 }
David Srbecky09ed0982016-02-12 21:58:43 +00001055 header_size = dchecked_integral_cast<uint8_t>(ptr - reinterpret_cast<const uint8_t*>(data));
1056 }
1057
1058 template<typename Vector>
1059 void Compress(Vector* dest) const {
1060 EncodeUnsignedLeb128(dest, non_header_size);
1061 EncodeUnsignedLeb128(dest, number_of_stack_maps);
1062 EncodeUnsignedLeb128(dest, stack_map_size_in_bytes);
1063 EncodeUnsignedLeb128(dest, number_of_location_catalog_entries);
David Srbecky61b28a12016-02-25 21:55:03 +00001064 const uint8_t* stack_map_ptr = reinterpret_cast<const uint8_t*>(&stack_map_encoding);
1065 dest->insert(dest->end(), stack_map_ptr, stack_map_ptr + sizeof(StackMapEncoding));
1066 if (stack_map_encoding.GetInlineInfoEncoding().BitSize() > 0) {
1067 const uint8_t* inline_info_ptr = reinterpret_cast<const uint8_t*>(&inline_info_encoding);
1068 dest->insert(dest->end(), inline_info_ptr, inline_info_ptr + sizeof(InlineInfoEncoding));
1069 }
David Srbecky09ed0982016-02-12 21:58:43 +00001070 }
1071};
1072
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001073/**
1074 * Wrapper around all compiler information collected for a method.
1075 * The information is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +01001076 *
David Srbecky09ed0982016-02-12 21:58:43 +00001077 * [CodeInfoEncoding, StackMap+, DexRegisterLocationCatalog+, DexRegisterMap+, InlineInfo*]
Roland Levillain1c1da432015-07-16 11:54:44 +01001078 *
David Srbecky09ed0982016-02-12 21:58:43 +00001079 * where CodeInfoEncoding is of the form:
Roland Levillain1c1da432015-07-16 11:54:44 +01001080 *
David Srbecky09ed0982016-02-12 21:58:43 +00001081 * [non_header_size, number_of_stack_maps, stack_map_size_in_bytes,
1082 * number_of_location_catalog_entries, StackMapEncoding]
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001083 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001084class CodeInfo {
1085 public:
David Srbecky09ed0982016-02-12 21:58:43 +00001086 explicit CodeInfo(MemoryRegion region) : region_(region) {
1087 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001088
Nicolas Geoffray39468442014-09-02 15:17:15 +01001089 explicit CodeInfo(const void* data) {
David Srbecky09ed0982016-02-12 21:58:43 +00001090 CodeInfoEncoding encoding = CodeInfoEncoding(data);
1091 region_ = MemoryRegion(const_cast<void*>(data),
1092 encoding.header_size + encoding.non_header_size);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001093 }
1094
David Srbecky09ed0982016-02-12 21:58:43 +00001095 CodeInfoEncoding ExtractEncoding() const {
1096 return CodeInfoEncoding(region_.start());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001097 }
1098
David Srbecky09ed0982016-02-12 21:58:43 +00001099 bool HasInlineInfo(const CodeInfoEncoding& encoding) const {
1100 return encoding.stack_map_encoding.GetInlineInfoEncoding().BitSize() > 0;
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001101 }
1102
David Srbecky09ed0982016-02-12 21:58:43 +00001103 DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const CodeInfoEncoding& encoding) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +00001104 return DexRegisterLocationCatalog(region_.Subregion(
David Brazdilf677ebf2015-05-29 16:29:43 +01001105 GetDexRegisterLocationCatalogOffset(encoding),
1106 GetDexRegisterLocationCatalogSize(encoding)));
Roland Levillaina552e1c2015-03-26 15:01:03 +00001107 }
1108
David Srbecky09ed0982016-02-12 21:58:43 +00001109 StackMap GetStackMapAt(size_t i, const CodeInfoEncoding& encoding) const {
1110 size_t stack_map_size = encoding.stack_map_size_in_bytes;
David Brazdilf677ebf2015-05-29 16:29:43 +01001111 return StackMap(GetStackMaps(encoding).Subregion(i * stack_map_size, stack_map_size));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001112 }
1113
David Srbecky09ed0982016-02-12 21:58:43 +00001114 uint32_t GetNumberOfLocationCatalogEntries(const CodeInfoEncoding& encoding) const {
1115 return encoding.number_of_location_catalog_entries;
Nicolas Geoffray39468442014-09-02 15:17:15 +01001116 }
1117
David Srbecky09ed0982016-02-12 21:58:43 +00001118 uint32_t GetDexRegisterLocationCatalogSize(const CodeInfoEncoding& encoding) const {
David Brazdilf677ebf2015-05-29 16:29:43 +01001119 return ComputeDexRegisterLocationCatalogSize(GetDexRegisterLocationCatalogOffset(encoding),
David Srbecky09ed0982016-02-12 21:58:43 +00001120 GetNumberOfLocationCatalogEntries(encoding));
Roland Levillaina552e1c2015-03-26 15:01:03 +00001121 }
1122
David Srbecky09ed0982016-02-12 21:58:43 +00001123 uint32_t GetNumberOfStackMaps(const CodeInfoEncoding& encoding) const {
1124 return encoding.number_of_stack_maps;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001125 }
1126
David Brazdil77a48ae2015-09-15 12:34:04 +00001127 // Get the size of all the stack maps of this CodeInfo object, in bytes.
David Srbecky09ed0982016-02-12 21:58:43 +00001128 size_t GetStackMapsSize(const CodeInfoEncoding& encoding) const {
1129 return encoding.stack_map_size_in_bytes * GetNumberOfStackMaps(encoding);
Roland Levillain29ba1b02015-03-13 11:45:07 +00001130 }
1131
David Srbecky09ed0982016-02-12 21:58:43 +00001132 uint32_t GetDexRegisterLocationCatalogOffset(const CodeInfoEncoding& encoding) const {
1133 return GetStackMapsOffset(encoding) + GetStackMapsSize(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001134 }
1135
David Srbecky09ed0982016-02-12 21:58:43 +00001136 size_t GetDexRegisterMapsOffset(const CodeInfoEncoding& encoding) const {
David Brazdilf677ebf2015-05-29 16:29:43 +01001137 return GetDexRegisterLocationCatalogOffset(encoding)
1138 + GetDexRegisterLocationCatalogSize(encoding);
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001139 }
1140
David Srbecky09ed0982016-02-12 21:58:43 +00001141 uint32_t GetStackMapsOffset(const CodeInfoEncoding& encoding) const {
1142 return encoding.header_size;
Nicolas Geoffray6530baf2015-05-26 15:22:58 +01001143 }
1144
David Brazdilf677ebf2015-05-29 16:29:43 +01001145 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
David Srbecky09ed0982016-02-12 21:58:43 +00001146 const CodeInfoEncoding& encoding,
David Brazdilf677ebf2015-05-29 16:29:43 +01001147 uint32_t number_of_dex_registers) const {
David Srbecky09ed0982016-02-12 21:58:43 +00001148 if (!stack_map.HasDexRegisterMap(encoding.stack_map_encoding)) {
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +00001149 return DexRegisterMap();
1150 } else {
1151 uint32_t offset = GetDexRegisterMapsOffset(encoding)
David Srbecky09ed0982016-02-12 21:58:43 +00001152 + stack_map.GetDexRegisterMapOffset(encoding.stack_map_encoding);
1153 size_t size = ComputeDexRegisterMapSizeOf(encoding, offset, number_of_dex_registers);
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +00001154 return DexRegisterMap(region_.Subregion(offset, size));
1155 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001156 }
1157
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001158 // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
1159 DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
1160 InlineInfo inline_info,
David Srbecky09ed0982016-02-12 21:58:43 +00001161 const CodeInfoEncoding& encoding,
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001162 uint32_t number_of_dex_registers) const {
David Srbecky61b28a12016-02-25 21:55:03 +00001163 if (!inline_info.HasDexRegisterMapAtDepth(encoding.inline_info_encoding, depth)) {
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +00001164 return DexRegisterMap();
1165 } else {
David Srbecky61b28a12016-02-25 21:55:03 +00001166 uint32_t offset = GetDexRegisterMapsOffset(encoding) +
1167 inline_info.GetDexRegisterMapOffsetAtDepth(encoding.inline_info_encoding, depth);
David Srbecky09ed0982016-02-12 21:58:43 +00001168 size_t size = ComputeDexRegisterMapSizeOf(encoding, offset, number_of_dex_registers);
Nicolas Geoffray012fc4e2016-01-08 15:58:19 +00001169 return DexRegisterMap(region_.Subregion(offset, size));
1170 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001171 }
1172
David Srbecky09ed0982016-02-12 21:58:43 +00001173 InlineInfo GetInlineInfoOf(StackMap stack_map, const CodeInfoEncoding& encoding) const {
1174 DCHECK(stack_map.HasInlineInfo(encoding.stack_map_encoding));
1175 uint32_t offset = stack_map.GetInlineDescriptorOffset(encoding.stack_map_encoding)
David Brazdilf677ebf2015-05-29 16:29:43 +01001176 + GetDexRegisterMapsOffset(encoding);
David Srbecky61b28a12016-02-25 21:55:03 +00001177 return InlineInfo(region_.Subregion(offset, region_.size() - offset));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001178 }
1179
David Srbecky09ed0982016-02-12 21:58:43 +00001180 StackMap GetStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const {
1181 for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001182 StackMap stack_map = GetStackMapAt(i, encoding);
David Srbecky09ed0982016-02-12 21:58:43 +00001183 if (stack_map.GetDexPc(encoding.stack_map_encoding) == dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001184 return stack_map;
1185 }
1186 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001187 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001188 }
1189
David Brazdil77a48ae2015-09-15 12:34:04 +00001190 // Searches the stack map list backwards because catch stack maps are stored
1191 // at the end.
David Srbecky09ed0982016-02-12 21:58:43 +00001192 StackMap GetCatchStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const {
1193 for (size_t i = GetNumberOfStackMaps(encoding); i > 0; --i) {
David Brazdil77a48ae2015-09-15 12:34:04 +00001194 StackMap stack_map = GetStackMapAt(i - 1, encoding);
David Srbecky09ed0982016-02-12 21:58:43 +00001195 if (stack_map.GetDexPc(encoding.stack_map_encoding) == dex_pc) {
David Brazdil77a48ae2015-09-15 12:34:04 +00001196 return stack_map;
1197 }
1198 }
1199 return StackMap();
1200 }
1201
David Srbecky09ed0982016-02-12 21:58:43 +00001202 StackMap GetOsrStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const {
1203 size_t e = GetNumberOfStackMaps(encoding);
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001204 if (e == 0) {
1205 // There cannot be OSR stack map if there is no stack map.
1206 return StackMap();
1207 }
1208 // Walk over all stack maps. If two consecutive stack maps are identical, then we
1209 // have found a stack map suitable for OSR.
David Srbecky09ed0982016-02-12 21:58:43 +00001210 const StackMapEncoding& stack_map_encoding = encoding.stack_map_encoding;
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001211 for (size_t i = 0; i < e - 1; ++i) {
1212 StackMap stack_map = GetStackMapAt(i, encoding);
David Srbecky09ed0982016-02-12 21:58:43 +00001213 if (stack_map.GetDexPc(stack_map_encoding) == dex_pc) {
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001214 StackMap other = GetStackMapAt(i + 1, encoding);
David Srbecky09ed0982016-02-12 21:58:43 +00001215 if (other.GetDexPc(stack_map_encoding) == dex_pc &&
1216 other.GetNativePcOffset(stack_map_encoding) ==
1217 stack_map.GetNativePcOffset(stack_map_encoding)) {
1218 DCHECK_EQ(other.GetDexRegisterMapOffset(stack_map_encoding),
1219 stack_map.GetDexRegisterMapOffset(stack_map_encoding));
1220 DCHECK(!stack_map.HasInlineInfo(stack_map_encoding));
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001221 if (i < e - 2) {
1222 // Make sure there are not three identical stack maps following each other.
David Srbecky09ed0982016-02-12 21:58:43 +00001223 DCHECK_NE(stack_map.GetNativePcOffset(stack_map_encoding),
1224 GetStackMapAt(i + 2, encoding).GetNativePcOffset(stack_map_encoding));
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +00001225 }
1226 return stack_map;
1227 }
1228 }
1229 }
1230 return StackMap();
1231 }
1232
David Brazdilf677ebf2015-05-29 16:29:43 +01001233 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset,
David Srbecky09ed0982016-02-12 21:58:43 +00001234 const CodeInfoEncoding& encoding) const {
David Brazdil77a48ae2015-09-15 12:34:04 +00001235 // TODO: Safepoint stack maps are sorted by native_pc_offset but catch stack
1236 // maps are not. If we knew that the method does not have try/catch,
1237 // we could do binary search.
David Srbecky09ed0982016-02-12 21:58:43 +00001238 for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001239 StackMap stack_map = GetStackMapAt(i, encoding);
David Srbecky09ed0982016-02-12 21:58:43 +00001240 if (stack_map.GetNativePcOffset(encoding.stack_map_encoding) == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001241 return stack_map;
1242 }
1243 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001244 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001245 }
1246
Roland Levillainf2650d12015-05-28 14:53:28 +01001247 // Dump this CodeInfo object on `os`. `code_offset` is the (absolute)
1248 // native PC of the compiled method and `number_of_dex_registers` the
1249 // number of Dex virtual registers used in this method. If
1250 // `dump_stack_maps` is true, also dump the stack maps and the
1251 // associated Dex register maps.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001252 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +01001253 uint32_t code_offset,
1254 uint16_t number_of_dex_registers,
1255 bool dump_stack_maps) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001256
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001257 private:
David Srbecky09ed0982016-02-12 21:58:43 +00001258 MemoryRegion GetStackMaps(const CodeInfoEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001259 return region_.size() == 0
1260 ? MemoryRegion()
David Srbecky09ed0982016-02-12 21:58:43 +00001261 : region_.Subregion(GetStackMapsOffset(encoding), GetStackMapsSize(encoding));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001262 }
1263
Roland Levillaina552e1c2015-03-26 15:01:03 +00001264 // Compute the size of the Dex register map associated to the stack map at
1265 // `dex_register_map_offset_in_code_info`.
David Srbecky09ed0982016-02-12 21:58:43 +00001266 size_t ComputeDexRegisterMapSizeOf(const CodeInfoEncoding& encoding,
1267 uint32_t dex_register_map_offset_in_code_info,
Roland Levillaina552e1c2015-03-26 15:01:03 +00001268 uint16_t number_of_dex_registers) const {
1269 // Offset where the actual mapping data starts within art::DexRegisterMap.
1270 size_t location_mapping_data_offset_in_dex_register_map =
1271 DexRegisterMap::GetLocationMappingDataOffset(number_of_dex_registers);
1272 // Create a temporary art::DexRegisterMap to be able to call
1273 // art::DexRegisterMap::GetNumberOfLiveDexRegisters and
1274 DexRegisterMap dex_register_map_without_locations(
1275 MemoryRegion(region_.Subregion(dex_register_map_offset_in_code_info,
1276 location_mapping_data_offset_in_dex_register_map)));
1277 size_t number_of_live_dex_registers =
1278 dex_register_map_without_locations.GetNumberOfLiveDexRegisters(number_of_dex_registers);
1279 size_t location_mapping_data_size_in_bits =
David Srbecky09ed0982016-02-12 21:58:43 +00001280 DexRegisterMap::SingleEntrySizeInBits(GetNumberOfLocationCatalogEntries(encoding))
Roland Levillaina552e1c2015-03-26 15:01:03 +00001281 * number_of_live_dex_registers;
1282 size_t location_mapping_data_size_in_bytes =
1283 RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
1284 size_t dex_register_map_size =
1285 location_mapping_data_offset_in_dex_register_map + location_mapping_data_size_in_bytes;
1286 return dex_register_map_size;
1287 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001288
Roland Levillaina552e1c2015-03-26 15:01:03 +00001289 // Compute the size of a Dex register location catalog starting at offset `origin`
1290 // in `region_` and containing `number_of_dex_locations` entries.
1291 size_t ComputeDexRegisterLocationCatalogSize(uint32_t origin,
1292 uint32_t number_of_dex_locations) const {
1293 // TODO: Ideally, we would like to use art::DexRegisterLocationCatalog::Size or
1294 // art::DexRegisterLocationCatalog::FindLocationOffset, but the
1295 // DexRegisterLocationCatalog is not yet built. Try to factor common code.
1296 size_t offset = origin + DexRegisterLocationCatalog::kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001297
Roland Levillaina552e1c2015-03-26 15:01:03 +00001298 // Skip the first `number_of_dex_locations - 1` entries.
1299 for (uint16_t i = 0; i < number_of_dex_locations; ++i) {
1300 // Read the first next byte and inspect its first 3 bits to decide
1301 // whether it is a short or a large location.
1302 DexRegisterLocationCatalog::ShortLocation first_byte =
1303 region_.LoadUnaligned<DexRegisterLocationCatalog::ShortLocation>(offset);
1304 DexRegisterLocation::Kind kind =
1305 DexRegisterLocationCatalog::ExtractKindFromShortLocation(first_byte);
1306 if (DexRegisterLocation::IsShortLocationKind(kind)) {
1307 // Short location. Skip the current byte.
1308 offset += DexRegisterLocationCatalog::SingleShortEntrySize();
1309 } else {
1310 // Large location. Skip the 5 next bytes.
1311 offset += DexRegisterLocationCatalog::SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001312 }
1313 }
1314 size_t size = offset - origin;
1315 return size;
1316 }
1317
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001318 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +01001319 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001320};
1321
Roland Levillain1c1da432015-07-16 11:54:44 +01001322#undef ELEMENT_BYTE_OFFSET_AFTER
1323#undef ELEMENT_BIT_OFFSET_AFTER
1324
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001325} // namespace art
1326
1327#endif // ART_RUNTIME_STACK_MAP_H_