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