LLVM  10.0.0svn
TpiStreamBuilder.cpp
Go to the documentation of this file.
1 //===- TpiStreamBuilder.cpp - -------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/Support/Allocator.h"
24 #include "llvm/Support/Endian.h"
25 #include "llvm/Support/Error.h"
26 #include <algorithm>
27 #include <cstdint>
28 
29 using namespace llvm;
30 using namespace llvm::msf;
31 using namespace llvm::pdb;
32 using namespace llvm::support;
33 
34 TpiStreamBuilder::TpiStreamBuilder(MSFBuilder &Msf, uint32_t StreamIdx)
35  : Msf(Msf), Allocator(Msf.getAllocator()), Header(nullptr), Idx(StreamIdx) {
36 }
37 
39 
41  VerHeader = Version;
42 }
43 
45  Optional<uint32_t> Hash) {
46  // If we just crossed an 8KB threshold, add a type index offset.
47  size_t NewSize = TypeRecordBytes + Record.size();
48  constexpr size_t EightKB = 8 * 1024;
49  if (NewSize / EightKB > TypeRecordBytes / EightKB || TypeRecords.empty()) {
50  TypeIndexOffsets.push_back(
52  TypeRecords.size()),
53  ulittle32_t(TypeRecordBytes)});
54  }
55  TypeRecordBytes = NewSize;
56 
57  TypeRecords.push_back(Record);
58  if (Hash)
59  TypeHashes.push_back(*Hash);
60 }
61 
62 Error TpiStreamBuilder::finalize() {
63  if (Header)
64  return Error::success();
65 
66  TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>();
67 
68  uint32_t Count = TypeRecords.size();
69 
70  H->Version = VerHeader;
71  H->HeaderSize = sizeof(TpiStreamHeader);
73  H->TypeIndexEnd = H->TypeIndexBegin + Count;
74  H->TypeRecordBytes = TypeRecordBytes;
75 
76  H->HashStreamIndex = HashStreamIndex;
78  H->HashKeySize = sizeof(ulittle32_t);
80 
81  // Recall that hash values go into a completely different stream identified by
82  // the `HashStreamIndex` field of the `TpiStreamHeader`. Therefore, the data
83  // begins at offset 0 of this independent stream.
84  H->HashValueBuffer.Off = 0;
85  H->HashValueBuffer.Length = calculateHashBufferSize();
86 
87  // We never write any adjustments into our PDBs, so this is usually some
88  // offset with zero length.
90  H->HashAdjBuffer.Length = 0;
91 
93  H->IndexOffsetBuffer.Length = calculateIndexOffsetSize();
94 
95  Header = H;
96  return Error::success();
97 }
98 
100  return sizeof(TpiStreamHeader) + TypeRecordBytes;
101 }
102 
103 uint32_t TpiStreamBuilder::calculateHashBufferSize() const {
104  assert((TypeRecords.size() == TypeHashes.size() || TypeHashes.empty()) &&
105  "either all or no type records should have hashes");
106  return TypeHashes.size() * sizeof(ulittle32_t);
107 }
108 
109 uint32_t TpiStreamBuilder::calculateIndexOffsetSize() const {
110  return TypeIndexOffsets.size() * sizeof(codeview::TypeIndexOffset);
111 }
112 
115  if (auto EC = Msf.setStreamSize(Idx, Length))
116  return EC;
117 
118  uint32_t HashStreamSize =
119  calculateHashBufferSize() + calculateIndexOffsetSize();
120 
121  if (HashStreamSize == 0)
122  return Error::success();
123 
124  auto ExpectedIndex = Msf.addStream(HashStreamSize);
125  if (!ExpectedIndex)
126  return ExpectedIndex.takeError();
127  HashStreamIndex = *ExpectedIndex;
128  if (!TypeHashes.empty()) {
129  ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeHashes.size());
130  MutableArrayRef<ulittle32_t> HashBuffer(H, TypeHashes.size());
131  for (uint32_t I = 0; I < TypeHashes.size(); ++I) {
132  HashBuffer[I] = TypeHashes[I] % (MaxTpiHashBuckets - 1);
133  }
134  ArrayRef<uint8_t> Bytes(
135  reinterpret_cast<const uint8_t *>(HashBuffer.data()),
136  calculateHashBufferSize());
137  HashValueStream =
138  std::make_unique<BinaryByteStream>(Bytes, llvm::support::little);
139  }
140  return Error::success();
141 }
142 
144  WritableBinaryStreamRef Buffer) {
145  if (auto EC = finalize())
146  return EC;
147 
148  auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
149  Idx, Allocator);
150 
151  BinaryStreamWriter Writer(*InfoS);
152  if (auto EC = Writer.writeObject(*Header))
153  return EC;
154 
155  for (auto Rec : TypeRecords) {
156  assert(!Rec.empty()); // An empty record will not write anything, but it
157  // would shift all offsets from here on.
158  if (auto EC = Writer.writeBytes(Rec))
159  return EC;
160  }
161 
162  if (HashStreamIndex != kInvalidStreamIndex) {
163  auto HVS = WritableMappedBlockStream::createIndexedStream(
164  Layout, Buffer, HashStreamIndex, Allocator);
165  BinaryStreamWriter HW(*HVS);
166  if (HashValueStream) {
167  if (auto EC = HW.writeStreamRef(*HashValueStream))
168  return EC;
169  }
170 
171  for (auto &IndexOffset : TypeIndexOffsets) {
172  if (auto EC = HW.writeObject(IndexOffset))
173  return EC;
174  }
175  }
176 
177  return Error::success();
178 }
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:23
support::ulittle16_t HashStreamIndex
Definition: RawTypes.h:290
EmbeddedBuf IndexOffsetBuffer
Definition: RawTypes.h:296
support::ulittle32_t NumHashBuckets
Definition: RawTypes.h:293
Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer)
This file defines the MallocAllocator and BumpPtrAllocator interfaces.
support::ulittle32_t TypeRecordBytes
Definition: RawTypes.h:287
static const uint32_t FirstNonSimpleIndex
Definition: TypeIndex.h:97
A 32-bit type reference.
Definition: TypeIndex.h:95
const uint16_t kInvalidStreamIndex
Definition: RawConstants.h:19
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:290
support::ulittle32_t TypeIndexEnd
Definition: RawTypes.h:286
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:274
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:148
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:214
#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:285
Error setStreamSize(uint32_t Idx, uint32_t Size)
Update the size of an existing stream.
Definition: MSFBuilder.cpp:191
Basic Register Allocator
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
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:154
EmbeddedBuf HashValueBuffer
Definition: RawTypes.h:295
void setVersionHeader(PdbRaw_TpiVer Version)
support::ulittle16_t HashAuxStreamIndex
Definition: RawTypes.h:291
#define I(x, y, z)
Definition: MD5.cpp:58
support::ulittle32_t HashKeySize
Definition: RawTypes.h:292
support::ulittle32_t HeaderSize
Definition: RawTypes.h:284
void addTypeRecord(ArrayRef< uint8_t > Type, Optional< uint32_t > Hash)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
support::ulittle32_t Version
Definition: RawTypes.h:283
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
const uint32_t MaxTpiHashBuckets
Definition: RawTypes.h:301
EmbeddedBuf HashAdjBuffer
Definition: RawTypes.h:297
const uint64_t Version
Definition: InstrProf.h:984