LLVM  8.0.1
TpiStreamBuilder.cpp
Go to the documentation of this file.
1 //===- TpiStreamBuilder.cpp - -------------------------------------------===//
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 
11 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/Support/Allocator.h"
25 #include "llvm/Support/Endian.h"
26 #include "llvm/Support/Error.h"
27 #include <algorithm>
28 #include <cstdint>
29 
30 using namespace llvm;
31 using namespace llvm::msf;
32 using namespace llvm::pdb;
33 using namespace llvm::support;
34 
35 TpiStreamBuilder::TpiStreamBuilder(MSFBuilder &Msf, uint32_t StreamIdx)
36  : Msf(Msf), Allocator(Msf.getAllocator()), Header(nullptr), Idx(StreamIdx) {
37 }
38 
40 
42  VerHeader = Version;
43 }
44 
46  Optional<uint32_t> Hash) {
47  // If we just crossed an 8KB threshold, add a type index offset.
48  size_t NewSize = TypeRecordBytes + Record.size();
49  constexpr size_t EightKB = 8 * 1024;
50  if (NewSize / EightKB > TypeRecordBytes / EightKB || TypeRecords.empty()) {
51  TypeIndexOffsets.push_back(
53  TypeRecords.size()),
54  ulittle32_t(TypeRecordBytes)});
55  }
56  TypeRecordBytes = NewSize;
57 
58  TypeRecords.push_back(Record);
59  if (Hash)
60  TypeHashes.push_back(*Hash);
61 }
62 
63 Error TpiStreamBuilder::finalize() {
64  if (Header)
65  return Error::success();
66 
67  TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>();
68 
69  uint32_t Count = TypeRecords.size();
70 
71  H->Version = VerHeader;
72  H->HeaderSize = sizeof(TpiStreamHeader);
74  H->TypeIndexEnd = H->TypeIndexBegin + Count;
75  H->TypeRecordBytes = TypeRecordBytes;
76 
77  H->HashStreamIndex = HashStreamIndex;
79  H->HashKeySize = sizeof(ulittle32_t);
81 
82  // Recall that hash values go into a completely different stream identified by
83  // the `HashStreamIndex` field of the `TpiStreamHeader`. Therefore, the data
84  // begins at offset 0 of this independent stream.
85  H->HashValueBuffer.Off = 0;
86  H->HashValueBuffer.Length = calculateHashBufferSize();
87 
88  // We never write any adjustments into our PDBs, so this is usually some
89  // offset with zero length.
91  H->HashAdjBuffer.Length = 0;
92 
94  H->IndexOffsetBuffer.Length = calculateIndexOffsetSize();
95 
96  Header = H;
97  return Error::success();
98 }
99 
101  return sizeof(TpiStreamHeader) + TypeRecordBytes;
102 }
103 
104 uint32_t TpiStreamBuilder::calculateHashBufferSize() const {
105  assert((TypeRecords.size() == TypeHashes.size() || TypeHashes.empty()) &&
106  "either all or no type records should have hashes");
107  return TypeHashes.size() * sizeof(ulittle32_t);
108 }
109 
110 uint32_t TpiStreamBuilder::calculateIndexOffsetSize() const {
111  return TypeIndexOffsets.size() * sizeof(codeview::TypeIndexOffset);
112 }
113 
116  if (auto EC = Msf.setStreamSize(Idx, Length))
117  return EC;
118 
119  uint32_t HashStreamSize =
120  calculateHashBufferSize() + calculateIndexOffsetSize();
121 
122  if (HashStreamSize == 0)
123  return Error::success();
124 
125  auto ExpectedIndex = Msf.addStream(HashStreamSize);
126  if (!ExpectedIndex)
127  return ExpectedIndex.takeError();
128  HashStreamIndex = *ExpectedIndex;
129  if (!TypeHashes.empty()) {
130  ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeHashes.size());
131  MutableArrayRef<ulittle32_t> HashBuffer(H, TypeHashes.size());
132  for (uint32_t I = 0; I < TypeHashes.size(); ++I) {
133  HashBuffer[I] = TypeHashes[I] % MinTpiHashBuckets;
134  }
135  ArrayRef<uint8_t> Bytes(
136  reinterpret_cast<const uint8_t *>(HashBuffer.data()),
137  calculateHashBufferSize());
138  HashValueStream =
139  llvm::make_unique<BinaryByteStream>(Bytes, llvm::support::little);
140  }
141  return Error::success();
142 }
143 
145  WritableBinaryStreamRef Buffer) {
146  if (auto EC = finalize())
147  return EC;
148 
149  auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
150  Idx, Allocator);
151 
152  BinaryStreamWriter Writer(*InfoS);
153  if (auto EC = Writer.writeObject(*Header))
154  return EC;
155 
156  for (auto Rec : TypeRecords)
157  if (auto EC = Writer.writeBytes(Rec))
158  return EC;
159 
160  if (HashStreamIndex != kInvalidStreamIndex) {
161  auto HVS = WritableMappedBlockStream::createIndexedStream(
162  Layout, Buffer, HashStreamIndex, Allocator);
163  BinaryStreamWriter HW(*HVS);
164  if (HashValueStream) {
165  if (auto EC = HW.writeStreamRef(*HashValueStream))
166  return EC;
167  }
168 
169  for (auto &IndexOffset : TypeIndexOffsets) {
170  if (auto EC = HW.writeObject(IndexOffset))
171  return EC;
172  }
173  }
174 
175  return Error::success();
176 }
Error writeObject(const T &Obj)
Writes the object Obj to the underlying stream, as if by using memcpy.
Error writeBytes(ArrayRef< uint8_t > Buffer)
Write the bytes specified in Buffer to the underlying stream.
This class represents lattice values for constants.
Definition: AllocatorList.h:24
support::ulittle16_t HashStreamIndex
Definition: RawTypes.h:291
EmbeddedBuf IndexOffsetBuffer
Definition: RawTypes.h:297
support::ulittle32_t NumHashBuckets
Definition: RawTypes.h:294
Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer)
This file defines the MallocAllocator and BumpPtrAllocator interfaces.
support::ulittle32_t TypeRecordBytes
Definition: RawTypes.h:288
static const uint32_t FirstNonSimpleIndex
Definition: TypeIndex.h:98
A 32-bit type reference.
Definition: TypeIndex.h:96
const uint16_t kInvalidStreamIndex
Definition: RawConstants.h:20
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:291
support::ulittle32_t TypeIndexEnd
Definition: RawTypes.h:287
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:271
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:149
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void * Allocate(size_t Size, size_t Alignment)
Allocate space at the specified alignment.
Definition: Allocator.h:215
#define H(x, y, z)
Definition: MD5.cpp:57
Error writeStreamRef(BinaryStreamRef Ref)
Efficiently reads all data from Ref, and writes it to this stream.
Provides write only access to a subclass of WritableBinaryStream.
support::ulittle32_t TypeIndexBegin
Definition: RawTypes.h:286
Error setStreamSize(uint32_t Idx, uint32_t Size)
Update the size of an existing stream.
Definition: MSFBuilder.cpp:192
const uint32_t MinTpiHashBuckets
Definition: RawTypes.h:301
Basic Register Allocator
static ErrorSuccess success()
Create a success value.
Definition: Error.h:327
Expected< uint32_t > addStream(uint32_t Size, ArrayRef< uint32_t > Blocks)
Add a stream to the MSF file with the given size, occupying the given list of blocks.
Definition: MSFBuilder.cpp:155
EmbeddedBuf HashValueBuffer
Definition: RawTypes.h:296
void setVersionHeader(PdbRaw_TpiVer Version)
support::ulittle16_t HashAuxStreamIndex
Definition: RawTypes.h:292
#define I(x, y, z)
Definition: MD5.cpp:58
support::ulittle32_t HashKeySize
Definition: RawTypes.h:293
support::ulittle32_t HeaderSize
Definition: RawTypes.h:285
void addTypeRecord(ArrayRef< uint8_t > Type, Optional< uint32_t > Hash)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
support::ulittle32_t Version
Definition: RawTypes.h:284
Lightweight error class with error context and mandatory checking.
Definition: Error.h:158
EmbeddedBuf HashAdjBuffer
Definition: RawTypes.h:298
const uint64_t Version
Definition: InstrProf.h:895