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 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? 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. 150 DexRegisterLocation() : kind_(Kind::kNone), value_(0) {} 151 152 DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {} 153 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. 160 Kind GetKind() const { 161 return ConvertToSurfaceKind(kind_); 162 } 163 164 // Get the value of the location. 165 int32_t GetValue() const { return value_; } 166 167 // Get the actual kind of the location. 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: 197 explicit DexRegisterLocationCatalog(MemoryRegion region) : region_(region) {} 198 199 // Short (compressed) location, fitting on one byte. 200 typedef uint8_t ShortLocation; 201 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`. 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`. 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`. 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`. 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? 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 350 static size_t EntrySize(const DexRegisterLocation& location) { 351 return CanBeEncodedAsShortLocation(location) ? SingleShortEntrySize() : SingleLargeEntrySize(); 352 } 353 354 static size_t SingleShortEntrySize() { 355 return sizeof(ShortLocation); 356 } 357 358 static size_t SingleLargeEntrySize() { 359 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t); 360 } 361 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 386 static bool IsShortStackOffsetValue(int32_t value) { 387 DCHECK_EQ(value % kFrameSlotSize, 0); 388 return IsShortValue(value / kFrameSlotSize); 389 } 390 391 static bool IsShortConstantValue(int32_t value) { 392 return IsShortValue(value); 393 } 394 395 static bool IsShortValue(int32_t value) { 396 return IsUint<kValueBits>(value); 397 } 398 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 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 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`. 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: 444 explicit DexRegisterMap(MemoryRegion region) : region_(region) {} 445 DexRegisterMap() {} 446 447 bool IsValid() const { return region_.pointer() != nullptr; } 448 449 // Get the surface kind of Dex register `dex_register_number`. 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 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 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 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`. 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`. 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 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 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 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 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. 591 static size_t GetLiveBitMaskSize(uint16_t number_of_dex_registers) { 592 return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte; 593 } 594 595 static size_t GetLocationMappingDataOffset(uint16_t number_of_dex_registers) { 596 return GetLiveBitMaskOffset() + GetLiveBitMaskSize(number_of_dex_registers); 597 } 598 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. 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. 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`. 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) 658 : 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 663 ALWAYS_INLINE size_t BitSize() const { return end_offset_ - start_offset_; } 664 665 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 695 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: 708 StackMapEncoding() {} 709 710 // Set stack map bit layout based on given sizes. 711 // Returns the size of stack map in bytes. 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 747 ALWAYS_INLINE FieldEncoding GetNativePcEncoding() const { 748 return FieldEncoding(kNativePcBitOffset, dex_pc_bit_offset_); 749 } 750 ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const { 751 return FieldEncoding(dex_pc_bit_offset_, dex_register_map_bit_offset_, -1 /* min_value */); 752 } 753 ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const { 754 return FieldEncoding(dex_register_map_bit_offset_, inline_info_bit_offset_, -1 /* min_value */); 755 } 756 ALWAYS_INLINE FieldEncoding GetInlineInfoEncoding() const { 757 return FieldEncoding(inline_info_bit_offset_, register_mask_bit_offset_, -1 /* min_value */); 758 } 759 ALWAYS_INLINE FieldEncoding GetRegisterMaskEncoding() const { 760 return FieldEncoding(register_mask_bit_offset_, stack_mask_bit_offset_); 761 } 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: 793 StackMap() {} 794 explicit StackMap(MemoryRegion region) : region_(region) {} 795 796 ALWAYS_INLINE bool IsValid() const { return region_.pointer() != nullptr; } 797 798 ALWAYS_INLINE uint32_t GetDexPc(const StackMapEncoding& encoding) const { 799 return encoding.GetDexPcEncoding().Load(region_); 800 } 801 802 ALWAYS_INLINE void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) { 803 encoding.GetDexPcEncoding().Store(region_, dex_pc); 804 } 805 806 ALWAYS_INLINE uint32_t GetNativePcOffset(const StackMapEncoding& encoding) const { 807 return encoding.GetNativePcEncoding().Load(region_); 808 } 809 810 ALWAYS_INLINE void SetNativePcOffset(const StackMapEncoding& encoding, uint32_t native_pc_offset) { 811 encoding.GetNativePcEncoding().Store(region_, native_pc_offset); 812 } 813 814 ALWAYS_INLINE uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const { 815 return encoding.GetDexRegisterMapEncoding().Load(region_); 816 } 817 818 ALWAYS_INLINE void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) { 819 encoding.GetDexRegisterMapEncoding().Store(region_, offset); 820 } 821 822 ALWAYS_INLINE uint32_t GetInlineDescriptorOffset(const StackMapEncoding& encoding) const { 823 return encoding.GetInlineInfoEncoding().Load(region_); 824 } 825 826 ALWAYS_INLINE void SetInlineDescriptorOffset(const StackMapEncoding& encoding, uint32_t offset) { 827 encoding.GetInlineInfoEncoding().Store(region_, offset); 828 } 829 830 ALWAYS_INLINE uint32_t GetRegisterMask(const StackMapEncoding& encoding) const { 831 return encoding.GetRegisterMaskEncoding().Load(region_); 832 } 833 834 ALWAYS_INLINE void SetRegisterMask(const StackMapEncoding& encoding, uint32_t mask) { 835 encoding.GetRegisterMaskEncoding().Store(region_, mask); 836 } 837 838 ALWAYS_INLINE size_t GetNumberOfStackMaskBits(const StackMapEncoding& encoding) const { 839 return region_.size_in_bits() - encoding.GetStackMaskBitOffset(); 840 } 841 842 ALWAYS_INLINE bool GetStackMaskBit(const StackMapEncoding& encoding, size_t index) const { 843 return region_.LoadBit(encoding.GetStackMaskBitOffset() + index); 844 } 845 846 ALWAYS_INLINE void SetStackMaskBit(const StackMapEncoding& encoding, size_t index, bool value) { 847 region_.StoreBit(encoding.GetStackMaskBitOffset() + index, value); 848 } 849 850 ALWAYS_INLINE bool HasDexRegisterMap(const StackMapEncoding& encoding) const { 851 return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap; 852 } 853 854 ALWAYS_INLINE bool HasInlineInfo(const StackMapEncoding& encoding) const { 855 return GetInlineDescriptorOffset(encoding) != kNoInlineInfo; 856 } 857 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: 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 906 ALWAYS_INLINE FieldEncoding GetMethodIndexEncoding() const { 907 return FieldEncoding(kMethodIndexBitOffset, dex_pc_bit_offset_); 908 } 909 ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const { 910 return FieldEncoding(dex_pc_bit_offset_, invoke_type_bit_offset_, -1 /* min_value */); 911 } 912 ALWAYS_INLINE FieldEncoding GetInvokeTypeEncoding() const { 913 return FieldEncoding(invoke_type_bit_offset_, dex_register_map_bit_offset_); 914 } 915 ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const { 916 return FieldEncoding(dex_register_map_bit_offset_, total_bit_size_, -1 /* min_value */); 917 } 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: 940 explicit InlineInfo(MemoryRegion region) : region_(region) { 941 } 942 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 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 956 ALWAYS_INLINE uint32_t GetMethodIndexAtDepth(const InlineInfoEncoding& encoding, 957 uint32_t depth) const { 958 return encoding.GetMethodIndexEncoding().Load(GetRegionAtDepth(encoding, depth)); 959 } 960 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 967 ALWAYS_INLINE uint32_t GetDexPcAtDepth(const InlineInfoEncoding& encoding, 968 uint32_t depth) const { 969 return encoding.GetDexPcEncoding().Load(GetRegionAtDepth(encoding, depth)); 970 } 971 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 978 ALWAYS_INLINE uint32_t GetInvokeTypeAtDepth(const InlineInfoEncoding& encoding, 979 uint32_t depth) const { 980 return encoding.GetInvokeTypeEncoding().Load(GetRegionAtDepth(encoding, depth)); 981 } 982 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 989 ALWAYS_INLINE uint32_t GetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding, 990 uint32_t depth) const { 991 return encoding.GetDexRegisterMapEncoding().Load(GetRegionAtDepth(encoding, depth)); 992 } 993 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 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: 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 1030 CodeInfoEncoding() { } 1031 1032 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> 1054 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: 1081 explicit CodeInfo(MemoryRegion region) : region_(region) { 1082 } 1083 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 1090 CodeInfoEncoding ExtractEncoding() const { 1091 return CodeInfoEncoding(region_.start()); 1092 } 1093 1094 bool HasInlineInfo(const CodeInfoEncoding& encoding) const { 1095 return encoding.stack_map_encoding.GetInlineInfoEncoding().BitSize() > 0; 1096 } 1097 1098 DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const CodeInfoEncoding& encoding) const { 1099 return DexRegisterLocationCatalog(region_.Subregion( 1100 GetDexRegisterLocationCatalogOffset(encoding), 1101 GetDexRegisterLocationCatalogSize(encoding))); 1102 } 1103 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 1109 uint32_t GetNumberOfLocationCatalogEntries(const CodeInfoEncoding& encoding) const { 1110 return encoding.number_of_location_catalog_entries; 1111 } 1112 1113 uint32_t GetDexRegisterLocationCatalogSize(const CodeInfoEncoding& encoding) const { 1114 return ComputeDexRegisterLocationCatalogSize(GetDexRegisterLocationCatalogOffset(encoding), 1115 GetNumberOfLocationCatalogEntries(encoding)); 1116 } 1117 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. 1123 size_t GetStackMapsSize(const CodeInfoEncoding& encoding) const { 1124 return encoding.stack_map_size_in_bytes * GetNumberOfStackMaps(encoding); 1125 } 1126 1127 uint32_t GetDexRegisterLocationCatalogOffset(const CodeInfoEncoding& encoding) const { 1128 return GetStackMapsOffset(encoding) + GetStackMapsSize(encoding); 1129 } 1130 1131 size_t GetDexRegisterMapsOffset(const CodeInfoEncoding& encoding) const { 1132 return GetDexRegisterLocationCatalogOffset(encoding) 1133 + GetDexRegisterLocationCatalogSize(encoding); 1134 } 1135 1136 uint32_t GetStackMapsOffset(const CodeInfoEncoding& encoding) const { 1137 return encoding.header_size; 1138 } 1139 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`. 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 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 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. 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 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 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: 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`. 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. 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