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