brintos

brintos / llvm-project-archived public Read only

0
0
Text · 46.5 KiB · 0999c91 Raw
1242 lines · cpp
1//===- DebugTypes.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "DebugTypes.h"10#include "COFFLinkerContext.h"11#include "Chunks.h"12#include "InputFiles.h"13#include "PDB.h"14#include "TypeMerger.h"15#include "lld/Common/ErrorHandler.h"16#include "lld/Common/Memory.h"17#include "llvm/ADT/StringExtras.h"18#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"19#include "llvm/DebugInfo/CodeView/TypeRecord.h"20#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"21#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"22#include "llvm/DebugInfo/PDB/GenericError.h"23#include "llvm/DebugInfo/PDB/Native/InfoStream.h"24#include "llvm/DebugInfo/PDB/Native/NativeSession.h"25#include "llvm/DebugInfo/PDB/Native/PDBFile.h"26#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"27#include "llvm/DebugInfo/PDB/Native/TpiStream.h"28#include "llvm/Support/FormatVariadic.h"29#include "llvm/Support/Parallel.h"30#include "llvm/Support/Path.h"31#include "llvm/Support/TimeProfiler.h"32 33using namespace llvm;34using namespace llvm::codeview;35using namespace lld;36using namespace lld::coff;37 38namespace {39class TypeServerIpiSource;40 41// The TypeServerSource class represents a PDB type server, a file referenced by42// OBJ files compiled with MSVC /Zi. A single PDB can be shared by several OBJ43// files, therefore there must be only once instance per OBJ lot. The file path44// is discovered from the dependent OBJ's debug type stream. The45// TypeServerSource object is then queued and loaded by the COFF Driver. The46// debug type stream for such PDB files will be merged first in the final PDB,47// before any dependent OBJ.48class TypeServerSource : public TpiSource {49public:50  explicit TypeServerSource(COFFLinkerContext &ctx, PDBInputFile *f)51      : TpiSource(ctx, PDB, nullptr), pdbInputFile(f) {52    if (f->loadErrorStr)53      return;54    pdb::PDBFile &file = f->session->getPDBFile();55    auto expectedInfo = file.getPDBInfoStream();56    if (!expectedInfo)57      return;58    Guid = expectedInfo->getGuid();59    auto it = ctx.typeServerSourceMappings.emplace(Guid, this);60    if (!it.second) {61      // If we hit here we have collision on Guid's in two PDB files.62      // This can happen if the PDB Guid is invalid or if we are really63      // unlucky. This should fall back on stright file-system lookup.64      it.first->second = nullptr;65    }66  }67 68  Error mergeDebugT(TypeMerger *m) override;69 70  void loadGHashes() override;71  void remapTpiWithGHashes(GHashState *g) override;72 73  bool isDependency() const override { return true; }74 75  PDBInputFile *pdbInputFile = nullptr;76 77  // TpiSource for IPI stream.78  TypeServerIpiSource *ipiSrc = nullptr;79 80  // The PDB signature GUID.81  codeview::GUID Guid;82};83 84// Companion to TypeServerSource. Stores the index map for the IPI stream in the85// PDB. Modeling PDBs with two sources for TPI and IPI helps establish the86// invariant of one type index space per source.87class TypeServerIpiSource : public TpiSource {88public:89  explicit TypeServerIpiSource(COFFLinkerContext &ctx)90      : TpiSource(ctx, PDBIpi, nullptr) {}91 92  friend class TypeServerSource;93 94  // All of the TpiSource methods are no-ops. The parent TypeServerSource95  // handles both TPI and IPI.96  Error mergeDebugT(TypeMerger *m) override { return Error::success(); }97  void loadGHashes() override {}98  void remapTpiWithGHashes(GHashState *g) override {}99  bool isDependency() const override { return true; }100};101 102// This class represents the debug type stream of an OBJ file that depends on a103// PDB type server (see TypeServerSource).104class UseTypeServerSource : public TpiSource {105  Expected<TypeServerSource *> getTypeServerSource();106 107public:108  UseTypeServerSource(COFFLinkerContext &ctx, ObjFile *f, TypeServer2Record ts)109      : TpiSource(ctx, UsingPDB, f), typeServerDependency(ts) {}110 111  Error mergeDebugT(TypeMerger *m) override;112 113  // No need to load ghashes from /Zi objects.114  void loadGHashes() override {}115  void remapTpiWithGHashes(GHashState *g) override;116 117  // Information about the PDB type server dependency, that needs to be loaded118  // in before merging this OBJ.119  TypeServer2Record typeServerDependency;120};121 122// This class represents the debug type stream of a Microsoft precompiled123// headers OBJ (PCH OBJ). This OBJ kind needs to be merged first in the output124// PDB, before any other OBJs that depend on this. Note that only MSVC generate125// such files, clang does not.126class PrecompSource : public TpiSource {127public:128  PrecompSource(COFFLinkerContext &ctx, ObjFile *f) : TpiSource(ctx, PCH, f) {129    // If the S_OBJNAME record contains the PCH signature, we'll register this130    // source file right away.131    registerMapping();132  }133 134  Error mergeDebugT(TypeMerger *m) override;135 136  void loadGHashes() override;137 138  bool isDependency() const override { return true; }139 140private:141  void registerMapping();142 143  // Whether this precomp OBJ was recorded in the precompSourceMappings map.144  // Only happens if the file->pchSignature is valid.145  bool registered = false;146};147 148// This class represents the debug type stream of an OBJ file that depends on a149// Microsoft precompiled headers OBJ (see PrecompSource).150class UsePrecompSource : public TpiSource {151public:152  UsePrecompSource(COFFLinkerContext &ctx, ObjFile *f, PrecompRecord precomp)153      : TpiSource(ctx, UsingPCH, f), precompDependency(precomp) {}154 155  Error mergeDebugT(TypeMerger *m) override;156 157  void loadGHashes() override;158  void remapTpiWithGHashes(GHashState *g) override;159 160private:161  Error mergeInPrecompHeaderObj();162 163  PrecompSource *findObjByName(StringRef fileNameOnly);164  PrecompSource *findPrecompSource(ObjFile *file, PrecompRecord &pr);165  Expected<PrecompSource *> findPrecompMap(ObjFile *file, PrecompRecord &pr);166 167public:168  // Information about the Precomp OBJ dependency, that needs to be loaded in169  // before merging this OBJ.170  PrecompRecord precompDependency;171};172} // namespace173 174TpiSource::TpiSource(COFFLinkerContext &ctx, TpiKind k, ObjFile *f)175    : ctx(ctx), kind(k), tpiSrcIdx(ctx.tpiSourceList.size()), file(f) {176  ctx.addTpiSource(this);177}178 179// Vtable key method.180TpiSource::~TpiSource() {181  // Silence any assertions about unchecked errors.182  consumeError(std::move(typeMergingError));183}184 185TpiSource *lld::coff::makeTpiSource(COFFLinkerContext &ctx, ObjFile *file) {186  return make<TpiSource>(ctx, TpiSource::Regular, file);187}188 189TpiSource *lld::coff::makeTypeServerSource(COFFLinkerContext &ctx,190                                           PDBInputFile *pdbInputFile) {191  // Type server sources come in pairs: the TPI stream, and the IPI stream.192  auto *tpiSource = make<TypeServerSource>(ctx, pdbInputFile);193  if (pdbInputFile->session->getPDBFile().hasPDBIpiStream())194    tpiSource->ipiSrc = make<TypeServerIpiSource>(ctx);195  return tpiSource;196}197 198TpiSource *lld::coff::makeUseTypeServerSource(COFFLinkerContext &ctx,199                                              ObjFile *file,200                                              TypeServer2Record ts) {201  return make<UseTypeServerSource>(ctx, file, ts);202}203 204TpiSource *lld::coff::makePrecompSource(COFFLinkerContext &ctx, ObjFile *file) {205  return make<PrecompSource>(ctx, file);206}207 208TpiSource *lld::coff::makeUsePrecompSource(COFFLinkerContext &ctx,209                                           ObjFile *file,210                                           PrecompRecord precomp) {211  return make<UsePrecompSource>(ctx, file, precomp);212}213 214bool TpiSource::remapTypeIndex(TypeIndex &ti, TiRefKind refKind) const {215  if (ti.isSimple())216    return true;217 218  // This can be an item index or a type index. Choose the appropriate map.219  ArrayRef<TypeIndex> tpiOrIpiMap =220      (refKind == TiRefKind::IndexRef) ? ipiMap : tpiMap;221  if (ti.toArrayIndex() >= tpiOrIpiMap.size())222    return false;223  ti = tpiOrIpiMap[ti.toArrayIndex()];224  return true;225}226 227void TpiSource::remapRecord(MutableArrayRef<uint8_t> rec,228                            ArrayRef<TiReference> typeRefs) {229  MutableArrayRef<uint8_t> contents = rec.drop_front(sizeof(RecordPrefix));230  for (const TiReference &ref : typeRefs) {231    unsigned byteSize = ref.Count * sizeof(TypeIndex);232    if (contents.size() < ref.Offset + byteSize)233      Fatal(ctx) << "symbol record too short";234 235    MutableArrayRef<TypeIndex> indices(236        reinterpret_cast<TypeIndex *>(contents.data() + ref.Offset), ref.Count);237    for (TypeIndex &ti : indices) {238      if (!remapTypeIndex(ti, ref.Kind)) {239        if (ctx.config.verbose) {240          uint16_t kind =241              reinterpret_cast<const RecordPrefix *>(rec.data())->RecordKind;242          StringRef fname = file ? file->getName() : "<unknown PDB>";243          Log(ctx) << "failed to remap type index in record of kind 0x"244                   << utohexstr(kind) << " in " << fname << " with bad "245                   << (ref.Kind == TiRefKind::IndexRef ? "item" : "type")246                   << " index 0x" << utohexstr(ti.getIndex());247        }248        ti = TypeIndex(SimpleTypeKind::NotTranslated);249        continue;250      }251    }252  }253}254 255void TpiSource::remapTypesInTypeRecord(MutableArrayRef<uint8_t> rec) {256  // TODO: Handle errors similar to symbols.257  SmallVector<TiReference, 32> typeRefs;258  discoverTypeIndices(CVType(rec), typeRefs);259  remapRecord(rec, typeRefs);260}261 262bool TpiSource::remapTypesInSymbolRecord(MutableArrayRef<uint8_t> rec) {263  // Discover type index references in the record. Skip it if we don't264  // know where they are.265  SmallVector<TiReference, 32> typeRefs;266  if (!discoverTypeIndicesInSymbol(rec, typeRefs))267    return false;268  remapRecord(rec, typeRefs);269  return true;270}271 272// A COFF .debug$H section is currently a clang extension.  This function checks273// if a .debug$H section is in a format that we expect / understand, so that we274// can ignore any sections which are coincidentally also named .debug$H but do275// not contain a format we recognize.276static bool canUseDebugH(ArrayRef<uint8_t> debugH) {277  if (debugH.size() < sizeof(object::debug_h_header))278    return false;279  auto *header =280      reinterpret_cast<const object::debug_h_header *>(debugH.data());281  debugH = debugH.drop_front(sizeof(object::debug_h_header));282  return header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC &&283         header->Version == 0 &&284         header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::BLAKE3) &&285         (debugH.size() % 8 == 0);286}287 288static std::optional<ArrayRef<uint8_t>> getDebugH(ObjFile *file) {289  SectionChunk *sec =290      SectionChunk::findByName(file->getDebugChunks(), ".debug$H");291  if (!sec)292    return std::nullopt;293  ArrayRef<uint8_t> contents = sec->getContents();294  if (!canUseDebugH(contents))295    return std::nullopt;296  return contents;297}298 299static ArrayRef<GloballyHashedType>300getHashesFromDebugH(ArrayRef<uint8_t> debugH) {301  assert(canUseDebugH(debugH));302  debugH = debugH.drop_front(sizeof(object::debug_h_header));303  uint32_t count = debugH.size() / sizeof(GloballyHashedType);304  return {reinterpret_cast<const GloballyHashedType *>(debugH.data()), count};305}306 307// Merge .debug$T for a generic object file.308Error TpiSource::mergeDebugT(TypeMerger *m) {309  assert(!ctx.config.debugGHashes &&310         "use remapTpiWithGHashes when ghash is enabled");311 312  CVTypeArray types;313  BinaryStreamReader reader(file->debugTypes, llvm::endianness::little);314  cantFail(reader.readArray(types, reader.getLength()));315 316  // When dealing with PCH.OBJ, some indices were already merged.317  unsigned nbHeadIndices = indexMapStorage.size();318 319  std::optional<PCHMergerInfo> pchInfo;320  if (auto err = mergeTypeAndIdRecords(m->idTable, m->typeTable,321                                       indexMapStorage, types, pchInfo))322    Fatal(ctx) << "codeview::mergeTypeAndIdRecords failed: "323               << toString(std::move(err));324  if (pchInfo) {325    file->pchSignature = pchInfo->PCHSignature;326    endPrecompIdx = pchInfo->EndPrecompIndex;327  }328 329  // In an object, there is only one mapping for both types and items.330  tpiMap = indexMapStorage;331  ipiMap = indexMapStorage;332 333  if (ctx.config.showSummary) {334    nbTypeRecords = indexMapStorage.size() - nbHeadIndices;335    nbTypeRecordsBytes = reader.getLength();336    // Count how many times we saw each type record in our input. This337    // calculation requires a second pass over the type records to classify each338    // record as a type or index. This is slow, but this code executes when339    // collecting statistics.340    m->tpiCounts.resize(m->getTypeTable().size());341    m->ipiCounts.resize(m->getIDTable().size());342    uint32_t srcIdx = nbHeadIndices;343    for (const CVType &ty : types) {344      TypeIndex dstIdx = tpiMap[srcIdx++];345      // Type merging may fail, so a complex source type may become the simple346      // NotTranslated type, which cannot be used as an array index.347      if (dstIdx.isSimple())348        continue;349      SmallVectorImpl<uint32_t> &counts =350          isIdRecord(ty.kind()) ? m->ipiCounts : m->tpiCounts;351      ++counts[dstIdx.toArrayIndex()];352    }353  }354 355  return Error::success();356}357 358// Merge types from a type server PDB.359Error TypeServerSource::mergeDebugT(TypeMerger *m) {360  assert(!ctx.config.debugGHashes &&361         "use remapTpiWithGHashes when ghash is enabled");362 363  pdb::PDBFile &pdbFile = pdbInputFile->session->getPDBFile();364  Expected<pdb::TpiStream &> expectedTpi = pdbFile.getPDBTpiStream();365  if (auto e = expectedTpi.takeError())366    Fatal(ctx) << "Type server does not have TPI stream: "367               << 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(ctx) << "Error getting type server IPI stream: "373                 << toString(std::move(e));374    maybeIpi = &*expectedIpi;375  }376 377  // Merge TPI first, because the IPI stream will reference type indices.378  if (auto err = mergeTypeRecords(m->typeTable, indexMapStorage,379                                  expectedTpi->typeArray()))380    Fatal(ctx) << "codeview::mergeTypeRecords failed: "381               << toString(std::move(err));382  tpiMap = indexMapStorage;383 384  // Merge IPI.385  if (maybeIpi) {386    if (auto err = mergeIdRecords(m->idTable, tpiMap, ipiSrc->indexMapStorage,387                                  maybeIpi->typeArray()))388      Fatal(ctx) << "codeview::mergeIdRecords failed: "389                 << toString(std::move(err));390    ipiMap = ipiSrc->indexMapStorage;391  }392 393  if (ctx.config.showSummary) {394    nbTypeRecords = tpiMap.size() + ipiMap.size();395    nbTypeRecordsBytes =396        expectedTpi->typeArray().getUnderlyingStream().getLength() +397        (maybeIpi ? maybeIpi->typeArray().getUnderlyingStream().getLength()398                  : 0);399 400    // Count how many times we saw each type record in our input. If a401    // destination type index is present in the source to destination type index402    // map, that means we saw it once in the input. Add it to our histogram.403    m->tpiCounts.resize(m->getTypeTable().size());404    m->ipiCounts.resize(m->getIDTable().size());405    for (TypeIndex ti : tpiMap)406      if (!ti.isSimple())407        ++m->tpiCounts[ti.toArrayIndex()];408    for (TypeIndex ti : ipiMap)409      if (!ti.isSimple())410        ++m->ipiCounts[ti.toArrayIndex()];411  }412 413  return Error::success();414}415 416Expected<TypeServerSource *> UseTypeServerSource::getTypeServerSource() {417  const codeview::GUID &tsId = typeServerDependency.getGuid();418  StringRef tsPath = typeServerDependency.getName();419 420  TypeServerSource *tsSrc = nullptr;421  auto it = ctx.typeServerSourceMappings.find(tsId);422  if (it != ctx.typeServerSourceMappings.end()) {423    tsSrc = (TypeServerSource *)it->second;424  }425  if (tsSrc == nullptr) {426    // The file failed to load, lookup by name427    PDBInputFile *pdb = PDBInputFile::findFromRecordPath(ctx, tsPath, file);428    if (!pdb)429      return createFileError(tsPath, errorCodeToError(std::error_code(430                                         ENOENT, std::generic_category())));431    // If an error occurred during loading, throw it now432    if (pdb->loadErrorStr)433      return createFileError(434          tsPath, make_error<StringError>(*pdb->loadErrorStr,435                                          llvm::inconvertibleErrorCode()));436 437    tsSrc = (TypeServerSource *)pdb->debugTypesObj;438 439    // Just because a file with a matching name was found and it was an actual440    // PDB file doesn't mean it matches.  For it to match the InfoStream's GUID441    // must match the GUID specified in the TypeServer2 record.442    if (tsSrc->Guid != tsId) {443      return createFileError(tsPath,444                             make_error<pdb::PDBError>(445                                 pdb::pdb_error_code::signature_out_of_date));446    }447  }448  return tsSrc;449}450 451Error UseTypeServerSource::mergeDebugT(TypeMerger *m) {452  Expected<TypeServerSource *> tsSrc = getTypeServerSource();453  if (!tsSrc)454    return tsSrc.takeError();455 456  pdb::PDBFile &pdbSession = (*tsSrc)->pdbInputFile->session->getPDBFile();457  auto expectedInfo = pdbSession.getPDBInfoStream();458  if (!expectedInfo)459    return expectedInfo.takeError();460 461  // Reuse the type index map of the type server.462  tpiMap = (*tsSrc)->tpiMap;463  ipiMap = (*tsSrc)->ipiMap;464  return Error::success();465}466 467static bool equalsPath(StringRef path1, StringRef path2) {468#if defined(_WIN32)469  return path1.equals_insensitive(path2);470#else471  return path1 == path2;472#endif473}474 475// Find by name an OBJ provided on the command line476PrecompSource *UsePrecompSource::findObjByName(StringRef fileNameOnly) {477  for (auto kv : ctx.precompSourceMappings) {478    StringRef currentFileName = sys::path::filename(kv.second->file->getName(),479                                                    sys::path::Style::windows);480 481    // Compare based solely on the file name (link.exe behavior)482    if (equalsPath(currentFileName, fileNameOnly))483      return (PrecompSource *)kv.second;484  }485  return nullptr;486}487 488PrecompSource *UsePrecompSource::findPrecompSource(ObjFile *file,489                                                   PrecompRecord &pr) {490  // Cross-compile warning: given that Clang doesn't generate LF_PRECOMP491  // records, we assume the OBJ comes from a Windows build of cl.exe. Thusly,492  // the paths embedded in the OBJs are in the Windows format.493  SmallString<128> prFileName =494      sys::path::filename(pr.getPrecompFilePath(), sys::path::Style::windows);495 496  auto it = ctx.precompSourceMappings.find(pr.getSignature());497  if (it != ctx.precompSourceMappings.end()) {498    return (PrecompSource *)it->second;499  }500  // Lookup by name501  return findObjByName(prFileName);502}503 504Expected<PrecompSource *> UsePrecompSource::findPrecompMap(ObjFile *file,505                                                           PrecompRecord &pr) {506  PrecompSource *precomp = findPrecompSource(file, pr);507 508  if (!precomp)509    return createFileError(510        pr.getPrecompFilePath(),511        make_error<pdb::PDBError>(pdb::pdb_error_code::no_matching_pch));512 513  // Don't rely on the PCH signature to validate the concordance between the PCH514  // and the OBJ that uses it. However we do validate here that the515  // LF_ENDPRECOMP record index lines up with the number of type records516  // LF_PRECOMP is expecting.517  if (precomp->endPrecompIdx != pr.getTypesCount())518    return createFileError(519        toString(file),520        make_error<pdb::PDBError>(pdb::pdb_error_code::no_matching_pch));521 522  return precomp;523}524 525/// Merges a precompiled headers TPI map into the current TPI map. The526/// precompiled headers object will also be loaded and remapped in the527/// process.528Error UsePrecompSource::mergeInPrecompHeaderObj() {529  auto e = findPrecompMap(file, precompDependency);530  if (!e)531    return e.takeError();532 533  PrecompSource *precompSrc = *e;534  if (precompSrc->tpiMap.empty())535    return Error::success();536 537  assert(precompDependency.getStartTypeIndex() ==538         TypeIndex::FirstNonSimpleIndex);539  assert(precompDependency.getTypesCount() <= precompSrc->tpiMap.size());540  // Use the previously remapped index map from the precompiled headers.541  indexMapStorage.insert(indexMapStorage.begin(), precompSrc->tpiMap.begin(),542                         precompSrc->tpiMap.begin() +543                             precompDependency.getTypesCount());544 545  return Error::success();546}547 548Error UsePrecompSource::mergeDebugT(TypeMerger *m) {549  // This object was compiled with /Yu, so process the corresponding550  // precompiled headers object (/Yc) first. Some type indices in the current551  // object are referencing data in the precompiled headers object, so we need552  // both to be loaded.553  if (Error e = mergeInPrecompHeaderObj())554    return e;555 556  return TpiSource::mergeDebugT(m);557}558 559Error PrecompSource::mergeDebugT(TypeMerger *m) {560  // In some cases, the S_OBJNAME record doesn't contain the PCH signature.561  // The signature comes later with the LF_ENDPRECOMP record, so we first need562  // to merge in all the .PCH.OBJ file type records, before registering below.563  if (Error e = TpiSource::mergeDebugT(m))564    return e;565 566  registerMapping();567 568  return Error::success();569}570 571void PrecompSource::registerMapping() {572  if (registered)573    return;574  if (file->pchSignature && *file->pchSignature) {575    auto it = ctx.precompSourceMappings.emplace(*file->pchSignature, this);576    if (!it.second)577      Fatal(ctx)578          << "a PCH object with the same signature has already been provided ("579          << toString(it.first->second->file) << " and " << toString(file)580          << ")";581    registered = true;582  }583}584 585//===----------------------------------------------------------------------===//586// Parellel GHash type merging implementation.587//===----------------------------------------------------------------------===//588 589void TpiSource::loadGHashes() {590  if (std::optional<ArrayRef<uint8_t>> debugH = getDebugH(file)) {591    ghashes = getHashesFromDebugH(*debugH);592    ownedGHashes = false;593  } else {594    CVTypeArray types;595    BinaryStreamReader reader(file->debugTypes, llvm::endianness::little);596    cantFail(reader.readArray(types, reader.getLength()));597    assignGHashesFromVector(GloballyHashedType::hashTypes(types));598  }599 600  fillIsItemIndexFromDebugT();601}602 603// Copies ghashes from a vector into an array. These are long lived, so it's604// worth the time to copy these into an appropriately sized vector to reduce605// memory usage.606void TpiSource::assignGHashesFromVector(607    std::vector<GloballyHashedType> &&hashVec) {608  if (hashVec.empty())609    return;610  GloballyHashedType *hashes = new GloballyHashedType[hashVec.size()];611  memcpy(hashes, hashVec.data(), hashVec.size() * sizeof(GloballyHashedType));612  ghashes = ArrayRef(hashes, hashVec.size());613  ownedGHashes = true;614}615 616// Faster way to iterate type records. forEachTypeChecked is faster than617// iterating CVTypeArray. It avoids virtual readBytes calls in inner loops.618static void forEachTypeChecked(ArrayRef<uint8_t> types,619                               function_ref<void(const CVType &)> fn) {620  checkError(621      forEachCodeViewRecord<CVType>(types, [fn](const CVType &ty) -> Error {622        fn(ty);623        return Error::success();624      }));625}626 627// Walk over file->debugTypes and fill in the isItemIndex bit vector.628// TODO: Store this information in .debug$H so that we don't have to recompute629// it. This is the main bottleneck slowing down parallel ghashing with one630// thread over single-threaded ghashing.631void TpiSource::fillIsItemIndexFromDebugT() {632  uint32_t index = 0;633  isItemIndex.resize(ghashes.size());634  forEachTypeChecked(file->debugTypes, [&](const CVType &ty) {635    if (isIdRecord(ty.kind()))636      isItemIndex.set(index);637    ++index;638  });639}640 641void TpiSource::mergeTypeRecord(TypeIndex curIndex, CVType ty) {642  // Decide if the merged type goes into TPI or IPI.643  bool isItem = isIdRecord(ty.kind());644  MergedInfo &merged = isItem ? mergedIpi : mergedTpi;645 646  // Copy the type into our mutable buffer.647  assert(ty.length() <= codeview::MaxRecordLength);648  size_t offset = merged.recs.size();649  size_t newSize = alignTo(ty.length(), 4);650  merged.recs.resize(offset + newSize);651  auto newRec = MutableArrayRef(&merged.recs[offset], newSize);652  memcpy(newRec.data(), ty.data().data(), newSize);653 654  // Fix up the record prefix and padding bytes if it required resizing.655  if (newSize != ty.length()) {656    reinterpret_cast<RecordPrefix *>(newRec.data())->RecordLen = newSize - 2;657    for (size_t i = ty.length(); i < newSize; ++i)658      newRec[i] = LF_PAD0 + (newSize - i);659  }660 661  // Remap the type indices in the new record.662  remapTypesInTypeRecord(newRec);663  uint32_t pdbHash = check(pdb::hashTypeRecord(CVType(newRec)));664  merged.recSizes.push_back(static_cast<uint16_t>(newSize));665  merged.recHashes.push_back(pdbHash);666 667  // Retain a mapping from PDB function id to PDB function type. This mapping is668  // used during symbol processing to rewrite S_GPROC32_ID symbols to S_GPROC32669  // symbols.670  if (ty.kind() == LF_FUNC_ID || ty.kind() == LF_MFUNC_ID) {671    bool success = ty.length() >= 12;672    TypeIndex funcId = curIndex;673    if (success)674      success &= remapTypeIndex(funcId, TiRefKind::IndexRef);675    TypeIndex funcType =676        *reinterpret_cast<const TypeIndex *>(&newRec.data()[8]);677    if (success) {678      funcIdToType.push_back({funcId, funcType});679    } else {680      StringRef fname = file ? file->getName() : "<unknown PDB>";681      Warn(ctx) << "corrupt LF_[M]FUNC_ID record 0x"682                << utohexstr(curIndex.getIndex()) << " in " << fname;683    }684  }685}686 687void TpiSource::mergeUniqueTypeRecords(ArrayRef<uint8_t> typeRecords,688                                       TypeIndex beginIndex) {689  // Re-sort the list of unique types by index.690  if (kind == PDB)691    assert(llvm::is_sorted(uniqueTypes));692  else693    llvm::sort(uniqueTypes);694 695  // Accumulate all the unique types into one buffer in mergedTypes.696  uint32_t ghashIndex = 0;697  auto nextUniqueIndex = uniqueTypes.begin();698  assert(mergedTpi.recs.empty());699  assert(mergedIpi.recs.empty());700 701  // Pre-compute the number of elements in advance to avoid std::vector resizes.702  unsigned nbTpiRecs = 0;703  unsigned nbIpiRecs = 0;704  forEachTypeChecked(typeRecords, [&](const CVType &ty) {705    if (nextUniqueIndex != uniqueTypes.end() &&706        *nextUniqueIndex == ghashIndex) {707      assert(ty.length() <= codeview::MaxRecordLength);708      size_t newSize = alignTo(ty.length(), 4);709      (isIdRecord(ty.kind()) ? nbIpiRecs : nbTpiRecs) += newSize;710      ++nextUniqueIndex;711    }712    ++ghashIndex;713  });714  mergedTpi.recs.reserve(nbTpiRecs);715  mergedIpi.recs.reserve(nbIpiRecs);716 717  // Do the actual type merge.718  ghashIndex = 0;719  nextUniqueIndex = uniqueTypes.begin();720  forEachTypeChecked(typeRecords, [&](const CVType &ty) {721    if (nextUniqueIndex != uniqueTypes.end() &&722        *nextUniqueIndex == ghashIndex) {723      mergeTypeRecord(beginIndex + ghashIndex, ty);724      ++nextUniqueIndex;725    }726    ++ghashIndex;727  });728  assert(nextUniqueIndex == uniqueTypes.end() &&729         "failed to merge all desired records");730  assert(uniqueTypes.size() ==731             mergedTpi.recSizes.size() + mergedIpi.recSizes.size() &&732         "missing desired record");733}734 735void TpiSource::remapTpiWithGHashes(GHashState *g) {736  assert(ctx.config.debugGHashes && "ghashes must be enabled");737  fillMapFromGHashes(g);738  tpiMap = indexMapStorage;739  ipiMap = indexMapStorage;740  mergeUniqueTypeRecords(file->debugTypes);741  // TODO: Free all unneeded ghash resources now that we have a full index map.742 743  if (ctx.config.showSummary) {744    nbTypeRecords = ghashes.size();745    nbTypeRecordsBytes = file->debugTypes.size();746  }747}748 749// PDBs do not actually store global hashes, so when merging a type server750// PDB we have to synthesize global hashes.  To do this, we first synthesize751// global hashes for the TPI stream, since it is independent, then we752// synthesize hashes for the IPI stream, using the hashes for the TPI stream753// as inputs.754void TypeServerSource::loadGHashes() {755  // Don't hash twice.756  if (!ghashes.empty())757    return;758  pdb::PDBFile &pdbFile = pdbInputFile->session->getPDBFile();759 760  // Hash TPI stream.761  Expected<pdb::TpiStream &> expectedTpi = pdbFile.getPDBTpiStream();762  if (auto e = expectedTpi.takeError())763    Fatal(ctx) << "Type server does not have TPI stream: "764               << toString(std::move(e));765  assignGHashesFromVector(766      GloballyHashedType::hashTypes(expectedTpi->typeArray()));767  isItemIndex.resize(ghashes.size());768 769  // Hash IPI stream, which depends on TPI ghashes.770  if (!pdbFile.hasPDBIpiStream())771    return;772  Expected<pdb::TpiStream &> expectedIpi = pdbFile.getPDBIpiStream();773  if (auto e = expectedIpi.takeError())774    Fatal(ctx) << "error retrieving IPI stream: " << toString(std::move(e));775  ipiSrc->assignGHashesFromVector(776      GloballyHashedType::hashIds(expectedIpi->typeArray(), ghashes));777 778  // The IPI stream isItemIndex bitvector should be all ones.779  ipiSrc->isItemIndex.resize(ipiSrc->ghashes.size());780  ipiSrc->isItemIndex.set(0, ipiSrc->ghashes.size());781}782 783// Flatten discontiguous PDB type arrays to bytes so that we can use784// forEachTypeChecked instead of CVTypeArray iteration. Copying all types from785// type servers is faster than iterating all object files compiled with /Z7 with786// CVTypeArray, which has high overheads due to the virtual interface of787// BinaryStream::readBytes.788static ArrayRef<uint8_t> typeArrayToBytes(const CVTypeArray &types) {789  BinaryStreamRef stream = types.getUnderlyingStream();790  ArrayRef<uint8_t> debugTypes;791  checkError(stream.readBytes(0, stream.getLength(), debugTypes));792  return debugTypes;793}794 795// Merge types from a type server PDB.796void TypeServerSource::remapTpiWithGHashes(GHashState *g) {797  assert(ctx.config.debugGHashes && "ghashes must be enabled");798 799  // IPI merging depends on TPI, so do TPI first, then do IPI.  No need to800  // propagate errors, those should've been handled during ghash loading.801  pdb::PDBFile &pdbFile = pdbInputFile->session->getPDBFile();802  pdb::TpiStream &tpi = check(pdbFile.getPDBTpiStream());803  fillMapFromGHashes(g);804  tpiMap = indexMapStorage;805  mergeUniqueTypeRecords(typeArrayToBytes(tpi.typeArray()));806  if (pdbFile.hasPDBIpiStream()) {807    pdb::TpiStream &ipi = check(pdbFile.getPDBIpiStream());808    ipiSrc->indexMapStorage.resize(ipiSrc->ghashes.size());809    ipiSrc->fillMapFromGHashes(g);810    ipiMap = ipiSrc->indexMapStorage;811    ipiSrc->tpiMap = tpiMap;812    ipiSrc->ipiMap = ipiMap;813    ipiSrc->mergeUniqueTypeRecords(typeArrayToBytes(ipi.typeArray()));814 815    if (ctx.config.showSummary) {816      nbTypeRecords = ipiSrc->ghashes.size();817      nbTypeRecordsBytes = ipi.typeArray().getUnderlyingStream().getLength();818    }819  }820 821  if (ctx.config.showSummary) {822    nbTypeRecords += ghashes.size();823    nbTypeRecordsBytes += tpi.typeArray().getUnderlyingStream().getLength();824  }825}826 827void UseTypeServerSource::remapTpiWithGHashes(GHashState *g) {828  // No remapping to do with /Zi objects. Simply use the index map from the type829  // server. Errors should have been reported earlier. Symbols from this object830  // will be ignored.831  Expected<TypeServerSource *> maybeTsSrc = getTypeServerSource();832  if (!maybeTsSrc) {833    typeMergingError =834        joinErrors(std::move(typeMergingError), maybeTsSrc.takeError());835    return;836  }837  TypeServerSource *tsSrc = *maybeTsSrc;838  tpiMap = tsSrc->tpiMap;839  ipiMap = tsSrc->ipiMap;840}841 842void PrecompSource::loadGHashes() {843  if (getDebugH(file)) {844    Warn(ctx) << "ignoring .debug$H section; pch with ghash is not implemented";845  }846 847  uint32_t ghashIdx = 0;848  std::vector<GloballyHashedType> hashVec;849  forEachTypeChecked(file->debugTypes, [&](const CVType &ty) {850    // Remember the index of the LF_ENDPRECOMP record so it can be excluded from851    // the PDB. There must be an entry in the list of ghashes so that the type852    // indexes of the following records in the /Yc PCH object line up.853    if (ty.kind() == LF_ENDPRECOMP) {854      EndPrecompRecord endPrecomp;855      cantFail(TypeDeserializer::deserializeAs<EndPrecompRecord>(856          const_cast<CVType &>(ty), endPrecomp));857      file->pchSignature = endPrecomp.getSignature();858      registerMapping();859      endPrecompIdx = ghashIdx;860    }861 862    hashVec.push_back(GloballyHashedType::hashType(ty, hashVec, hashVec));863    isItemIndex.push_back(isIdRecord(ty.kind()));864    ++ghashIdx;865  });866  assignGHashesFromVector(std::move(hashVec));867}868 869void UsePrecompSource::loadGHashes() {870  auto e = findPrecompMap(file, precompDependency);871  if (!e) {872    Warn(ctx) << e.takeError();873    return;874  }875 876  PrecompSource *pchSrc = *e;877 878  // To compute ghashes of a /Yu object file, we need to build on the ghashes of879  // the /Yc PCH object. After we are done hashing, discard the ghashes from the880  // PCH source so we don't unnecessarily try to deduplicate them.881  std::vector<GloballyHashedType> hashVec =882      pchSrc->ghashes.take_front(precompDependency.getTypesCount());883  forEachTypeChecked(file->debugTypes, [&](const CVType &ty) {884    hashVec.push_back(GloballyHashedType::hashType(ty, hashVec, hashVec));885    isItemIndex.push_back(isIdRecord(ty.kind()));886  });887  hashVec.erase(hashVec.begin(),888                hashVec.begin() + precompDependency.getTypesCount());889  assignGHashesFromVector(std::move(hashVec));890}891 892void UsePrecompSource::remapTpiWithGHashes(GHashState *g) {893  fillMapFromGHashes(g);894  // This object was compiled with /Yu, so process the corresponding895  // precompiled headers object (/Yc) first. Some type indices in the current896  // object are referencing data in the precompiled headers object, so we need897  // both to be loaded.898  if (Error e = mergeInPrecompHeaderObj()) {899    typeMergingError = joinErrors(std::move(typeMergingError), std::move(e));900    return;901  }902 903  tpiMap = indexMapStorage;904  ipiMap = indexMapStorage;905  mergeUniqueTypeRecords(file->debugTypes,906                         TypeIndex(precompDependency.getStartTypeIndex() +907                                   precompDependency.getTypesCount()));908  if (ctx.config.showSummary) {909    nbTypeRecords = ghashes.size();910    nbTypeRecordsBytes = file->debugTypes.size();911  }912}913 914namespace {915/// A concurrent hash table for global type hashing. It is based on this paper:916/// Concurrent Hash Tables: Fast and General(?)!917/// https://dl.acm.org/doi/10.1145/3309206918///919/// This hash table is meant to be used in two phases:920/// 1. concurrent insertions921/// 2. concurrent reads922/// It does not support lookup, deletion, or rehashing. It uses linear probing.923///924/// The paper describes storing a key-value pair in two machine words.925/// Generally, the values stored in this map are type indices, and we can use926/// those values to recover the ghash key from a side table. This allows us to927/// shrink the table entries further at the cost of some loads, and sidesteps928/// the need for a 128 bit atomic compare-and-swap operation.929///930/// During insertion, a priority function is used to decide which insertion931/// should be preferred. This ensures that the output is deterministic. For932/// ghashing, lower tpiSrcIdx values (earlier inputs) are preferred.933///934class GHashCell;935struct GHashTable {936  GHashCell *table = nullptr;937  uint32_t tableSize = 0;938 939  GHashTable() = default;940  ~GHashTable();941 942  /// Initialize the table with the given size. Because the table cannot be943  /// resized, the initial size of the table must be large enough to contain all944  /// inputs, or insertion may not be able to find an empty cell.945  void init(uint32_t newTableSize);946 947  /// Insert the cell with the given ghash into the table. Return the insertion948  /// position in the table. It is safe for the caller to store the insertion949  /// position because the table cannot be resized.950  uint32_t insert(COFFLinkerContext &ctx, GloballyHashedType ghash,951                  GHashCell newCell);952};953 954/// A ghash table cell for deduplicating types from TpiSources.955class GHashCell {956  // Force "data" to be 64-bit aligned; otherwise, some versions of clang957  // will generate calls to libatomic when using some versions of libstdc++958  // on 32-bit targets.  (Also, in theory, there could be a target where959  // new[] doesn't always return an 8-byte-aligned allocation.)960  alignas(sizeof(uint64_t)) uint64_t data = 0;961 962public:963  GHashCell() = default;964 965  // Construct data most to least significant so that sorting works well:966  // - isItem967  // - tpiSrcIdx968  // - ghashIdx969  // Add one to the tpiSrcIdx so that the 0th record from the 0th source has a970  // non-zero representation.971  GHashCell(bool isItem, uint32_t tpiSrcIdx, uint32_t ghashIdx)972      : data((uint64_t(isItem) << 63U) | (uint64_t(tpiSrcIdx + 1) << 32ULL) |973             ghashIdx) {974    assert(tpiSrcIdx == getTpiSrcIdx() && "round trip failure");975    assert(ghashIdx == getGHashIdx() && "round trip failure");976  }977 978  explicit GHashCell(uint64_t data) : data(data) {}979 980  // The empty cell is all zeros.981  bool isEmpty() const { return data == 0ULL; }982 983  /// Extract the tpiSrcIdx.984  uint32_t getTpiSrcIdx() const {985    return ((uint32_t)(data >> 32U) & 0x7FFFFFFF) - 1;986  }987 988  /// Extract the index into the ghash array of the TpiSource.989  uint32_t getGHashIdx() const { return (uint32_t)data; }990 991  bool isItem() const { return data & (1ULL << 63U); }992 993  /// Get the ghash key for this cell.994  GloballyHashedType getGHash(const COFFLinkerContext &ctx) const {995    return ctx.tpiSourceList[getTpiSrcIdx()]->ghashes[getGHashIdx()];996  }997 998  /// The priority function for the cell. The data is stored such that lower999  /// tpiSrcIdx and ghashIdx values are preferred, which means that type record1000  /// from earlier sources are more likely to prevail.1001  friend inline bool operator<(const GHashCell &l, const GHashCell &r) {1002    return l.data < r.data;1003  }1004};1005} // namespace1006 1007namespace lld::coff {1008/// This type is just a wrapper around GHashTable with external linkage so it1009/// can be used from a header.1010struct GHashState {1011  GHashTable table;1012};1013} // namespace lld::coff1014 1015GHashTable::~GHashTable() { delete[] table; }1016 1017void GHashTable::init(uint32_t newTableSize) {1018  table = new GHashCell[newTableSize];1019  memset(table, 0, newTableSize * sizeof(GHashCell));1020  tableSize = newTableSize;1021}1022 1023uint32_t GHashTable::insert(COFFLinkerContext &ctx, GloballyHashedType ghash,1024                            GHashCell newCell) {1025  assert(!newCell.isEmpty() && "cannot insert empty cell value");1026 1027  // FIXME: The low bytes of SHA1 have low entropy for short records, which1028  // type records are. Swap the byte order for better entropy. A better ghash1029  // won't need this.1030  uint32_t startIdx =1031      llvm::byteswap<uint64_t>(*reinterpret_cast<uint64_t *>(&ghash)) %1032      tableSize;1033 1034  // Do a linear probe starting at startIdx.1035  uint32_t idx = startIdx;1036  while (true) {1037    // Run a compare and swap loop. There are four cases:1038    // - cell is empty: CAS into place and return1039    // - cell has matching key, earlier priority: do nothing, return1040    // - cell has matching key, later priority: CAS into place and return1041    // - cell has non-matching key: hash collision, probe next cell1042    auto *cellPtr = reinterpret_cast<std::atomic<GHashCell> *>(&table[idx]);1043    GHashCell oldCell(cellPtr->load());1044    while (oldCell.isEmpty() || oldCell.getGHash(ctx) == ghash) {1045      // Check if there is an existing ghash entry with a higher priority1046      // (earlier ordering). If so, this is a duplicate, we are done.1047      if (!oldCell.isEmpty() && oldCell < newCell)1048        return idx;1049      // Either the cell is empty, or our value is higher priority. Try to1050      // compare and swap. If it succeeds, we are done.1051      if (cellPtr->compare_exchange_weak(oldCell, newCell))1052        return idx;1053      // If the CAS failed, check this cell again.1054    }1055 1056    // Advance the probe. Wrap around to the beginning if we run off the end.1057    ++idx;1058    idx = idx == tableSize ? 0 : idx;1059    if (idx == startIdx) {1060      // If this becomes an issue, we could mark failure and rehash from the1061      // beginning with a bigger table. There is no difference between rehashing1062      // internally and starting over.1063      report_fatal_error("ghash table is full");1064    }1065  }1066  llvm_unreachable("left infloop");1067}1068 1069TypeMerger::TypeMerger(COFFLinkerContext &c, llvm::BumpPtrAllocator &alloc)1070    : typeTable(alloc), idTable(alloc), ctx(c) {}1071 1072TypeMerger::~TypeMerger() = default;1073 1074void TypeMerger::mergeTypesWithGHash() {1075  // Load ghashes. Do type servers and PCH objects first.1076  {1077    llvm::TimeTraceScope timeScope("Load GHASHes");1078    ScopedTimer t1(ctx.loadGHashTimer);1079    parallelForEach(dependencySources,1080                    [&](TpiSource *source) { source->loadGHashes(); });1081    parallelForEach(objectSources,1082                    [&](TpiSource *source) { source->loadGHashes(); });1083  }1084 1085  llvm::TimeTraceScope timeScope("Merge types (GHASH)");1086  ScopedTimer t2(ctx.mergeGHashTimer);1087  GHashState ghashState;1088 1089  // Estimate the size of hash table needed to deduplicate ghashes. This *must*1090  // be larger than the number of unique types, or hash table insertion may not1091  // be able to find a vacant slot. Summing the input types guarantees this, but1092  // it is a gross overestimate. The table size could be reduced to save memory,1093  // but it would require implementing rehashing, and this table is generally1094  // small compared to total memory usage, at eight bytes per input type record,1095  // and most input type records are larger than eight bytes.1096  size_t tableSize = 0;1097  for (TpiSource *source : ctx.tpiSourceList)1098    tableSize += source->ghashes.size();1099 1100  // Cap the table size so that we can use 32-bit cell indices. Type indices are1101  // also 32-bit, so this is an inherent PDB file format limit anyway.1102  tableSize =1103      std::min(size_t(INT32_MAX) - TypeIndex::FirstNonSimpleIndex, tableSize);1104  ghashState.table.init(static_cast<uint32_t>(tableSize));1105 1106  // Insert ghashes in parallel. During concurrent insertion, we cannot observe1107  // the contents of the hash table cell, but we can remember the insertion1108  // position. Because the table does not rehash, the position will not change1109  // under insertion. After insertion is done, the value of the cell can be read1110  // to retrieve the final PDB type index.1111  parallelFor(0, ctx.tpiSourceList.size(), [&](size_t tpiSrcIdx) {1112    TpiSource *source = ctx.tpiSourceList[tpiSrcIdx];1113    source->indexMapStorage.resize(source->ghashes.size());1114    for (uint32_t i = 0, e = source->ghashes.size(); i < e; i++) {1115      if (source->shouldOmitFromPdb(i)) {1116        source->indexMapStorage[i] = TypeIndex(SimpleTypeKind::NotTranslated);1117        continue;1118      }1119      GloballyHashedType ghash = source->ghashes[i];1120      bool isItem = source->isItemIndex.test(i);1121      uint32_t cellIdx =1122          ghashState.table.insert(ctx, ghash, GHashCell(isItem, tpiSrcIdx, i));1123 1124      // Store the ghash cell index as a type index in indexMapStorage. Later1125      // we will replace it with the PDB type index.1126      source->indexMapStorage[i] = TypeIndex::fromArrayIndex(cellIdx);1127    }1128  });1129 1130  // Collect all non-empty cells and sort them. This will implicitly assign1131  // destination type indices, and partition the entries into type records and1132  // item records. It arranges types in this order:1133  // - type records1134  //   - source 0, type 0...1135  //   - source 1, type 1...1136  // - item records1137  //   - source 0, type 1...1138  //   - source 1, type 0...1139  std::vector<GHashCell> entries;1140  for (const GHashCell &cell : ArrayRef(ghashState.table.table, tableSize)) {1141    if (!cell.isEmpty())1142      entries.push_back(cell);1143  }1144  parallelSort(entries, std::less<GHashCell>());1145  Log(ctx) << formatv(1146      "ghash table load factor: {0:p} (size {1} / capacity {2})\n",1147      tableSize ? double(entries.size()) / tableSize : 0, entries.size(),1148      tableSize);1149 1150  // Find out how many type and item indices there are.1151  auto mid = llvm::lower_bound(entries, GHashCell(true, 0, 0));1152  assert((mid == entries.end() || mid->isItem()) &&1153         (mid == entries.begin() || !std::prev(mid)->isItem()) &&1154         "midpoint is not midpoint");1155  uint32_t numTypes = std::distance(entries.begin(), mid);1156  uint32_t numItems = std::distance(mid, entries.end());1157  Log(ctx) << "Tpi record count: " << numTypes;1158  Log(ctx) << "Ipi record count: " << numItems;1159 1160  // Make a list of the "unique" type records to merge for each tpi source. Type1161  // merging will skip indices not on this list. Store the destination PDB type1162  // index for these unique types in the tpiMap for each source. The entries for1163  // non-unique types will be filled in prior to type merging.1164  for (uint32_t i = 0, e = entries.size(); i < e; ++i) {1165    auto &cell = entries[i];1166    uint32_t tpiSrcIdx = cell.getTpiSrcIdx();1167    TpiSource *source = ctx.tpiSourceList[tpiSrcIdx];1168    source->uniqueTypes.push_back(cell.getGHashIdx());1169 1170    // Update the ghash table to store the destination PDB type index in the1171    // table.1172    uint32_t pdbTypeIndex = i < numTypes ? i : i - numTypes;1173    uint32_t ghashCellIndex =1174        source->indexMapStorage[cell.getGHashIdx()].toArrayIndex();1175    ghashState.table.table[ghashCellIndex] =1176        GHashCell(cell.isItem(), cell.getTpiSrcIdx(), pdbTypeIndex);1177  }1178 1179  // In parallel, remap all types.1180  for (TpiSource *source : dependencySources)1181    source->remapTpiWithGHashes(&ghashState);1182  parallelForEach(objectSources, [&](TpiSource *source) {1183    source->remapTpiWithGHashes(&ghashState);1184  });1185 1186  // Build a global map of from function ID to function type.1187  for (TpiSource *source : ctx.tpiSourceList) {1188    funcIdToType.insert_range(source->funcIdToType);1189    source->funcIdToType.clear();1190  }1191 1192  clearGHashes();1193}1194 1195void TypeMerger::sortDependencies() {1196  // Order dependencies first, but preserve the existing order.1197  std::vector<TpiSource *> deps;1198  std::vector<TpiSource *> objs;1199  for (TpiSource *s : ctx.tpiSourceList)1200    (s->isDependency() ? deps : objs).push_back(s);1201  uint32_t numDeps = deps.size();1202  uint32_t numObjs = objs.size();1203  ctx.tpiSourceList = std::move(deps);1204  ctx.tpiSourceList.insert(ctx.tpiSourceList.end(), objs.begin(), objs.end());1205  for (uint32_t i = 0, e = ctx.tpiSourceList.size(); i < e; ++i)1206    ctx.tpiSourceList[i]->tpiSrcIdx = i;1207  dependencySources = ArrayRef(ctx.tpiSourceList.data(), numDeps);1208  objectSources = ArrayRef(ctx.tpiSourceList.data() + numDeps, numObjs);1209}1210 1211/// Given the index into the ghash table for a particular type, return the type1212/// index for that type in the output PDB.1213static TypeIndex loadPdbTypeIndexFromCell(GHashState *g,1214                                          uint32_t ghashCellIdx) {1215  GHashCell cell = g->table.table[ghashCellIdx];1216  return TypeIndex::fromArrayIndex(cell.getGHashIdx());1217}1218 1219/// Free heap allocated ghashes.1220void TypeMerger::clearGHashes() {1221  for (TpiSource *src : ctx.tpiSourceList) {1222    if (src->ownedGHashes)1223      delete[] src->ghashes.data();1224    src->ghashes = {};1225    src->isItemIndex.clear();1226    src->uniqueTypes.clear();1227  }1228}1229 1230// Fill in a TPI or IPI index map using ghashes. For each source type, use its1231// ghash to lookup its final type index in the PDB, and store that in the map.1232void TpiSource::fillMapFromGHashes(GHashState *g) {1233  for (size_t i = 0, e = ghashes.size(); i < e; ++i) {1234    TypeIndex fakeCellIndex = indexMapStorage[i];1235    if (fakeCellIndex.isSimple())1236      indexMapStorage[i] = fakeCellIndex;1237    else1238      indexMapStorage[i] =1239          loadPdbTypeIndexFromCell(g, fakeCellIndex.toArrayIndex());1240  }1241}1242