1//===-------- StackMapParser.h - StackMap Parsing Support -------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#ifndef LLVM_CODEGEN_STACKMAPPARSER_H 11#define LLVM_CODEGEN_STACKMAPPARSER_H 12 13#include "llvm/ADT/ArrayRef.h" 14#include "llvm/Support/Endian.h" 15#include <vector> 16 17namespace llvm { 18 19template <support::endianness Endianness> 20class StackMapV2Parser { 21public: 22 23 template <typename AccessorT> 24 class AccessorIterator { 25 public: 26 27 AccessorIterator(AccessorT A) : A(A) {} 28 AccessorIterator& operator++() { A = A.next(); return *this; } 29 AccessorIterator operator++(int) { 30 auto tmp = *this; 31 ++*this; 32 return tmp; 33 } 34 35 bool operator==(const AccessorIterator &Other) { 36 return A.P == Other.A.P; 37 } 38 39 bool operator!=(const AccessorIterator &Other) { return !(*this == Other); } 40 41 AccessorT& operator*() { return A; } 42 AccessorT* operator->() { return &A; } 43 44 private: 45 AccessorT A; 46 }; 47 48 /// Accessor for function records. 49 class FunctionAccessor { 50 friend class StackMapV2Parser; 51 public: 52 53 /// Get the function address. 54 uint64_t getFunctionAddress() const { 55 return read<uint64_t>(P); 56 } 57 58 /// Get the function's stack size. 59 uint64_t getStackSize() const { 60 return read<uint64_t>(P + sizeof(uint64_t)); 61 } 62 63 /// Get the number of callsite records. 64 uint64_t getRecordCount() const { 65 return read<uint64_t>(P + (2 * sizeof(uint64_t))); 66 } 67 68 private: 69 FunctionAccessor(const uint8_t *P) : P(P) {} 70 71 const static int FunctionAccessorSize = 3 * sizeof(uint64_t); 72 73 FunctionAccessor next() const { 74 return FunctionAccessor(P + FunctionAccessorSize); 75 } 76 77 const uint8_t *P; 78 }; 79 80 /// Accessor for constants. 81 class ConstantAccessor { 82 friend class StackMapV2Parser; 83 public: 84 85 /// Return the value of this constant. 86 uint64_t getValue() const { return read<uint64_t>(P); } 87 88 private: 89 90 ConstantAccessor(const uint8_t *P) : P(P) {} 91 92 const static int ConstantAccessorSize = sizeof(uint64_t); 93 94 ConstantAccessor next() const { 95 return ConstantAccessor(P + ConstantAccessorSize); 96 } 97 98 const uint8_t *P; 99 }; 100 101 // Forward-declare RecordAccessor so we can friend it below. 102 class RecordAccessor; 103 104 enum class LocationKind : uint8_t { 105 Register = 1, Direct = 2, Indirect = 3, Constant = 4, ConstantIndex = 5 106 }; 107 108 109 /// Accessor for location records. 110 class LocationAccessor { 111 friend class StackMapV2Parser; 112 friend class RecordAccessor; 113 public: 114 115 /// Get the Kind for this location. 116 LocationKind getKind() const { 117 return LocationKind(P[KindOffset]); 118 } 119 120 /// Get the Dwarf register number for this location. 121 uint16_t getDwarfRegNum() const { 122 return read<uint16_t>(P + DwarfRegNumOffset); 123 } 124 125 /// Get the small-constant for this location. (Kind must be Constant). 126 uint32_t getSmallConstant() const { 127 assert(getKind() == LocationKind::Constant && "Not a small constant."); 128 return read<uint32_t>(P + SmallConstantOffset); 129 } 130 131 /// Get the constant-index for this location. (Kind must be ConstantIndex). 132 uint32_t getConstantIndex() const { 133 assert(getKind() == LocationKind::ConstantIndex && 134 "Not a constant-index."); 135 return read<uint32_t>(P + SmallConstantOffset); 136 } 137 138 /// Get the offset for this location. (Kind must be Direct or Indirect). 139 int32_t getOffset() const { 140 assert((getKind() == LocationKind::Direct || 141 getKind() == LocationKind::Indirect) && 142 "Not direct or indirect."); 143 return read<int32_t>(P + SmallConstantOffset); 144 } 145 146 private: 147 148 LocationAccessor(const uint8_t *P) : P(P) {} 149 150 LocationAccessor next() const { 151 return LocationAccessor(P + LocationAccessorSize); 152 } 153 154 static const int KindOffset = 0; 155 static const int DwarfRegNumOffset = KindOffset + sizeof(uint16_t); 156 static const int SmallConstantOffset = DwarfRegNumOffset + sizeof(uint16_t); 157 static const int LocationAccessorSize = sizeof(uint64_t); 158 159 const uint8_t *P; 160 }; 161 162 /// Accessor for stackmap live-out fields. 163 class LiveOutAccessor { 164 friend class StackMapV2Parser; 165 friend class RecordAccessor; 166 public: 167 168 /// Get the Dwarf register number for this live-out. 169 uint16_t getDwarfRegNum() const { 170 return read<uint16_t>(P + DwarfRegNumOffset); 171 } 172 173 /// Get the size in bytes of live [sub]register. 174 unsigned getSizeInBytes() const { 175 return read<uint8_t>(P + SizeOffset); 176 } 177 178 private: 179 180 LiveOutAccessor(const uint8_t *P) : P(P) {} 181 182 LiveOutAccessor next() const { 183 return LiveOutAccessor(P + LiveOutAccessorSize); 184 } 185 186 static const int DwarfRegNumOffset = 0; 187 static const int SizeOffset = 188 DwarfRegNumOffset + sizeof(uint16_t) + sizeof(uint8_t); 189 static const int LiveOutAccessorSize = sizeof(uint32_t); 190 191 const uint8_t *P; 192 }; 193 194 /// Accessor for stackmap records. 195 class RecordAccessor { 196 friend class StackMapV2Parser; 197 public: 198 199 typedef AccessorIterator<LocationAccessor> location_iterator; 200 typedef AccessorIterator<LiveOutAccessor> liveout_iterator; 201 202 /// Get the patchpoint/stackmap ID for this record. 203 uint64_t getID() const { 204 return read<uint64_t>(P + PatchpointIDOffset); 205 } 206 207 /// Get the instruction offset (from the start of the containing function) 208 /// for this record. 209 uint32_t getInstructionOffset() const { 210 return read<uint32_t>(P + InstructionOffsetOffset); 211 } 212 213 /// Get the number of locations contained in this record. 214 uint16_t getNumLocations() const { 215 return read<uint16_t>(P + NumLocationsOffset); 216 } 217 218 /// Get the location with the given index. 219 LocationAccessor getLocation(unsigned LocationIndex) const { 220 unsigned LocationOffset = 221 LocationListOffset + LocationIndex * LocationSize; 222 return LocationAccessor(P + LocationOffset); 223 } 224 225 /// Begin iterator for locations. 226 location_iterator location_begin() const { 227 return location_iterator(getLocation(0)); 228 } 229 230 /// End iterator for locations. 231 location_iterator location_end() const { 232 return location_iterator(getLocation(getNumLocations())); 233 } 234 235 /// Iterator range for locations. 236 iterator_range<location_iterator> locations() const { 237 return make_range(location_begin(), location_end()); 238 } 239 240 /// Get the number of liveouts contained in this record. 241 uint16_t getNumLiveOuts() const { 242 return read<uint16_t>(P + getNumLiveOutsOffset()); 243 } 244 245 /// Get the live-out with the given index. 246 LiveOutAccessor getLiveOut(unsigned LiveOutIndex) const { 247 unsigned LiveOutOffset = 248 getNumLiveOutsOffset() + sizeof(uint16_t) + LiveOutIndex * LiveOutSize; 249 return LiveOutAccessor(P + LiveOutOffset); 250 } 251 252 /// Begin iterator for live-outs. 253 liveout_iterator liveouts_begin() const { 254 return liveout_iterator(getLiveOut(0)); 255 } 256 257 258 /// End iterator for live-outs. 259 liveout_iterator liveouts_end() const { 260 return liveout_iterator(getLiveOut(getNumLiveOuts())); 261 } 262 263 /// Iterator range for live-outs. 264 iterator_range<liveout_iterator> liveouts() const { 265 return make_range(liveouts_begin(), liveouts_end()); 266 } 267 268 private: 269 270 RecordAccessor(const uint8_t *P) : P(P) {} 271 272 unsigned getNumLiveOutsOffset() const { 273 return LocationListOffset + LocationSize * getNumLocations() + 274 sizeof(uint16_t); 275 } 276 277 unsigned getSizeInBytes() const { 278 unsigned RecordSize = 279 getNumLiveOutsOffset() + sizeof(uint16_t) + getNumLiveOuts() * LiveOutSize; 280 return (RecordSize + 7) & ~0x7; 281 } 282 283 RecordAccessor next() const { 284 return RecordAccessor(P + getSizeInBytes()); 285 } 286 287 static const unsigned PatchpointIDOffset = 0; 288 static const unsigned InstructionOffsetOffset = 289 PatchpointIDOffset + sizeof(uint64_t); 290 static const unsigned NumLocationsOffset = 291 InstructionOffsetOffset + sizeof(uint32_t) + sizeof(uint16_t); 292 static const unsigned LocationListOffset = 293 NumLocationsOffset + sizeof(uint16_t); 294 static const unsigned LocationSize = sizeof(uint64_t); 295 static const unsigned LiveOutSize = sizeof(uint32_t); 296 297 const uint8_t *P; 298 }; 299 300 /// Construct a parser for a version-2 stackmap. StackMap data will be read 301 /// from the given array. 302 StackMapV2Parser(ArrayRef<uint8_t> StackMapSection) 303 : StackMapSection(StackMapSection) { 304 ConstantsListOffset = FunctionListOffset + getNumFunctions() * FunctionSize; 305 306 assert(StackMapSection[0] == 2 && 307 "StackMapV2Parser can only parse version 2 stackmaps"); 308 309 unsigned CurrentRecordOffset = 310 ConstantsListOffset + getNumConstants() * ConstantSize; 311 312 for (unsigned I = 0, E = getNumRecords(); I != E; ++I) { 313 StackMapRecordOffsets.push_back(CurrentRecordOffset); 314 CurrentRecordOffset += 315 RecordAccessor(&StackMapSection[CurrentRecordOffset]).getSizeInBytes(); 316 } 317 } 318 319 typedef AccessorIterator<FunctionAccessor> function_iterator; 320 typedef AccessorIterator<ConstantAccessor> constant_iterator; 321 typedef AccessorIterator<RecordAccessor> record_iterator; 322 323 /// Get the version number of this stackmap. (Always returns 2). 324 unsigned getVersion() const { return 2; } 325 326 /// Get the number of functions in the stack map. 327 uint32_t getNumFunctions() const { 328 return read<uint32_t>(&StackMapSection[NumFunctionsOffset]); 329 } 330 331 /// Get the number of large constants in the stack map. 332 uint32_t getNumConstants() const { 333 return read<uint32_t>(&StackMapSection[NumConstantsOffset]); 334 } 335 336 /// Get the number of stackmap records in the stackmap. 337 uint32_t getNumRecords() const { 338 return read<uint32_t>(&StackMapSection[NumRecordsOffset]); 339 } 340 341 /// Return an FunctionAccessor for the given function index. 342 FunctionAccessor getFunction(unsigned FunctionIndex) const { 343 return FunctionAccessor(StackMapSection.data() + 344 getFunctionOffset(FunctionIndex)); 345 } 346 347 /// Begin iterator for functions. 348 function_iterator functions_begin() const { 349 return function_iterator(getFunction(0)); 350 } 351 352 /// End iterator for functions. 353 function_iterator functions_end() const { 354 return function_iterator( 355 FunctionAccessor(StackMapSection.data() + 356 getFunctionOffset(getNumFunctions()))); 357 } 358 359 /// Iterator range for functions. 360 iterator_range<function_iterator> functions() const { 361 return make_range(functions_begin(), functions_end()); 362 } 363 364 /// Return the large constant at the given index. 365 ConstantAccessor getConstant(unsigned ConstantIndex) const { 366 return ConstantAccessor(StackMapSection.data() + 367 getConstantOffset(ConstantIndex)); 368 } 369 370 /// Begin iterator for constants. 371 constant_iterator constants_begin() const { 372 return constant_iterator(getConstant(0)); 373 } 374 375 /// End iterator for constants. 376 constant_iterator constants_end() const { 377 return constant_iterator( 378 ConstantAccessor(StackMapSection.data() + 379 getConstantOffset(getNumConstants()))); 380 } 381 382 /// Iterator range for constants. 383 iterator_range<constant_iterator> constants() const { 384 return make_range(constants_begin(), constants_end()); 385 } 386 387 /// Return a RecordAccessor for the given record index. 388 RecordAccessor getRecord(unsigned RecordIndex) const { 389 std::size_t RecordOffset = StackMapRecordOffsets[RecordIndex]; 390 return RecordAccessor(StackMapSection.data() + RecordOffset); 391 } 392 393 /// Begin iterator for records. 394 record_iterator records_begin() const { 395 if (getNumRecords() == 0) 396 return record_iterator(RecordAccessor(nullptr)); 397 return record_iterator(getRecord(0)); 398 } 399 400 /// End iterator for records. 401 record_iterator records_end() const { 402 // Records need to be handled specially, since we cache the start addresses 403 // for them: We can't just compute the 1-past-the-end address, we have to 404 // look at the last record and use the 'next' method. 405 if (getNumRecords() == 0) 406 return record_iterator(RecordAccessor(nullptr)); 407 return record_iterator(getRecord(getNumRecords() - 1).next()); 408 } 409 410 /// Iterator range for records. 411 iterator_range<record_iterator> records() const { 412 return make_range(records_begin(), records_end()); 413 } 414 415private: 416 417 template <typename T> 418 static T read(const uint8_t *P) { 419 return support::endian::read<T, Endianness, 1>(P); 420 } 421 422 static const unsigned HeaderOffset = 0; 423 static const unsigned NumFunctionsOffset = HeaderOffset + sizeof(uint32_t); 424 static const unsigned NumConstantsOffset = NumFunctionsOffset + sizeof(uint32_t); 425 static const unsigned NumRecordsOffset = NumConstantsOffset + sizeof(uint32_t); 426 static const unsigned FunctionListOffset = NumRecordsOffset + sizeof(uint32_t); 427 428 static const unsigned FunctionSize = 3 * sizeof(uint64_t); 429 static const unsigned ConstantSize = sizeof(uint64_t); 430 431 std::size_t getFunctionOffset(unsigned FunctionIndex) const { 432 return FunctionListOffset + FunctionIndex * FunctionSize; 433 } 434 435 std::size_t getConstantOffset(unsigned ConstantIndex) const { 436 return ConstantsListOffset + ConstantIndex * ConstantSize; 437 } 438 439 ArrayRef<uint8_t> StackMapSection; 440 unsigned ConstantsListOffset; 441 std::vector<unsigned> StackMapRecordOffsets; 442}; 443 444} 445 446#endif 447