[PDB] Split TypeServerSource and extend type index map lifetime
authorReid Kleckner <rnk@google.com>
Thu, 4 Jun 2020 01:08:55 +0000 (18:08 -0700)
committerReid Kleckner <rnk@google.com>
Thu, 17 Sep 2020 18:53:10 +0000 (11:53 -0700)
Extending the lifetime of these type index mappings does increase memory
usage (+2% in my case), but it decouples type merging from symbol
merging. This is a pre-requisite for two changes that I have in mind:
- parallel type merging: speeds up slow type merging
- defered symbol merging: avoid heap allocating (relocating) all symbols

This eliminates CVIndexMap and moves its data into TpiSource. The maps
are also split into a SmallVector and ArrayRef component, so that the
ipiMap can alias the tpiMap for /Z7 object files, and so that both maps
can simply alias the PDB type server maps for /Zi files.

Splitting TypeServerSource establishes that all input types to be merged
can be identified with two 32-bit indices:
- The index of the TpiSource object
- The type index of the record
This is useful, because this information can be stored in a single
64-bit atomic word to enable concurrent hashtable insertion.

One last change is that now all object files with debugChunks get a
TpiSource, even if they have no type info. This avoids some null checks
and special cases.

Differential Revision: https://reviews.llvm.org/D87736

lld/COFF/DebugTypes.cpp
lld/COFF/DebugTypes.h
lld/COFF/InputFiles.cpp
lld/COFF/PDB.cpp
lld/COFF/TypeMerger.h

index 3a9bd83..4695933 100644 (file)
@@ -29,6 +29,8 @@ using namespace lld;
 using namespace lld::coff;
 
 namespace {
+class TypeServerIpiSource;
+
 // The TypeServerSource class represents a PDB type server, a file referenced by
 // OBJ files compiled with MSVC /Zi. A single PDB can be shared by several OBJ
 // files, therefore there must be only once instance per OBJ lot. The file path
@@ -49,20 +51,35 @@ public:
     auto it = mappings.emplace(expectedInfo->getGuid(), this);
     assert(it.second);
     (void)it;
-    tsIndexMap.isTypeServerMap = true;
   }
 
-  Expected<const CVIndexMap *> mergeDebugT(TypeMerger *m,
-                                           CVIndexMap *indexMap) override;
+  Error mergeDebugT(TypeMerger *m) override;
   bool isDependency() const override { return true; }
 
   PDBInputFile *pdbInputFile = nullptr;
 
-  CVIndexMap tsIndexMap;
+  // TpiSource for IPI stream.
+  TypeServerIpiSource *ipiSrc = nullptr;
 
   static std::map<codeview::GUID, TypeServerSource *> mappings;
 };
 
+// Companion to TypeServerSource. Stores the index map for the IPI stream in the
+// PDB. Modeling PDBs with two sources for TPI and IPI helps establish the
+// invariant of one type index space per source.
+class TypeServerIpiSource : public TpiSource {
+public:
+  explicit TypeServerIpiSource() : TpiSource(PDBIpi, nullptr) {}
+
+  friend class TypeServerSource;
+
+  // IPI merging is handled in TypeServerSource::mergeDebugT, since it depends
+  // directly on type merging.
+  Error mergeDebugT(TypeMerger *m) override { return Error::success(); }
+
+  bool isDependency() const override { return true; }
+};
+
 // This class represents the debug type stream of an OBJ file that depends on a
 // PDB type server (see TypeServerSource).
 class UseTypeServerSource : public TpiSource {
@@ -70,8 +87,7 @@ public:
   UseTypeServerSource(ObjFile *f, TypeServer2Record ts)
       : TpiSource(UsingPDB, f), typeServerDependency(ts) {}
 
-  Expected<const CVIndexMap *> mergeDebugT(TypeMerger *m,
-                                           CVIndexMap *indexMap) override;
+  Error mergeDebugT(TypeMerger *m) override;
 
   // Information about the PDB type server dependency, that needs to be loaded
   // in before merging this OBJ.
@@ -92,15 +108,10 @@ public:
     if (!it.second)
       fatal("a PCH object with the same signature has already been provided (" +
             toString(it.first->second->file) + " and " + toString(file) + ")");
-    precompIndexMap.isPrecompiledTypeMap = true;
   }
 
