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 <limits> 21 22 #include "arch/code_offset.h" 23 #include "base/bit_vector.h" 24 #include "base/bit_utils.h" 25 #include "bit_memory_region.h" 26 #include "dex_file.h" 27 #include "memory_region.h" 28 #include "method_info.h" 29 #include "leb128.h" 30 31 namespace art { 32 33 class VariableIndentationOutputStream; 34 35 // Size of a frame slot, in bytes. This constant is a signed value, 36 // to please the compiler in arithmetic operations involving int32_t 37 // (signed) values. 38 static constexpr ssize_t kFrameSlotSize = 4; 39 40 // Size of Dex virtual registers. 41 static constexpr size_t kVRegSize = 4; 42 43 class ArtMethod; 44 class CodeInfo; 45 class StackMapEncoding; 46 struct CodeInfoEncoding; 47 48 /** 49 * Classes in the following file are wrapper on stack map information backed 50 * by a MemoryRegion. As such they read and write to the region, they don't have 51 * their own fields. 52 */ 53 54 // Dex register location container used by DexRegisterMap and StackMapStream. 55 class DexRegisterLocation { 56 public: 57 /* 58 * The location kind used to populate the Dex register information in a 59 * StackMapStream can either be: 60 * - kStack: vreg stored on the stack, value holds the stack offset; 61 * - kInRegister: vreg stored in low 32 bits of a core physical register, 62 * value holds the register number; 63 * - kInRegisterHigh: vreg stored in high 32 bits of a core physical register, 64 * value holds the register number; 65 * - kInFpuRegister: vreg stored in low 32 bits of an FPU register, 66 * value holds the register number; 67 * - kInFpuRegisterHigh: vreg stored in high 32 bits of an FPU register, 68 * value holds the register number; 69 * - kConstant: value holds the constant; 70 * 71 * In addition, DexRegisterMap also uses these values: 72 * - kInStackLargeOffset: value holds a "large" stack offset (greater than 73 * or equal to 128 bytes); 74 * - kConstantLargeValue: value holds a "large" constant (lower than 0, or 75 * or greater than or equal to 32); 76 * - kNone: the register has no location, meaning it has not been set. 77 */ 78 enum class Kind : uint8_t { 79 // Short location kinds, for entries fitting on one byte (3 bits 80 // for the kind, 5 bits for the value) in a DexRegisterMap. 81 kInStack = 0, // 0b000 82 kInRegister = 1, // 0b001 83 kInRegisterHigh = 2, // 0b010 84 kInFpuRegister = 3, // 0b011 85 kInFpuRegisterHigh = 4, // 0b100 86 kConstant = 5, // 0b101 87 88 // Large location kinds, requiring a 5-byte encoding (1 byte for the 89 // kind, 4 bytes for the value). 90 91 // Stack location at a large offset, meaning that the offset value 92 // divided by the stack frame slot size (4 bytes) cannot fit on a 93 // 5-bit unsigned integer (i.e., this offset value is greater than 94 // or equal to 2^5 * 4 = 128 bytes). 95 kInStackLargeOffset = 6, // 0b110 96 97 // Large constant, that cannot fit on a 5-bit signed integer (i.e., 98 // lower than 0, or greater than or equal to 2^5 = 32). 99 kConstantLargeValue = 7, // 0b111 100 101 // Entries with no location are not stored and do not need own marker. 102 kNone = static_cast<uint8_t>(-1), 103 104 kLastLocationKind = kConstantLargeValue 105 }; 106 107 static_assert( 108 sizeof(Kind) == 1u, 109 "art::DexRegisterLocation::Kind has a size different from one byte."); 110 IsShortLocationKind(Kind kind)111 static bool IsShortLocationKind(Kind kind) { 112 switch (kind) { 113 case Kind::kInStack: 114 case Kind::kInRegister: 115 case Kind::kInRegisterHigh: 116 case Kind::kInFpuRegister: 117 case Kind::kInFpuRegisterHigh: 118 case Kind::kConstant: 119 return true; 120 121 case Kind::kInStackLargeOffset: 122 case Kind::kConstantLargeValue: 123 return false; 124 125 case Kind::kNone: 126 LOG(FATAL) << "Unexpected location kind"; 127 } 128 UNREACHABLE(); 129 } 130 131 // Convert `kind` to a "surface" kind, i.e. one that doesn't include 132 // any value with a "large" qualifier. 133 // TODO: Introduce another enum type for the surface kind? ConvertToSurfaceKind(Kind kind)134 static Kind ConvertToSurfaceKind(Kind kind) { 135 switch (kind) { 136 case Kind::kInStack: 137 case Kind::kInRegister: 138 case Kind::kInRegisterHigh: 139 case Kind::kInFpuRegister: 140 case Kind::kInFpuRegisterHigh: 141 case Kind::kConstant: 142 return kind; 143 144 case Kind::kInStackLargeOffset: 145 return Kind::kInStack; 146 147 case Kind::kConstantLargeValue: 148 return Kind::kConstant; 149 150 case Kind::kNone: 151 return kind; 152 } 153 UNREACHABLE(); 154 } 155 156 // Required by art::StackMapStream::LocationCatalogEntriesIndices. DexRegisterLocation()157 DexRegisterLocation() : kind_(Kind::kNone), value_(0) {} 158 DexRegisterLocation(Kind kind,int32_t value)159 DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {} 160 None()161 static DexRegisterLocation None() { 162 return DexRegisterLocation(Kind::kNone, 0); 163 } 164 165 // Get the "surface" kind of the location, i.e., the one that doesn't 166 // include any value with a "large" qualifier. GetKind()167 Kind GetKind() const { 168 return ConvertToSurfaceKind(kind_); 169 } 170 171 // Get the value of the location. GetValue()172 int32_t GetValue() const { return value_; } 173 174 // Get the actual kind of the location. GetInternalKind()175 Kind GetInternalKind() const { return kind_; } 176 177 bool operator==(DexRegisterLocation other) const { 178 return kind_ == other.kind_ && value_ == other.value_; 179 } 180 181 bool operator!=(DexRegisterLocation other) const { 182 return !(*this == other); 183 } 184 185 private: 186 Kind kind_; 187 int32_t value_; 188 189 friend class DexRegisterLocationHashFn; 190 }; 191 192 std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind); 193 194 /** 195 * Store information on unique Dex register locations used in a method. 196 * The information is of the form: 197 * 198 * [DexRegisterLocation+]. 199 * 200 * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind). 201 */ 202 class DexRegisterLocationCatalog { 203 public: DexRegisterLocationCatalog(MemoryRegion region)204 explicit DexRegisterLocationCatalog(MemoryRegion region) : region_(region) {} 205 206 // Short (compressed) location, fitting on one byte. 207 typedef uint8_t ShortLocation; 208 SetRegisterInfo(size_t offset,const DexRegisterLocation & dex_register_location)209 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) { 210 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location); 211 int32_t value = dex_register_location.GetValue(); 212 if (DexRegisterLocation::IsShortLocationKind(kind)) { 213 // Short location. Compress the kind and the value as a single byte. 214 if (kind == DexRegisterLocation::Kind::kInStack) { 215 // Instead of storing stack offsets expressed in bytes for 216 // short stack locations, store slot offsets. A stack offset 217 // is a multiple of 4 (kFrameSlotSize). This means that by 218 // dividing it by 4, we can fit values from the [0, 128) 219 // interval in a short stack location, and not just values 220 // from the [0, 32) interval. 221 DCHECK_EQ(value % kFrameSlotSize, 0); 222 value /= kFrameSlotSize; 223 } 224 DCHECK(IsShortValue(value)) << value; 225 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value)); 226 } else { 227 // Large location. Write the location on one byte and the value 228 // on 4 bytes. 229 DCHECK(!IsShortValue(value)) << value; 230 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) { 231 // Also divide large stack offsets by 4 for the sake of consistency. 232 DCHECK_EQ(value % kFrameSlotSize, 0); 233 value /= kFrameSlotSize; 234 } 235 // Data can be unaligned as the written Dex register locations can 236 // either be 1-byte or 5-byte wide. Use 237 // art::MemoryRegion::StoreUnaligned instead of 238 // art::MemoryRegion::Store to prevent unligned word accesses on ARM. 239 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind); 240 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value); 241 } 242 } 243 244 // Find the offset of the location catalog entry number `location_catalog_entry_index`. FindLocationOffset(size_t location_catalog_entry_index)245 size_t FindLocationOffset(size_t location_catalog_entry_index) const { 246 size_t offset = kFixedSize; 247 // Skip the first `location_catalog_entry_index - 1` entries. 248 for (uint16_t i = 0; i < location_catalog_entry_index; ++i) { 249 // Read the first next byte and inspect its first 3 bits to decide 250 // whether it is a short or a large location. 251 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset); 252 if (DexRegisterLocation::IsShortLocationKind(kind)) { 253 // Short location. Skip the current byte. 254 offset += SingleShortEntrySize(); 255 } else { 256 // Large location. Skip the 5 next bytes. 257 offset += SingleLargeEntrySize(); 258 } 259 } 260 return offset; 261 } 262 263 // Get the internal kind of entry at `location_catalog_entry_index`. GetLocationInternalKind(size_t location_catalog_entry_index)264 DexRegisterLocation::Kind GetLocationInternalKind(size_t location_catalog_entry_index) const { 265 if (location_catalog_entry_index == kNoLocationEntryIndex) { 266 return DexRegisterLocation::Kind::kNone; 267 } 268 return ExtractKindAtOffset(FindLocationOffset(location_catalog_entry_index)); 269 } 270 271 // Get the (surface) kind and value of entry at `location_catalog_entry_index`. GetDexRegisterLocation(size_t location_catalog_entry_index)272 DexRegisterLocation GetDexRegisterLocation(size_t location_catalog_entry_index) const { 273 if (location_catalog_entry_index == kNoLocationEntryIndex) { 274 return DexRegisterLocation::None(); 275 } 276 size_t offset = FindLocationOffset(location_catalog_entry_index); 277 // Read the first byte and inspect its first 3 bits to get the location. 278 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset); 279 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte); 280 if (DexRegisterLocation::IsShortLocationKind(kind)) { 281 // Short location. Extract the value from the remaining 5 bits. 282 int32_t value = ExtractValueFromShortLocation(first_byte); 283 if (kind == DexRegisterLocation::Kind::kInStack) { 284 // Convert the stack slot (short) offset to a byte offset value. 285 value *= kFrameSlotSize; 286 } 287 return DexRegisterLocation(kind, value); 288 } else { 289 // Large location. Read the four next bytes to get the value. 290 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind)); 291 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) { 292 // Convert the stack slot (large) offset to a byte offset value. 293 value *= kFrameSlotSize; 294 } 295 return DexRegisterLocation(kind, value); 296 } 297 } 298 299 // Compute the compressed kind of `location`. ComputeCompressedKind(const DexRegisterLocation & location)300 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) { 301 DexRegisterLocation::Kind kind = location.GetInternalKind(); 302 switch (kind) { 303 case DexRegisterLocation::Kind::kInStack: 304 return IsShortStackOffsetValue(location.GetValue()) 305 ? DexRegisterLocation::Kind::kInStack 306 : DexRegisterLocation::Kind::kInStackLargeOffset; 307 308 case DexRegisterLocation::Kind::kInRegister: 309 case DexRegisterLocation::Kind::kInRegisterHigh: 310 DCHECK_GE(location.GetValue(), 0); 311 DCHECK_LT(location.GetValue(), 1 << kValueBits); 312 return kind; 313 314 case DexRegisterLocation::Kind::kInFpuRegister: 315 case DexRegisterLocation::Kind::kInFpuRegisterHigh: 316 DCHECK_GE(location.GetValue(), 0); 317 DCHECK_LT(location.GetValue(), 1 << kValueBits); 318 return kind; 319 320 case DexRegisterLocation::Kind::kConstant: 321 return IsShortConstantValue(location.GetValue()) 322 ? DexRegisterLocation::Kind::kConstant 323 : DexRegisterLocation::Kind::kConstantLargeValue; 324 325 case DexRegisterLocation::Kind::kConstantLargeValue: 326 case DexRegisterLocation::Kind::kInStackLargeOffset: 327 case DexRegisterLocation::Kind::kNone: 328 LOG(FATAL) << "Unexpected location kind " << kind; 329 } 330 UNREACHABLE(); 331 } 332 333 // Can `location` be turned into a short location? CanBeEncodedAsShortLocation(const DexRegisterLocation & location)334 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) { 335 DexRegisterLocation::Kind kind = location.GetInternalKind(); 336 switch (kind) { 337 case DexRegisterLocation::Kind::kInStack: 338 return IsShortStackOffsetValue(location.GetValue()); 339 340 case DexRegisterLocation::Kind::kInRegister: 341 case DexRegisterLocation::Kind::kInRegisterHigh: 342 case DexRegisterLocation::Kind::kInFpuRegister: 343 case DexRegisterLocation::Kind::kInFpuRegisterHigh: 344 return true; 345 346 case DexRegisterLocation::Kind::kConstant: 347 return IsShortConstantValue(location.GetValue()); 348 349 case DexRegisterLocation::Kind::kConstantLargeValue: 350 case DexRegisterLocation::Kind::kInStackLargeOffset: 351 case DexRegisterLocation::Kind::kNone: 352 LOG(FATAL) << "Unexpected location kind " << kind; 353 } 354 UNREACHABLE(); 355 } 356 EntrySize(const DexRegisterLocation & location)357 static size_t EntrySize(const DexRegisterLocation& location) { 358 return CanBeEncodedAsShortLocation(location) ? SingleShortEntrySize() : SingleLargeEntrySize(); 359 } 360 SingleShortEntrySize()361 static size_t SingleShortEntrySize() { 362 return sizeof(ShortLocation); 363 } 364 SingleLargeEntrySize()365 static size_t SingleLargeEntrySize() { 366 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t); 367 } 368 Size()369 size_t Size() const { 370 return region_.size(); 371 } 372 373 void Dump(VariableIndentationOutputStream* vios, 374 const CodeInfo& code_info); 375 376 // Special (invalid) Dex register location catalog entry index meaning 377 // that there is no location for a given Dex register (i.e., it is 378 // mapped to a DexRegisterLocation::Kind::kNone location). 379 static constexpr size_t kNoLocationEntryIndex = -1; 380 381 private: 382 static constexpr int kFixedSize = 0; 383 384 // Width of the kind "field" in a short location, in bits. 385 static constexpr size_t kKindBits = 3; 386 // Width of the value "field" in a short location, in bits. 387 static constexpr size_t kValueBits = 5; 388 389 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1; 390 static constexpr int32_t kValueMask = (1 << kValueBits) - 1; 391 static constexpr size_t kKindOffset = 0; 392 static constexpr size_t kValueOffset = kKindBits; 393 IsShortStackOffsetValue(int32_t value)394 static bool IsShortStackOffsetValue(int32_t value) { 395 DCHECK_EQ(value % kFrameSlotSize, 0); 396 return IsShortValue(value / kFrameSlotSize); 397 } 398 IsShortConstantValue(int32_t value)399 static bool IsShortConstantValue(int32_t value) { 400 return IsShortValue(value); 401 } 402 IsShortValue(int32_t value)403 static bool IsShortValue(int32_t value) { 404 return IsUint<kValueBits>(value); 405 } 406 MakeShortLocation(DexRegisterLocation::Kind kind,int32_t value)407 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) { 408 uint8_t kind_integer_value = static_cast<uint8_t>(kind); 409 DCHECK(IsUint<kKindBits>(kind_integer_value)) << kind_integer_value; 410 DCHECK(IsShortValue(value)) << value; 411 return (kind_integer_value & kKindMask) << kKindOffset 412 | (value & kValueMask) << kValueOffset; 413 } 414 ExtractKindFromShortLocation(ShortLocation location)415 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) { 416 uint8_t kind = (location >> kKindOffset) & kKindMask; 417 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind)); 418 // We do not encode kNone locations in the stack map. 419 DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone)); 420 return static_cast<DexRegisterLocation::Kind>(kind); 421 } 422 ExtractValueFromShortLocation(ShortLocation location)423 static int32_t ExtractValueFromShortLocation(ShortLocation location) { 424 return (location >> kValueOffset) & kValueMask; 425 } 426 427 // Extract a location kind from the byte at position `offset`. ExtractKindAtOffset(size_t offset)428 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const { 429 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset); 430 return ExtractKindFromShortLocation(first_byte); 431 } 432 433 MemoryRegion region_; 434 435 friend class CodeInfo; 436 friend class StackMapStream; 437 }; 438 439 /* Information on Dex register locations for a specific PC, mapping a 440 * stack map's Dex register to a location entry in a DexRegisterLocationCatalog. 441 * The information is of the form: 442 * 443 * [live_bit_mask, entries*] 444 * 445 * where entries are concatenated unsigned integer values encoded on a number 446 * of bits (fixed per DexRegisterMap instances of a CodeInfo object) depending 447 * on the number of entries in the Dex register location catalog 448 * (see DexRegisterMap::SingleEntrySizeInBits). The map is 1-byte aligned. 449 */ 450 class DexRegisterMap { 451 public: DexRegisterMap(MemoryRegion region)452 explicit DexRegisterMap(MemoryRegion region) : region_(region) {} DexRegisterMap()453 DexRegisterMap() {} 454 IsValid()455 bool IsValid() const { return region_.pointer() != nullptr; } 456 457 // 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)458 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number, 459 uint16_t number_of_dex_registers, 460 const CodeInfo& code_info, 461 const CodeInfoEncoding& enc) const { 462 return DexRegisterLocation::ConvertToSurfaceKind( 463 GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info, enc)); 464 } 465 466 // Get the internal kind of Dex register `dex_register_number`. 467 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number, 468 uint16_t number_of_dex_registers, 469 const CodeInfo& code_info, 470 const CodeInfoEncoding& enc) const; 471 472 // Get the Dex register location `dex_register_number`. 473 DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number, 474 uint16_t number_of_dex_registers, 475 const CodeInfo& code_info, 476 const CodeInfoEncoding& enc) const; 477 GetStackOffsetInBytes(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info,const CodeInfoEncoding & enc)478 int32_t GetStackOffsetInBytes(uint16_t dex_register_number, 479 uint16_t number_of_dex_registers, 480 const CodeInfo& code_info, 481 const CodeInfoEncoding& enc) const { 482 DexRegisterLocation location = 483 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc); 484 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack); 485 // GetDexRegisterLocation returns the offset in bytes. 486 return location.GetValue(); 487 } 488 GetConstant(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info,const CodeInfoEncoding & enc)489 int32_t GetConstant(uint16_t dex_register_number, 490 uint16_t number_of_dex_registers, 491 const CodeInfo& code_info, 492 const CodeInfoEncoding& enc) const { 493 DexRegisterLocation location = 494 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc); 495 DCHECK_EQ(location.GetKind(), DexRegisterLocation::Kind::kConstant); 496 return location.GetValue(); 497 } 498 GetMachineRegister(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info,const CodeInfoEncoding & enc)499 int32_t GetMachineRegister(uint16_t dex_register_number, 500 uint16_t number_of_dex_registers, 501 const CodeInfo& code_info, 502 const CodeInfoEncoding& enc) const { 503 DexRegisterLocation location = 504 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc); 505 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister || 506 location.GetInternalKind() == DexRegisterLocation::Kind::kInRegisterHigh || 507 location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister || 508 location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh) 509 << location.GetInternalKind(); 510 return location.GetValue(); 511 } 512 513 // Get the index of the entry in the Dex register location catalog 514 // corresponding to `dex_register_number`. GetLocationCatalogEntryIndex(uint16_t dex_register_number,uint16_t number_of_dex_registers,size_t number_of_location_catalog_entries)515 size_t GetLocationCatalogEntryIndex(uint16_t dex_register_number, 516 uint16_t number_of_dex_registers, 517 size_t number_of_location_catalog_entries) const { 518 if (!IsDexRegisterLive(dex_register_number)) { 519 return DexRegisterLocationCatalog::kNoLocationEntryIndex; 520 } 521 522 if (number_of_location_catalog_entries == 1) { 523 // We do not allocate space for location maps in the case of a 524 // single-entry location catalog, as it is useless. The only valid 525 // entry index is 0; 526 return 0; 527 } 528 529 // The bit offset of the beginning of the map locations. 530 size_t map_locations_offset_in_bits = 531 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte; 532 size_t index_in_dex_register_map = GetIndexInDexRegisterMap(dex_register_number); 533 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers)); 534 // The bit size of an entry. 535 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries); 536 // The bit offset where `index_in_dex_register_map` is located. 537 size_t entry_offset_in_bits = 538 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits; 539 size_t location_catalog_entry_index = 540 region_.LoadBits(entry_offset_in_bits, map_entry_size_in_bits); 541 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries); 542 return location_catalog_entry_index; 543 } 544 545 // 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)546 void SetLocationCatalogEntryIndex(size_t index_in_dex_register_map, 547 size_t location_catalog_entry_index, 548 uint16_t number_of_dex_registers, 549 size_t number_of_location_catalog_entries) { 550 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers)); 551 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries); 552 553 if (number_of_location_catalog_entries == 1) { 554 // We do not allocate space for location maps in the case of a 555 // single-entry location catalog, as it is useless. 556 return; 557 } 558 559 // The bit offset of the beginning of the map locations. 560 size_t map_locations_offset_in_bits = 561 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte; 562 // The bit size of an entry. 563 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries); 564 // The bit offset where `index_in_dex_register_map` is located. 565 size_t entry_offset_in_bits = 566 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits; 567 region_.StoreBits(entry_offset_in_bits, location_catalog_entry_index, map_entry_size_in_bits); 568 } 569 SetLiveBitMask(uint16_t number_of_dex_registers,const BitVector & live_dex_registers_mask)570 void SetLiveBitMask(uint16_t number_of_dex_registers, 571 const BitVector& live_dex_registers_mask) { 572 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte; 573 for (uint16_t i = 0; i < number_of_dex_registers; ++i) { 574 region_.StoreBit(live_bit_mask_offset_in_bits + i, live_dex_registers_mask.IsBitSet(i)); 575 } 576 } 577 IsDexRegisterLive(uint16_t dex_register_number)578 ALWAYS_INLINE bool IsDexRegisterLive(uint16_t dex_register_number) const { 579 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte; 580 return region_.LoadBit(live_bit_mask_offset_in_bits + dex_register_number); 581 } 582 GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers)583 size_t GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers) const { 584 size_t number_of_live_dex_registers = 0; 585 for (size_t i = 0; i < number_of_dex_registers; ++i) { 586 if (IsDexRegisterLive(i)) { 587 ++number_of_live_dex_registers; 588 } 589 } 590 return number_of_live_dex_registers; 591 } 592 GetLiveBitMaskOffset()593 static size_t GetLiveBitMaskOffset() { 594 return kFixedSize; 595 } 596 597 // Compute the size of the live register bit mask (in bytes), for a 598 // method having `number_of_dex_registers` Dex registers. GetLiveBitMaskSize(uint16_t number_of_dex_registers)599 static size_t GetLiveBitMaskSize(uint16_t number_of_dex_registers) { 600 return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte; 601 } 602 GetLocationMappingDataOffset(uint16_t number_of_dex_registers)603 static size_t GetLocationMappingDataOffset(uint16_t number_of_dex_registers) { 604 return GetLiveBitMaskOffset() + GetLiveBitMaskSize(number_of_dex_registers); 605 } 606 GetLocationMappingDataSize(uint16_t number_of_dex_registers,size_t number_of_location_catalog_entries)607 size_t GetLocationMappingDataSize(uint16_t number_of_dex_registers, 608 size_t number_of_location_catalog_entries) const { 609 size_t location_mapping_data_size_in_bits = 610 GetNumberOfLiveDexRegisters(number_of_dex_registers) 611 * SingleEntrySizeInBits(number_of_location_catalog_entries); 612 return RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte; 613 } 614 615 // Return the size of a map entry in bits. Note that if 616 // `number_of_location_catalog_entries` equals 1, this function returns 0, 617 // which is fine, as there is no need to allocate a map for a 618 // single-entry location catalog; the only valid location catalog entry index 619 // for a live register in this case is 0 and there is no need to 620 // store it. SingleEntrySizeInBits(size_t number_of_location_catalog_entries)621 static size_t SingleEntrySizeInBits(size_t number_of_location_catalog_entries) { 622 // Handle the case of 0, as we cannot pass 0 to art::WhichPowerOf2. 623 return number_of_location_catalog_entries == 0 624 ? 0u 625 : WhichPowerOf2(RoundUpToPowerOfTwo(number_of_location_catalog_entries)); 626 } 627 628 // Return the size of the DexRegisterMap object, in bytes. Size()629 size_t Size() const { 630 return region_.size(); 631 } 632 633 void Dump(VariableIndentationOutputStream* vios, 634 const CodeInfo& code_info, uint16_t number_of_dex_registers) const; 635 636 private: 637 // Return the index in the Dex register map corresponding to the Dex 638 // register number `dex_register_number`. GetIndexInDexRegisterMap(uint16_t dex_register_number)639 size_t GetIndexInDexRegisterMap(uint16_t dex_register_number) const { 640 if (!IsDexRegisterLive(dex_register_number)) { 641 return kInvalidIndexInDexRegisterMap; 642 } 643 return GetNumberOfLiveDexRegisters(dex_register_number); 644 } 645 646 // Special (invalid) Dex register map entry index meaning that there 647 // is no index in the map for a given Dex register (i.e., it must 648 // have been mapped to a DexRegisterLocation::Kind::kNone location). 649 static constexpr size_t kInvalidIndexInDexRegisterMap = -1; 650 651 static constexpr int kFixedSize = 0; 652 653 MemoryRegion region_; 654 655 friend class CodeInfo; 656 friend class StackMapStream; 657 }; 658 659 // Represents bit range of bit-packed integer field. 660 // We reuse the idea from ULEB128p1 to support encoding of -1 (aka 0xFFFFFFFF). 661 // If min_value is set to -1, we implicitly subtract one from any loaded value, 662 // and add one to any stored value. This is generalized to any negative values. 663 // In other words, min_value acts as a base and the stored value is added to it. 664 struct FieldEncoding { 665 FieldEncoding(size_t start_offset, size_t end_offset, int32_t min_value = 0) start_offset_FieldEncoding666 : start_offset_(start_offset), end_offset_(end_offset), min_value_(min_value) { 667 DCHECK_LE(start_offset_, end_offset_); 668 DCHECK_LE(BitSize(), 32u); 669 } 670 BitSizeFieldEncoding671 ALWAYS_INLINE size_t BitSize() const { return end_offset_ - start_offset_; } 672 673 template <typename Region> LoadFieldEncoding674 ALWAYS_INLINE int32_t Load(const Region& region) const { 675 DCHECK_LE(end_offset_, region.size_in_bits()); 676 return static_cast<int32_t>(region.LoadBits(start_offset_, BitSize())) + min_value_; 677 } 678 679 template <typename Region> StoreFieldEncoding680 ALWAYS_INLINE void Store(Region region, int32_t value) const { 681 region.StoreBits(start_offset_, value - min_value_, BitSize()); 682 DCHECK_EQ(Load(region), value); 683 } 684 685 private: 686 size_t start_offset_; 687 size_t end_offset_; 688 int32_t min_value_; 689 }; 690 691 class StackMapEncoding { 692 public: StackMapEncoding()693 StackMapEncoding() 694 : dex_pc_bit_offset_(0), 695 dex_register_map_bit_offset_(0), 696 inline_info_bit_offset_(0), 697 register_mask_index_bit_offset_(0), 698 stack_mask_index_bit_offset_(0), 699 total_bit_size_(0) {} 700 701 // Set stack map bit layout based on given sizes. 702 // Returns the size of stack map in bits. SetFromSizes(size_t native_pc_max,size_t dex_pc_max,size_t dex_register_map_size,size_t number_of_inline_info,size_t number_of_register_masks,size_t number_of_stack_masks)703 size_t SetFromSizes(size_t native_pc_max, 704 size_t dex_pc_max, 705 size_t dex_register_map_size, 706 size_t number_of_inline_info, 707 size_t number_of_register_masks, 708 size_t number_of_stack_masks) { 709 total_bit_size_ = 0; 710 DCHECK_EQ(kNativePcBitOffset, total_bit_size_); 711 total_bit_size_ += MinimumBitsToStore(native_pc_max); 712 713 dex_pc_bit_offset_ = total_bit_size_; 714 total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max); 715 716 // We also need +1 for kNoDexRegisterMap, but since the size is strictly 717 // greater than any offset we might try to encode, we already implicitly have it. 718 dex_register_map_bit_offset_ = total_bit_size_; 719 total_bit_size_ += MinimumBitsToStore(dex_register_map_size); 720 721 // We also need +1 for kNoInlineInfo, but since the inline_info_size is strictly 722 // greater than the offset we might try to encode, we already implicitly have it. 723 // If inline_info_size is zero, we can encode only kNoInlineInfo (in zero bits). 724 inline_info_bit_offset_ = total_bit_size_; 725 total_bit_size_ += MinimumBitsToStore(number_of_inline_info); 726 727 register_mask_index_bit_offset_ = total_bit_size_; 728 total_bit_size_ += MinimumBitsToStore(number_of_register_masks); 729 730 stack_mask_index_bit_offset_ = total_bit_size_; 731 total_bit_size_ += MinimumBitsToStore(number_of_stack_masks); 732 733 return total_bit_size_; 734 } 735 GetNativePcEncoding()736 ALWAYS_INLINE FieldEncoding GetNativePcEncoding() const { 737 return FieldEncoding(kNativePcBitOffset, dex_pc_bit_offset_); 738 } GetDexPcEncoding()739 ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const { 740 return FieldEncoding(dex_pc_bit_offset_, dex_register_map_bit_offset_, -1 /* min_value */); 741 } GetDexRegisterMapEncoding()742 ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const { 743 return FieldEncoding(dex_register_map_bit_offset_, inline_info_bit_offset_, -1 /* min_value */); 744 } GetInlineInfoEncoding()745 ALWAYS_INLINE FieldEncoding GetInlineInfoEncoding() const { 746 return FieldEncoding(inline_info_bit_offset_, 747 register_mask_index_bit_offset_, 748 -1 /* min_value */); 749 } GetRegisterMaskIndexEncoding()750 ALWAYS_INLINE FieldEncoding GetRegisterMaskIndexEncoding() const { 751 return FieldEncoding(register_mask_index_bit_offset_, stack_mask_index_bit_offset_); 752 } GetStackMaskIndexEncoding()753 ALWAYS_INLINE FieldEncoding GetStackMaskIndexEncoding() const { 754 return FieldEncoding(stack_mask_index_bit_offset_, total_bit_size_); 755 } BitSize()756 ALWAYS_INLINE size_t BitSize() const { 757 return total_bit_size_; 758 } 759 760 // Encode the encoding into the vector. 761 template<typename Vector> Encode(Vector * dest)762 void Encode(Vector* dest) const { 763 static_assert(alignof(StackMapEncoding) == 1, "Should not require alignment"); 764 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this); 765 dest->insert(dest->end(), ptr, ptr + sizeof(*this)); 766 } 767 768 // Decode the encoding from a pointer, updates the pointer. Decode(const uint8_t ** ptr)769 void Decode(const uint8_t** ptr) { 770 *this = *reinterpret_cast<const StackMapEncoding*>(*ptr); 771 *ptr += sizeof(*this); 772 } 773 774 void Dump(VariableIndentationOutputStream* vios) const; 775 776 private: 777 static constexpr size_t kNativePcBitOffset = 0; 778 uint8_t dex_pc_bit_offset_; 779 uint8_t dex_register_map_bit_offset_; 780 uint8_t inline_info_bit_offset_; 781 uint8_t register_mask_index_bit_offset_; 782 uint8_t stack_mask_index_bit_offset_; 783 uint8_t total_bit_size_; 784 }; 785 786 /** 787 * A Stack Map holds compilation information for a specific PC necessary for: 788 * - Mapping it to a dex PC, 789 * - Knowing which stack entries are objects, 790 * - Knowing which registers hold objects, 791 * - Knowing the inlining information, 792 * - Knowing the values of dex registers. 793 * 794 * The information is of the form: 795 * 796 * [native_pc_offset, dex_pc, dex_register_map_offset, inlining_info_index, register_mask_index, 797 * stack_mask_index]. 798 */ 799 class StackMap { 800 public: StackMap()801 StackMap() {} StackMap(BitMemoryRegion region)802 explicit StackMap(BitMemoryRegion region) : region_(region) {} 803 IsValid()804 ALWAYS_INLINE bool IsValid() const { return region_.pointer() != nullptr; } 805 GetDexPc(const StackMapEncoding & encoding)806 ALWAYS_INLINE uint32_t GetDexPc(const StackMapEncoding& encoding) const { 807 return encoding.GetDexPcEncoding().Load(region_); 808 } 809 SetDexPc(const StackMapEncoding & encoding,uint32_t dex_pc)810 ALWAYS_INLINE void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) { 811 encoding.GetDexPcEncoding().Store(region_, dex_pc); 812 } 813 GetNativePcOffset(const StackMapEncoding & encoding,InstructionSet instruction_set)814 ALWAYS_INLINE uint32_t GetNativePcOffset(const StackMapEncoding& encoding, 815 InstructionSet instruction_set) const { 816 CodeOffset offset( 817 CodeOffset::FromCompressedOffset(encoding.GetNativePcEncoding().Load(region_))); 818 return offset.Uint32Value(instruction_set); 819 } 820 SetNativePcCodeOffset(const StackMapEncoding & encoding,CodeOffset native_pc_offset)821 ALWAYS_INLINE void SetNativePcCodeOffset(const StackMapEncoding& encoding, 822 CodeOffset native_pc_offset) { 823 encoding.GetNativePcEncoding().Store(region_, native_pc_offset.CompressedValue()); 824 } 825 GetDexRegisterMapOffset(const StackMapEncoding & encoding)826 ALWAYS_INLINE uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const { 827 return encoding.GetDexRegisterMapEncoding().Load(region_); 828 } 829 SetDexRegisterMapOffset(const StackMapEncoding & encoding,uint32_t offset)830 ALWAYS_INLINE void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) { 831 encoding.GetDexRegisterMapEncoding().Store(region_, offset); 832 } 833 GetInlineInfoIndex(const StackMapEncoding & encoding)834 ALWAYS_INLINE uint32_t GetInlineInfoIndex(const StackMapEncoding& encoding) const { 835 return encoding.GetInlineInfoEncoding().Load(region_); 836 } 837 SetInlineInfoIndex(const StackMapEncoding & encoding,uint32_t index)838 ALWAYS_INLINE void SetInlineInfoIndex(const StackMapEncoding& encoding, uint32_t index) { 839 encoding.GetInlineInfoEncoding().Store(region_, index); 840 } 841 GetRegisterMaskIndex(const StackMapEncoding & encoding)842 ALWAYS_INLINE uint32_t GetRegisterMaskIndex(const StackMapEncoding& encoding) const { 843 return encoding.GetRegisterMaskIndexEncoding().Load(region_); 844 } 845 SetRegisterMaskIndex(const StackMapEncoding & encoding,uint32_t mask)846 ALWAYS_INLINE void SetRegisterMaskIndex(const StackMapEncoding& encoding, uint32_t mask) { 847 encoding.GetRegisterMaskIndexEncoding().Store(region_, mask); 848 } 849 GetStackMaskIndex(const StackMapEncoding & encoding)850 ALWAYS_INLINE uint32_t GetStackMaskIndex(const StackMapEncoding& encoding) const { 851 return encoding.GetStackMaskIndexEncoding().Load(region_); 852 } 853 SetStackMaskIndex(const StackMapEncoding & encoding,uint32_t mask)854 ALWAYS_INLINE void SetStackMaskIndex(const StackMapEncoding& encoding, uint32_t mask) { 855 encoding.GetStackMaskIndexEncoding().Store(region_, mask); 856 } 857 HasDexRegisterMap(const StackMapEncoding & encoding)858 ALWAYS_INLINE bool HasDexRegisterMap(const StackMapEncoding& encoding) const { 859 return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap; 860 } 861 HasInlineInfo(const StackMapEncoding & encoding)862 ALWAYS_INLINE bool HasInlineInfo(const StackMapEncoding& encoding) const { 863 return GetInlineInfoIndex(encoding) != kNoInlineInfo; 864 } 865 Equals(const StackMap & other)866 ALWAYS_INLINE bool Equals(const StackMap& other) const { 867 return region_.pointer() == other.region_.pointer() && 868 region_.size() == other.region_.size() && 869 region_.BitOffset() == other.region_.BitOffset(); 870 } 871 872 void Dump(VariableIndentationOutputStream* vios, 873 const CodeInfo& code_info, 874 const CodeInfoEncoding& encoding, 875 const MethodInfo& method_info, 876 uint32_t code_offset, 877 uint16_t number_of_dex_registers, 878 InstructionSet instruction_set, 879 const std::string& header_suffix = "") const; 880 881 // Special (invalid) offset for the DexRegisterMapOffset field meaning 882 // that there is no Dex register map for this stack map. 883 static constexpr uint32_t kNoDexRegisterMap = -1; 884 885 // Special (invalid) offset for the InlineDescriptorOffset field meaning 886 // that there is no inline info for this stack map. 887 static constexpr uint32_t kNoInlineInfo = -1; 888 889 private: 890 static constexpr int kFixedSize = 0; 891 892 BitMemoryRegion region_; 893 894 friend class StackMapStream; 895 }; 896 897 class InlineInfoEncoding { 898 public: SetFromSizes(size_t method_index_idx_max,size_t dex_pc_max,size_t extra_data_max,size_t dex_register_map_size)899 void SetFromSizes(size_t method_index_idx_max, 900 size_t dex_pc_max, 901 size_t extra_data_max, 902 size_t dex_register_map_size) { 903 total_bit_size_ = kMethodIndexBitOffset; 904 total_bit_size_ += MinimumBitsToStore(method_index_idx_max); 905 906 dex_pc_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_); 907 // Note: We're not encoding the dex pc if there is none. That's the case 908 // for an intrinsified native method, such as String.charAt(). 909 if (dex_pc_max != DexFile::kDexNoIndex) { 910 total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max); 911 } 912 913 extra_data_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_); 914 total_bit_size_ += MinimumBitsToStore(extra_data_max); 915 916 // We also need +1 for kNoDexRegisterMap, but since the size is strictly 917 // greater than any offset we might try to encode, we already implicitly have it. 918 dex_register_map_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_); 919 total_bit_size_ += MinimumBitsToStore(dex_register_map_size); 920 } 921 GetMethodIndexIdxEncoding()922 ALWAYS_INLINE FieldEncoding GetMethodIndexIdxEncoding() const { 923 return FieldEncoding(kMethodIndexBitOffset, dex_pc_bit_offset_); 924 } GetDexPcEncoding()925 ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const { 926 return FieldEncoding(dex_pc_bit_offset_, extra_data_bit_offset_, -1 /* min_value */); 927 } GetExtraDataEncoding()928 ALWAYS_INLINE FieldEncoding GetExtraDataEncoding() const { 929 return FieldEncoding(extra_data_bit_offset_, dex_register_map_bit_offset_); 930 } GetDexRegisterMapEncoding()931 ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const { 932 return FieldEncoding(dex_register_map_bit_offset_, total_bit_size_, -1 /* min_value */); 933 } BitSize()934 ALWAYS_INLINE size_t BitSize() const { 935 return total_bit_size_; 936 } 937 938 void Dump(VariableIndentationOutputStream* vios) const; 939 940 // Encode the encoding into the vector. 941 template<typename Vector> Encode(Vector * dest)942 void Encode(Vector* dest) const { 943 static_assert(alignof(InlineInfoEncoding) == 1, "Should not require alignment"); 944 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this); 945 dest->insert(dest->end(), ptr, ptr + sizeof(*this)); 946 } 947 948 // Decode the encoding from a pointer, updates the pointer. Decode(const uint8_t ** ptr)949 void Decode(const uint8_t** ptr) { 950 *this = *reinterpret_cast<const InlineInfoEncoding*>(*ptr); 951 *ptr += sizeof(*this); 952 } 953 954 private: 955 static constexpr uint8_t kIsLastBitOffset = 0; 956 static constexpr uint8_t kMethodIndexBitOffset = 1; 957 uint8_t dex_pc_bit_offset_; 958 uint8_t extra_data_bit_offset_; 959 uint8_t dex_register_map_bit_offset_; 960 uint8_t total_bit_size_; 961 }; 962 963 /** 964 * Inline information for a specific PC. The information is of the form: 965 * 966 * [is_last, 967 * method_index (or ArtMethod high bits), 968 * dex_pc, 969 * extra_data (ArtMethod low bits or 1), 970 * dex_register_map_offset]+. 971 */ 972 class InlineInfo { 973 public: InlineInfo(BitMemoryRegion region)974 explicit InlineInfo(BitMemoryRegion region) : region_(region) {} 975 GetDepth(const InlineInfoEncoding & encoding)976 ALWAYS_INLINE uint32_t GetDepth(const InlineInfoEncoding& encoding) const { 977 size_t depth = 0; 978 while (!GetRegionAtDepth(encoding, depth++).LoadBit(0)) { } // Check is_last bit. 979 return depth; 980 } 981 SetDepth(const InlineInfoEncoding & encoding,uint32_t depth)982 ALWAYS_INLINE void SetDepth(const InlineInfoEncoding& encoding, uint32_t depth) { 983 DCHECK_GT(depth, 0u); 984 for (size_t d = 0; d < depth; ++d) { 985 GetRegionAtDepth(encoding, d).StoreBit(0, d == depth - 1); // Set is_last bit. 986 } 987 } 988 GetMethodIndexIdxAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)989 ALWAYS_INLINE uint32_t GetMethodIndexIdxAtDepth(const InlineInfoEncoding& encoding, 990 uint32_t depth) const { 991 DCHECK(!EncodesArtMethodAtDepth(encoding, depth)); 992 return encoding.GetMethodIndexIdxEncoding().Load(GetRegionAtDepth(encoding, depth)); 993 } 994 SetMethodIndexIdxAtDepth(const InlineInfoEncoding & encoding,uint32_t depth,uint32_t index)995 ALWAYS_INLINE void SetMethodIndexIdxAtDepth(const InlineInfoEncoding& encoding, 996 uint32_t depth, 997 uint32_t index) { 998 encoding.GetMethodIndexIdxEncoding().Store(GetRegionAtDepth(encoding, depth), index); 999 } 1000 1001 GetMethodIndexAtDepth(const InlineInfoEncoding & encoding,const MethodInfo & method_info,uint32_t depth)1002 ALWAYS_INLINE uint32_t GetMethodIndexAtDepth(const InlineInfoEncoding& encoding, 1003 const MethodInfo& method_info, 1004 uint32_t depth) const { 1005 return method_info.GetMethodIndex(GetMethodIndexIdxAtDepth(encoding, depth)); 1006 } 1007 GetDexPcAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)1008 ALWAYS_INLINE uint32_t GetDexPcAtDepth(const InlineInfoEncoding& encoding, 1009 uint32_t depth) const { 1010 return encoding.GetDexPcEncoding().Load(GetRegionAtDepth(encoding, depth)); 1011 } 1012 SetDexPcAtDepth(const InlineInfoEncoding & encoding,uint32_t depth,uint32_t dex_pc)1013 ALWAYS_INLINE void SetDexPcAtDepth(const InlineInfoEncoding& encoding, 1014 uint32_t depth, 1015 uint32_t dex_pc) { 1016 encoding.GetDexPcEncoding().Store(GetRegionAtDepth(encoding, depth), dex_pc); 1017 } 1018 EncodesArtMethodAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)1019 ALWAYS_INLINE bool EncodesArtMethodAtDepth(const InlineInfoEncoding& encoding, 1020 uint32_t depth) const { 1021 return (encoding.GetExtraDataEncoding().Load(GetRegionAtDepth(encoding, depth)) & 1) == 0; 1022 } 1023 SetExtraDataAtDepth(const InlineInfoEncoding & encoding,uint32_t depth,uint32_t extra_data)1024 ALWAYS_INLINE void SetExtraDataAtDepth(const InlineInfoEncoding& encoding, 1025 uint32_t depth, 1026 uint32_t extra_data) { 1027 encoding.GetExtraDataEncoding().Store(GetRegionAtDepth(encoding, depth), extra_data); 1028 } 1029 GetArtMethodAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)1030 ALWAYS_INLINE ArtMethod* GetArtMethodAtDepth(const InlineInfoEncoding& encoding, 1031 uint32_t depth) const { 1032 uint32_t low_bits = encoding.GetExtraDataEncoding().Load(GetRegionAtDepth(encoding, depth)); 1033 uint32_t high_bits = encoding.GetMethodIndexIdxEncoding().Load( 1034 GetRegionAtDepth(encoding, depth)); 1035 if (high_bits == 0) { 1036 return reinterpret_cast<ArtMethod*>(low_bits); 1037 } else { 1038 uint64_t address = high_bits; 1039 address = address << 32; 1040 return reinterpret_cast<ArtMethod*>(address | low_bits); 1041 } 1042 } 1043 GetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)1044 ALWAYS_INLINE uint32_t GetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding, 1045 uint32_t depth) const { 1046 return encoding.GetDexRegisterMapEncoding().Load(GetRegionAtDepth(encoding, depth)); 1047 } 1048 SetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding & encoding,uint32_t depth,uint32_t offset)1049 ALWAYS_INLINE void SetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding, 1050 uint32_t depth, 1051 uint32_t offset) { 1052 encoding.GetDexRegisterMapEncoding().Store(GetRegionAtDepth(encoding, depth), offset); 1053 } 1054 HasDexRegisterMapAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)1055 ALWAYS_INLINE bool HasDexRegisterMapAtDepth(const InlineInfoEncoding& encoding, 1056 uint32_t depth) const { 1057 return GetDexRegisterMapOffsetAtDepth(encoding, depth) != StackMap::kNoDexRegisterMap; 1058 } 1059 1060 void Dump(VariableIndentationOutputStream* vios, 1061 const CodeInfo& info, 1062 const MethodInfo& method_info, 1063 uint16_t* number_of_dex_registers) const; 1064 1065 private: GetRegionAtDepth(const InlineInfoEncoding & encoding,uint32_t depth)1066 ALWAYS_INLINE BitMemoryRegion GetRegionAtDepth(const InlineInfoEncoding& encoding, 1067 uint32_t depth) const { 1068 size_t entry_size = encoding.BitSize(); 1069 DCHECK_GT(entry_size, 0u); 1070 return region_.Subregion(depth * entry_size, entry_size); 1071 } 1072 1073 BitMemoryRegion region_; 1074 }; 1075 1076 // Bit sized region encoding, may be more than 255 bits. 1077 class BitRegionEncoding { 1078 public: 1079 uint32_t num_bits = 0; 1080 BitSize()1081 ALWAYS_INLINE size_t BitSize() const { 1082 return num_bits; 1083 } 1084 1085 template<typename Vector> Encode(Vector * dest)1086 void Encode(Vector* dest) const { 1087 EncodeUnsignedLeb128(dest, num_bits); // Use leb in case num_bits is greater than 255. 1088 } 1089 Decode(const uint8_t ** ptr)1090 void Decode(const uint8_t** ptr) { 1091 num_bits = DecodeUnsignedLeb128(ptr); 1092 } 1093 }; 1094 1095 // A table of bit sized encodings. 1096 template <typename Encoding> 1097 struct BitEncodingTable { 1098 static constexpr size_t kInvalidOffset = static_cast<size_t>(-1); 1099 // How the encoding is laid out (serialized). 1100 Encoding encoding; 1101 1102 // Number of entries in the table (serialized). 1103 size_t num_entries; 1104 1105 // Bit offset for the base of the table (computed). 1106 size_t bit_offset = kInvalidOffset; 1107 1108 template<typename Vector> EncodeBitEncodingTable1109 void Encode(Vector* dest) const { 1110 EncodeUnsignedLeb128(dest, num_entries); 1111 encoding.Encode(dest); 1112 } 1113 DecodeBitEncodingTable1114 ALWAYS_INLINE void Decode(const uint8_t** ptr) { 1115 num_entries = DecodeUnsignedLeb128(ptr); 1116 encoding.Decode(ptr); 1117 } 1118 1119 // Set the bit offset in the table and adds the space used by the table to offset. UpdateBitOffsetBitEncodingTable1120 void UpdateBitOffset(size_t* offset) { 1121 DCHECK(offset != nullptr); 1122 bit_offset = *offset; 1123 *offset += encoding.BitSize() * num_entries; 1124 } 1125 1126 // Return the bit region for the map at index i. BitRegionBitEncodingTable1127 ALWAYS_INLINE BitMemoryRegion BitRegion(MemoryRegion region, size_t index) const { 1128 DCHECK_NE(bit_offset, kInvalidOffset) << "Invalid table offset"; 1129 DCHECK_LT(index, num_entries); 1130 const size_t map_size = encoding.BitSize(); 1131 return BitMemoryRegion(region, bit_offset + index * map_size, map_size); 1132 } 1133 }; 1134 1135 // A byte sized table of possible variable sized encodings. 1136 struct ByteSizedTable { 1137 static constexpr size_t kInvalidOffset = static_cast<size_t>(-1); 1138 1139 // Number of entries in the table (serialized). 1140 size_t num_entries = 0; 1141 1142 // Number of bytes of the table (serialized). 1143 size_t num_bytes; 1144 1145 // Bit offset for the base of the table (computed). 1146 size_t byte_offset = kInvalidOffset; 1147 1148 template<typename Vector> EncodeByteSizedTable1149 void Encode(Vector* dest) const { 1150 EncodeUnsignedLeb128(dest, num_entries); 1151 EncodeUnsignedLeb128(dest, num_bytes); 1152 } 1153 DecodeByteSizedTable1154 ALWAYS_INLINE void Decode(const uint8_t** ptr) { 1155 num_entries = DecodeUnsignedLeb128(ptr); 1156 num_bytes = DecodeUnsignedLeb128(ptr); 1157 } 1158 1159 // Set the bit offset of the table. Adds the total bit size of the table to offset. UpdateBitOffsetByteSizedTable1160 void UpdateBitOffset(size_t* offset) { 1161 DCHECK(offset != nullptr); 1162 DCHECK_ALIGNED(*offset, kBitsPerByte); 1163 byte_offset = *offset / kBitsPerByte; 1164 *offset += num_bytes * kBitsPerByte; 1165 } 1166 }; 1167 1168 // Format is [native pc, invoke type, method index]. 1169 class InvokeInfoEncoding { 1170 public: SetFromSizes(size_t native_pc_max,size_t invoke_type_max,size_t method_index_max)1171 void SetFromSizes(size_t native_pc_max, 1172 size_t invoke_type_max, 1173 size_t method_index_max) { 1174 total_bit_size_ = 0; 1175 DCHECK_EQ(kNativePcBitOffset, total_bit_size_); 1176 total_bit_size_ += MinimumBitsToStore(native_pc_max); 1177 invoke_type_bit_offset_ = total_bit_size_; 1178 total_bit_size_ += MinimumBitsToStore(invoke_type_max); 1179 method_index_bit_offset_ = total_bit_size_; 1180 total_bit_size_ += MinimumBitsToStore(method_index_max); 1181 } 1182 GetNativePcEncoding()1183 ALWAYS_INLINE FieldEncoding GetNativePcEncoding() const { 1184 return FieldEncoding(kNativePcBitOffset, invoke_type_bit_offset_); 1185 } 1186 GetInvokeTypeEncoding()1187 ALWAYS_INLINE FieldEncoding GetInvokeTypeEncoding() const { 1188 return FieldEncoding(invoke_type_bit_offset_, method_index_bit_offset_); 1189 } 1190 GetMethodIndexEncoding()1191 ALWAYS_INLINE FieldEncoding GetMethodIndexEncoding() const { 1192 return FieldEncoding(method_index_bit_offset_, total_bit_size_); 1193 } 1194 BitSize()1195 ALWAYS_INLINE size_t BitSize() const { 1196 return total_bit_size_; 1197 } 1198 1199 template<typename Vector> Encode(Vector * dest)1200 void Encode(Vector* dest) const { 1201 static_assert(alignof(InvokeInfoEncoding) == 1, "Should not require alignment"); 1202 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this); 1203 dest->insert(dest->end(), ptr, ptr + sizeof(*this)); 1204 } 1205 Decode(const uint8_t ** ptr)1206 void Decode(const uint8_t** ptr) { 1207 *this = *reinterpret_cast<const InvokeInfoEncoding*>(*ptr); 1208 *ptr += sizeof(*this); 1209 } 1210 1211 private: 1212 static constexpr uint8_t kNativePcBitOffset = 0; 1213 uint8_t invoke_type_bit_offset_; 1214 uint8_t method_index_bit_offset_; 1215 uint8_t total_bit_size_; 1216 }; 1217 1218 class InvokeInfo { 1219 public: InvokeInfo(BitMemoryRegion region)1220 explicit InvokeInfo(BitMemoryRegion region) : region_(region) {} 1221 GetNativePcOffset(const InvokeInfoEncoding & encoding,InstructionSet instruction_set)1222 ALWAYS_INLINE uint32_t GetNativePcOffset(const InvokeInfoEncoding& encoding, 1223 InstructionSet instruction_set) const { 1224 CodeOffset offset( 1225 CodeOffset::FromCompressedOffset(encoding.GetNativePcEncoding().Load(region_))); 1226 return offset.Uint32Value(instruction_set); 1227 } 1228 SetNativePcCodeOffset(const InvokeInfoEncoding & encoding,CodeOffset native_pc_offset)1229 ALWAYS_INLINE void SetNativePcCodeOffset(const InvokeInfoEncoding& encoding, 1230 CodeOffset native_pc_offset) { 1231 encoding.GetNativePcEncoding().Store(region_, native_pc_offset.CompressedValue()); 1232 } 1233 GetInvokeType(const InvokeInfoEncoding & encoding)1234 ALWAYS_INLINE uint32_t GetInvokeType(const InvokeInfoEncoding& encoding) const { 1235 return encoding.GetInvokeTypeEncoding().Load(region_); 1236 } 1237 SetInvokeType(const InvokeInfoEncoding & encoding,uint32_t invoke_type)1238 ALWAYS_INLINE void SetInvokeType(const InvokeInfoEncoding& encoding, uint32_t invoke_type) { 1239 encoding.GetInvokeTypeEncoding().Store(region_, invoke_type); 1240 } 1241 GetMethodIndexIdx(const InvokeInfoEncoding & encoding)1242 ALWAYS_INLINE uint32_t GetMethodIndexIdx(const InvokeInfoEncoding& encoding) const { 1243 return encoding.GetMethodIndexEncoding().Load(region_); 1244 } 1245 SetMethodIndexIdx(const InvokeInfoEncoding & encoding,uint32_t method_index_idx)1246 ALWAYS_INLINE void SetMethodIndexIdx(const InvokeInfoEncoding& encoding, 1247 uint32_t method_index_idx) { 1248 encoding.GetMethodIndexEncoding().Store(region_, method_index_idx); 1249 } 1250 GetMethodIndex(const InvokeInfoEncoding & encoding,MethodInfo method_info)1251 ALWAYS_INLINE uint32_t GetMethodIndex(const InvokeInfoEncoding& encoding, 1252 MethodInfo method_info) const { 1253 return method_info.GetMethodIndex(GetMethodIndexIdx(encoding)); 1254 } 1255 IsValid()1256 bool IsValid() const { return region_.pointer() != nullptr; } 1257 1258 private: 1259 BitMemoryRegion region_; 1260 }; 1261 1262 // Most of the fields are encoded as ULEB128 to save space. 1263 struct CodeInfoEncoding { 1264 using SizeType = uint32_t; 1265 1266 static constexpr SizeType kInvalidSize = std::numeric_limits<SizeType>::max(); 1267 1268 // Byte sized tables go first to avoid unnecessary alignment bits. 1269 ByteSizedTable dex_register_map; 1270 ByteSizedTable location_catalog; 1271 BitEncodingTable<StackMapEncoding> stack_map; 1272 BitEncodingTable<BitRegionEncoding> register_mask; 1273 BitEncodingTable<BitRegionEncoding> stack_mask; 1274 BitEncodingTable<InvokeInfoEncoding> invoke_info; 1275 BitEncodingTable<InlineInfoEncoding> inline_info; 1276 CodeInfoEncodingCodeInfoEncoding1277 CodeInfoEncoding() {} 1278 CodeInfoEncodingCodeInfoEncoding1279 explicit CodeInfoEncoding(const void* data) { 1280 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data); 1281 dex_register_map.Decode(&ptr); 1282 location_catalog.Decode(&ptr); 1283 stack_map.Decode(&ptr); 1284 register_mask.Decode(&ptr); 1285 stack_mask.Decode(&ptr); 1286 invoke_info.Decode(&ptr); 1287 if (stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0) { 1288 inline_info.Decode(&ptr); 1289 } else { 1290 inline_info = BitEncodingTable<InlineInfoEncoding>(); 1291 } 1292 cache_header_size = 1293 dchecked_integral_cast<SizeType>(ptr - reinterpret_cast<const uint8_t*>(data)); 1294 ComputeTableOffsets(); 1295 } 1296 1297 // Compress is not const since it calculates cache_header_size. This is used by PrepareForFillIn. 1298 template<typename Vector> CompressCodeInfoEncoding1299 void Compress(Vector* dest) { 1300 dex_register_map.Encode(dest); 1301 location_catalog.Encode(dest); 1302 stack_map.Encode(dest); 1303 register_mask.Encode(dest); 1304 stack_mask.Encode(dest); 1305 invoke_info.Encode(dest); 1306 if (stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0) { 1307 inline_info.Encode(dest); 1308 } 1309 cache_header_size = dest->size(); 1310 } 1311 ComputeTableOffsetsCodeInfoEncoding1312 ALWAYS_INLINE void ComputeTableOffsets() { 1313 // Skip the header. 1314 size_t bit_offset = HeaderSize() * kBitsPerByte; 1315 // The byte tables must be aligned so they must go first. 1316 dex_register_map.UpdateBitOffset(&bit_offset); 1317 location_catalog.UpdateBitOffset(&bit_offset); 1318 // Other tables don't require alignment. 1319 stack_map.UpdateBitOffset(&bit_offset); 1320 register_mask.UpdateBitOffset(&bit_offset); 1321 stack_mask.UpdateBitOffset(&bit_offset); 1322 invoke_info.UpdateBitOffset(&bit_offset); 1323 inline_info.UpdateBitOffset(&bit_offset); 1324 cache_non_header_size = RoundUp(bit_offset, kBitsPerByte) / kBitsPerByte - HeaderSize(); 1325 } 1326 HeaderSizeCodeInfoEncoding1327 ALWAYS_INLINE size_t HeaderSize() const { 1328 DCHECK_NE(cache_header_size, kInvalidSize) << "Uninitialized"; 1329 return cache_header_size; 1330 } 1331 NonHeaderSizeCodeInfoEncoding1332 ALWAYS_INLINE size_t NonHeaderSize() const { 1333 DCHECK_NE(cache_non_header_size, kInvalidSize) << "Uninitialized"; 1334 return cache_non_header_size; 1335 } 1336 1337 private: 1338 // Computed fields (not serialized). 1339 // Header size in bytes, cached to avoid needing to re-decoding the encoding in HeaderSize. 1340 SizeType cache_header_size = kInvalidSize; 1341 // Non header size in bytes, cached to avoid needing to re-decoding the encoding in NonHeaderSize. 1342 SizeType cache_non_header_size = kInvalidSize; 1343 }; 1344 1345 /** 1346 * Wrapper around all compiler information collected for a method. 1347 * The information is of the form: 1348 * 1349 * [CodeInfoEncoding, DexRegisterMap+, DexLocationCatalog+, StackMap+, RegisterMask+, StackMask+, 1350 * InlineInfo*] 1351 * 1352 * where CodeInfoEncoding is of the form: 1353 * 1354 * [ByteSizedTable(dex_register_map), ByteSizedTable(location_catalog), 1355 * BitEncodingTable<StackMapEncoding>, BitEncodingTable<BitRegionEncoding>, 1356 * BitEncodingTable<BitRegionEncoding>, BitEncodingTable<InlineInfoEncoding>] 1357 */ 1358 class CodeInfo { 1359 public: CodeInfo(MemoryRegion region)1360 explicit CodeInfo(MemoryRegion region) : region_(region) { 1361 } 1362 CodeInfo(const void * data)1363 explicit CodeInfo(const void* data) { 1364 CodeInfoEncoding encoding = CodeInfoEncoding(data); 1365 region_ = MemoryRegion(const_cast<void*>(data), 1366 encoding.HeaderSize() + encoding.NonHeaderSize()); 1367 } 1368 ExtractEncoding()1369 CodeInfoEncoding ExtractEncoding() const { 1370 CodeInfoEncoding encoding(region_.begin()); 1371 AssertValidStackMap(encoding); 1372 return encoding; 1373 } 1374 HasInlineInfo(const CodeInfoEncoding & encoding)1375 bool HasInlineInfo(const CodeInfoEncoding& encoding) const { 1376 return encoding.stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0; 1377 } 1378 GetDexRegisterLocationCatalog(const CodeInfoEncoding & encoding)1379 DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const CodeInfoEncoding& encoding) const { 1380 return DexRegisterLocationCatalog(region_.Subregion(encoding.location_catalog.byte_offset, 1381 encoding.location_catalog.num_bytes)); 1382 } 1383 GetNumberOfStackMaskBits(const CodeInfoEncoding & encoding)1384 ALWAYS_INLINE size_t GetNumberOfStackMaskBits(const CodeInfoEncoding& encoding) const { 1385 return encoding.stack_mask.encoding.BitSize(); 1386 } 1387 GetStackMapAt(size_t index,const CodeInfoEncoding & encoding)1388 ALWAYS_INLINE StackMap GetStackMapAt(size_t index, const CodeInfoEncoding& encoding) const { 1389 return StackMap(encoding.stack_map.BitRegion(region_, index)); 1390 } 1391 GetStackMask(size_t index,const CodeInfoEncoding & encoding)1392 BitMemoryRegion GetStackMask(size_t index, const CodeInfoEncoding& encoding) const { 1393 return encoding.stack_mask.BitRegion(region_, index); 1394 } 1395 GetStackMaskOf(const CodeInfoEncoding & encoding,const StackMap & stack_map)1396 BitMemoryRegion GetStackMaskOf(const CodeInfoEncoding& encoding, 1397 const StackMap& stack_map) const { 1398 return GetStackMask(stack_map.GetStackMaskIndex(encoding.stack_map.encoding), encoding); 1399 } 1400 GetRegisterMask(size_t index,const CodeInfoEncoding & encoding)1401 BitMemoryRegion GetRegisterMask(size_t index, const CodeInfoEncoding& encoding) const { 1402 return encoding.register_mask.BitRegion(region_, index); 1403 } 1404 GetRegisterMaskOf(const CodeInfoEncoding & encoding,const StackMap & stack_map)1405 uint32_t GetRegisterMaskOf(const CodeInfoEncoding& encoding, const StackMap& stack_map) const { 1406 size_t index = stack_map.GetRegisterMaskIndex(encoding.stack_map.encoding); 1407 return GetRegisterMask(index, encoding).LoadBits(0u, encoding.register_mask.encoding.BitSize()); 1408 } 1409 GetNumberOfLocationCatalogEntries(const CodeInfoEncoding & encoding)1410 uint32_t GetNumberOfLocationCatalogEntries(const CodeInfoEncoding& encoding) const { 1411 return encoding.location_catalog.num_entries; 1412 } 1413 GetDexRegisterLocationCatalogSize(const CodeInfoEncoding & encoding)1414 uint32_t GetDexRegisterLocationCatalogSize(const CodeInfoEncoding& encoding) const { 1415 return encoding.location_catalog.num_bytes; 1416 } 1417 GetNumberOfStackMaps(const CodeInfoEncoding & encoding)1418 uint32_t GetNumberOfStackMaps(const CodeInfoEncoding& encoding) const { 1419 return encoding.stack_map.num_entries; 1420 } 1421 1422 // Get the size of all the stack maps of this CodeInfo object, in bits. Not byte aligned. GetStackMapsSizeInBits(const CodeInfoEncoding & encoding)1423 ALWAYS_INLINE size_t GetStackMapsSizeInBits(const CodeInfoEncoding& encoding) const { 1424 return encoding.stack_map.encoding.BitSize() * GetNumberOfStackMaps(encoding); 1425 } 1426 GetInvokeInfo(const CodeInfoEncoding & encoding,size_t index)1427 InvokeInfo GetInvokeInfo(const CodeInfoEncoding& encoding, size_t index) const { 1428 return InvokeInfo(encoding.invoke_info.BitRegion(region_, index)); 1429 } 1430 GetDexRegisterMapOf(StackMap stack_map,const CodeInfoEncoding & encoding,size_t number_of_dex_registers)1431 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, 1432 const CodeInfoEncoding& encoding, 1433 size_t number_of_dex_registers) const { 1434 if (!stack_map.HasDexRegisterMap(encoding.stack_map.encoding)) { 1435 return DexRegisterMap(); 1436 } 1437 const uint32_t offset = encoding.dex_register_map.byte_offset + 1438 stack_map.GetDexRegisterMapOffset(encoding.stack_map.encoding); 1439 size_t size = ComputeDexRegisterMapSizeOf(encoding, offset, number_of_dex_registers); 1440 return DexRegisterMap(region_.Subregion(offset, size)); 1441 } 1442 GetDexRegisterMapsSize(const CodeInfoEncoding & encoding,uint32_t number_of_dex_registers)1443 size_t GetDexRegisterMapsSize(const CodeInfoEncoding& encoding, 1444 uint32_t number_of_dex_registers) const { 1445 size_t total = 0; 1446 for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) { 1447 StackMap stack_map = GetStackMapAt(i, encoding); 1448 DexRegisterMap map(GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers)); 1449 total += map.Size(); 1450 } 1451 return total; 1452 } 1453 1454 // 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)1455 DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth, 1456 InlineInfo inline_info, 1457 const CodeInfoEncoding& encoding, 1458 uint32_t number_of_dex_registers) const { 1459 if (!inline_info.HasDexRegisterMapAtDepth(encoding.inline_info.encoding, depth)) { 1460 return DexRegisterMap(); 1461 } else { 1462 uint32_t offset = encoding.dex_register_map.byte_offset + 1463 inline_info.GetDexRegisterMapOffsetAtDepth(encoding.inline_info.encoding, depth); 1464 size_t size = ComputeDexRegisterMapSizeOf(encoding, offset, number_of_dex_registers); 1465 return DexRegisterMap(region_.Subregion(offset, size)); 1466 } 1467 } 1468 GetInlineInfo(size_t index,const CodeInfoEncoding & encoding)1469 InlineInfo GetInlineInfo(size_t index, const CodeInfoEncoding& encoding) const { 1470 // Since we do not know the depth, we just return the whole remaining map. The caller may 1471 // access the inline info for arbitrary depths. To return the precise inline info we would need 1472 // to count the depth before returning. 1473 // TODO: Clean this up. 1474 const size_t bit_offset = encoding.inline_info.bit_offset + 1475 index * encoding.inline_info.encoding.BitSize(); 1476 return InlineInfo(BitMemoryRegion(region_, bit_offset, region_.size_in_bits() - bit_offset)); 1477 } 1478 GetInlineInfoOf(StackMap stack_map,const CodeInfoEncoding & encoding)1479 InlineInfo GetInlineInfoOf(StackMap stack_map, const CodeInfoEncoding& encoding) const { 1480 DCHECK(stack_map.HasInlineInfo(encoding.stack_map.encoding)); 1481 uint32_t index = stack_map.GetInlineInfoIndex(encoding.stack_map.encoding); 1482 return GetInlineInfo(index, encoding); 1483 } 1484 GetStackMapForDexPc(uint32_t dex_pc,const CodeInfoEncoding & encoding)1485 StackMap GetStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const { 1486 for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) { 1487 StackMap stack_map = GetStackMapAt(i, encoding); 1488 if (stack_map.GetDexPc(encoding.stack_map.encoding) == dex_pc) { 1489 return stack_map; 1490 } 1491 } 1492 return StackMap(); 1493 } 1494 1495 // Searches the stack map list backwards because catch stack maps are stored 1496 // at the end. GetCatchStackMapForDexPc(uint32_t dex_pc,const CodeInfoEncoding & encoding)1497 StackMap GetCatchStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const { 1498 for (size_t i = GetNumberOfStackMaps(encoding); i > 0; --i) { 1499 StackMap stack_map = GetStackMapAt(i - 1, encoding); 1500 if (stack_map.GetDexPc(encoding.stack_map.encoding) == dex_pc) { 1501 return stack_map; 1502 } 1503 } 1504 return StackMap(); 1505 } 1506 GetOsrStackMapForDexPc(uint32_t dex_pc,const CodeInfoEncoding & encoding)1507 StackMap GetOsrStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const { 1508 size_t e = GetNumberOfStackMaps(encoding); 1509 if (e == 0) { 1510 // There cannot be OSR stack map if there is no stack map. 1511 return StackMap(); 1512 } 1513 // Walk over all stack maps. If two consecutive stack maps are identical, then we 1514 // have found a stack map suitable for OSR. 1515 const StackMapEncoding& stack_map_encoding = encoding.stack_map.encoding; 1516 for (size_t i = 0; i < e - 1; ++i) { 1517 StackMap stack_map = GetStackMapAt(i, encoding); 1518 if (stack_map.GetDexPc(stack_map_encoding) == dex_pc) { 1519 StackMap other = GetStackMapAt(i + 1, encoding); 1520 if (other.GetDexPc(stack_map_encoding) == dex_pc && 1521 other.GetNativePcOffset(stack_map_encoding, kRuntimeISA) == 1522 stack_map.GetNativePcOffset(stack_map_encoding, kRuntimeISA)) { 1523 DCHECK_EQ(other.GetDexRegisterMapOffset(stack_map_encoding), 1524 stack_map.GetDexRegisterMapOffset(stack_map_encoding)); 1525 DCHECK(!stack_map.HasInlineInfo(stack_map_encoding)); 1526 if (i < e - 2) { 1527 // Make sure there are not three identical stack maps following each other. 1528 DCHECK_NE( 1529 stack_map.GetNativePcOffset(stack_map_encoding, kRuntimeISA), 1530 GetStackMapAt(i + 2, encoding).GetNativePcOffset(stack_map_encoding, kRuntimeISA)); 1531 } 1532 return stack_map; 1533 } 1534 } 1535 } 1536 return StackMap(); 1537 } 1538 GetStackMapForNativePcOffset(uint32_t native_pc_offset,const CodeInfoEncoding & encoding)1539 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset, 1540 const CodeInfoEncoding& encoding) const { 1541 // TODO: Safepoint stack maps are sorted by native_pc_offset but catch stack 1542 // maps are not. If we knew that the method does not have try/catch, 1543 // we could do binary search. 1544 for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) { 1545 StackMap stack_map = GetStackMapAt(i, encoding); 1546 if (stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA) == 1547 native_pc_offset) { 1548 return stack_map; 1549 } 1550 } 1551 return StackMap(); 1552 } 1553 GetInvokeInfoForNativePcOffset(uint32_t native_pc_offset,const CodeInfoEncoding & encoding)1554 InvokeInfo GetInvokeInfoForNativePcOffset(uint32_t native_pc_offset, 1555 const CodeInfoEncoding& encoding) { 1556 for (size_t index = 0; index < encoding.invoke_info.num_entries; index++) { 1557 InvokeInfo item = GetInvokeInfo(encoding, index); 1558 if (item.GetNativePcOffset(encoding.invoke_info.encoding, kRuntimeISA) == native_pc_offset) { 1559 return item; 1560 } 1561 } 1562 return InvokeInfo(BitMemoryRegion()); 1563 } 1564 1565 // Dump this CodeInfo object on `os`. `code_offset` is the (absolute) 1566 // native PC of the compiled method and `number_of_dex_registers` the 1567 // number of Dex virtual registers used in this method. If 1568 // `dump_stack_maps` is true, also dump the stack maps and the 1569 // associated Dex register maps. 1570 void Dump(VariableIndentationOutputStream* vios, 1571 uint32_t code_offset, 1572 uint16_t number_of_dex_registers, 1573 bool dump_stack_maps, 1574 InstructionSet instruction_set, 1575 const MethodInfo& method_info) const; 1576 1577 // Check that the code info has valid stack map and abort if it does not. AssertValidStackMap(const CodeInfoEncoding & encoding)1578 void AssertValidStackMap(const CodeInfoEncoding& encoding) const { 1579 if (region_.size() != 0 && region_.size_in_bits() < GetStackMapsSizeInBits(encoding)) { 1580 LOG(FATAL) << region_.size() << "\n" 1581 << encoding.HeaderSize() << "\n" 1582 << encoding.NonHeaderSize() << "\n" 1583 << encoding.location_catalog.num_entries << "\n" 1584 << encoding.stack_map.num_entries << "\n" 1585 << encoding.stack_map.encoding.BitSize(); 1586 } 1587 } 1588 1589 private: 1590 // Compute the size of the Dex register map associated to the stack map at 1591 // `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)1592 size_t ComputeDexRegisterMapSizeOf(const CodeInfoEncoding& encoding, 1593 uint32_t dex_register_map_offset_in_code_info, 1594 uint16_t number_of_dex_registers) const { 1595 // Offset where the actual mapping data starts within art::DexRegisterMap. 1596 size_t location_mapping_data_offset_in_dex_register_map = 1597 DexRegisterMap::GetLocationMappingDataOffset(number_of_dex_registers); 1598 // Create a temporary art::DexRegisterMap to be able to call 1599 // art::DexRegisterMap::GetNumberOfLiveDexRegisters and 1600 DexRegisterMap dex_register_map_without_locations( 1601 MemoryRegion(region_.Subregion(dex_register_map_offset_in_code_info, 1602 location_mapping_data_offset_in_dex_register_map))); 1603 size_t number_of_live_dex_registers = 1604 dex_register_map_without_locations.GetNumberOfLiveDexRegisters(number_of_dex_registers); 1605 size_t location_mapping_data_size_in_bits = 1606 DexRegisterMap::SingleEntrySizeInBits(GetNumberOfLocationCatalogEntries(encoding)) 1607 * number_of_live_dex_registers; 1608 size_t location_mapping_data_size_in_bytes = 1609 RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte; 1610 size_t dex_register_map_size = 1611 location_mapping_data_offset_in_dex_register_map + location_mapping_data_size_in_bytes; 1612 return dex_register_map_size; 1613 } 1614 1615 // Compute the size of a Dex register location catalog starting at offset `origin` 1616 // in `region_` and containing `number_of_dex_locations` entries. ComputeDexRegisterLocationCatalogSize(uint32_t origin,uint32_t number_of_dex_locations)1617 size_t ComputeDexRegisterLocationCatalogSize(uint32_t origin, 1618 uint32_t number_of_dex_locations) const { 1619 // TODO: Ideally, we would like to use art::DexRegisterLocationCatalog::Size or 1620 // art::DexRegisterLocationCatalog::FindLocationOffset, but the 1621 // DexRegisterLocationCatalog is not yet built. Try to factor common code. 1622 size_t offset = origin + DexRegisterLocationCatalog::kFixedSize; 1623 1624 // Skip the first `number_of_dex_locations - 1` entries. 1625 for (uint16_t i = 0; i < number_of_dex_locations; ++i) { 1626 // Read the first next byte and inspect its first 3 bits to decide 1627 // whether it is a short or a large location. 1628 DexRegisterLocationCatalog::ShortLocation first_byte = 1629 region_.LoadUnaligned<DexRegisterLocationCatalog::ShortLocation>(offset); 1630 DexRegisterLocation::Kind kind = 1631 DexRegisterLocationCatalog::ExtractKindFromShortLocation(first_byte); 1632 if (DexRegisterLocation::IsShortLocationKind(kind)) { 1633 // Short location. Skip the current byte. 1634 offset += DexRegisterLocationCatalog::SingleShortEntrySize(); 1635 } else { 1636 // Large location. Skip the 5 next bytes. 1637 offset += DexRegisterLocationCatalog::SingleLargeEntrySize(); 1638 } 1639 } 1640 size_t size = offset - origin; 1641 return size; 1642 } 1643 1644 MemoryRegion region_; 1645 friend class StackMapStream; 1646 }; 1647 1648 #undef ELEMENT_BYTE_OFFSET_AFTER 1649 #undef ELEMENT_BIT_OFFSET_AFTER 1650 1651 } // namespace art 1652 1653 #endif // ART_RUNTIME_STACK_MAP_H_ 1654