1 /*
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"
21 #include "base/bit_utils.h"
22 #include "memory_region.h"
23 #include "leb128.h"
24 
25 namespace art {
26 
27 class VariableIndentationOutputStream;
28 
29 // Size of a frame slot, in bytes.  This constant is a signed value,
30 // to please the compiler in arithmetic operations involving int32_t
31 // (signed) values.
32 static constexpr ssize_t kFrameSlotSize = 4;
33 
34 // Size of Dex virtual registers.
35 static constexpr size_t kVRegSize = 4;
36 
37 class CodeInfo;
38 class StackMapEncoding;
39 struct CodeInfoEncoding;
40 
41 /**
42  * Classes in the following file are wrapper on stack map information backed
43  * by a MemoryRegion. As such they read and write to the region, they don't have
44  * their own fields.
45  */
46 
47 // Dex register location container used by DexRegisterMap and StackMapStream.
48 class DexRegisterLocation {
49  public:
50   /*
51    * The location kind used to populate the Dex register information in a
52    * StackMapStream can either be:
53    * - kStack: vreg stored on the stack, value holds the stack offset;
54    * - kInRegister: vreg stored in low 32 bits of a core physical register,
55    *                value holds the register number;
56    * - kInRegisterHigh: vreg stored in high 32 bits of a core physical register,
57    *                    value holds the register number;
58    * - kInFpuRegister: vreg stored in low 32 bits of an FPU register,
59    *                   value holds the register number;
60    * - kInFpuRegisterHigh: vreg stored in high 32 bits of an FPU register,
61    *                       value holds the register number;
62    * - kConstant: value holds the constant;
63    *
64    * In addition, DexRegisterMap also uses these values:
65    * - kInStackLargeOffset: value holds a "large" stack offset (greater than
66    *   or equal to 128 bytes);
67    * - kConstantLargeValue: value holds a "large" constant (lower than 0, or
68    *   or greater than or equal to 32);
69    * - kNone: the register has no location, meaning it has not been set.
70    */
71   enum class Kind : uint8_t {
72     // Short location kinds, for entries fitting on one byte (3 bits
73     // for the kind, 5 bits for the value) in a DexRegisterMap.
74     kInStack = 0,             // 0b000
75     kInRegister = 1,          // 0b001
76     kInRegisterHigh = 2,      // 0b010
77     kInFpuRegister = 3,       // 0b011
78     kInFpuRegisterHigh = 4,   // 0b100
79     kConstant = 5,            // 0b101
80 
81     // Large location kinds, requiring a 5-byte encoding (1 byte for the
82     // kind, 4 bytes for the value).
83 
84     // Stack location at a large offset, meaning that the offset value
85     // divided by the stack frame slot size (4 bytes) cannot fit on a
86     // 5-bit unsigned integer (i.e., this offset value is greater than
87     // or equal to 2^5 * 4 = 128 bytes).
88     kInStackLargeOffset = 6,  // 0b110
89 
90     // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
91     // lower than 0, or greater than or equal to 2^5 = 32).
92     kConstantLargeValue = 7,  // 0b111
93 
94     // Entries with no location are not stored and do not need own marker.
95     kNone = static_cast<uint8_t>(-1),
96 
97     kLastLocationKind = kConstantLargeValue
98   };
99 
100   static_assert(
101       sizeof(Kind) == 1u,
102       "art::DexRegisterLocation::Kind has a size different from one byte.");
103 
IsShortLocationKind(Kind kind)104   static bool IsShortLocationKind(Kind kind) {
105     switch (kind) {
106       case Kind::kInStack:
107       case Kind::kInRegister:
108       case Kind::kInRegisterHigh:
109       case Kind::kInFpuRegister:
110       case Kind::kInFpuRegisterHigh:
111       case Kind::kConstant:
112         return true;
113 
114       case Kind::kInStackLargeOffset:
115       case Kind::kConstantLargeValue:
116         return false;
117 
118       case Kind::kNone:
119         LOG(FATAL) << "Unexpected location kind";
120     }
121     UNREACHABLE();
122   }
123 
124   // Convert `kind` to a "surface" kind, i.e. one that doesn't include
125   // any value with a "large" qualifier.
126   // TODO: Introduce another enum type for the surface kind?
ConvertToSurfaceKind(Kind kind)127   static Kind ConvertToSurfaceKind(Kind kind) {
128     switch (kind) {
129       case Kind::kInStack:
130       case Kind::kInRegister:
131       case Kind::kInRegisterHigh:
132       case Kind::kInFpuRegister:
133       case Kind::kInFpuRegisterHigh:
134       case Kind::kConstant:
135         return kind;
136 
137       case Kind::kInStackLargeOffset:
138         return Kind::kInStack;
139 
140       case Kind::kConstantLargeValue:
141         return Kind::kConstant;
142 
143       case Kind::kNone:
144         return kind;
145     }
146     UNREACHABLE();
147   }
148 
149   // Required by art::StackMapStream::LocationCatalogEntriesIndices.
DexRegisterLocation()150   DexRegisterLocation() : kind_(Kind::kNone), value_(0) {}
151 
DexRegisterLocation(Kind kind,int32_t value)152   DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {}
153 
None()154   static DexRegisterLocation None() {
155     return DexRegisterLocation(Kind::kNone, 0);
156   }
157 
158   // Get the "surface" kind of the location, i.e., the one that doesn't
159   // include any value with a "large" qualifier.
GetKind()160   Kind GetKind() const {
161     return ConvertToSurfaceKind(kind_);
162   }
163 
164   // Get the value of the location.
GetValue()165   int32_t GetValue() const { return value_; }
166 
167   // Get the actual kind of the location.
GetInternalKind()168   Kind GetInternalKind() const { return kind_; }
169 
170   bool operator==(DexRegisterLocation other) const {
171     return kind_ == other.kind_ && value_ == other.value_;
172   }
173 
174   bool operator!=(DexRegisterLocation other) const {
175     return !(*this == other);
176   }
177 
178  private:
179   Kind kind_;
180   int32_t value_;
181 
182   friend class DexRegisterLocationHashFn;
183 };
184 
185 std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind);
186 
187 /**
188  * Store information on unique Dex register locations used in a method.
189  * The information is of the form:
190  *
191  *   [DexRegisterLocation+].
192  *
193  * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind).
194  */
195 class DexRegisterLocationCatalog {
196  public:
DexRegisterLocationCatalog(MemoryRegion region)197   explicit DexRegisterLocationCatalog(MemoryRegion region) : region_(region) {}
198 
199   // Short (compressed) location, fitting on one byte.
200   typedef uint8_t ShortLocation;
201 
SetRegisterInfo(size_t offset,const DexRegisterLocation & dex_register_location)202   void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
203     DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
204     int32_t value = dex_register_location.GetValue();
205     if (DexRegisterLocation::IsShortLocationKind(kind)) {
206       // Short location.  Compress the kind and the value as a single byte.
207       if (kind == DexRegisterLocation::Kind::kInStack) {
208         // Instead of storing stack offsets expressed in bytes for
209         // short stack locations, store slot offsets.  A stack offset
210         // is a multiple of 4 (kFrameSlotSize).  This means that by
211         // dividing it by 4, we can fit values from the [0, 128)
212         // interval in a short stack location, and not just values
213         // from the [0, 32) interval.
214         DCHECK_EQ(value % kFrameSlotSize, 0);
215         value /= kFrameSlotSize;
216       }
217       DCHECK(IsShortValue(value)) << value;
218       region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
219     } else {
220       // Large location.  Write the location on one byte and the value
221       // on 4 bytes.
222       DCHECK(!IsShortValue(value)) << value;
223       if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
224         // Also divide large stack offsets by 4 for the sake of consistency.
225         DCHECK_EQ(value % kFrameSlotSize, 0);
226         value /= kFrameSlotSize;
227       }
228       // Data can be unaligned as the written Dex register locations can
229       // either be 1-byte or 5-byte wide.  Use
230       // art::MemoryRegion::StoreUnaligned instead of
231       // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
232       region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
233       region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
234     }
235   }
236 
237   // Find the offset of the location catalog entry number `location_catalog_entry_index`.
FindLocationOffset(size_t location_catalog_entry_index)238   size_t FindLocationOffset(size_t location_catalog_entry_index) const {
239     size_t offset = kFixedSize;
240     // Skip the first `location_catalog_entry_index - 1` entries.
241     for (uint16_t i = 0; i < location_catalog_entry_index; ++i) {
242       // Read the first next byte and inspect its first 3 bits to decide
243       // whether it is a short or a large location.
244       DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
245       if (DexRegisterLocation::IsShortLocationKind(kind)) {
246         // Short location.  Skip the current byte.
247         offset += SingleShortEntrySize();
248       } else {
249         // Large location.  Skip the 5 next bytes.
250         offset += SingleLargeEntrySize();
251       }
252     }
253     return offset;
254   }
255 
256   // Get the internal kind of entry at `location_catalog_entry_index`.
GetLocationInternalKind(size_t location_catalog_entry_index)257   DexRegisterLocation::Kind GetLocationInternalKind(size_t location_catalog_entry_index) const {
258     if (location_catalog_entry_index == kNoLocationEntryIndex) {
259       return DexRegisterLocation::Kind::kNone;
260     }
261     return ExtractKindAtOffset(FindLocationOffset(location_catalog_entry_index));
262   }
263 
264   // Get the (surface) kind and value of entry at `location_catalog_entry_index`.
GetDexRegisterLocation(size_t location_catalog_entry_index)265   DexRegisterLocation GetDexRegisterLocation(size_t location_catalog_entry_index) const {
266     if (location_catalog_entry_index == kNoLocationEntryIndex) {
267       return DexRegisterLocation::None();
268     }
269     size_t offset = FindLocationOffset(location_catalog_entry_index);
270     // Read the first byte and inspect its first 3 bits to get the location.
271     ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
272     DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
273     if (DexRegisterLocation::IsShortLocationKind(kind)) {
274       // Short location.  Extract the value from the remaining 5 bits.
275       int32_t value = ExtractValueFromShortLocation(first_byte);
276       if (kind == DexRegisterLocation::Kind::kInStack) {
277         // Convert the stack slot (short) offset to a byte offset value.
278         value *= kFrameSlotSize;
279       }
280       return DexRegisterLocation(kind, value);
281     } else {
282       // Large location.  Read the four next bytes to get the value.
283       int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
284       if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
285         // Convert the stack slot (large) offset to a byte offset value.
286         value *= kFrameSlotSize;
287       }
288       return DexRegisterLocation(kind, value);
289     }
290   }
291 
292   // Compute the compressed kind of `location`.
ComputeCompressedKind(const DexRegisterLocation & location)293   static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
294     DexRegisterLocation::Kind kind = location.GetInternalKind();
295     switch (kind) {
296       case DexRegisterLocation::Kind::kInStack:
297         return IsShortStackOffsetValue(location.GetValue())
298             ? DexRegisterLocation::Kind::kInStack
299             : DexRegisterLocation::Kind::kInStackLargeOffset;
300 
301       case DexRegisterLocation::Kind::kInRegister:
302       case DexRegisterLocation::Kind::kInRegisterHigh:
303         DCHECK_GE(location.GetValue(), 0);
304         DCHECK_LT(location.GetValue(), 1 << kValueBits);
305         return kind;
306 
307       case DexRegisterLocation::Kind::kInFpuRegister:
308       case DexRegisterLocation::Kind::kInFpuRegisterHigh:
309         DCHECK_GE(location.GetValue(), 0);
310         DCHECK_LT(location.GetValue(), 1 << kValueBits);
311         return kind;
312 
313       case DexRegisterLocation::Kind::kConstant:
314         return IsShortConstantValue(location.GetValue())
315             ? DexRegisterLocation::Kind::kConstant
316             : DexRegisterLocation::Kind::kConstantLargeValue;
317 
318       case DexRegisterLocation::Kind::kConstantLargeValue:
319       case DexRegisterLocation::Kind::kInStackLargeOffset:
320       case DexRegisterLocation::Kind::kNone:
321         LOG(FATAL) << "Unexpected location kind " << kind;
322     }
323     UNREACHABLE();
324   }
325 
326   // Can `location` be turned into a short location?
CanBeEncodedAsShortLocation(const DexRegisterLocation & location)327   static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
328     DexRegisterLocation::Kind kind = location.GetInternalKind();
329     switch (kind) {
330       case DexRegisterLocation::Kind::kInStack:
331         return IsShortStackOffsetValue(location.GetValue());
332 
333       case DexRegisterLocation::Kind::kInRegister:
334       case DexRegisterLocation::Kind::kInRegisterHigh:
335       case DexRegisterLocation::Kind::kInFpuRegister:
336       case DexRegisterLocation::Kind::kInFpuRegisterHigh:
337         return true;
338 
339       case DexRegisterLocation::Kind::kConstant:
340         return IsShortConstantValue(location.GetValue());
341 
342       case DexRegisterLocation::Kind::kConstantLargeValue:
343       case DexRegisterLocation::Kind::kInStackLargeOffset:
344       case DexRegisterLocation::Kind::kNone:
345         LOG(FATAL) << "Unexpected location kind " << kind;
346     }
347     UNREACHABLE();
348   }
349 
EntrySize(const DexRegisterLocation & location)350   static size_t EntrySize(const DexRegisterLocation& location) {
351     return CanBeEncodedAsShortLocation(location) ? SingleShortEntrySize() : SingleLargeEntrySize();
352   }
353 
SingleShortEntrySize()354   static size_t SingleShortEntrySize() {
355     return sizeof(ShortLocation);
356   }
357 
SingleLargeEntrySize()358   static size_t SingleLargeEntrySize() {
359     return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
360   }
361 
Size()362   size_t Size() const {
363     return region_.size();
364   }
365 
366   void Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info);
367 
368   // Special (invalid) Dex register location catalog entry index meaning
369   // that there is no location for a given Dex register (i.e., it is
370   // mapped to a DexRegisterLocation::Kind::kNone location).
371   static constexpr size_t kNoLocationEntryIndex = -1;
372 
373  private:
374   static constexpr int kFixedSize = 0;
375 
376   // Width of the kind "field" in a short location, in bits.
377   static constexpr size_t kKindBits = 3;
378   // Width of the value "field" in a short location, in bits.
379   static constexpr size_t kValueBits = 5;
380 
381   static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
382   static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
383   static constexpr size_t kKindOffset = 0;
384   static constexpr size_t kValueOffset = kKindBits;
385 
IsShortStackOffsetValue(int32_t value)386   static bool IsShortStackOffsetValue(int32_t value) {
387     DCHECK_EQ(value % kFrameSlotSize, 0);
388     return IsShortValue(value / kFrameSlotSize);
389   }
390 
IsShortConstantValue(int32_t value)391   static bool IsShortConstantValue(int32_t value) {
392     return IsShortValue(value);
393   }
394 
IsShortValue(int32_t value)395   static bool IsShortValue(int32_t value) {
396     return IsUint<kValueBits>(value);
397   }
398 
MakeShortLocation(DexRegisterLocation::Kind kind,int32_t value)399   static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
400     uint8_t kind_integer_value = static_cast<uint8_t>(kind);
401     DCHECK(IsUint<kKindBits>(kind_integer_value)) << kind_integer_value;
402     DCHECK(IsShortValue(value)) << value;
403     return (kind_integer_value & kKindMask) << kKindOffset
404         | (value & kValueMask) << kValueOffset;
405   }
406 
ExtractKindFromShortLocation(ShortLocation location)407   static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
408     uint8_t kind = (location >> kKindOffset) & kKindMask;
409     DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
410     // We do not encode kNone locations in the stack map.
411     DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone));
412     return static_cast<DexRegisterLocation::Kind>(kind);
413   }
414 
ExtractValueFromShortLocation(ShortLocation location)415   static int32_t ExtractValueFromShortLocation(ShortLocation location) {
416     return (location >> kValueOffset) & kValueMask;
417   }
418 
419   // Extract a location kind from the byte at position `offset`.
ExtractKindAtOffset(size_t offset)420   DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
421     ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
422     return ExtractKindFromShortLocation(first_byte);
423   }
424 
425   MemoryRegion region_;
426 
427   friend class CodeInfo;
428   friend class StackMapStream;
429 };
430 
431 /* Information on Dex register locations for a specific PC, mapping a
432  * stack map's Dex register to a location entry in a DexRegisterLocationCatalog.
433  * The information is of the form:
434  *
435  *   [live_bit_mask, entries*]
436  *
437  * where entries are concatenated unsigned integer values encoded on a number
438  * of bits (fixed per DexRegisterMap instances of a CodeInfo object) depending
439  * on the number of entries in the Dex register location catalog
440  * (see DexRegisterMap::SingleEntrySizeInBits).  The map is 1-byte aligned.
441  */
442 class DexRegisterMap {
443  public:
DexRegisterMap(MemoryRegion region)444   explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
DexRegisterMap()445   DexRegisterMap() {}
446 
IsValid()447   bool IsValid() const { return region_.pointer() != nullptr; }
448 
449   // Get the surface kind of Dex register `dex_register_number`.
GetLocationKind(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info,const CodeInfoEncoding & enc)450   DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number,
451                                             uint16_t number_of_dex_registers,
452                                             const CodeInfo& code_info,
453                                             const CodeInfoEncoding& enc) const {
454     return DexRegisterLocation::ConvertToSurfaceKind(
455         GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info, enc));
456   }
457 
458   // Get the internal kind of Dex register `dex_register_number`.
459   DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number,
460                                                     uint16_t number_of_dex_registers,
461                                                     const CodeInfo& code_info,
462                                                     const CodeInfoEncoding& enc) const;
463 
464   // Get the Dex register location `dex_register_number`.
465   DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number,
466                                              uint16_t number_of_dex_registers,
467                                              const CodeInfo& code_info,
468                                              const CodeInfoEncoding& enc) const;
469 
GetStackOffsetInBytes(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info,const CodeInfoEncoding & enc)470   int32_t GetStackOffsetInBytes(uint16_t dex_register_number,
471                                 uint16_t number_of_dex_registers,
472                                 const CodeInfo& code_info,
473                                 const CodeInfoEncoding& enc) const {
474     DexRegisterLocation location =
475         GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
476     DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
477     // GetDexRegisterLocation returns the offset in bytes.
478     return location.GetValue();
479   }
480 
GetConstant(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info,const CodeInfoEncoding & enc)481   int32_t GetConstant(uint16_t dex_register_number,
482                       uint16_t number_of_dex_registers,
483                       const CodeInfo& code_info,
484                       const CodeInfoEncoding& enc) const {
485     DexRegisterLocation location =
486         GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
487     DCHECK_EQ(location.GetKind(), DexRegisterLocation::Kind::kConstant);
488     return location.GetValue();
489   }
490 
GetMachineRegister(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info,const CodeInfoEncoding & enc)491   int32_t GetMachineRegister(uint16_t dex_register_number,
492                              uint16_t number_of_dex_registers,
493                              const CodeInfo& code_info,
494                              const CodeInfoEncoding& enc) const {
495     DexRegisterLocation location =
496         GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
497     DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister ||
498            location.GetInternalKind() == DexRegisterLocation::Kind::kInRegisterHigh ||
499            location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister ||
500            location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh)
501         << location.GetInternalKind();
502     return location.GetValue();
503   }
504 
505   // Get the index of the entry in the Dex register location catalog
506   // corresponding to `dex_register_number`.
GetLocationCatalogEntryIndex(uint16_t dex_register_number,uint16_t number_of_dex_registers,size_t number_of_location_catalog_entries)507   size_t GetLocationCatalogEntryIndex(uint16_t dex_register_number,
508                                       uint16_t number_of_dex_registers,
509                                       size_t number_of_location_catalog_entries) const {
510     if (!IsDexRegisterLive(dex_register_number)) {
511       return DexRegisterLocationCatalog::kNoLocationEntryIndex;
512     }
513 
514     if (number_of_location_catalog_entries == 1) {
515       // We do not allocate space for location maps in the case of a
516       // single-entry location catalog, as it is useless.  The only valid
517       // entry index is 0;
518       return 0;
519     }
520 
521     // The bit offset of the beginning of the map locations.
522     size_t map_locations_offset_in_bits =
523         GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
524     size_t index_in_dex_register_map = GetIndexInDexRegisterMap(dex_register_number);
525     DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
526     // The bit size of an entry.
527     size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
528     // The bit offset where `index_in_dex_register_map` is located.
529     size_t entry_offset_in_bits =
530         map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
531     size_t location_catalog_entry_index =
532         region_.LoadBits(entry_offset_in_bits, map_entry_size_in_bits);
533     DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
534     return location_catalog_entry_index;
535   }
536 
537   // Map entry at `index_in_dex_register_map` to `location_catalog_entry_index`.
SetLocationCatalogEntryIndex(size_t index_in_dex_register_map,size_t location_catalog_entry_index,uint16_t number_of_dex_registers,size_t number_of_location_catalog_entries)538   void SetLocationCatalogEntryIndex(size_t index_in_dex_register_map,
539                                     size_t location_catalog_entry_index,
540                                     uint16_t number_of_dex_registers,
541                                     size_t number_of_location_catalog_entries) {
542     DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
543     DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
544 
545     if (number_of_location_catalog_entries == 1) {
546       // We do not allocate space for location maps in the case of a
547       // single-entry location catalog, as it is useless.
548       return;
549     }
550 
551     // The bit offset of the beginning of the map locations.
552     size_t map_locations_offset_in_bits =
553         GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
554     // The bit size of an entry.
555     size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
556     // The bit offset where `index_in_dex_register_map` is located.
557     size_t entry_offset_in_bits =
558         map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
559     region_.StoreBits(entry_offset_in_bits, location_catalog_entry_index, map_entry_size_in_bits);
560   }
561 
SetLiveBitMask(uint16_t number_of_dex_registers,const BitVector & live_dex_registers_mask)562   void SetLiveBitMask(uint16_t number_of_dex_registers,
563                       const BitVector& live_dex_registers_mask) {
564     size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
565     for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
566       region_.StoreBit(live_bit_mask_offset_in_bits + i, live_dex_registers_mask.IsBitSet(i));
567     }
568   }
569 
IsDexRegisterLive(uint16_t dex_register_number)570   bool IsDexRegisterLive(uint16_t dex_register_number) const {
571     size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
572     return region_.LoadBit(live_bit_mask_offset_in_bits + dex_register_number);
573   }
574 
GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers)575   size_t GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers) const {
576     size_t number_of_live_dex_registers = 0;
577     for (size_t i = 0; i < number_of_dex_registers; ++i) {
578       if (IsDexRegisterLive(i)) {
579         ++number_of_live_dex_registers;
580       }
581     }
582     return number_of_live_dex_registers;
583   }
584 
GetLiveBitMaskOffset()585   static size_t GetLiveBitMaskOffset() {
586     return kFixedSize;
587   }
588 
589   // Compute the size of the live register bit mask (in bytes), for a
590   // method having `number_of_dex_registers` Dex registers.
GetLiveBitMaskSize(uint16_t number_of_dex_registers)591   static size_t GetLiveBitMaskSize(uint16_t number_of_dex_registers) {
592     return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte;
593   }
594 
GetLocationMappingDataOffset(uint16_t number_of_dex_registers)595   static size_t GetLocationMappingDataOffset(uint16_t number_of_dex_registers) {
596     return GetLiveBitMaskOffset() + GetLiveBitMaskSize(number_of_dex_registers);
597   }
598 
GetLocationMappingDataSize(uint16_t number_of_dex_registers,size_t number_of_location_catalog_entries)599   size_t GetLocationMappingDataSize(uint16_t number_of_dex_registers,
600                                     size_t number_of_location_catalog_entries) const {
601     size_t location_mapping_data_size_in_bits =
602         GetNumberOfLiveDexRegisters(number_of_dex_registers)
603         * SingleEntrySizeInBits(number_of_location_catalog_entries);
604     return RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
605   }
606 
607   // Return the size of a map entry in bits.  Note that if
608   // `number_of_location_catalog_entries` equals 1, this function returns 0,
609   // which is fine, as there is no need to allocate a map for a
610   // single-entry location catalog; the only valid location catalog entry index
611   // for a live register in this case is 0 and there is no need to
612   // store it.
SingleEntrySizeInBits(size_t number_of_location_catalog_entries)613   static size_t SingleEntrySizeInBits(size_t number_of_location_catalog_entries) {
614     // Handle the case of 0, as we cannot pass 0 to art::WhichPowerOf2.
615     return number_of_location_catalog_entries == 0
616         ? 0u
617         : WhichPowerOf2(RoundUpToPowerOfTwo(number_of_location_catalog_entries));
618   }
619 
620   // Return the size of the DexRegisterMap object, in bytes.
Size()621   size_t Size() const {
622     return region_.size();
623   }
624 
625   void Dump(VariableIndentationOutputStream* vios,
626             const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
627 
628  private:
629   // Return the index in the Dex register map corresponding to the Dex
630   // register number `dex_register_number`.
GetIndexInDexRegisterMap(uint16_t dex_register_number)631   size_t GetIndexInDexRegisterMap(uint16_t dex_register_number) const {
632     if (!IsDexRegisterLive(dex_register_number)) {
633       return kInvalidIndexInDexRegisterMap;
634     }
635     return GetNumberOfLiveDexRegisters(dex_register_number);
636   }
637 
638   // Special (invalid) Dex register map entry index meaning that there
639   // is no index in the map for a given Dex register (i.e., it must
640   // have been mapped to a DexRegisterLocation::Kind::kNone location).
641   static constexpr size_t kInvalidIndexInDexRegisterMap = -1;
642 
643   static constexpr int kFixedSize = 0;
644 
645   MemoryRegion region_;
646 
647   friend class CodeInfo;
648   friend class StackMapStream;
649 };
650 
651 // Represents bit range of bit-packed integer field.
652 // We reuse the idea from ULEB128p1 to support encoding of -1 (aka 0xFFFFFFFF).
653 // If min_value is set to -1, we implicitly subtract one from any loaded value,
654 // and add one to any stored value. This is generalized to any negative values.
655 // In other words, min_value acts as a base and the stored value is added to it.
656 struct FieldEncoding {
657   FieldEncoding(size_t start_offset, size_t end_offset, int32_t min_value = 0)
start_offset_FieldEncoding658       : start_offset_(start_offset), end_offset_(end_offset), min_value_(min_value) {
659     DCHECK_LE(start_offset_, end_offset_);
660     DCHECK_LE(BitSize(), 32u);
661   }
662 
BitSizeFieldEncoding663   ALWAYS_INLINE size_t BitSize() const { return end_offset_ - start_offset_; }
664 
LoadFieldEncoding665   ALWAYS_INLINE int32_t Load(const MemoryRegion& region) const {
666     DCHECK_LE(end_offset_, region.size_in_bits());
667     const size_t bit_count = BitSize();
668     if (bit_count == 0) {
669       // Do not touch any memory if the range is empty.
670       return min_value_;
671     }
672     uint8_t* address = region.start() + start_offset_ / kBitsPerByte;
673     const uint32_t shift = start_offset_ & (kBitsPerByte - 1);
674     // Load the value (reading only the strictly needed bytes).
675     const uint32_t load_bit_count = shift + bit_count;
676     uint32_t value = *address++ >> shift;
677     if (load_bit_count > 8) {
678       value |= static_cast<uint32_t>(*address++) << (8 - shift);
679       if (load_bit_count > 16) {
680         value |= static_cast<uint32_t>(*address++) << (16 - shift);
681         if (load_bit_count > 24) {
682           value |= static_cast<uint32_t>(*address++) << (24 - shift);
683           if (load_bit_count > 32) {
684             value |= static_cast<uint32_t>(*address++) << (32 - shift);
685           }
686         }
687       }
688     }
689     // Clear unwanted most significant bits.
690     uint32_t clear_bit_count = 32 - bit_count;
691     value = (value << clear_bit_count) >> clear_bit_count;
692     return value + min_value_;
693   }
694 
StoreFieldEncoding695   ALWAYS_INLINE void Store(MemoryRegion region, int32_t value) const {
696     region.StoreBits(start_offset_, value - min_value_, BitSize());
697     DCHECK_EQ(Load(region), value);
698   }
699 
700  private:
701   size_t start_offset_;
702   size_t end_offset_;
703   int32_t min_value_;
704 };
705 
706 class StackMapEncoding {
707  public:
StackMapEncoding()708   StackMapEncoding() {}
709 
710   // Set stack map bit layout based on given sizes.
711   // Returns the size of stack map in bytes.
SetFromSizes(size_t native_pc_max,size_t dex_pc_max,size_t dex_register_map_size,size_t inline_info_size,size_t register_mask_max,size_t stack_mask_bit_size)712   size_t SetFromSizes(size_t native_pc_max,
713                       size_t dex_pc_max,
714                       size_t dex_register_map_size,
715                       size_t inline_info_size,
716                       size_t register_mask_max,
717                       size_t stack_mask_bit_size) {
718     size_t bit_offset = 0;
719     DCHECK_EQ(kNativePcBitOffset, bit_offset);
720     bit_offset += MinimumBitsToStore(native_pc_max);
721 
722     dex_pc_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
723     bit_offset += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max);
724 
725     // We also need +1 for kNoDexRegisterMap, but since the size is strictly
726     // greater than any offset we might try to encode, we already implicitly have it.
727     dex_register_map_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
728     bit_offset += MinimumBitsToStore(dex_register_map_size);
729 
730     // We also need +1 for kNoInlineInfo, but since the inline_info_size is strictly
731     // greater than the offset we might try to encode, we already implicitly have it.
732     // If inline_info_size is zero, we can encode only kNoInlineInfo (in zero bits).
733     inline_info_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
734     if (inline_info_size != 0) {
735       bit_offset += MinimumBitsToStore(dex_register_map_size + inline_info_size);
736     }
737 
738     register_mask_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
739     bit_offset += MinimumBitsToStore(register_mask_max);
740 
741     stack_mask_bit_offset_ = dchecked_integral_cast<uint8_t>(bit_offset);
742     bit_offset += stack_mask_bit_size;
743 
744     return RoundUp(bit_offset, kBitsPerByte) / kBitsPerByte;
745   }
746 
GetNativePcEncoding()747   ALWAYS_INLINE FieldEncoding GetNativePcEncoding() const {
748     return FieldEncoding(kNativePcBitOffset, dex_pc_bit_offset_);
749   }
GetDexPcEncoding()750   ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const {
751     return FieldEncoding(dex_pc_bit_offset_, dex_register_map_bit_offset_, -1 /* min_value */);
752   }
GetDexRegisterMapEncoding()753   ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const {
754     return FieldEncoding(dex_register_map_bit_offset_, inline_info_bit_offset_, -1 /* min_value */);
755   }
GetInlineInfoEncoding()756   ALWAYS_INLINE FieldEncoding GetInlineInfoEncoding() const {
757     return FieldEncoding(inline_info_bit_offset_, register_mask_bit_offset_, -1 /* min_value */);
758   }
GetRegisterMaskEncoding()759   ALWAYS_INLINE FieldEncoding GetRegisterMaskEncoding() const {
760     return FieldEncoding(register_mask_bit_offset_, stack_mask_bit_offset_);
761   }
GetStackMaskBitOffset()762   ALWAYS_INLINE size_t GetStackMaskBitOffset() const {
763     // The end offset is not encoded. It is implicitly the end of stack map entry.
764     return stack_mask_bit_offset_;
765   }
766 
767   void Dump(VariableIndentationOutputStream* vios) const;
768 
769  private:
770   static constexpr size_t kNativePcBitOffset = 0;
771   uint8_t dex_pc_bit_offset_;
772   uint8_t dex_register_map_bit_offset_;
773   uint8_t inline_info_bit_offset_;
774   uint8_t register_mask_bit_offset_;
775   uint8_t stack_mask_bit_offset_;
776 };
777 
778 /**
779  * A Stack Map holds compilation information for a specific PC necessary for:
780  * - Mapping it to a dex PC,
781  * - Knowing which stack entries are objects,
782  * - Knowing which registers hold objects,
783  * - Knowing the inlining information,
784  * - Knowing the values of dex registers.
785  *
786  * The information is of the form:
787  *
788  *   [native_pc_offset, dex_pc, dex_register_map_offset, inlining_info_offset, register_mask,
789  *   stack_mask].
790  */
791 class StackMap {
792  public:
StackMap()793   StackMap() {}
StackMap(MemoryRegion region)794   explicit StackMap(MemoryRegion region) : region_(region) {}
795 
IsValid()796   ALWAYS_INLINE bool IsValid() const { return region_.pointer() != nullptr; }
797 
GetDexPc(const StackMapEncoding & encoding)798   ALWAYS_INLINE uint32_t GetDexPc(const StackMapEncoding& encoding) const {
799     return encoding.GetDexPcEncoding().Load(region_);
800   }
801 
SetDexPc(const StackMapEncoding & encoding,uint32_t dex_pc)802   ALWAYS_INLINE void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) {
803     encoding.GetDexPcEncoding().Store(region_, dex_pc);
804   }
805 
GetNativePcOffset(const StackMapEncoding & encoding)806   ALWAYS_INLINE uint32_t GetNativePcOffset(const StackMapEncoding& encoding) const {
807     return encoding.GetNativePcEncoding().Load(region_);
808   }
809 
SetNativePcOffset(const StackMapEncoding & encoding,uint32_t native_pc_offset)810   ALWAYS_INLINE void SetNativePcOffset(const StackMapEncoding& encoding, uint32_t native_pc_offset) {
811     encoding.GetNativePcEncoding().Store(region_, native_pc_offset);
812   }
813 
GetDexRegisterMapOffset(const StackMapEncoding & encoding)814   ALWAYS_INLINE uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const {
815     return encoding.GetDexRegisterMapEncoding().Load(region_);
816   }
817 
SetDexRegisterMapOffset(const StackMapEncoding & encoding,uint32_t offset)818   ALWAYS_INLINE void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) {
819     encoding.GetDexRegisterMapEncoding().Store(region_, offset);
820   }
821 
GetInlineDescriptorOffset(const StackMapEncoding & encoding)822   ALWAYS_INLINE uint32_t GetInlineDescriptorOffset(const StackMapEncoding& encoding) const {
823     return encoding.GetInlineInfoEncoding().Load(region_);
824   }
825 
SetInlineDescriptorOffset(const StackMapEncoding & encoding,uint32_t offset)826   ALWAYS_INLINE void SetInlineDescriptorOffset(const StackMapEncoding& encoding, uint32_t offset) {
827     encoding.GetInlineInfoEncoding().Store(region_, offset);
828   }
829 
GetRegisterMask(const StackMapEncoding & encoding)830   ALWAYS_INLINE uint32_t GetRegisterMask(const StackMapEncoding& encoding) const {
831     return encoding.GetRegisterMaskEncoding().Load(region_);
832   }
833 
SetRegisterMask(const StackMapEncoding & encoding,uint32_t mask)834   ALWAYS_INLINE void SetRegisterMask(const StackMapEncoding& encoding, uint32_t mask) {
835     encoding.GetRegisterMaskEncoding().Store(region_, mask);
836   }
837 
GetNumberOfStackMaskBits(const StackMapEncoding & encoding)838   ALWAYS_INLINE size_t GetNumberOfStackMaskBits(const StackMapEncoding& encoding) const {
839     return region_.size_in_bits() - encoding.GetStackMaskBitOffset();
840   }
841 
GetStackMaskBit(const StackMapEncoding & encoding,size_t index)842   ALWAYS_INLINE bool GetStackMaskBit(const StackMapEncoding& encoding, size_t index) const {
843     return region_.LoadBit(encoding.GetStackMaskBitOffset() + index);
844   }
845 
SetStackMaskBit(const StackMapEncoding & encoding,size_t index,bool value)846   ALWAYS_INLINE void SetStackMaskBit(const StackMapEncoding& encoding, size_t index, bool value) {
847     region_.StoreBit(encoding.GetStackMaskBitOffset() + index, value);
848   }
849 
HasDexRegisterMap(const StackMapEncoding & encoding)850   ALWAYS_INLINE bool HasDexRegisterMap(const StackMapEncoding& encoding) const {
851     return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap;
852   }
853 
HasInlineInfo(const StackMapEncoding & encoding)854   ALWAYS_INLINE bool HasInlineInfo(const StackMapEncoding& encoding) const {
855     return GetInlineDescriptorOffset(encoding) != kNoInlineInfo;
856   }
857 
Equals(const StackMap & other)858   ALWAYS_INLINE bool Equals(const StackMap& other) const {
859     return region_.pointer() == other.region_.pointer() && region_.size() == other.region_.size();
860   }
861 
862   void Dump(VariableIndentationOutputStream* vios,
863             const CodeInfo& code_info,
864             const CodeInfoEncoding& encoding,
865             uint32_t code_offset,
866             uint16_t number_of_dex_registers,
867             const std::string& header_suffix = "") const;
868 
869   // Special (invalid) offset for the DexRegisterMapOffset field meaning
870   // that there is no Dex register map for this stack map.
871   static constexpr uint32_t kNoDexRegisterMap = -1;
872 
873   // Special (invalid) offset for the InlineDescriptorOffset field meaning
874   // that there is no inline info for this stack map.
875   static constexpr uint32_t kNoInlineInfo = -1;
876 
877  private:
878   static constexpr int kFixedSize = 0;
879 
880   MemoryRegion region_;
881 
882   friend class StackMapStream;
883 };
884 
885 class InlineInfoEncoding {
886  public:
SetFromSizes(size_t method_index_max,size_t dex_pc_max,size_t invoke_type_max,size_t dex_register_map_size)887   void SetFromSizes(size_t method_index_max,
888                     size_t dex_pc_max,
889                     size_t invoke_type_max,
890                     size_t dex_register_map_size) {
891     total_bit_size_ = kMethodIndexBitOffset;
892     total_bit_size_ += MinimumBitsToStore(method_index_max);
893 
894     dex_pc_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
895     total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max);
896 
897     invoke_type_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
898     total_bit_size_ += MinimumBitsToStore(invoke_type_max);
899 
900     // We also need +1 for kNoDexRegisterMap, but since the size is strictly
901     // greater than any offset we might try to encode, we already implicitly have it.
902     dex_register_map_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
903     total_bit_size_ += MinimumBitsToStore(dex_register_map_size);
904   }
905 
GetMethodIndexEncoding()906   ALWAYS_INLINE FieldEncoding GetMethodIndexEncoding() const {
907     return FieldEncoding(kMethodIndexBitOffset, dex_pc_bit_offset_);
908   }
GetDexPcEncoding()909   ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const {
910     return FieldEncoding(dex_pc_bit_offset_, invoke_type_bit_offset_, -1 /* min_value */);
911   }
GetInvokeTypeEncoding()912   ALWAYS_INLINE FieldEncoding GetInvokeTypeEncoding() const {
913     return FieldEncoding(invoke_type_bit_offset_, dex_register_map_bit_offset_);
914   }
GetDexRegisterMapEncoding()915   ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const {
916     return FieldEncoding(dex_register_map_bit_offset_, total_bit_size_, -1 /* min_value */);
917   }
GetEntrySize()918   ALWAYS_INLINE size_t GetEntrySize() const {
919     return RoundUp(total_bit_size_, kBitsPerByte) / kBitsPerByte;
920   }
921 
922   void Dump(VariableIndentationOutputStream* vios) const;
923 
924  private:
925   static constexpr uint8_t kIsLastBitOffset = 0;
926   static constexpr uint8_t kMethodIndexBitOffset = 1;
927   uint8_t dex_pc_bit_offset_;
928   uint8_t invoke_type_bit_offset_;
929   uint8_t dex_register_map_bit_offset_;
930   uint8_t total_bit_size_;
931 };
932 
933 /**
934  * Inline information for a specific PC. The information is of the form:
935  *
936  *   [is_last, method_index, dex_pc, invoke_type, dex_register_map_offset]+.
937  */
938 class InlineInfo {
939  public:
InlineInfo(MemoryRegion region)940   explicit InlineInfo(MemoryRegion region) : region_(region) {
941   }
942 
GetDepth(const InlineInfoEncoding & encoding)943   ALWAYS_INLINE uint32_t GetDepth(const InlineInfoEncoding& encoding) const {
944     size_t depth = 0;
945     while (!GetRegionAtDepth(encoding, depth++).LoadBit(0)) { }  // Check is_last bit.
946     return depth;
947   }
948 
SetDepth(const InlineInfoEncoding & encoding,uint32_t depth)949   ALWAYS_INLINE void SetDepth(const InlineInfoEncoding& encoding, uint32_t depth) {
950     DCHECK_GT(depth, 0u);
951     for (size_t d = 0; d < depth; ++d) {
952       GetRegionAtDepth(encoding, d).StoreBit(0, d == depth - 1);  // Set is_last bit.
953     }
954   }
955 
GetMethodIndexAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)956   ALWAYS_INLINE uint32_t GetMethodIndexAtDepth(const InlineInfoEncoding& encoding,
957                                                uint32_t depth) const {
958     return encoding.GetMethodIndexEncoding().Load(GetRegionAtDepth(encoding, depth));
959   }
960 
SetMethodIndexAtDepth(const InlineInfoEncoding & encoding,uint32_t depth,uint32_t index)961   ALWAYS_INLINE void SetMethodIndexAtDepth(const InlineInfoEncoding& encoding,
962                                            uint32_t depth,
963                                            uint32_t index) {
964     encoding.GetMethodIndexEncoding().Store(GetRegionAtDepth(encoding, depth), index);
965   }
966 
GetDexPcAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)967   ALWAYS_INLINE uint32_t GetDexPcAtDepth(const InlineInfoEncoding& encoding,
968                                          uint32_t depth) const {
969     return encoding.GetDexPcEncoding().Load(GetRegionAtDepth(encoding, depth));
970   }
971 
SetDexPcAtDepth(const InlineInfoEncoding & encoding,uint32_t depth,uint32_t dex_pc)972   ALWAYS_INLINE void SetDexPcAtDepth(const InlineInfoEncoding& encoding,
973                                      uint32_t depth,
974                                      uint32_t dex_pc) {
975     encoding.GetDexPcEncoding().Store(GetRegionAtDepth(encoding, depth), dex_pc);
976   }
977 
GetInvokeTypeAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)978   ALWAYS_INLINE uint32_t GetInvokeTypeAtDepth(const InlineInfoEncoding& encoding,
979                                               uint32_t depth) const {
980     return encoding.GetInvokeTypeEncoding().Load(GetRegionAtDepth(encoding, depth));
981   }
982 
SetInvokeTypeAtDepth(const InlineInfoEncoding & encoding,uint32_t depth,uint32_t invoke_type)983   ALWAYS_INLINE void SetInvokeTypeAtDepth(const InlineInfoEncoding& encoding,
984                                           uint32_t depth,
985                                           uint32_t invoke_type) {
986     encoding.GetInvokeTypeEncoding().Store(GetRegionAtDepth(encoding, depth), invoke_type);
987   }
988 
GetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)989   ALWAYS_INLINE uint32_t GetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding,
990                                                         uint32_t depth) const {
991     return encoding.GetDexRegisterMapEncoding().Load(GetRegionAtDepth(encoding, depth));
992   }
993 
SetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding & encoding,uint32_t depth,uint32_t offset)994   ALWAYS_INLINE void SetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding,
995                                                     uint32_t depth,
996                                                     uint32_t offset) {
997     encoding.GetDexRegisterMapEncoding().Store(GetRegionAtDepth(encoding, depth), offset);
998   }
999 
HasDexRegisterMapAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)1000   ALWAYS_INLINE bool HasDexRegisterMapAtDepth(const InlineInfoEncoding& encoding,
1001                                               uint32_t depth) const {
1002     return GetDexRegisterMapOffsetAtDepth(encoding, depth) != StackMap::kNoDexRegisterMap;
1003   }
1004 
1005   void Dump(VariableIndentationOutputStream* vios,
1006             const CodeInfo& info,
1007             uint16_t* number_of_dex_registers) const;
1008 
1009  private:
GetRegionAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)1010   ALWAYS_INLINE MemoryRegion GetRegionAtDepth(const InlineInfoEncoding& encoding,
1011                                               uint32_t depth) const {
1012     size_t entry_size = encoding.GetEntrySize();
1013     DCHECK_GT(entry_size, 0u);
1014     return region_.Subregion(depth * entry_size, entry_size);
1015   }
1016 
1017   MemoryRegion region_;
1018 };
1019 
1020 // Most of the fields are encoded as ULEB128 to save space.
1021 struct CodeInfoEncoding {
1022   uint32_t non_header_size;
1023   uint32_t number_of_stack_maps;
1024   uint32_t stack_map_size_in_bytes;
1025   uint32_t number_of_location_catalog_entries;
1026   StackMapEncoding stack_map_encoding;
1027   InlineInfoEncoding inline_info_encoding;
1028   uint8_t header_size;
1029 
CodeInfoEncodingCodeInfoEncoding1030   CodeInfoEncoding() { }
1031 
CodeInfoEncodingCodeInfoEncoding1032   explicit CodeInfoEncoding(const void* data) {
1033     const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
1034     non_header_size = DecodeUnsignedLeb128(&ptr);
1035     number_of_stack_maps = DecodeUnsignedLeb128(&ptr);
1036     stack_map_size_in_bytes = DecodeUnsignedLeb128(&ptr);
1037     number_of_location_catalog_entries = DecodeUnsignedLeb128(&ptr);
1038     static_assert(alignof(StackMapEncoding) == 1,
1039                   "StackMapEncoding should not require alignment");
1040     stack_map_encoding = *reinterpret_cast<const StackMapEncoding*>(ptr);
1041     ptr += sizeof(StackMapEncoding);
1042     if (stack_map_encoding.GetInlineInfoEncoding().BitSize() > 0) {
1043       static_assert(alignof(InlineInfoEncoding) == 1,
1044                     "InlineInfoEncoding should not require alignment");
1045       inline_info_encoding = *reinterpret_cast<const InlineInfoEncoding*>(ptr);
1046       ptr += sizeof(InlineInfoEncoding);
1047     } else {
1048       inline_info_encoding = InlineInfoEncoding{}; // NOLINT.
1049     }
1050     header_size = dchecked_integral_cast<uint8_t>(ptr - reinterpret_cast<const uint8_t*>(data));
1051   }
1052 
1053   template<typename Vector>
CompressCodeInfoEncoding1054   void Compress(Vector* dest) const {
1055     EncodeUnsignedLeb128(dest, non_header_size);
1056     EncodeUnsignedLeb128(dest, number_of_stack_maps);
1057     EncodeUnsignedLeb128(dest, stack_map_size_in_bytes);
1058     EncodeUnsignedLeb128(dest, number_of_location_catalog_entries);
1059     const uint8_t* stack_map_ptr = reinterpret_cast<const uint8_t*>(&stack_map_encoding);
1060     dest->insert(dest->end(), stack_map_ptr, stack_map_ptr + sizeof(StackMapEncoding));
1061     if (stack_map_encoding.GetInlineInfoEncoding().BitSize() > 0) {
1062       const uint8_t* inline_info_ptr = reinterpret_cast<const uint8_t*>(&inline_info_encoding);
1063       dest->insert(dest->end(), inline_info_ptr, inline_info_ptr + sizeof(InlineInfoEncoding));
1064     }
1065   }
1066 };
1067 
1068 /**
1069  * Wrapper around all compiler information collected for a method.
1070  * The information is of the form:
1071  *
1072  *   [CodeInfoEncoding, StackMap+, DexRegisterLocationCatalog+, DexRegisterMap+, InlineInfo*]
1073  *
1074  * where CodeInfoEncoding is of the form:
1075  *
1076  *   [non_header_size, number_of_stack_maps, stack_map_size_in_bytes,
1077  *    number_of_location_catalog_entries, StackMapEncoding]
1078  */
1079 class CodeInfo {
1080  public:
CodeInfo(MemoryRegion region)1081   explicit CodeInfo(MemoryRegion region) : region_(region) {
1082   }
1083 
CodeInfo(const void * data)1084   explicit CodeInfo(const void* data) {
1085     CodeInfoEncoding encoding = CodeInfoEncoding(data);
1086     region_ = MemoryRegion(const_cast<void*>(data),
1087                            encoding.header_size + encoding.non_header_size);
1088   }
1089 
ExtractEncoding()1090   CodeInfoEncoding ExtractEncoding() const {
1091     return CodeInfoEncoding(region_.start());
1092   }
1093 
HasInlineInfo(const CodeInfoEncoding & encoding)1094   bool HasInlineInfo(const CodeInfoEncoding& encoding) const {
1095     return encoding.stack_map_encoding.GetInlineInfoEncoding().BitSize() > 0;
1096   }
1097 
GetDexRegisterLocationCatalog(const CodeInfoEncoding & encoding)1098   DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const CodeInfoEncoding& encoding) const {
1099     return DexRegisterLocationCatalog(region_.Subregion(
1100         GetDexRegisterLocationCatalogOffset(encoding),
1101         GetDexRegisterLocationCatalogSize(encoding)));
1102   }
1103 
GetStackMapAt(size_t i,const CodeInfoEncoding & encoding)1104   StackMap GetStackMapAt(size_t i, const CodeInfoEncoding& encoding) const {
1105     size_t stack_map_size = encoding.stack_map_size_in_bytes;
1106     return StackMap(GetStackMaps(encoding).Subregion(i * stack_map_size, stack_map_size));
1107   }
1108 
GetNumberOfLocationCatalogEntries(const CodeInfoEncoding & encoding)1109   uint32_t GetNumberOfLocationCatalogEntries(const CodeInfoEncoding& encoding) const {
1110     return encoding.number_of_location_catalog_entries;
1111   }
1112 
GetDexRegisterLocationCatalogSize(const CodeInfoEncoding & encoding)1113   uint32_t GetDexRegisterLocationCatalogSize(const CodeInfoEncoding& encoding) const {
1114     return ComputeDexRegisterLocationCatalogSize(GetDexRegisterLocationCatalogOffset(encoding),
1115                                                  GetNumberOfLocationCatalogEntries(encoding));
1116   }
1117 
GetNumberOfStackMaps(const CodeInfoEncoding & encoding)1118   uint32_t GetNumberOfStackMaps(const CodeInfoEncoding& encoding) const {
1119     return encoding.number_of_stack_maps;
1120   }
1121 
1122   // Get the size of all the stack maps of this CodeInfo object, in bytes.
GetStackMapsSize(const CodeInfoEncoding & encoding)1123   size_t GetStackMapsSize(const CodeInfoEncoding& encoding) const {
1124     return encoding.stack_map_size_in_bytes * GetNumberOfStackMaps(encoding);
1125   }
1126 
GetDexRegisterLocationCatalogOffset(const CodeInfoEncoding & encoding)1127   uint32_t GetDexRegisterLocationCatalogOffset(const CodeInfoEncoding& encoding) const {
1128     return GetStackMapsOffset(encoding) + GetStackMapsSize(encoding);
1129   }
1130 
GetDexRegisterMapsOffset(const CodeInfoEncoding & encoding)1131   size_t GetDexRegisterMapsOffset(const CodeInfoEncoding& encoding) const {
1132     return GetDexRegisterLocationCatalogOffset(encoding)
1133          + GetDexRegisterLocationCatalogSize(encoding);
1134   }
1135 
GetStackMapsOffset(const CodeInfoEncoding & encoding)1136   uint32_t GetStackMapsOffset(const CodeInfoEncoding& encoding) const {
1137     return encoding.header_size;
1138   }
1139 
GetDexRegisterMapOf(StackMap stack_map,const CodeInfoEncoding & encoding,uint32_t number_of_dex_registers)1140   DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
1141                                      const CodeInfoEncoding& encoding,
1142                                      uint32_t number_of_dex_registers) const {
1143     if (!stack_map.HasDexRegisterMap(encoding.stack_map_encoding)) {
1144       return DexRegisterMap();
1145     } else {
1146       uint32_t offset = GetDexRegisterMapsOffset(encoding)
1147                         + stack_map.GetDexRegisterMapOffset(encoding.stack_map_encoding);
1148       size_t size = ComputeDexRegisterMapSizeOf(encoding, offset, number_of_dex_registers);
1149       return DexRegisterMap(region_.Subregion(offset, size));
1150     }
1151   }
1152 
1153   // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
GetDexRegisterMapAtDepth(uint8_t depth,InlineInfo inline_info,const CodeInfoEncoding & encoding,uint32_t number_of_dex_registers)1154   DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
1155                                           InlineInfo inline_info,
1156                                           const CodeInfoEncoding& encoding,
1157                                           uint32_t number_of_dex_registers) const {
1158     if (!inline_info.HasDexRegisterMapAtDepth(encoding.inline_info_encoding, depth)) {
1159       return DexRegisterMap();
1160     } else {
1161       uint32_t offset = GetDexRegisterMapsOffset(encoding) +
1162           inline_info.GetDexRegisterMapOffsetAtDepth(encoding.inline_info_encoding, depth);
1163       size_t size = ComputeDexRegisterMapSizeOf(encoding, offset, number_of_dex_registers);
1164       return DexRegisterMap(region_.Subregion(offset, size));
1165     }
1166   }
1167 
GetInlineInfoOf(StackMap stack_map,const CodeInfoEncoding & encoding)1168   InlineInfo GetInlineInfoOf(StackMap stack_map, const CodeInfoEncoding& encoding) const {
1169     DCHECK(stack_map.HasInlineInfo(encoding.stack_map_encoding));
1170     uint32_t offset = stack_map.GetInlineDescriptorOffset(encoding.stack_map_encoding)
1171                       + GetDexRegisterMapsOffset(encoding);
1172     return InlineInfo(region_.Subregion(offset, region_.size() - offset));
1173   }
1174 
GetStackMapForDexPc(uint32_t dex_pc,const CodeInfoEncoding & encoding)1175   StackMap GetStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const {
1176     for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) {
1177       StackMap stack_map = GetStackMapAt(i, encoding);
1178       if (stack_map.GetDexPc(encoding.stack_map_encoding) == dex_pc) {
1179         return stack_map;
1180       }
1181     }
1182     return StackMap();
1183   }
1184 
1185   // Searches the stack map list backwards because catch stack maps are stored
1186   // at the end.
GetCatchStackMapForDexPc(uint32_t dex_pc,const CodeInfoEncoding & encoding)1187   StackMap GetCatchStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const {
1188     for (size_t i = GetNumberOfStackMaps(encoding); i > 0; --i) {
1189       StackMap stack_map = GetStackMapAt(i - 1, encoding);
1190       if (stack_map.GetDexPc(encoding.stack_map_encoding) == dex_pc) {
1191         return stack_map;
1192       }
1193     }
1194     return StackMap();
1195   }
1196 
GetOsrStackMapForDexPc(uint32_t dex_pc,const CodeInfoEncoding & encoding)1197   StackMap GetOsrStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const {
1198     size_t e = GetNumberOfStackMaps(encoding);
1199     if (e == 0) {
1200       // There cannot be OSR stack map if there is no stack map.
1201       return StackMap();
1202     }
1203     // Walk over all stack maps. If two consecutive stack maps are identical, then we
1204     // have found a stack map suitable for OSR.
1205     const StackMapEncoding& stack_map_encoding = encoding.stack_map_encoding;
1206     for (size_t i = 0; i < e - 1; ++i) {
1207       StackMap stack_map = GetStackMapAt(i, encoding);
1208       if (stack_map.GetDexPc(stack_map_encoding) == dex_pc) {
1209         StackMap other = GetStackMapAt(i + 1, encoding);
1210         if (other.GetDexPc(stack_map_encoding) == dex_pc &&
1211             other.GetNativePcOffset(stack_map_encoding) ==
1212                 stack_map.GetNativePcOffset(stack_map_encoding)) {
1213           DCHECK_EQ(other.GetDexRegisterMapOffset(stack_map_encoding),
1214                     stack_map.GetDexRegisterMapOffset(stack_map_encoding));
1215           DCHECK(!stack_map.HasInlineInfo(stack_map_encoding));
1216           if (i < e - 2) {
1217             // Make sure there are not three identical stack maps following each other.
1218             DCHECK_NE(stack_map.GetNativePcOffset(stack_map_encoding),
1219                       GetStackMapAt(i + 2, encoding).GetNativePcOffset(stack_map_encoding));
1220           }
1221           return stack_map;
1222         }
1223       }
1224     }
1225     return StackMap();
1226   }
1227 
GetStackMapForNativePcOffset(uint32_t native_pc_offset,const CodeInfoEncoding & encoding)1228   StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset,
1229                                         const CodeInfoEncoding& encoding) const {
1230     // TODO: Safepoint stack maps are sorted by native_pc_offset but catch stack
1231     //       maps are not. If we knew that the method does not have try/catch,
1232     //       we could do binary search.
1233     for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) {
1234       StackMap stack_map = GetStackMapAt(i, encoding);
1235       if (stack_map.GetNativePcOffset(encoding.stack_map_encoding) == native_pc_offset) {
1236         return stack_map;
1237       }
1238     }
1239     return StackMap();
1240   }
1241 
1242   // Dump this CodeInfo object on `os`.  `code_offset` is the (absolute)
1243   // native PC of the compiled method and `number_of_dex_registers` the
1244   // number of Dex virtual registers used in this method.  If
1245   // `dump_stack_maps` is true, also dump the stack maps and the
1246   // associated Dex register maps.
1247   void Dump(VariableIndentationOutputStream* vios,
1248             uint32_t code_offset,
1249             uint16_t number_of_dex_registers,
1250             bool dump_stack_maps) const;
1251 
1252  private:
GetStackMaps(const CodeInfoEncoding & encoding)1253   MemoryRegion GetStackMaps(const CodeInfoEncoding& encoding) const {
1254     return region_.size() == 0
1255         ? MemoryRegion()
1256         : region_.Subregion(GetStackMapsOffset(encoding), GetStackMapsSize(encoding));
1257   }
1258 
1259   // Compute the size of the Dex register map associated to the stack map at
1260   // `dex_register_map_offset_in_code_info`.
ComputeDexRegisterMapSizeOf(const CodeInfoEncoding & encoding,uint32_t dex_register_map_offset_in_code_info,uint16_t number_of_dex_registers)1261   size_t ComputeDexRegisterMapSizeOf(const CodeInfoEncoding& encoding,
1262                                      uint32_t dex_register_map_offset_in_code_info,
1263                                      uint16_t number_of_dex_registers) const {
1264     // Offset where the actual mapping data starts within art::DexRegisterMap.
1265     size_t location_mapping_data_offset_in_dex_register_map =
1266         DexRegisterMap::GetLocationMappingDataOffset(number_of_dex_registers);
1267     // Create a temporary art::DexRegisterMap to be able to call
1268     // art::DexRegisterMap::GetNumberOfLiveDexRegisters and
1269     DexRegisterMap dex_register_map_without_locations(
1270         MemoryRegion(region_.Subregion(dex_register_map_offset_in_code_info,
1271                                        location_mapping_data_offset_in_dex_register_map)));
1272     size_t number_of_live_dex_registers =
1273         dex_register_map_without_locations.GetNumberOfLiveDexRegisters(number_of_dex_registers);
1274     size_t location_mapping_data_size_in_bits =
1275         DexRegisterMap::SingleEntrySizeInBits(GetNumberOfLocationCatalogEntries(encoding))
1276         * number_of_live_dex_registers;
1277     size_t location_mapping_data_size_in_bytes =
1278         RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
1279     size_t dex_register_map_size =
1280         location_mapping_data_offset_in_dex_register_map + location_mapping_data_size_in_bytes;
1281     return dex_register_map_size;
1282   }
1283 
1284   // Compute the size of a Dex register location catalog starting at offset `origin`
1285   // in `region_` and containing `number_of_dex_locations` entries.
ComputeDexRegisterLocationCatalogSize(uint32_t origin,uint32_t number_of_dex_locations)1286   size_t ComputeDexRegisterLocationCatalogSize(uint32_t origin,
1287                                                uint32_t number_of_dex_locations) const {
1288     // TODO: Ideally, we would like to use art::DexRegisterLocationCatalog::Size or
1289     // art::DexRegisterLocationCatalog::FindLocationOffset, but the
1290     // DexRegisterLocationCatalog is not yet built.  Try to factor common code.
1291     size_t offset = origin + DexRegisterLocationCatalog::kFixedSize;
1292 
1293     // Skip the first `number_of_dex_locations - 1` entries.
1294     for (uint16_t i = 0; i < number_of_dex_locations; ++i) {
1295       // Read the first next byte and inspect its first 3 bits to decide
1296       // whether it is a short or a large location.
1297       DexRegisterLocationCatalog::ShortLocation first_byte =
1298           region_.LoadUnaligned<DexRegisterLocationCatalog::ShortLocation>(offset);
1299       DexRegisterLocation::Kind kind =
1300           DexRegisterLocationCatalog::ExtractKindFromShortLocation(first_byte);
1301       if (DexRegisterLocation::IsShortLocationKind(kind)) {
1302         // Short location.  Skip the current byte.
1303         offset += DexRegisterLocationCatalog::SingleShortEntrySize();
1304       } else {
1305         // Large location.  Skip the 5 next bytes.
1306         offset += DexRegisterLocationCatalog::SingleLargeEntrySize();
1307       }
1308     }
1309     size_t size = offset - origin;
1310     return size;
1311   }
1312 
1313   MemoryRegion region_;
1314   friend class StackMapStream;
1315 };
1316 
1317 #undef ELEMENT_BYTE_OFFSET_AFTER
1318 #undef ELEMENT_BIT_OFFSET_AFTER
1319 
1320 }  // namespace art
1321 
1322 #endif  // ART_RUNTIME_STACK_MAP_H_
1323