-  Expected<const CVIndexMap *> mergeDebugT(TypeMerger *m,
-                                           CVIndexMap *indexMap) override;
   bool isDependency() const override { return true; }
 
-  CVIndexMap precompIndexMap;
-
   static std::map<uint32_t, PrecompSource *> mappings;
 };
 
@@ -111,8 +122,7 @@ public:
   UsePrecompSource(ObjFile *f, PrecompRecord precomp)
       : TpiSource(UsingPCH, f), precompDependency(precomp) {}
 
-  Expected<const CVIndexMap *> mergeDebugT(TypeMerger *m,
-                                           CVIndexMap *indexMap) override;
+  Error mergeDebugT(TypeMerger *m) override;
 
   // Information about the Precomp OBJ dependency, that needs to be loaded in
   // before merging this OBJ.
@@ -134,7 +144,11 @@ TpiSource *lld::coff::makeTpiSource(ObjFile *file) {
 }
 
 TpiSource *lld::coff::makeTypeServerSource(PDBInputFile *pdbInputFile) {
-  return make<TypeServerSource>(pdbInputFile);
+  // Type server sources come in pairs: the TPI stream, and the IPI stream.
+  auto *tpiSource = make<TypeServerSource>(pdbInputFile);
+  if (pdbInputFile->session->getPDBFile().hasPDBIpiStream())
+    tpiSource->ipiSrc = make<TypeServerIpiSource>();
+  return tpiSource;
 }
 
 TpiSource *lld::coff::makeUseTypeServerSource(ObjFile *file,
@@ -196,8 +210,7 @@ getHashesFromDebugH(ArrayRef<uint8_t> debugH) {
 }
 
 // Merge .debug$T for a generic object file.
-Expected<const CVIndexMap *> TpiSource::mergeDebugT(TypeMerger *m,
-                                                    CVIndexMap *indexMap) {
+Error TpiSource::mergeDebugT(TypeMerger *m) {
   CVTypeArray types;
   BinaryStreamReader reader(file->debugTypes, support::little);
   cantFail(reader.readArray(types, reader.getLength()));
@@ -213,18 +226,22 @@ Expected<const CVIndexMap *> TpiSource::mergeDebugT(TypeMerger *m,
     }
 
     if (auto err = mergeTypeAndIdRecords(m->globalIDTable, m->globalTypeTable,
-                                         indexMap->tpiMap, types, hashes,
+                                         indexMapStorage, types, hashes,
                                          file->pchSignature))
       fatal("codeview::mergeTypeAndIdRecords failed: " +
             toString(std::move(err)));
   } else {
     if (auto err =
-            mergeTypeAndIdRecords(m->idTable, m->typeTable, indexMap->tpiMap,
+            mergeTypeAndIdRecords(m->idTable, m->typeTable, indexMapStorage,
                                   types, file->pchSignature))
       fatal("codeview::mergeTypeAndIdRecords failed: " +
             toString(std::move(err)));
   }
 
+  // In an object, there is only one mapping for both types and items.
+  tpiMap = indexMapStorage;
+  ipiMap = indexMapStorage;
+
   if (config->showSummary) {
     // Count how many times we saw each type record in our input. This
     // calculation requires a second pass over the type records to classify each
@@ -234,7 +251,7 @@ Expected<const CVIndexMap *> TpiSource::mergeDebugT(TypeMerger *m,
     m->ipiCounts.resize(m->getIDTable().size());
     uint32_t srcIdx = 0;
     for (CVType &ty : types) {
-      TypeIndex dstIdx = indexMap->tpiMap[srcIdx++];
+      TypeIndex dstIdx = tpiMap[srcIdx++];
       // Type merging may fail, so a complex source type may become the simple
       // NotTranslated type, which cannot be used as an array index.
       if (dstIdx.isSimple())
@@ -245,12 +262,11 @@ Expected<const CVIndexMap *> TpiSource::mergeDebugT(TypeMerger *m,
     }
   }
 
-  return indexMap;
+  return Error::success();
 }
 
 // Merge types from a type server PDB.
-Expected<const CVIndexMap *> TypeServerSource::mergeDebugT(TypeMerger *m,
-                                                           CVIndexMap *) {
+Error TypeServerSource::mergeDebugT(TypeMerger *m) {
   pdb::PDBFile &pdbFile = pdbInputFile->session->getPDBFile();
   Expected<pdb::TpiStream &> expectedTpi = pdbFile.getPDBTpiStream();
   if (auto e = expectedTpi.takeError())
@@ -273,30 +289,34 @@ Expected<const CVIndexMap *> TypeServerSource::mergeDebugT(TypeMerger *m,
     Optional<uint32_t> endPrecomp;
     // Merge TPI first, because the IPI stream will reference type indices.
     if (auto err =
-            mergeTypeRecords(m->globalTypeTable, tsIndexMap.tpiMap,
+            mergeTypeRecords(m->globalTypeTable, indexMapStorage,
                              expectedTpi->typeArray(), tpiHashes, endPrecomp))
       fatal("codeview::mergeTypeRecords failed: " + toString(std::move(err)));
+    tpiMap = indexMapStorage;
 
     // Merge IPI.
     if (maybeIpi) {
       auto ipiHashes =
           GloballyHashedType::hashIds(maybeIpi->typeArray(), tpiHashes);
-      if (auto err = mergeIdRecords(m->globalIDTable, tsIndexMap.tpiMap,
-                                    tsIndexMap.ipiMap, maybeIpi->typeArray(),
-                                    ipiHashes))
+      if (auto err =
+              mergeIdRecords(m->globalIDTable, tpiMap, ipiSrc->indexMapStorage,
+                             maybeIpi->typeArray(), ipiHashes))
         fatal("codeview::mergeIdRecords failed: " + toString(std::move(err)));
+      ipiMap = ipiSrc->indexMapStorage;
     }
   } else {
     // Merge TPI first, because the IPI stream will reference type indices.
-    if (auto err = mergeTypeRecords(m->typeTable, tsIndexMap.tpiMap,
+    if (auto err = mergeTypeRecords(m->typeTable, indexMapStorage,
                                     expectedTpi->typeArray()))
       fatal("codeview::mergeTypeRecords failed: " + toString(std::move(err)));
+    tpiMap = indexMapStorage;
 
     // Merge IPI.
     if (maybeIpi) {
-      if (auto err = mergeIdRecords(m->idTable, tsIndexMap.tpiMap,
-                                    tsIndexMap.ipiMap, maybeIpi->typeArray()))
+      if (auto err = mergeIdRecords(m->idTable, tpiMap, ipiSrc->indexMapStorage,
+                                    maybeIpi->typeArray()))
         fatal("codeview::mergeIdRecords failed: " + toString(std::move(err)));
+      ipiMap = ipiSrc->indexMapStorage;
     }
   }
 
@@ -306,19 +326,18 @@ Expected<const CVIndexMap *> TypeServerSource::mergeDebugT(TypeMerger *m,
     // map, that means we saw it once in the input. Add it to our histogram.
     m->tpiCounts.resize(m->getTypeTable().size());
     m->ipiCounts.resize(m->getIDTable().size());
-    for (TypeIndex ti : tsIndexMap.tpiMap)
+    for (TypeIndex ti : tpiMap)
       if (!ti.isSimple())
         ++m->tpiCounts[ti.toArrayIndex()];
-    for (TypeIndex ti : tsIndexMap.ipiMap)
+    for (TypeIndex ti : ipiMap)
       if (!ti.isSimple())
         ++m->ipiCounts[ti.toArrayIndex()];
   }
 
-  return &tsIndexMap;
+  return Error::success();
 }
 
-Expected<const CVIndexMap *>
-UseTypeServerSource::mergeDebugT(TypeMerger *m, CVIndexMap *indexMap) {
+Error UseTypeServerSource::mergeDebugT(TypeMerger *m) {
   const codeview::GUID &tsId = typeServerDependency.getGuid();
   StringRef tsPath = typeServerDependency.getName();
 
@@ -342,7 +361,7 @@ UseTypeServerSource::mergeDebugT(TypeMerger *m, CVIndexMap *indexMap) {
   pdb::PDBFile &pdbSession = tsSrc->pdbInputFile->session->getPDBFile();
   auto expectedInfo = pdbSession.getPDBInfoStream();
   if (!expectedInfo)
-    return &tsSrc->tsIndexMap;
+    return expectedInfo.takeError();
 
   // Just because a file with a matching name was found and it was an actual
   // PDB file doesn't mean it matches.  For it to match the InfoStream's GUID
@@ -352,7 +371,10 @@ UseTypeServerSource::mergeDebugT(TypeMerger *m, CVIndexMap *indexMap) {
         tsPath,
         make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date));
 
-  return &tsSrc->tsIndexMap;
+  // Reuse the type index map of the type server.
+  tpiMap = tsSrc->tpiMap;
+  ipiMap = tsSrc->ipiMap;
+  return Error::success();
 }
 
 static bool equalsPath(StringRef path1, StringRef path2) {
@@ -377,8 +399,8 @@ static PrecompSource *findObjByName(StringRef fileNameOnly) {
   return nullptr;
 }
 
-static Expected<const CVIndexMap *> findPrecompMap(ObjFile *file,
-                                                   PrecompRecord &pr) {
+static Expected<PrecompSource *> findPrecompMap(ObjFile *file,
+                                                PrecompRecord &pr) {
   // Cross-compile warning: given that Clang doesn't generate LF_PRECOMP
   // records, we assume the OBJ comes from a Windows build of cl.exe. Thusly,
   // the paths embedded in the OBJs are in the Windows format.
@@ -409,53 +431,42 @@ static Expected<const CVIndexMap *> findPrecompMap(ObjFile *file,
         toString(precomp->file),
         make_error<pdb::PDBError>(pdb::pdb_error_code::no_matching_pch));
 
-  return &precomp->precompIndexMap;
+  return precomp;
 }
 
 /// Merges a precompiled headers TPI map into the current TPI map. The
 /// precompiled headers object will also be loaded and remapped in the
 /// process.
-static Expected<const CVIndexMap *>
-mergeInPrecompHeaderObj(ObjFile *file, CVIndexMap *indexMap,
+static Error
+mergeInPrecompHeaderObj(ObjFile *file,
+                        SmallVectorImpl<TypeIndex> &indexMapStorage,
                         PrecompRecord &precomp) {
   auto e = findPrecompMap(file, precomp);
   if (!e)
     return e.takeError();
 
-  const CVIndexMap *precompIndexMap = *e;
-  assert(precompIndexMap->isPrecompiledTypeMap);
-
-  if (precompIndexMap->tpiMap.empty())
-    return precompIndexMap;
+  PrecompSource *precompSrc = *e;
+  if (precompSrc->tpiMap.empty())
+    return Error::success();
 
   assert(precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex);
-  assert(precomp.getTypesCount() <= precompIndexMap->tpiMap.size());
+  assert(precomp.getTypesCount() <= precompSrc->tpiMap.size());
   // Use the previously remapped index map from the precompiled headers.
-  indexMap->tpiMap.append(precompIndexMap->tpiMap.begin(),
-                          precompIndexMap->tpiMap.begin() +
-                              precomp.getTypesCount());
-  return indexMap;
+  indexMapStorage.append(precompSrc->tpiMap.begin(),
+                         precompSrc->tpiMap.begin() + precomp.getTypesCount());
+  return Error::success();
 }
 
-Expected<const CVIndexMap *>
-UsePrecompSource::mergeDebugT(TypeMerger *m, CVIndexMap *indexMap) {
+Error UsePrecompSource::mergeDebugT(TypeMerger *m) {
   // This object was compiled with /Yu, so process the corresponding
   // precompiled headers object (/Yc) first. Some type indices in the current
   // object are referencing data in the precompiled headers object, so we need
   // both to be loaded.
-  auto e = mergeInPrecompHeaderObj(file, indexMap, precompDependency);
-  if (!e)
-    return e.takeError();
-
-  return TpiSource::mergeDebugT(m, indexMap);
-}
+  if (Error e =
+          mergeInPrecompHeaderObj(file, indexMapStorage, precompDependency))
+    return e;
 
-Expected<const CVIndexMap *> PrecompSource::mergeDebugT(TypeMerger *m,
-                                                        CVIndexMap *) {
-  // Note that we're not using the provided CVIndexMap. Instead, we use our
-  // local one. Precompiled headers objects need to save the index map for
-  // further reference by other objects which use the precompiled headers.
-  return TpiSource::mergeDebugT(m, &precompIndexMap);
+  return TpiSource::mergeDebugT(m);
 }
 
 uint32_t TpiSource::countTypeServerPDBs() {
index 24d79d8..f97c0f7 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef LLD_COFF_DEBUGTYPES_H
 #define LLD_COFF_DEBUGTYPES_H
 
+#include "lld/Common/LLVM.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/MemoryBuffer.h"
 
@@ -25,14 +27,15 @@ class NativeSession;
 namespace lld {
 namespace coff {
 
+using llvm::codeview::TypeIndex;
+
 class ObjFile;
 class PDBInputFile;
-struct CVIndexMap;
 class TypeMerger;
 
 class TpiSource {
 public:
-  enum TpiKind { Regular, PCH, UsingPCH, PDB, UsingPDB };
+  enum TpiKind { Regular, PCH, UsingPCH, PDB, PDBIpi, UsingPDB };
 
   TpiSource(TpiKind k, ObjFile *f);
   virtual ~TpiSource();
@@ -48,8 +51,8 @@ public:
   /// If the object does not use a type server PDB (compiled with /Z7), we merge
   /// all the type and item records from the .debug$S stream and fill in the
   /// caller-provided ObjectIndexMap.
-  virtual llvm::Expected<const CVIndexMap *> mergeDebugT(TypeMerger *m,
-                                                         CVIndexMap *indexMap);
+  virtual Error mergeDebugT(TypeMerger *m);
+
   /// Is this a dependent file that needs to be processed first, before other
   /// OBJs?
   virtual bool isDependency() const { return false; }
@@ -64,6 +67,15 @@ public:
 
   const TpiKind kind;
   ObjFile *file;
+
+  // Storage for tpiMap or ipiMap, depending on the kind of source.
+  llvm::SmallVector<TypeIndex, 0> indexMapStorage;
+
+  // Source type index to PDB type index mapping for type and item records.
+  // These mappings will be the same for /Z7 objects, and distinct for /Zi
+  // objects.
+  llvm::ArrayRef<TypeIndex> tpiMap;
+  llvm::ArrayRef<TypeIndex> ipiMap;
 };
 
 TpiSource *makeTpiSource(ObjFile *file);
index 6522d68..aaa00d0 100644 (file)
@@ -785,8 +785,14 @@ void ObjFile::initializeDependencies() {
   else
     data = getDebugSection(".debug$T");
 
-  if (data.empty())
+  // Don't make a TpiSource for objects with no debug info. If the object has
+  // symbols but no types, make a plain, empty TpiSource anyway, because it
+  // simplifies adding the symbols later.
+  if (data.empty()) {
+    if (!debugChunks.empty())
+      debugTypesObj = makeTpiSource(this);
     return;
+  }
 
   // Get the first type record. It will indicate if this object uses a type
   // server (/Zi) or a PCH file (/Yu).
index 49d04ad..bfa7bd8 100644 (file)
@@ -112,11 +112,11 @@ public:
   /// externally.
   void addDebug(TpiSource *source);
 
-  const CVIndexMap *mergeTypeRecords(TpiSource *source, CVIndexMap *localMap);
+  bool mergeTypeRecords(TpiSource *source);
 
-  void addDebugSymbols(ObjFile *file, const CVIndexMap *indexMap);
+  void addDebugSymbols(TpiSource *source);
 
-  void mergeSymbolRecords(ObjFile *file, const CVIndexMap &indexMap,
+  void mergeSymbolRecords(TpiSource *source,
                           std::vector<ulittle32_t *> &stringTableRefs,
                           BinaryStreamRef symData);
 
@@ -156,7 +156,7 @@ class DebugSHandler {
   ObjFile &file;
 
   /// The result of merging type indices.
-  const CVIndexMap *indexMap;
+  TpiSource *source;
 
   /// The DEBUG_S_STRINGTABLE subsection.  These strings are referred to by
   /// index from other records in the .debug$S section.  All of these strings
@@ -188,8 +188,8 @@ class DebugSHandler {
   void mergeInlineeLines(const DebugSubsectionRecord &inlineeLines);
 
 public:
-  DebugSHandler(PDBLinker &linker, ObjFile &file, const CVIndexMap *indexMap)
-      : linker(linker), file(file), indexMap(indexMap) {}
+  DebugSHandler(PDBLinker &linker, ObjFile &file, TpiSource *source)
+      : linker(linker), file(file), source(source) {}
 
   void handleDebugS(ArrayRef<uint8_t> relocatedDebugContents);
 
@@ -261,7 +261,7 @@ static bool remapTypeIndex(TypeIndex &ti, ArrayRef<TypeIndex> typeIndexMap) {
 
 static void remapTypesInSymbolRecord(ObjFile *file, SymbolKind symKind,
                                      MutableArrayRef<uint8_t> recordBytes,
-                                     const CVIndexMap &indexMap,
+                                     TpiSource *source,
                                      ArrayRef<TiReference> typeRefs) {
   MutableArrayRef<uint8_t> contents =
       recordBytes.drop_front(sizeof(RecordPrefix));
@@ -271,10 +271,9 @@ static void remapTypesInSymbolRecord(ObjFile *file, SymbolKind symKind,
       fatal("symbol record too short");
 
     // This can be an item index or a type index. Choose the appropriate map.
-    ArrayRef<TypeIndex> typeOrItemMap = indexMap.tpiMap;
     bool isItemIndex = ref.Kind == TiRefKind::IndexRef;
-    if (isItemIndex && indexMap.isTypeServerMap)
-      typeOrItemMap = indexMap.ipiMap;
+    ArrayRef<TypeIndex> typeOrItemMap =
+        isItemIndex ? source->ipiMap : source->tpiMap;
 
     MutableArrayRef<TypeIndex> tIs(
         reinterpret_cast<TypeIndex *>(contents.data() + ref.Offset), ref.Count);
@@ -505,9 +504,10 @@ static void addGlobalSymbol(pdb::GSIStreamBuilder &builder, uint16_t modIndex,
   }
 }
 
-void PDBLinker::mergeSymbolRecords(ObjFile *file, const CVIndexMap &indexMap,
+void PDBLinker::mergeSymbolRecords(TpiSource *source,
                                    std::vector<ulittle32_t *> &stringTableRefs,
                                    BinaryStreamRef symData) {
+  ObjFile *file = source->file;
   ArrayRef<uint8_t> symsBuffer;
   cantFail(symData.readBytes(0, symData.getLength(), symsBuffer));
   SmallVector<SymbolScope, 4> scopes;
@@ -571,7 +571,7 @@ void PDBLinker::mergeSymbolRecords(ObjFile *file, const CVIndexMap &indexMap,
         }
 
         // Re-map all the type index references.
-        remapTypesInSymbolRecord(file, sym.kind(), recordBytes, indexMap,
+        remapTypesInSymbolRecord(file, sym.kind(), recordBytes, source,
                                  typeRefs);
 
         // An object file may have S_xxx_ID symbols, but these get converted to
@@ -665,11 +665,6 @@ void DebugSHandler::handleDebugS(ArrayRef<uint8_t> relocatedDebugContents) {
   BinaryStreamReader reader(relocatedDebugContents, support::little);
   exitOnErr(reader.readArray(subsections, relocatedDebugContents.size()));
 
-  // If there is no index map, use an empty one.
-  CVIndexMap tempIndexMap;
-  if (!indexMap)
-    indexMap = &tempIndexMap;
-
   for (const DebugSubsectionRecord &ss : subsections) {
     // Ignore subsections with the 'ignore' bit. Some versions of the Visual C++
     // runtime have subsections with this bit set.
@@ -709,7 +704,7 @@ void DebugSHandler::handleDebugS(ArrayRef<uint8_t> relocatedDebugContents) {
       break;
     }
     case DebugSubsectionKind::Symbols: {
-      linker.mergeSymbolRecords(&file, *indexMap, stringTableReferences,
+      linker.mergeSymbolRecords(source, stringTableReferences,
                                 ss.getRecordData());
       break;
     }
@@ -757,9 +752,7 @@ void DebugSHandler::mergeInlineeLines(
   // Remap type indices in inlinee line records in place.
   for (const InlineeSourceLine &line : inlineeLines) {
     TypeIndex &inlinee = *const_cast<TypeIndex *>(&line.Header->Inlinee);
-    ArrayRef<TypeIndex> typeOrItemMap =
-        indexMap->isTypeServerMap ? indexMap->ipiMap : indexMap->tpiMap;
-    if (!remapTypeIndex(inlinee, typeOrItemMap)) {
+    if (!remapTypeIndex(inlinee, source->ipiMap)) {
       log("bad inlinee line record in " + file.getName() +
           " with bad inlinee index 0x" + utohexstr(inlinee.getIndex()));
     }
@@ -834,21 +827,18 @@ static void warnUnusable(InputFile *f, Error e) {
     warn(msg);
 }
 
-const CVIndexMap *PDBLinker::mergeTypeRecords(TpiSource *source,
-                                              CVIndexMap *localMap) {
+bool PDBLinker::mergeTypeRecords(TpiSource *source) {
   ScopedTimer t(typeMergingTimer);
   // Before we can process symbol substreams from .debug$S, we need to process
   // type information, file checksums, and the string table.  Add type info to
   // the PDB first, so that we can get the map from object file type and item
   // indices to PDB type and item indices.
-  Expected<const CVIndexMap *> r = source->mergeDebugT(&tMerger, localMap);
-
-  // If the .debug$T sections fail to merge, assume there is no debug info.
-  if (!r) {
-    warnUnusable(source->file, r.takeError());
-    return nullptr;
+  if (Error e = source->mergeDebugT(&tMerger)) {
+    // If the .debug$T sections fail to merge, assume there is no debug info.
+    warnUnusable(source->file, std::move(e));
+    return false;
   }
-  return *r;
+  return true;
 }
 
 // Allocate memory for a .debug$S / .debug$F section and relocate it.
@@ -860,12 +850,17 @@ static ArrayRef<uint8_t> relocateDebugChunk(SectionChunk &debugChunk) {
   return makeArrayRef(buffer, debugChunk.getSize());
 }
 
-void PDBLinker::addDebugSymbols(ObjFile *file, const CVIndexMap *indexMap) {
+void PDBLinker::addDebugSymbols(TpiSource *source) {
+  // If this TpiSource doesn't have an object file, it must be from a type
+  // server PDB. Type server PDBs do not contain symbols, so stop here.
+  if (!source->file)
+    return;
+
   ScopedTimer t(symbolMergingTimer);
   pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
-  DebugSHandler dsh(*this, *file, indexMap);
+  DebugSHandler dsh(*this, *source->file, source);
   // Now do all live .debug$S and .debug$F sections.
-  for (SectionChunk *debugChunk : file->getDebugChunks()) {
+  for (SectionChunk *debugChunk : source->file->getDebugChunks()) {
     if (!debugChunk->live || debugChunk->getSize() == 0)
       continue;
 
@@ -925,13 +920,9 @@ static void createModuleDBI(pdb::PDBFileBuilder &builder, ObjFile *file) {
 }
 
 void PDBLinker::addDebug(TpiSource *source) {
-  CVIndexMap localMap;
-  const CVIndexMap *indexMap = mergeTypeRecords(source, &localMap);
-
-  if (source->kind == TpiSource::PDB)
-    return; // No symbols in TypeServer PDBs
-
-  addDebugSymbols(source->file, indexMap);
+  // If type merging failed, ignore the symbols.
+  if (mergeTypeRecords(source))
+    addDebugSymbols(source);
 }
 
 static pdb::BulkPublic createPublic(Defined *def) {
@@ -964,15 +955,6 @@ void PDBLinker::addObjectsToPDB() {
   for_each(ObjFile::instances,
            [&](ObjFile *obj) { createModuleDBI(builder, obj); });
 
-  // Merge OBJs that do not have debug types
-  for_each(ObjFile::instances, [&](ObjFile *obj) {
-    if (obj->debugTypesObj)
-      return;
-    // Even if there're no types, still merge non-symbol .Debug$S and .Debug$F
-    // sections
-    addDebugSymbols(obj, nullptr);
-  });
-
   // Merge dependencies
   TpiSource::forEachSource([&](TpiSource *source) {
     if (source->isDependency())
index 858f55b..d3184a7 100644 (file)
@@ -55,15 +55,6 @@ public:
   SmallVector<uint32_t, 0> ipiCounts;
 };
 
-/// Map from type index and item index in a type server PDB to the
-/// corresponding index in the destination PDB.
-struct CVIndexMap {
-  llvm::SmallVector<llvm::codeview::TypeIndex, 0> tpiMap;
-  llvm::SmallVector<llvm::codeview::TypeIndex, 0> ipiMap;
-  bool isTypeServerMap = false;
-  bool isPrecompiledTypeMap = false;
-};
-
 } // namespace coff
 } // namespace lld