1 //===- DebugTypes.cpp -----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "DebugTypes.h"
10 #include "COFFLinkerContext.h"
13 #include "InputFiles.h"
15 #include "TypeMerger.h"
16 #include "lld/Common/ErrorHandler.h"
17 #include "lld/Common/Memory.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
20 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
21 #include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
22 #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
23 #include "llvm/DebugInfo/PDB/GenericError.h"
24 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
25 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
26 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
27 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
28 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
29 #include "llvm/Support/FormatVariadic.h"
30 #include "llvm/Support/Parallel.h"
31 #include "llvm/Support/Path.h"
32 #include "llvm/Support/TimeProfiler.h"
35 using namespace llvm::codeview
;
37 using namespace lld::coff
;
40 class TypeServerIpiSource
;
42 // The TypeServerSource class represents a PDB type server, a file referenced by
43 // OBJ files compiled with MSVC /Zi. A single PDB can be shared by several OBJ
44 // files, therefore there must be only once instance per OBJ lot. The file path
45 // is discovered from the dependent OBJ's debug type stream. The
46 // TypeServerSource object is then queued and loaded by the COFF Driver. The
47 // debug type stream for such PDB files will be merged first in the final PDB,
48 // before any dependent OBJ.
49 class TypeServerSource
: public TpiSource
{
51 explicit TypeServerSource(COFFLinkerContext
&ctx
, PDBInputFile
*f
)
52 : TpiSource(ctx
, PDB
, nullptr), pdbInputFile(f
) {
55 pdb::PDBFile
&file
= f
->session
->getPDBFile();
56 auto expectedInfo
= file
.getPDBInfoStream();
59 Guid
= expectedInfo
->getGuid();
60 auto it
= ctx
.typeServerSourceMappings
.emplace(Guid
, this);
62 // If we hit here we have collision on Guid's in two PDB files.
63 // This can happen if the PDB Guid is invalid or if we are really
64 // unlucky. This should fall back on stright file-system lookup.
65 it
.first
->second
= nullptr;
69 Error
mergeDebugT(TypeMerger
*m
) override
;
71 void loadGHashes() override
;
72 void remapTpiWithGHashes(GHashState
*g
) override
;
74 bool isDependency() const override
{ return true; }
76 PDBInputFile
*pdbInputFile
= nullptr;
78 // TpiSource for IPI stream.
79 TypeServerIpiSource
*ipiSrc
= nullptr;
81 // The PDB signature GUID.
85 // Companion to TypeServerSource. Stores the index map for the IPI stream in the
86 // PDB. Modeling PDBs with two sources for TPI and IPI helps establish the
87 // invariant of one type index space per source.
88 class TypeServerIpiSource
: public TpiSource
{
90 explicit TypeServerIpiSource(COFFLinkerContext
&ctx
)
91 : TpiSource(ctx
, PDBIpi
, nullptr) {}
93 friend class TypeServerSource
;
95 // All of the TpiSource methods are no-ops. The parent TypeServerSource
96 // handles both TPI and IPI.
97 Error
mergeDebugT(TypeMerger
*m
) override
{ return Error::success(); }
98 void loadGHashes() override
{}
99 void remapTpiWithGHashes(GHashState
*g
) override
{}
100 bool isDependency() const override
{ return true; }
103 // This class represents the debug type stream of an OBJ file that depends on a
104 // PDB type server (see TypeServerSource).
105 class UseTypeServerSource
: public TpiSource
{
106 Expected
<TypeServerSource
*> getTypeServerSource();
109 UseTypeServerSource(COFFLinkerContext
&ctx
, ObjFile
*f
, TypeServer2Record ts
)
110 : TpiSource(ctx
, UsingPDB
, f
), typeServerDependency(ts
) {}
112 Error
mergeDebugT(TypeMerger
*m
) override
;
114 // No need to load ghashes from /Zi objects.
115 void loadGHashes() override
{}
116 void remapTpiWithGHashes(GHashState
*g
) override
;
118 // Information about the PDB type server dependency, that needs to be loaded
119 // in before merging this OBJ.
120 TypeServer2Record typeServerDependency
;
123 // This class represents the debug type stream of a Microsoft precompiled
124 // headers OBJ (PCH OBJ). This OBJ kind needs to be merged first in the output
125 // PDB, before any other OBJs that depend on this. Note that only MSVC generate
126 // such files, clang does not.
127 class PrecompSource
: public TpiSource
{
129 PrecompSource(COFFLinkerContext
&ctx
, ObjFile
*f
) : TpiSource(ctx
, PCH
, f
) {
130 // If the S_OBJNAME record contains the PCH signature, we'll register this
131 // source file right away.
135 Error
mergeDebugT(TypeMerger
*m
) override
;
137 void loadGHashes() override
;
139 bool isDependency() const override
{ return true; }
142 void registerMapping();
144 // Whether this precomp OBJ was recorded in the precompSourceMappings map.
145 // Only happens if the file->pchSignature is valid.
146 bool registered
= false;
149 // This class represents the debug type stream of an OBJ file that depends on a
150 // Microsoft precompiled headers OBJ (see PrecompSource).
151 class UsePrecompSource
: public TpiSource
{
153 UsePrecompSource(COFFLinkerContext
&ctx
, ObjFile
*f
, PrecompRecord precomp
)
154 : TpiSource(ctx
, UsingPCH
, f
), precompDependency(precomp
) {}
156 Error
mergeDebugT(TypeMerger
*m
) override
;
158 void loadGHashes() override
;
159 void remapTpiWithGHashes(GHashState
*g
) override
;
162 Error
mergeInPrecompHeaderObj();
164 PrecompSource
*findObjByName(StringRef fileNameOnly
);
165 PrecompSource
*findPrecompSource(ObjFile
*file
, PrecompRecord
&pr
);
166 Expected
<PrecompSource
*> findPrecompMap(ObjFile
*file
, PrecompRecord
&pr
);
169 // Information about the Precomp OBJ dependency, that needs to be loaded in
170 // before merging this OBJ.
171 PrecompRecord precompDependency
;
175 TpiSource::TpiSource(COFFLinkerContext
&ctx
, TpiKind k
, ObjFile
*f
)
176 : ctx(ctx
), kind(k
), tpiSrcIdx(ctx
.tpiSourceList
.size()), file(f
) {
177 ctx
.addTpiSource(this);
180 // Vtable key method.
181 TpiSource::~TpiSource() {
182 // Silence any assertions about unchecked errors.
183 consumeError(std::move(typeMergingError
));
186 TpiSource
*lld::coff::makeTpiSource(COFFLinkerContext
&ctx
, ObjFile
*file
) {
187 return make
<TpiSource
>(ctx
, TpiSource::Regular
, file
);
190 TpiSource
*lld::coff::makeTypeServerSource(COFFLinkerContext
&ctx
,
191 PDBInputFile
*pdbInputFile
) {
192 // Type server sources come in pairs: the TPI stream, and the IPI stream.
193 auto *tpiSource
= make
<TypeServerSource
>(ctx
, pdbInputFile
);
194 if (pdbInputFile
->session
->getPDBFile().hasPDBIpiStream())
195 tpiSource
->ipiSrc
= make
<TypeServerIpiSource
>(ctx
);
199 TpiSource
*lld::coff::makeUseTypeServerSource(COFFLinkerContext
&ctx
,
201 TypeServer2Record ts
) {
202 return make
<UseTypeServerSource
>(ctx
, file
, ts
);
205 TpiSource
*lld::coff::makePrecompSource(COFFLinkerContext
&ctx
, ObjFile
*file
) {
206 return make
<PrecompSource
>(ctx
, file
);
209 TpiSource
*lld::coff::makeUsePrecompSource(COFFLinkerContext
&ctx
,
211 PrecompRecord precomp
) {
212 return make
<UsePrecompSource
>(ctx
, file
, precomp
);
215 bool TpiSource::remapTypeIndex(TypeIndex
&ti
, TiRefKind refKind
) const {
219 // This can be an item index or a type index. Choose the appropriate map.
220 ArrayRef
<TypeIndex
> tpiOrIpiMap
=
221 (refKind
== TiRefKind::IndexRef
) ? ipiMap
: tpiMap
;
222 if (ti
.toArrayIndex() >= tpiOrIpiMap
.size())
224 ti
= tpiOrIpiMap
[ti
.toArrayIndex()];
228 void TpiSource::remapRecord(MutableArrayRef
<uint8_t> rec
,
229 ArrayRef
<TiReference
> typeRefs
) {
230 MutableArrayRef
<uint8_t> contents
= rec
.drop_front(sizeof(RecordPrefix
));
231 for (const TiReference
&ref
: typeRefs
) {
232 unsigned byteSize
= ref
.Count
* sizeof(TypeIndex
);
233 if (contents
.size() < ref
.Offset
+ byteSize
)
234 fatal("symbol record too short");
236 MutableArrayRef
<TypeIndex
> indices(
237 reinterpret_cast<TypeIndex
*>(contents
.data() + ref
.Offset
), ref
.Count
);
238 for (TypeIndex
&ti
: indices
) {
239 if (!remapTypeIndex(ti
, ref
.Kind
)) {
240 if (ctx
.config
.verbose
) {
242 reinterpret_cast<const RecordPrefix
*>(rec
.data())->RecordKind
;
243 StringRef fname
= file
? file
->getName() : "<unknown PDB>";
244 log("failed to remap type index in record of kind 0x" +
245 utohexstr(kind
) + " in " + fname
+ " with bad " +
246 (ref
.Kind
== TiRefKind::IndexRef
? "item" : "type") +
247 " index 0x" + utohexstr(ti
.getIndex()));
249 ti
= TypeIndex(SimpleTypeKind::NotTranslated
);
256 void TpiSource::remapTypesInTypeRecord(MutableArrayRef
<uint8_t> rec
) {
257 // TODO: Handle errors similar to symbols.
258 SmallVector
<TiReference
, 32> typeRefs
;
259 discoverTypeIndices(CVType(rec
), typeRefs
);
260 remapRecord(rec
, typeRefs
);
263 bool TpiSource::remapTypesInSymbolRecord(MutableArrayRef
<uint8_t> rec
) {
264 // Discover type index references in the record. Skip it if we don't
265 // know where they are.
266 SmallVector
<TiReference
, 32> typeRefs
;
267 if (!discoverTypeIndicesInSymbol(rec
, typeRefs
))
269 remapRecord(rec
, typeRefs
);
273 // A COFF .debug$H section is currently a clang extension. This function checks
274 // if a .debug$H section is in a format that we expect / understand, so that we
275 // can ignore any sections which are coincidentally also named .debug$H but do
276 // not contain a format we recognize.
277 static bool canUseDebugH(ArrayRef
<uint8_t> debugH
) {
278 if (debugH
.size() < sizeof(object::debug_h_header
))
281 reinterpret_cast<const object::debug_h_header
*>(debugH
.data());
282 debugH
= debugH
.drop_front(sizeof(object::debug_h_header
));
283 return header
->Magic
== COFF::DEBUG_HASHES_SECTION_MAGIC
&&
284 header
->Version
== 0 &&
285 header
->HashAlgorithm
== uint16_t(GlobalTypeHashAlg::BLAKE3
) &&
286 (debugH
.size() % 8 == 0);
289 static std::optional
<ArrayRef
<uint8_t>> getDebugH(ObjFile
*file
) {
291 SectionChunk::findByName(file
->getDebugChunks(), ".debug$H");
294 ArrayRef
<uint8_t> contents
= sec
->getContents();
295 if (!canUseDebugH(contents
))
300 static ArrayRef
<GloballyHashedType
>
301 getHashesFromDebugH(ArrayRef
<uint8_t> debugH
) {
302 assert(canUseDebugH(debugH
));
303 debugH
= debugH
.drop_front(sizeof(object::debug_h_header
));
304 uint32_t count
= debugH
.size() / sizeof(GloballyHashedType
);
305 return {reinterpret_cast<const GloballyHashedType
*>(debugH
.data()), count
};
308 // Merge .debug$T for a generic object file.
309 Error
TpiSource::mergeDebugT(TypeMerger
*m
) {
310 assert(!ctx
.config
.debugGHashes
&&
311 "use remapTpiWithGHashes when ghash is enabled");
314 BinaryStreamReader
reader(file
->debugTypes
, llvm::endianness::little
);
315 cantFail(reader
.readArray(types
, reader
.getLength()));
317 // When dealing with PCH.OBJ, some indices were already merged.
318 unsigned nbHeadIndices
= indexMapStorage
.size();
320 std::optional
<PCHMergerInfo
> pchInfo
;
321 if (auto err
= mergeTypeAndIdRecords(m
->idTable
, m
->typeTable
,
322 indexMapStorage
, types
, pchInfo
))
323 fatal("codeview::mergeTypeAndIdRecords failed: " +
324 toString(std::move(err
)));
326 file
->pchSignature
= pchInfo
->PCHSignature
;
327 endPrecompIdx
= pchInfo
->EndPrecompIndex
;
330 // In an object, there is only one mapping for both types and items.
331 tpiMap
= indexMapStorage
;
332 ipiMap
= indexMapStorage
;
334 if (ctx
.config
.showSummary
) {
335 nbTypeRecords
= indexMapStorage
.size() - nbHeadIndices
;
336 nbTypeRecordsBytes
= reader
.getLength();
337 // Count how many times we saw each type record in our input. This
338 // calculation requires a second pass over the type records to classify each
339 // record as a type or index. This is slow, but this code executes when
340 // collecting statistics.
341 m
->tpiCounts
.resize(m
->getTypeTable().size());
342 m
->ipiCounts
.resize(m
->getIDTable().size());
343 uint32_t srcIdx
= nbHeadIndices
;
344 for (const CVType
&ty
: types
) {
345 TypeIndex dstIdx
= tpiMap
[srcIdx
++];
346 // Type merging may fail, so a complex source type may become the simple
347 // NotTranslated type, which cannot be used as an array index.
348 if (dstIdx
.isSimple())
350 SmallVectorImpl
<uint32_t> &counts
=
351 isIdRecord(ty
.kind()) ? m
->ipiCounts
: m
->tpiCounts
;
352 ++counts
[dstIdx
.toArrayIndex()];
356 return Error::success();
359 // Merge types from a type server PDB.
360 Error
TypeServerSource::mergeDebugT(TypeMerger
*m
) {
361 assert(!ctx
.config
.debugGHashes
&&
362 "use remapTpiWithGHashes when ghash is enabled");
364 pdb::PDBFile
&pdbFile
= pdbInputFile
->session
->getPDBFile();
365 Expected
<pdb::TpiStream
&> expectedTpi
= pdbFile
.getPDBTpiStream();
366 if (auto e
= expectedTpi
.takeError())
367 fatal("Type server does not have TPI stream: " + toString(std::move(e
)));
368 pdb::TpiStream
*maybeIpi
= nullptr;
369 if (pdbFile
.hasPDBIpiStream()) {
370 Expected
<pdb::TpiStream
&> expectedIpi
= pdbFile
.getPDBIpiStream();
371 if (auto e
= expectedIpi
.takeError())
372 fatal("Error getting type server IPI stream: " + toString(std::move(e
)));
373 maybeIpi
= &*expectedIpi
;
376 // Merge TPI first, because the IPI stream will reference type indices.
377 if (auto err
= mergeTypeRecords(m
->typeTable
, indexMapStorage
,
378 expectedTpi
->typeArray()))
379 fatal("codeview::mergeTypeRecords failed: " + toString(std::move(err
)));
380 tpiMap
= indexMapStorage
;
384 if (auto err
= mergeIdRecords(m
->idTable
, tpiMap
, ipiSrc
->indexMapStorage
,
385 maybeIpi
->typeArray()))
386 fatal("codeview::mergeIdRecords failed: " + toString(std::move(err
)));
387 ipiMap
= ipiSrc
->indexMapStorage
;
390 if (ctx
.config
.showSummary
) {
391 nbTypeRecords
= tpiMap
.size() + ipiMap
.size();
393 expectedTpi
->typeArray().getUnderlyingStream().getLength() +
394 (maybeIpi
? maybeIpi
->typeArray().getUnderlyingStream().getLength()
397 // Count how many times we saw each type record in our input. If a
398 // destination type index is present in the source to destination type index
399 // map, that means we saw it once in the input. Add it to our histogram.
400 m
->tpiCounts
.resize(m
->getTypeTable().size());
401 m
->ipiCounts
.resize(m
->getIDTable().size());
402 for (TypeIndex ti
: tpiMap
)
404 ++m
->tpiCounts
[ti
.toArrayIndex()];
405 for (TypeIndex ti
: ipiMap
)
407 ++m
->ipiCounts
[ti
.toArrayIndex()];
410 return Error::success();
413 Expected
<TypeServerSource
*> UseTypeServerSource::getTypeServerSource() {
414 const codeview::GUID
&tsId
= typeServerDependency
.getGuid();
415 StringRef tsPath
= typeServerDependency
.getName();
417 TypeServerSource
*tsSrc
= nullptr;
418 auto it
= ctx
.typeServerSourceMappings
.find(tsId
);
419 if (it
!= ctx
.typeServerSourceMappings
.end()) {
420 tsSrc
= (TypeServerSource
*)it
->second
;
422 if (tsSrc
== nullptr) {
423 // The file failed to load, lookup by name
424 PDBInputFile
*pdb
= PDBInputFile::findFromRecordPath(ctx
, tsPath
, file
);
426 return createFileError(tsPath
, errorCodeToError(std::error_code(
427 ENOENT
, std::generic_category())));
428 // If an error occurred during loading, throw it now
429 if (pdb
->loadErrorStr
)
430 return createFileError(
431 tsPath
, make_error
<StringError
>(*pdb
->loadErrorStr
,
432 llvm::inconvertibleErrorCode()));
434 tsSrc
= (TypeServerSource
*)pdb
->debugTypesObj
;
436 // Just because a file with a matching name was found and it was an actual
437 // PDB file doesn't mean it matches. For it to match the InfoStream's GUID
438 // must match the GUID specified in the TypeServer2 record.
439 if (tsSrc
->Guid
!= tsId
) {
440 return createFileError(tsPath
,
441 make_error
<pdb::PDBError
>(
442 pdb::pdb_error_code::signature_out_of_date
));
448 Error
UseTypeServerSource::mergeDebugT(TypeMerger
*m
) {
449 Expected
<TypeServerSource
*> tsSrc
= getTypeServerSource();
451 return tsSrc
.takeError();
453 pdb::PDBFile
&pdbSession
= (*tsSrc
)->pdbInputFile
->session
->getPDBFile();
454 auto expectedInfo
= pdbSession
.getPDBInfoStream();
456 return expectedInfo
.takeError();
458 // Reuse the type index map of the type server.
459 tpiMap
= (*tsSrc
)->tpiMap
;
460 ipiMap
= (*tsSrc
)->ipiMap
;
461 return Error::success();
464 static bool equalsPath(StringRef path1
, StringRef path2
) {
466 return path1
.equals_insensitive(path2
);
468 return path1
== path2
;
472 // Find by name an OBJ provided on the command line
473 PrecompSource
*UsePrecompSource::findObjByName(StringRef fileNameOnly
) {
474 SmallString
<128> currentPath
;
475 for (auto kv
: ctx
.precompSourceMappings
) {
476 StringRef currentFileName
= sys::path::filename(kv
.second
->file
->getName(),
477 sys::path::Style::windows
);
479 // Compare based solely on the file name (link.exe behavior)
480 if (equalsPath(currentFileName
, fileNameOnly
))
481 return (PrecompSource
*)kv
.second
;
486 PrecompSource
*UsePrecompSource::findPrecompSource(ObjFile
*file
,
488 // Cross-compile warning: given that Clang doesn't generate LF_PRECOMP
489 // records, we assume the OBJ comes from a Windows build of cl.exe. Thusly,
490 // the paths embedded in the OBJs are in the Windows format.
491 SmallString
<128> prFileName
=
492 sys::path::filename(pr
.getPrecompFilePath(), sys::path::Style::windows
);
494 auto it
= ctx
.precompSourceMappings
.find(pr
.getSignature());
495 if (it
!= ctx
.precompSourceMappings
.end()) {
496 return (PrecompSource
*)it
->second
;
499 return findObjByName(prFileName
);
502 Expected
<PrecompSource
*> UsePrecompSource::findPrecompMap(ObjFile
*file
,
504 PrecompSource
*precomp
= findPrecompSource(file
, pr
);
507 return createFileError(
508 pr
.getPrecompFilePath(),
509 make_error
<pdb::PDBError
>(pdb::pdb_error_code::no_matching_pch
));
511 // Don't rely on the PCH signature to validate the concordance between the PCH
512 // and the OBJ that uses it. However we do validate here that the
513 // LF_ENDPRECOMP record index lines up with the number of type records
514 // LF_PRECOMP is expecting.
515 if (precomp
->endPrecompIdx
!= pr
.getTypesCount())
516 return createFileError(
518 make_error
<pdb::PDBError
>(pdb::pdb_error_code::no_matching_pch
));
523 /// Merges a precompiled headers TPI map into the current TPI map. The
524 /// precompiled headers object will also be loaded and remapped in the
526 Error
UsePrecompSource::mergeInPrecompHeaderObj() {
527 auto e
= findPrecompMap(file
, precompDependency
);
529 return e
.takeError();
531 PrecompSource
*precompSrc
= *e
;
532 if (precompSrc
->tpiMap
.empty())
533 return Error::success();
535 assert(precompDependency
.getStartTypeIndex() ==
536 TypeIndex::FirstNonSimpleIndex
);
537 assert(precompDependency
.getTypesCount() <= precompSrc
->tpiMap
.size());
538 // Use the previously remapped index map from the precompiled headers.
539 indexMapStorage
.insert(indexMapStorage
.begin(), precompSrc
->tpiMap
.begin(),
540 precompSrc
->tpiMap
.begin() +
541 precompDependency
.getTypesCount());
543 return Error::success();
546 Error
UsePrecompSource::mergeDebugT(TypeMerger
*m
) {
547 // This object was compiled with /Yu, so process the corresponding
548 // precompiled headers object (/Yc) first. Some type indices in the current
549 // object are referencing data in the precompiled headers object, so we need
550 // both to be loaded.
551 if (Error e
= mergeInPrecompHeaderObj())
554 return TpiSource::mergeDebugT(m
);
557 Error
PrecompSource::mergeDebugT(TypeMerger
*m
) {
558 // In some cases, the S_OBJNAME record doesn't contain the PCH signature.
559 // The signature comes later with the LF_ENDPRECOMP record, so we first need
560 // to merge in all the .PCH.OBJ file type records, before registering below.
561 if (Error e
= TpiSource::mergeDebugT(m
))
566 return Error::success();
569 void PrecompSource::registerMapping() {
572 if (file
->pchSignature
&& *file
->pchSignature
) {
573 auto it
= ctx
.precompSourceMappings
.emplace(*file
->pchSignature
, this);
575 fatal("a PCH object with the same signature has already been provided (" +
576 toString(it
.first
->second
->file
) + " and " + toString(file
) + ")");
581 //===----------------------------------------------------------------------===//
582 // Parellel GHash type merging implementation.
583 //===----------------------------------------------------------------------===//
585 void TpiSource::loadGHashes() {
586 if (std::optional
<ArrayRef
<uint8_t>> debugH
= getDebugH(file
)) {
587 ghashes
= getHashesFromDebugH(*debugH
);
588 ownedGHashes
= false;
591 BinaryStreamReader
reader(file
->debugTypes
, llvm::endianness::little
);
592 cantFail(reader
.readArray(types
, reader
.getLength()));
593 assignGHashesFromVector(GloballyHashedType::hashTypes(types
));
596 fillIsItemIndexFromDebugT();
599 // Copies ghashes from a vector into an array. These are long lived, so it's
600 // worth the time to copy these into an appropriately sized vector to reduce
602 void TpiSource::assignGHashesFromVector(
603 std::vector
<GloballyHashedType
> &&hashVec
) {
606 GloballyHashedType
*hashes
= new GloballyHashedType
[hashVec
.size()];
607 memcpy(hashes
, hashVec
.data(), hashVec
.size() * sizeof(GloballyHashedType
));
608 ghashes
= ArrayRef(hashes
, hashVec
.size());
612 // Faster way to iterate type records. forEachTypeChecked is faster than
613 // iterating CVTypeArray. It avoids virtual readBytes calls in inner loops.
614 static void forEachTypeChecked(ArrayRef
<uint8_t> types
,
615 function_ref
<void(const CVType
&)> fn
) {
617 forEachCodeViewRecord
<CVType
>(types
, [fn
](const CVType
&ty
) -> Error
{
619 return Error::success();
623 // Walk over file->debugTypes and fill in the isItemIndex bit vector.
624 // TODO: Store this information in .debug$H so that we don't have to recompute
625 // it. This is the main bottleneck slowing down parallel ghashing with one
626 // thread over single-threaded ghashing.
627 void TpiSource::fillIsItemIndexFromDebugT() {
629 isItemIndex
.resize(ghashes
.size());
630 forEachTypeChecked(file
->debugTypes
, [&](const CVType
&ty
) {
631 if (isIdRecord(ty
.kind()))
632 isItemIndex
.set(index
);
637 void TpiSource::mergeTypeRecord(TypeIndex curIndex
, CVType ty
) {
638 // Decide if the merged type goes into TPI or IPI.
639 bool isItem
= isIdRecord(ty
.kind());
640 MergedInfo
&merged
= isItem
? mergedIpi
: mergedTpi
;
642 // Copy the type into our mutable buffer.
643 assert(ty
.length() <= codeview::MaxRecordLength
);
644 size_t offset
= merged
.recs
.size();
645 size_t newSize
= alignTo(ty
.length(), 4);
646 merged
.recs
.resize(offset
+ newSize
);
647 auto newRec
= MutableArrayRef(&merged
.recs
[offset
], newSize
);
648 memcpy(newRec
.data(), ty
.data().data(), newSize
);
650 // Fix up the record prefix and padding bytes if it required resizing.
651 if (newSize
!= ty
.length()) {
652 reinterpret_cast<RecordPrefix
*>(newRec
.data())->RecordLen
= newSize
- 2;
653 for (size_t i
= ty
.length(); i
< newSize
; ++i
)
654 newRec
[i
] = LF_PAD0
+ (newSize
- i
);
657 // Remap the type indices in the new record.
658 remapTypesInTypeRecord(newRec
);
659 uint32_t pdbHash
= check(pdb::hashTypeRecord(CVType(newRec
)));
660 merged
.recSizes
.push_back(static_cast<uint16_t>(newSize
));
661 merged
.recHashes
.push_back(pdbHash
);
663 // Retain a mapping from PDB function id to PDB function type. This mapping is
664 // used during symbol processing to rewrite S_GPROC32_ID symbols to S_GPROC32
666 if (ty
.kind() == LF_FUNC_ID
|| ty
.kind() == LF_MFUNC_ID
) {
667 bool success
= ty
.length() >= 12;
668 TypeIndex funcId
= curIndex
;
670 success
&= remapTypeIndex(funcId
, TiRefKind::IndexRef
);
672 *reinterpret_cast<const TypeIndex
*>(&newRec
.data()[8]);
674 funcIdToType
.push_back({funcId
, funcType
});
676 StringRef fname
= file
? file
->getName() : "<unknown PDB>";
677 warn("corrupt LF_[M]FUNC_ID record 0x" + utohexstr(curIndex
.getIndex()) +
683 void TpiSource::mergeUniqueTypeRecords(ArrayRef
<uint8_t> typeRecords
,
684 TypeIndex beginIndex
) {
685 // Re-sort the list of unique types by index.
687 assert(llvm::is_sorted(uniqueTypes
));
689 llvm::sort(uniqueTypes
);
691 // Accumulate all the unique types into one buffer in mergedTypes.
692 uint32_t ghashIndex
= 0;
693 auto nextUniqueIndex
= uniqueTypes
.begin();
694 assert(mergedTpi
.recs
.empty());
695 assert(mergedIpi
.recs
.empty());
697 // Pre-compute the number of elements in advance to avoid std::vector resizes.
698 unsigned nbTpiRecs
= 0;
699 unsigned nbIpiRecs
= 0;
700 forEachTypeChecked(typeRecords
, [&](const CVType
&ty
) {
701 if (nextUniqueIndex
!= uniqueTypes
.end() &&
702 *nextUniqueIndex
== ghashIndex
) {
703 assert(ty
.length() <= codeview::MaxRecordLength
);
704 size_t newSize
= alignTo(ty
.length(), 4);
705 (isIdRecord(ty
.kind()) ? nbIpiRecs
: nbTpiRecs
) += newSize
;
710 mergedTpi
.recs
.reserve(nbTpiRecs
);
711 mergedIpi
.recs
.reserve(nbIpiRecs
);
713 // Do the actual type merge.
715 nextUniqueIndex
= uniqueTypes
.begin();
716 forEachTypeChecked(typeRecords
, [&](const CVType
&ty
) {
717 if (nextUniqueIndex
!= uniqueTypes
.end() &&
718 *nextUniqueIndex
== ghashIndex
) {
719 mergeTypeRecord(beginIndex
+ ghashIndex
, ty
);
724 assert(nextUniqueIndex
== uniqueTypes
.end() &&
725 "failed to merge all desired records");
726 assert(uniqueTypes
.size() ==
727 mergedTpi
.recSizes
.size() + mergedIpi
.recSizes
.size() &&
728 "missing desired record");
731 void TpiSource::remapTpiWithGHashes(GHashState
*g
) {
732 assert(ctx
.config
.debugGHashes
&& "ghashes must be enabled");
733 fillMapFromGHashes(g
);
734 tpiMap
= indexMapStorage
;
735 ipiMap
= indexMapStorage
;
736 mergeUniqueTypeRecords(file
->debugTypes
);
737 // TODO: Free all unneeded ghash resources now that we have a full index map.
739 if (ctx
.config
.showSummary
) {
740 nbTypeRecords
= ghashes
.size();
741 nbTypeRecordsBytes
= file
->debugTypes
.size();
745 // PDBs do not actually store global hashes, so when merging a type server
746 // PDB we have to synthesize global hashes. To do this, we first synthesize
747 // global hashes for the TPI stream, since it is independent, then we
748 // synthesize hashes for the IPI stream, using the hashes for the TPI stream
750 void TypeServerSource::loadGHashes() {
752 if (!ghashes
.empty())
754 pdb::PDBFile
&pdbFile
= pdbInputFile
->session
->getPDBFile();
757 Expected
<pdb::TpiStream
&> expectedTpi
= pdbFile
.getPDBTpiStream();
758 if (auto e
= expectedTpi
.takeError())
759 fatal("Type server does not have TPI stream: " + toString(std::move(e
)));
760 assignGHashesFromVector(
761 GloballyHashedType::hashTypes(expectedTpi
->typeArray()));
762 isItemIndex
.resize(ghashes
.size());
764 // Hash IPI stream, which depends on TPI ghashes.
765 if (!pdbFile
.hasPDBIpiStream())
767 Expected
<pdb::TpiStream
&> expectedIpi
= pdbFile
.getPDBIpiStream();
768 if (auto e
= expectedIpi
.takeError())
769 fatal("error retrieving IPI stream: " + toString(std::move(e
)));
770 ipiSrc
->assignGHashesFromVector(
771 GloballyHashedType::hashIds(expectedIpi
->typeArray(), ghashes
));
773 // The IPI stream isItemIndex bitvector should be all ones.
774 ipiSrc
->isItemIndex
.resize(ipiSrc
->ghashes
.size());
775 ipiSrc
->isItemIndex
.set(0, ipiSrc
->ghashes
.size());
778 // Flatten discontiguous PDB type arrays to bytes so that we can use
779 // forEachTypeChecked instead of CVTypeArray iteration. Copying all types from
780 // type servers is faster than iterating all object files compiled with /Z7 with
781 // CVTypeArray, which has high overheads due to the virtual interface of
782 // BinaryStream::readBytes.
783 static ArrayRef
<uint8_t> typeArrayToBytes(const CVTypeArray
&types
) {
784 BinaryStreamRef stream
= types
.getUnderlyingStream();
785 ArrayRef
<uint8_t> debugTypes
;
786 checkError(stream
.readBytes(0, stream
.getLength(), debugTypes
));
790 // Merge types from a type server PDB.
791 void TypeServerSource::remapTpiWithGHashes(GHashState
*g
) {
792 assert(ctx
.config
.debugGHashes
&& "ghashes must be enabled");
794 // IPI merging depends on TPI, so do TPI first, then do IPI. No need to
795 // propagate errors, those should've been handled during ghash loading.
796 pdb::PDBFile
&pdbFile
= pdbInputFile
->session
->getPDBFile();
797 pdb::TpiStream
&tpi
= check(pdbFile
.getPDBTpiStream());
798 fillMapFromGHashes(g
);
799 tpiMap
= indexMapStorage
;
800 mergeUniqueTypeRecords(typeArrayToBytes(tpi
.typeArray()));
801 if (pdbFile
.hasPDBIpiStream()) {
802 pdb::TpiStream
&ipi
= check(pdbFile
.getPDBIpiStream());
803 ipiSrc
->indexMapStorage
.resize(ipiSrc
->ghashes
.size());
804 ipiSrc
->fillMapFromGHashes(g
);
805 ipiMap
= ipiSrc
->indexMapStorage
;
806 ipiSrc
->tpiMap
= tpiMap
;
807 ipiSrc
->ipiMap
= ipiMap
;
808 ipiSrc
->mergeUniqueTypeRecords(typeArrayToBytes(ipi
.typeArray()));
810 if (ctx
.config
.showSummary
) {
811 nbTypeRecords
= ipiSrc
->ghashes
.size();
812 nbTypeRecordsBytes
= ipi
.typeArray().getUnderlyingStream().getLength();
816 if (ctx
.config
.showSummary
) {
817 nbTypeRecords
+= ghashes
.size();
818 nbTypeRecordsBytes
+= tpi
.typeArray().getUnderlyingStream().getLength();
822 void UseTypeServerSource::remapTpiWithGHashes(GHashState
*g
) {
823 // No remapping to do with /Zi objects. Simply use the index map from the type
824 // server. Errors should have been reported earlier. Symbols from this object
826 Expected
<TypeServerSource
*> maybeTsSrc
= getTypeServerSource();
829 joinErrors(std::move(typeMergingError
), maybeTsSrc
.takeError());
832 TypeServerSource
*tsSrc
= *maybeTsSrc
;
833 tpiMap
= tsSrc
->tpiMap
;
834 ipiMap
= tsSrc
->ipiMap
;
837 void PrecompSource::loadGHashes() {
838 if (getDebugH(file
)) {
839 warn("ignoring .debug$H section; pch with ghash is not implemented");
842 uint32_t ghashIdx
= 0;
843 std::vector
<GloballyHashedType
> hashVec
;
844 forEachTypeChecked(file
->debugTypes
, [&](const CVType
&ty
) {
845 // Remember the index of the LF_ENDPRECOMP record so it can be excluded from
846 // the PDB. There must be an entry in the list of ghashes so that the type
847 // indexes of the following records in the /Yc PCH object line up.
848 if (ty
.kind() == LF_ENDPRECOMP
) {
849 EndPrecompRecord endPrecomp
;
850 cantFail(TypeDeserializer::deserializeAs
<EndPrecompRecord
>(
851 const_cast<CVType
&>(ty
), endPrecomp
));
852 file
->pchSignature
= endPrecomp
.getSignature();
854 endPrecompIdx
= ghashIdx
;
857 hashVec
.push_back(GloballyHashedType::hashType(ty
, hashVec
, hashVec
));
858 isItemIndex
.push_back(isIdRecord(ty
.kind()));
861 assignGHashesFromVector(std::move(hashVec
));
864 void UsePrecompSource::loadGHashes() {
865 auto e
= findPrecompMap(file
, precompDependency
);
867 warn(toString(e
.takeError()));
871 PrecompSource
*pchSrc
= *e
;
873 // To compute ghashes of a /Yu object file, we need to build on the ghashes of
874 // the /Yc PCH object. After we are done hashing, discard the ghashes from the
875 // PCH source so we don't unnecessarily try to deduplicate them.
876 std::vector
<GloballyHashedType
> hashVec
=
877 pchSrc
->ghashes
.take_front(precompDependency
.getTypesCount());
878 forEachTypeChecked(file
->debugTypes
, [&](const CVType
&ty
) {
879 hashVec
.push_back(GloballyHashedType::hashType(ty
, hashVec
, hashVec
));
880 isItemIndex
.push_back(isIdRecord(ty
.kind()));
882 hashVec
.erase(hashVec
.begin(),
883 hashVec
.begin() + precompDependency
.getTypesCount());
884 assignGHashesFromVector(std::move(hashVec
));
887 void UsePrecompSource::remapTpiWithGHashes(GHashState
*g
) {
888 fillMapFromGHashes(g
);
889 // This object was compiled with /Yu, so process the corresponding
890 // precompiled headers object (/Yc) first. Some type indices in the current
891 // object are referencing data in the precompiled headers object, so we need
892 // both to be loaded.
893 if (Error e
= mergeInPrecompHeaderObj()) {
894 typeMergingError
= joinErrors(std::move(typeMergingError
), std::move(e
));
898 tpiMap
= indexMapStorage
;
899 ipiMap
= indexMapStorage
;
900 mergeUniqueTypeRecords(file
->debugTypes
,
901 TypeIndex(precompDependency
.getStartTypeIndex() +
902 precompDependency
.getTypesCount()));
903 if (ctx
.config
.showSummary
) {
904 nbTypeRecords
= ghashes
.size();
905 nbTypeRecordsBytes
= file
->debugTypes
.size();
910 /// A concurrent hash table for global type hashing. It is based on this paper:
911 /// Concurrent Hash Tables: Fast and General(?)!
912 /// https://dl.acm.org/doi/10.1145/3309206
914 /// This hash table is meant to be used in two phases:
915 /// 1. concurrent insertions
916 /// 2. concurrent reads
917 /// It does not support lookup, deletion, or rehashing. It uses linear probing.
919 /// The paper describes storing a key-value pair in two machine words.
920 /// Generally, the values stored in this map are type indices, and we can use
921 /// those values to recover the ghash key from a side table. This allows us to
922 /// shrink the table entries further at the cost of some loads, and sidesteps
923 /// the need for a 128 bit atomic compare-and-swap operation.
925 /// During insertion, a priority function is used to decide which insertion
926 /// should be preferred. This ensures that the output is deterministic. For
927 /// ghashing, lower tpiSrcIdx values (earlier inputs) are preferred.
931 GHashCell
*table
= nullptr;
932 uint32_t tableSize
= 0;
934 GHashTable() = default;
937 /// Initialize the table with the given size. Because the table cannot be
938 /// resized, the initial size of the table must be large enough to contain all
939 /// inputs, or insertion may not be able to find an empty cell.
940 void init(uint32_t newTableSize
);
942 /// Insert the cell with the given ghash into the table. Return the insertion
943 /// position in the table. It is safe for the caller to store the insertion
944 /// position because the table cannot be resized.
945 uint32_t insert(COFFLinkerContext
&ctx
, GloballyHashedType ghash
,
949 /// A ghash table cell for deduplicating types from TpiSources.
951 // Force "data" to be 64-bit aligned; otherwise, some versions of clang
952 // will generate calls to libatomic when using some versions of libstdc++
953 // on 32-bit targets. (Also, in theory, there could be a target where
954 // new[] doesn't always return an 8-byte-aligned allocation.)
955 alignas(sizeof(uint64_t)) uint64_t data
= 0;
958 GHashCell() = default;
960 // Construct data most to least significant so that sorting works well:
964 // Add one to the tpiSrcIdx so that the 0th record from the 0th source has a
965 // non-zero representation.
966 GHashCell(bool isItem
, uint32_t tpiSrcIdx
, uint32_t ghashIdx
)
967 : data((uint64_t(isItem
) << 63U) | (uint64_t(tpiSrcIdx
+ 1) << 32ULL) |
969 assert(tpiSrcIdx
== getTpiSrcIdx() && "round trip failure");
970 assert(ghashIdx
== getGHashIdx() && "round trip failure");
973 explicit GHashCell(uint64_t data
) : data(data
) {}
975 // The empty cell is all zeros.
976 bool isEmpty() const { return data
== 0ULL; }
978 /// Extract the tpiSrcIdx.
979 uint32_t getTpiSrcIdx() const {
980 return ((uint32_t)(data
>> 32U) & 0x7FFFFFFF) - 1;
983 /// Extract the index into the ghash array of the TpiSource.
984 uint32_t getGHashIdx() const { return (uint32_t)data
; }
986 bool isItem() const { return data
& (1ULL << 63U); }
988 /// Get the ghash key for this cell.
989 GloballyHashedType
getGHash(const COFFLinkerContext
&ctx
) const {
990 return ctx
.tpiSourceList
[getTpiSrcIdx()]->ghashes
[getGHashIdx()];
993 /// The priority function for the cell. The data is stored such that lower
994 /// tpiSrcIdx and ghashIdx values are preferred, which means that type record
995 /// from earlier sources are more likely to prevail.
996 friend inline bool operator<(const GHashCell
&l
, const GHashCell
&r
) {
997 return l
.data
< r
.data
;
1002 namespace lld::coff
{
1003 /// This type is just a wrapper around GHashTable with external linkage so it
1004 /// can be used from a header.
1008 } // namespace lld::coff
1010 GHashTable::~GHashTable() { delete[] table
; }
1012 void GHashTable::init(uint32_t newTableSize
) {
1013 table
= new GHashCell
[newTableSize
];
1014 memset(table
, 0, newTableSize
* sizeof(GHashCell
));
1015 tableSize
= newTableSize
;
1018 uint32_t GHashTable::insert(COFFLinkerContext
&ctx
, GloballyHashedType ghash
,
1019 GHashCell newCell
) {
1020 assert(!newCell
.isEmpty() && "cannot insert empty cell value");
1022 // FIXME: The low bytes of SHA1 have low entropy for short records, which
1023 // type records are. Swap the byte order for better entropy. A better ghash
1026 llvm::byteswap
<uint64_t>(*reinterpret_cast<uint64_t *>(&ghash
)) %
1029 // Do a linear probe starting at startIdx.
1030 uint32_t idx
= startIdx
;
1032 // Run a compare and swap loop. There are four cases:
1033 // - cell is empty: CAS into place and return
1034 // - cell has matching key, earlier priority: do nothing, return
1035 // - cell has matching key, later priority: CAS into place and return
1036 // - cell has non-matching key: hash collision, probe next cell
1037 auto *cellPtr
= reinterpret_cast<std::atomic
<GHashCell
> *>(&table
[idx
]);
1038 GHashCell
oldCell(cellPtr
->load());
1039 while (oldCell
.isEmpty() || oldCell
.getGHash(ctx
) == ghash
) {
1040 // Check if there is an existing ghash entry with a higher priority
1041 // (earlier ordering). If so, this is a duplicate, we are done.
1042 if (!oldCell
.isEmpty() && oldCell
< newCell
)
1044 // Either the cell is empty, or our value is higher priority. Try to
1045 // compare and swap. If it succeeds, we are done.
1046 if (cellPtr
->compare_exchange_weak(oldCell
, newCell
))
1048 // If the CAS failed, check this cell again.
1051 // Advance the probe. Wrap around to the beginning if we run off the end.
1053 idx
= idx
== tableSize
? 0 : idx
;
1054 if (idx
== startIdx
) {
1055 // If this becomes an issue, we could mark failure and rehash from the
1056 // beginning with a bigger table. There is no difference between rehashing
1057 // internally and starting over.
1058 report_fatal_error("ghash table is full");
1061 llvm_unreachable("left infloop");
1064 TypeMerger::TypeMerger(COFFLinkerContext
&c
, llvm::BumpPtrAllocator
&alloc
)
1065 : typeTable(alloc
), idTable(alloc
), ctx(c
) {}
1067 TypeMerger::~TypeMerger() = default;
1069 void TypeMerger::mergeTypesWithGHash() {
1070 // Load ghashes. Do type servers and PCH objects first.
1072 llvm::TimeTraceScope
timeScope("Load GHASHes");
1073 ScopedTimer
t1(ctx
.loadGHashTimer
);
1074 parallelForEach(dependencySources
,
1075 [&](TpiSource
*source
) { source
->loadGHashes(); });
1076 parallelForEach(objectSources
,
1077 [&](TpiSource
*source
) { source
->loadGHashes(); });
1080 llvm::TimeTraceScope
timeScope("Merge types (GHASH)");
1081 ScopedTimer
t2(ctx
.mergeGHashTimer
);
1082 GHashState ghashState
;
1084 // Estimate the size of hash table needed to deduplicate ghashes. This *must*
1085 // be larger than the number of unique types, or hash table insertion may not
1086 // be able to find a vacant slot. Summing the input types guarantees this, but
1087 // it is a gross overestimate. The table size could be reduced to save memory,
1088 // but it would require implementing rehashing, and this table is generally
1089 // small compared to total memory usage, at eight bytes per input type record,
1090 // and most input type records are larger than eight bytes.
1091 size_t tableSize
= 0;
1092 for (TpiSource
*source
: ctx
.tpiSourceList
)
1093 tableSize
+= source
->ghashes
.size();
1095 // Cap the table size so that we can use 32-bit cell indices. Type indices are
1096 // also 32-bit, so this is an inherent PDB file format limit anyway.
1098 std::min(size_t(INT32_MAX
) - TypeIndex::FirstNonSimpleIndex
, tableSize
);
1099 ghashState
.table
.init(static_cast<uint32_t>(tableSize
));
1101 // Insert ghashes in parallel. During concurrent insertion, we cannot observe
1102 // the contents of the hash table cell, but we can remember the insertion
1103 // position. Because the table does not rehash, the position will not change
1104 // under insertion. After insertion is done, the value of the cell can be read
1105 // to retrieve the final PDB type index.
1106 parallelFor(0, ctx
.tpiSourceList
.size(), [&](size_t tpiSrcIdx
) {
1107 TpiSource
*source
= ctx
.tpiSourceList
[tpiSrcIdx
];
1108 source
->indexMapStorage
.resize(source
->ghashes
.size());
1109 for (uint32_t i
= 0, e
= source
->ghashes
.size(); i
< e
; i
++) {
1110 if (source
->shouldOmitFromPdb(i
)) {
1111 source
->indexMapStorage
[i
] = TypeIndex(SimpleTypeKind::NotTranslated
);
1114 GloballyHashedType ghash
= source
->ghashes
[i
];
1115 bool isItem
= source
->isItemIndex
.test(i
);
1117 ghashState
.table
.insert(ctx
, ghash
, GHashCell(isItem
, tpiSrcIdx
, i
));
1119 // Store the ghash cell index as a type index in indexMapStorage. Later
1120 // we will replace it with the PDB type index.
1121 source
->indexMapStorage
[i
] = TypeIndex::fromArrayIndex(cellIdx
);
1125 // Collect all non-empty cells and sort them. This will implicitly assign
1126 // destination type indices, and partition the entries into type records and
1127 // item records. It arranges types in this order:
1129 // - source 0, type 0...
1130 // - source 1, type 1...
1132 // - source 0, type 1...
1133 // - source 1, type 0...
1134 std::vector
<GHashCell
> entries
;
1135 for (const GHashCell
&cell
: ArrayRef(ghashState
.table
.table
, tableSize
)) {
1136 if (!cell
.isEmpty())
1137 entries
.push_back(cell
);
1139 parallelSort(entries
, std::less
<GHashCell
>());
1140 log(formatv("ghash table load factor: {0:p} (size {1} / capacity {2})\n",
1141 tableSize
? double(entries
.size()) / tableSize
: 0,
1142 entries
.size(), tableSize
));
1144 // Find out how many type and item indices there are.
1145 auto mid
= llvm::lower_bound(entries
, GHashCell(true, 0, 0));
1146 assert((mid
== entries
.end() || mid
->isItem()) &&
1147 (mid
== entries
.begin() || !std::prev(mid
)->isItem()) &&
1148 "midpoint is not midpoint");
1149 uint32_t numTypes
= std::distance(entries
.begin(), mid
);
1150 uint32_t numItems
= std::distance(mid
, entries
.end());
1151 log("Tpi record count: " + Twine(numTypes
));
1152 log("Ipi record count: " + Twine(numItems
));
1154 // Make a list of the "unique" type records to merge for each tpi source. Type
1155 // merging will skip indices not on this list. Store the destination PDB type
1156 // index for these unique types in the tpiMap for each source. The entries for
1157 // non-unique types will be filled in prior to type merging.
1158 for (uint32_t i
= 0, e
= entries
.size(); i
< e
; ++i
) {
1159 auto &cell
= entries
[i
];
1160 uint32_t tpiSrcIdx
= cell
.getTpiSrcIdx();
1161 TpiSource
*source
= ctx
.tpiSourceList
[tpiSrcIdx
];
1162 source
->uniqueTypes
.push_back(cell
.getGHashIdx());
1164 // Update the ghash table to store the destination PDB type index in the
1166 uint32_t pdbTypeIndex
= i
< numTypes
? i
: i
- numTypes
;
1167 uint32_t ghashCellIndex
=
1168 source
->indexMapStorage
[cell
.getGHashIdx()].toArrayIndex();
1169 ghashState
.table
.table
[ghashCellIndex
] =
1170 GHashCell(cell
.isItem(), cell
.getTpiSrcIdx(), pdbTypeIndex
);
1173 // In parallel, remap all types.
1174 for (TpiSource
*source
: dependencySources
)
1175 source
->remapTpiWithGHashes(&ghashState
);
1176 parallelForEach(objectSources
, [&](TpiSource
*source
) {
1177 source
->remapTpiWithGHashes(&ghashState
);
1180 // Build a global map of from function ID to function type.
1181 for (TpiSource
*source
: ctx
.tpiSourceList
) {
1182 for (auto idToType
: source
->funcIdToType
)
1183 funcIdToType
.insert(idToType
);
1184 source
->funcIdToType
.clear();
1190 void TypeMerger::sortDependencies() {
1191 // Order dependencies first, but preserve the existing order.
1192 std::vector
<TpiSource
*> deps
;
1193 std::vector
<TpiSource
*> objs
;
1194 for (TpiSource
*s
: ctx
.tpiSourceList
)
1195 (s
->isDependency() ? deps
: objs
).push_back(s
);
1196 uint32_t numDeps
= deps
.size();
1197 uint32_t numObjs
= objs
.size();
1198 ctx
.tpiSourceList
= std::move(deps
);
1199 ctx
.tpiSourceList
.insert(ctx
.tpiSourceList
.end(), objs
.begin(), objs
.end());
1200 for (uint32_t i
= 0, e
= ctx
.tpiSourceList
.size(); i
< e
; ++i
)
1201 ctx
.tpiSourceList
[i
]->tpiSrcIdx
= i
;
1202 dependencySources
= ArrayRef(ctx
.tpiSourceList
.data(), numDeps
);
1203 objectSources
= ArrayRef(ctx
.tpiSourceList
.data() + numDeps
, numObjs
);
1206 /// Given the index into the ghash table for a particular type, return the type
1207 /// index for that type in the output PDB.
1208 static TypeIndex
loadPdbTypeIndexFromCell(GHashState
*g
,
1209 uint32_t ghashCellIdx
) {
1210 GHashCell cell
= g
->table
.table
[ghashCellIdx
];
1211 return TypeIndex::fromArrayIndex(cell
.getGHashIdx());
1214 /// Free heap allocated ghashes.
1215 void TypeMerger::clearGHashes() {
1216 for (TpiSource
*src
: ctx
.tpiSourceList
) {
1217 if (src
->ownedGHashes
)
1218 delete[] src
->ghashes
.data();
1220 src
->isItemIndex
.clear();
1221 src
->uniqueTypes
.clear();
1225 // Fill in a TPI or IPI index map using ghashes. For each source type, use its
1226 // ghash to lookup its final type index in the PDB, and store that in the map.
1227 void TpiSource::fillMapFromGHashes(GHashState
*g
) {
1228 for (size_t i
= 0, e
= ghashes
.size(); i
< e
; ++i
) {
1229 TypeIndex fakeCellIndex
= indexMapStorage
[i
];
1230 if (fakeCellIndex
.isSimple())
1231 indexMapStorage
[i
] = fakeCellIndex
;
1233 indexMapStorage
[i
] =
1234 loadPdbTypeIndexFromCell(g
, fakeCellIndex
.toArrayIndex());