Home | History | Annotate | Download | only in Object
      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 StackMapV2Parser {
     21 public:
     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 
    415 private:
    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