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