diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp index 0266148cc6c9..2dbc3797c857 100644 --- a/lld/COFF/PDB.cpp +++ b/lld/COFF/PDB.cpp @@ -117,8 +117,9 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, Handler.addSearchPath(llvm::sys::path::parent_path(File->getName())); if (auto EC = Reader.readArray(Types, Reader.getLength())) fatal(EC, "Reader::readArray failed"); - if (auto Err = codeview::mergeTypeStreams(IDTable, TypeTable, SourceToDest, - &Handler, Types)) + codeview::LazyRandomTypeCollection TypesAndIds(Types, 100); + if (auto Err = codeview::mergeTypeAndIdRecords( + IDTable, TypeTable, SourceToDest, &Handler, TypesAndIds)) fatal(Err, "codeview::mergeTypeStreams failed"); } diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h b/llvm/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h index 65bcf9812e68..58192bd55cfd 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h @@ -22,11 +22,74 @@ class TypeIndex; class TypeServerHandler; class TypeTableBuilder; -/// Merges one type stream into another. Returns true on success. -Error mergeTypeStreams(TypeTableBuilder &DestIdStream, - TypeTableBuilder &DestTypeStream, +/// \brief Merge one set of type records into another. This method assumes +/// that all records are type records, and there are no Id records present. +/// +/// \param Dest The table to store the re-written type records into. +/// +/// \param SourceToDest A vector, indexed by the TypeIndex in the source +/// type stream, that contains the index of the corresponding type record +/// in the destination stream. +/// +/// \param Handler (optional) If non-null, an interface that gets invoked +/// to handle type server records. +/// +/// \param Types The collection of types to merge in. +/// +/// \returns Error::success() if the operation succeeded, otherwise an +/// appropriate error code. +Error mergeTypeRecords(TypeTableBuilder &Dest, SmallVectorImpl &SourceToDest, - TypeServerHandler *Handler, const CVTypeArray &Types); + TypeServerHandler *Handler, TypeCollection &Types); + +/// \brief Merge one set of id records into another. This method assumes +/// that all records are id records, and there are no Type records present. +/// However, since Id records can refer back to Type records, this method +/// assumes that the referenced type records have also been merged into +/// another type stream (for example using the above method), and accepts +/// the mapping from source to dest for that stream so that it can re-write +/// the type record mappings accordingly. +/// +/// \param Dest The table to store the re-written id records into. +/// +/// \param Types The mapping to use for the type records that these id +/// records refer to. +/// +/// \param SourceToDest A vector, indexed by the TypeIndex in the source +/// id stream, that contains the index of the corresponding id record +/// in the destination stream. +/// +/// \param Types The collection of id records to merge in. +/// +/// \returns Error::success() if the operation succeeded, otherwise an +/// appropriate error code. +Error mergeIdRecords(TypeTableBuilder &Dest, ArrayRef Types, + SmallVectorImpl &SourceToDest, + TypeCollection &Ids); + +/// \brief Merge a unified set of type and id records, splitting them into +/// separate output streams. +/// +/// \param DestIds The table to store the re-written id records into. +/// +/// \param DestTypes the table to store the re-written type records into. +/// +/// \param SourceToDest A vector, indexed by the TypeIndex in the source +/// id stream, that contains the index of the corresponding id record +/// in the destination stream. +/// +/// \param Handler (optional) If non-null, an interface that gets invoked +/// to handle type server records. +/// +/// \param IdsAndTypes The collection of id records to merge in. +/// +/// \returns Error::success() if the operation succeeded, otherwise an +/// appropriate error code. +Error mergeTypeAndIdRecords(TypeTableBuilder &DestIds, + TypeTableBuilder &DestTypes, + SmallVectorImpl &SourceToDest, + TypeServerHandler *Handler, + TypeCollection &IdsAndTypes); } // end namespace codeview } // end namespace llvm diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h index c5549983ed43..17fba9991c2e 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h @@ -21,6 +21,9 @@ #include "llvm/Support/Error.h" namespace llvm { +namespace codeview { +class LazyRandomTypeCollection; +} namespace msf { class MappedBlockStream; } @@ -53,12 +56,16 @@ public: codeview::CVTypeRange types(bool *HadError) const; const codeview::CVTypeArray &typeArray() const { return TypeRecords; } + codeview::LazyRandomTypeCollection &typeCollection() { return *Types; } + Error commit(); private: const PDBFile &Pdb; std::unique_ptr Stream; + std::unique_ptr Types; + codeview::CVTypeArray TypeRecords; std::unique_ptr HashStream; diff --git a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp index 46747f8eab99..c3f8973abb8d 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -57,13 +57,11 @@ namespace { /// looking at the record kind. class TypeStreamMerger : public TypeVisitorCallbacks { public: - TypeStreamMerger(TypeTableBuilder &DestIdStream, - TypeTableBuilder &DestTypeStream, - SmallVectorImpl &SourceToDest, - TypeServerHandler *Handler) - : DestIdStream(DestIdStream), DestTypeStream(DestTypeStream), - FieldListBuilder(DestTypeStream), Handler(Handler), - IndexMap(SourceToDest) {} + explicit TypeStreamMerger(SmallVectorImpl &SourceToDest, + TypeServerHandler *Handler) + : Handler(Handler), IndexMap(SourceToDest) { + SourceToDest.clear(); + } static const TypeIndex Untranslated; @@ -82,12 +80,22 @@ public: Error visitTypeEnd(CVType &Record) override; Error visitMemberEnd(CVMemberRecord &Record) override; - Error mergeStream(const CVTypeArray &Types); + Error mergeTypesAndIds(TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes, + TypeCollection &IdsAndTypes); + Error mergeIdRecords(TypeTableBuilder &Dest, + ArrayRef TypeSourceToDest, + TypeCollection &Ids); + Error mergeTypeRecords(TypeTableBuilder &Dest, TypeCollection &Types); private: + Error doit(TypeCollection &Types); + void addMapping(TypeIndex Idx); - bool remapIndex(TypeIndex &Idx); + bool remapTypeIndex(TypeIndex &Idx); + bool remapItemIndex(TypeIndex &Idx); + + bool remapIndex(TypeIndex &Idx, ArrayRef Map); size_t slotForIndex(TypeIndex Idx) const { assert(!Idx.isSimple() && "simple type indices have no slots"); @@ -102,7 +110,7 @@ private: Error writeRecord(RecordType &R, bool RemapSuccess) { TypeIndex DestIdx = Untranslated; if (RemapSuccess) - DestIdx = DestTypeStream.writeKnownType(R); + DestIdx = DestTypeStream->writeKnownType(R); addMapping(DestIdx); return Error::success(); } @@ -111,7 +119,7 @@ private: Error writeIdRecord(RecordType &R, bool RemapSuccess) { TypeIndex DestIdx = Untranslated; if (RemapSuccess) - DestIdx = DestIdStream.writeKnownType(R); + DestIdx = DestIdStream->writeKnownType(R); addMapping(DestIdx); return Error::success(); } @@ -119,7 +127,7 @@ private: template Error writeMember(RecordType &R, bool RemapSuccess) { if (RemapSuccess) - FieldListBuilder.writeMemberType(R); + FieldListBuilder->writeMemberType(R); else HadUntranslatedMember = true; return Error::success(); @@ -135,13 +143,17 @@ private: BumpPtrAllocator Allocator; - TypeTableBuilder &DestIdStream; - TypeTableBuilder &DestTypeStream; - FieldListRecordBuilder FieldListBuilder; - TypeServerHandler *Handler; - TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex}; + TypeTableBuilder *DestIdStream = nullptr; + TypeTableBuilder *DestTypeStream = nullptr; + std::unique_ptr FieldListBuilder; + TypeServerHandler *Handler = nullptr; + + // If we're only mapping id records, this array contains the mapping for + // type records. + ArrayRef TypeLookup; + /// Map from source type index to destination type index. Indexed by source /// type index minus 0x1000. SmallVectorImpl &IndexMap; @@ -178,7 +190,7 @@ void TypeStreamMerger::addMapping(TypeIndex Idx) { } } -bool TypeStreamMerger::remapIndex(TypeIndex &Idx) { +bool TypeStreamMerger::remapIndex(TypeIndex &Idx, ArrayRef Map) { // Simple types are unchanged. if (Idx.isSimple()) return true; @@ -187,14 +199,14 @@ bool TypeStreamMerger::remapIndex(TypeIndex &Idx) { // successfully. If it refers to a type later in the stream or a record we // had to defer, defer it until later pass. unsigned MapPos = slotForIndex(Idx); - if (MapPos < IndexMap.size() && IndexMap[MapPos] != Untranslated) { - Idx = IndexMap[MapPos]; + if (MapPos < Map.size() && Map[MapPos] != Untranslated) { + Idx = Map[MapPos]; return true; } // If this is the second pass and this index isn't in the map, then it points // outside the current type stream, and this is a corrupt record. - if (IsSecondPass && MapPos >= IndexMap.size()) { + if (IsSecondPass && MapPos >= Map.size()) { // FIXME: Print a more useful error. We can give the current record and the // index that we think its pointing to. LastError = joinErrors(std::move(*LastError), errorCorruptRecord()); @@ -208,55 +220,82 @@ bool TypeStreamMerger::remapIndex(TypeIndex &Idx) { return false; } +bool TypeStreamMerger::remapTypeIndex(TypeIndex &Idx) { + // If we're mapping a pure index stream, then IndexMap only contains mappings + // from OldIdStream -> NewIdStream, in which case we will need to use the + // special mapping from OldTypeStream -> NewTypeStream which was computed + // externally. Regardless, we use this special map if and only if we are + // doing an id-only mapping. + if (DestTypeStream == nullptr) + return remapIndex(Idx, TypeLookup); + + assert(TypeLookup.empty()); + return remapIndex(Idx, IndexMap); +} + +bool TypeStreamMerger::remapItemIndex(TypeIndex &Idx) { + assert(DestIdStream); + return remapIndex(Idx, IndexMap); +} + //----------------------------------------------------------------------------// // Item records //----------------------------------------------------------------------------// Error TypeStreamMerger::visitKnownRecord(CVType &, FuncIdRecord &R) { + assert(DestIdStream); bool Success = true; - Success &= remapIndex(R.ParentScope); - Success &= remapIndex(R.FunctionType); + Success &= remapItemIndex(R.ParentScope); + Success &= remapTypeIndex(R.FunctionType); return writeIdRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFuncIdRecord &R) { + assert(DestIdStream); bool Success = true; - Success &= remapIndex(R.ClassType); - Success &= remapIndex(R.FunctionType); + Success &= remapTypeIndex(R.ClassType); + Success &= remapTypeIndex(R.FunctionType); return writeIdRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, StringIdRecord &R) { - return writeIdRecord(R, remapIndex(R.Id)); + assert(DestIdStream); + return writeIdRecord(R, remapItemIndex(R.Id)); } Error TypeStreamMerger::visitKnownRecord(CVType &, StringListRecord &R) { + assert(DestIdStream); bool Success = true; for (TypeIndex &Str : R.StringIndices) - Success &= remapIndex(Str); + Success &= remapItemIndex(Str); return writeIdRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, BuildInfoRecord &R) { + assert(DestIdStream); bool Success = true; for (TypeIndex &Arg : R.ArgIndices) - Success &= remapIndex(Arg); + Success &= remapItemIndex(Arg); return writeIdRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, UdtSourceLineRecord &R) { + assert(DestIdStream); bool Success = true; - Success &= remapIndex(R.UDT); - Success &= remapIndex(R.SourceFile); + Success &= remapTypeIndex(R.UDT); + Success &= remapItemIndex(R.SourceFile); // FIXME: Translate UdtSourceLineRecord into UdtModSourceLineRecords in the // IPI stream. return writeIdRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, UdtModSourceLineRecord &R) { + assert(DestIdStream); bool Success = true; - Success &= remapIndex(R.UDT); - Success &= remapIndex(R.SourceFile); + Success &= remapTypeIndex(R.UDT); + // UdtModSourceLine Source File Ids are offsets into the global string table. + // FIXME: We need to merge string table records for this to be valid. + // Success &= remapItemIndex(R.SourceFile); return writeIdRecord(R, Success); } @@ -265,112 +304,128 @@ Error TypeStreamMerger::visitKnownRecord(CVType &, UdtModSourceLineRecord &R) { //----------------------------------------------------------------------------// Error TypeStreamMerger::visitKnownRecord(CVType &, ModifierRecord &R) { - return writeRecord(R, remapIndex(R.ModifiedType)); + assert(DestTypeStream); + return writeRecord(R, remapTypeIndex(R.ModifiedType)); } Error TypeStreamMerger::visitKnownRecord(CVType &, ProcedureRecord &R) { + assert(DestTypeStream); bool Success = true; - Success &= remapIndex(R.ReturnType); - Success &= remapIndex(R.ArgumentList); + Success &= remapTypeIndex(R.ReturnType); + Success &= remapTypeIndex(R.ArgumentList); return writeRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFunctionRecord &R) { + assert(DestTypeStream); bool Success = true; - Success &= remapIndex(R.ReturnType); - Success &= remapIndex(R.ClassType); - Success &= remapIndex(R.ThisType); - Success &= remapIndex(R.ArgumentList); + Success &= remapTypeIndex(R.ReturnType); + Success &= remapTypeIndex(R.ClassType); + Success &= remapTypeIndex(R.ThisType); + Success &= remapTypeIndex(R.ArgumentList); return writeRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &Type, ArgListRecord &R) { + assert(DestTypeStream); bool Success = true; for (TypeIndex &Arg : R.ArgIndices) - Success &= remapIndex(Arg); + Success &= remapTypeIndex(Arg); if (auto EC = writeRecord(R, Success)) return EC; return Error::success(); } Error TypeStreamMerger::visitKnownRecord(CVType &, PointerRecord &R) { + assert(DestTypeStream); bool Success = true; - Success &= remapIndex(R.ReferentType); + Success &= remapTypeIndex(R.ReferentType); if (R.isPointerToMember()) - Success &= remapIndex(R.MemberInfo->ContainingType); + Success &= remapTypeIndex(R.MemberInfo->ContainingType); return writeRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, ArrayRecord &R) { + assert(DestTypeStream); bool Success = true; - Success &= remapIndex(R.ElementType); - Success &= remapIndex(R.IndexType); + Success &= remapTypeIndex(R.ElementType); + Success &= remapTypeIndex(R.IndexType); return writeRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, ClassRecord &R) { + assert(DestTypeStream); bool Success = true; - Success &= remapIndex(R.FieldList); - Success &= remapIndex(R.DerivationList); - Success &= remapIndex(R.VTableShape); + Success &= remapTypeIndex(R.FieldList); + Success &= remapTypeIndex(R.DerivationList); + Success &= remapTypeIndex(R.VTableShape); return writeRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, UnionRecord &R) { - return writeRecord(R, remapIndex(R.FieldList)); + assert(DestTypeStream); + return writeRecord(R, remapTypeIndex(R.FieldList)); } Error TypeStreamMerger::visitKnownRecord(CVType &, EnumRecord &R) { + assert(DestTypeStream); bool Success = true; - Success &= remapIndex(R.FieldList); - Success &= remapIndex(R.UnderlyingType); + Success &= remapTypeIndex(R.FieldList); + Success &= remapTypeIndex(R.UnderlyingType); return writeRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, BitFieldRecord &R) { - return writeRecord(R, remapIndex(R.Type)); + assert(DestTypeStream); + return writeRecord(R, remapTypeIndex(R.Type)); } Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableShapeRecord &R) { + assert(DestTypeStream); return writeRecord(R, true); } Error TypeStreamMerger::visitKnownRecord(CVType &, TypeServer2Record &R) { + assert(DestTypeStream); return writeRecord(R, true); } Error TypeStreamMerger::visitKnownRecord(CVType &, LabelRecord &R) { + assert(DestTypeStream); return writeRecord(R, true); } Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableRecord &R) { + assert(DestTypeStream); bool Success = true; - Success &= remapIndex(R.CompleteClass); - Success &= remapIndex(R.OverriddenVFTable); + Success &= remapTypeIndex(R.CompleteClass); + Success &= remapTypeIndex(R.OverriddenVFTable); return writeRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, MethodOverloadListRecord &R) { + assert(DestTypeStream); bool Success = true; for (OneMethodRecord &Meth : R.Methods) - Success &= remapIndex(Meth.Type); + Success &= remapTypeIndex(Meth.Type); return writeRecord(R, Success); } Error TypeStreamMerger::visitKnownRecord(CVType &, FieldListRecord &R) { + assert(DestTypeStream); // Visit the members inside the field list. HadUntranslatedMember = false; - FieldListBuilder.begin(); + FieldListBuilder->begin(); if (auto EC = codeview::visitMemberRecordStream(R.Data, *this)) return EC; // Write the record if we translated all field list members. TypeIndex DestIdx = Untranslated; if (!HadUntranslatedMember) - DestIdx = FieldListBuilder.end(); + DestIdx = FieldListBuilder->end(); else - FieldListBuilder.reset(); + FieldListBuilder->reset(); addMapping(DestIdx); return Error::success(); @@ -382,28 +437,28 @@ Error TypeStreamMerger::visitKnownRecord(CVType &, FieldListRecord &R) { Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, NestedTypeRecord &R) { - return writeMember(R, remapIndex(R.Type)); + return writeMember(R, remapTypeIndex(R.Type)); } Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, OneMethodRecord &R) { bool Success = true; - Success &= remapIndex(R.Type); + Success &= remapTypeIndex(R.Type); return writeMember(R, Success); } Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, OverloadedMethodRecord &R) { - return writeMember(R, remapIndex(R.MethodList)); + return writeMember(R, remapTypeIndex(R.MethodList)); } Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, DataMemberRecord &R) { - return writeMember(R, remapIndex(R.Type)); + return writeMember(R, remapTypeIndex(R.Type)); } Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, StaticDataMemberRecord &R) { - return writeMember(R, remapIndex(R.Type)); + return writeMember(R, remapTypeIndex(R.Type)); } Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, @@ -412,24 +467,24 @@ Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, } Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, VFPtrRecord &R) { - return writeMember(R, remapIndex(R.Type)); + return writeMember(R, remapTypeIndex(R.Type)); } Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, BaseClassRecord &R) { - return writeMember(R, remapIndex(R.Type)); + return writeMember(R, remapTypeIndex(R.Type)); } Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, VirtualBaseClassRecord &R) { bool Success = true; - Success &= remapIndex(R.BaseType); - Success &= remapIndex(R.VBPtrType); + Success &= remapTypeIndex(R.BaseType); + Success &= remapTypeIndex(R.VBPtrType); return writeMember(R, Success); } Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, ListContinuationRecord &R) { - return writeMember(R, remapIndex(R.ContinuationIndex)); + return writeMember(R, remapTypeIndex(R.ContinuationIndex)); } Error TypeStreamMerger::visitUnknownType(CVType &Rec) { @@ -438,8 +493,34 @@ Error TypeStreamMerger::visitUnknownType(CVType &Rec) { return errorCorruptRecord(); } -Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) { - assert(IndexMap.empty()); +Error TypeStreamMerger::mergeTypeRecords(TypeTableBuilder &Dest, + TypeCollection &Types) { + DestTypeStream = &Dest; + FieldListBuilder = llvm::make_unique(Dest); + + return doit(Types); +} + +Error TypeStreamMerger::mergeIdRecords(TypeTableBuilder &Dest, + ArrayRef TypeSourceToDest, + TypeCollection &Ids) { + DestIdStream = &Dest; + TypeLookup = TypeSourceToDest; + + return doit(Ids); +} + +Error TypeStreamMerger::mergeTypesAndIds(TypeTableBuilder &DestIds, + TypeTableBuilder &DestTypes, + TypeCollection &IdsAndTypes) { + DestIdStream = &DestIds; + DestTypeStream = &DestTypes; + FieldListBuilder = llvm::make_unique(DestTypes); + + return doit(IdsAndTypes); +} + +Error TypeStreamMerger::doit(TypeCollection &Types) { LastError = Error::success(); if (auto EC = codeview::visitTypeStream(Types, *this, Handler)) @@ -469,18 +550,32 @@ Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) { } } - IndexMap.clear(); - Error Ret = std::move(*LastError); LastError.reset(); return Ret; } -Error llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestIdStream, - TypeTableBuilder &DestTypeStream, +Error llvm::codeview::mergeTypeRecords(TypeTableBuilder &Dest, SmallVectorImpl &SourceToDest, TypeServerHandler *Handler, - const CVTypeArray &Types) { - return TypeStreamMerger(DestIdStream, DestTypeStream, SourceToDest, Handler) - .mergeStream(Types); + TypeCollection &Types) { + TypeStreamMerger M(SourceToDest, Handler); + return M.mergeTypeRecords(Dest, Types); +} + +Error llvm::codeview::mergeIdRecords(TypeTableBuilder &Dest, + ArrayRef TypeSourceToDest, + SmallVectorImpl &SourceToDest, + TypeCollection &Ids) { + TypeStreamMerger M(SourceToDest, nullptr); + return M.mergeIdRecords(Dest, TypeSourceToDest, Ids); +} + +Error llvm::codeview::mergeTypeAndIdRecords( + TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes, + SmallVectorImpl &SourceToDest, TypeServerHandler *Handler, + TypeCollection &IdsAndTypes) { + + TypeStreamMerger M(SourceToDest, Handler); + return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes); } diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp index 8e0065873892..623afb371b50 100644 --- a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -8,7 +8,9 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Native/TpiStream.h" + #include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" @@ -104,6 +106,8 @@ Error TpiStream::reload() { HashStream = std::move(HS); } + Types = llvm::make_unique( + TypeRecords, getNumTypeRecords(), getTypeIndexOffsets()); return Error::success(); } diff --git a/llvm/test/DebugInfo/PDB/Inputs/merge-ids-1.yaml b/llvm/test/DebugInfo/PDB/Inputs/merge-ids-1.yaml new file mode 100644 index 000000000000..3b5e8b5e761a --- /dev/null +++ b/llvm/test/DebugInfo/PDB/Inputs/merge-ids-1.yaml @@ -0,0 +1,36 @@ +IpiStream: + Records: + # 'One' [TypeIndex: 0x1000 (4096)] + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'One' + # 'Two' [TypeIndex: 0x1001 (4097)] + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'Two' + # 'OnlyInFirst' [TypeIndex: 0x1002 (4098)] + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'OnlyInFirst' + # 'SubOne' [TypeIndex: 0x1003 (4099)] + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'SubOne' + # 'SubTwo' [TypeIndex: 0x1004 (4100)] + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'SubTwo' + # 'SubOne', 'SubTwo' [TypeIndex: 0x1005 (4101)] + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4099, 4100 ] + # 'Main' {'SubOne', 'SubTwo'} [TypeIndex: 0x1006 (4102)] + - Kind: LF_STRING_ID + StringId: + Id: 4101 + String: 'Main' diff --git a/llvm/test/DebugInfo/PDB/Inputs/merge-ids-2.yaml b/llvm/test/DebugInfo/PDB/Inputs/merge-ids-2.yaml new file mode 100644 index 000000000000..74f6ee502249 --- /dev/null +++ b/llvm/test/DebugInfo/PDB/Inputs/merge-ids-2.yaml @@ -0,0 +1,31 @@ +IpiStream: + Records: + # 'SubTwo' [TypeIndex: 0x1000 (4096)] + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'SubTwo' + # 'OnlyInSecond' [TypeIndex: 0x1001 (4097)] + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'OnlyInSecond' + # 'SubOne' [TypeIndex: 0x1002 (4098)] + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'SubOne' + # 'SubOne', 'SubTwo' [TypeIndex: 0x1003 (4099)] + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4098, 4096 ] + # 'One' [TypeIndex: 0x1004 (4100)] + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'One' + # 'Main' {'SubOne', 'SubTwo'} [TypeIndex: 0x1005 (4101)] + - Kind: LF_STRING_ID + StringId: + Id: 4099 + String: 'Main' diff --git a/llvm/test/DebugInfo/PDB/Inputs/merge-ids-and-types-1.yaml b/llvm/test/DebugInfo/PDB/Inputs/merge-ids-and-types-1.yaml new file mode 100644 index 000000000000..30ff563d7fc6 --- /dev/null +++ b/llvm/test/DebugInfo/PDB/Inputs/merge-ids-and-types-1.yaml @@ -0,0 +1,113 @@ +# The idea is to set up some types in the TPI stream, and then have records in +# the IPI stream that refer to them. There are three types of IPI records that +# can refer to TPI records. They are: +# 1) LF_PROCEDURE - Referred to by LF_FUNC_ID +# 2) LF_STRUCTURE - Referred to by LF_UDT_MOD_SRC_LINE +# Referred to by LF_UDT_SRC_LINE +# 3) LF_MFUNCTION - Referred to by LF_MFUNC_ID +# We will set up one of each of these, and then create IPI records that refer to +# them. We intentionally choose an unintuitive ordering of the records in both +# streams (while still maintaining the topological sorting required by CodeView +# type streams), to make sure the merging algorithm is sufficiently exercised. +# For easy understanding, a semantic representation of the types we will set up +# is as follows: +# - int main(int, char**) +# +# - struct FooBar { +# public: +# void *FooMember; +# void FooMethod(int); +# }; +TpiStream: + Records: + # TypeIndex: 4096 (0x1000) + # char** + - Kind: LF_POINTER + Pointer: + ReferentType: 1136 + Attrs: 32778 + # TypeIndex: 4097 (0x1001) + # public void *FooMember + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_MEMBER + DataMember: + Attrs: 3 # public + Type: 1027 # void* + FieldOffset: 0 + Name: FooMember # FooMember + # TypeIndex: 4098 (0x1002) + # (int, char**) + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116, 4096 ] + # TypeIndex: 4099 (0x1003) + # struct FooBar { + # public: + # void *FooMember; + # }; + - Kind: LF_STRUCTURE + Class: + MemberCount: 1 + Options: [ None, HasUniqueName ] + FieldList: 4097 + Name: FooBar + UniqueName: 'FooBar' + DerivationList: 0 + VTableShape: 0 + Size: 4 + # TypeIndex: 4100 (0x1004) + # FooBar * + - Kind: LF_POINTER + Pointer: + ReferentType: 4099 # FooBar + Attrs: 32778 + # TypeIndex: 4101 (0x1005) + # (int) + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116 ] + # TypeIndex: 4102 (0x1006) + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 # void + ClassType: 4099 # struct FooBar + ThisType: 4100 # FooBar * + CallConv: ThisCall + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4101 # (int) + ThisPointerAdjustment: 0 + # TypeIndex: 4103 (0x1007) + # int (int, char**) + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 # int + CallConv: NearC + Options: [ None ] + ParameterCount: 2 + ArgumentList: 4098 # (int, char**) +IpiStream: + Records: + # TypeIndex: 4096 (0x1000) + # int main(int, char **) + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4103 # int main(int, char**) + Name: main + # TypeIndex: 4097 (0x1001) + # void FooBar::FooMethod(int) + - Kind: LF_MFUNC_ID + MemberFuncId: + ClassType: 4099 # struct FooBar + FunctionType: 4102 # void FooMethod(int) + Name: FooMethod + # TypeIndex: 4098 (0x1002) + # struct FooBar + - Kind: LF_UDT_MOD_SRC_LINE + UdtModSourceLine: + UDT: 4099 # struct FooBar + SourceFile: 0 # We don't support this yet + LineNumber: 0 + Module: 0 # We don't support this yet diff --git a/llvm/test/DebugInfo/PDB/Inputs/merge-ids-and-types-2.yaml b/llvm/test/DebugInfo/PDB/Inputs/merge-ids-and-types-2.yaml new file mode 100644 index 000000000000..1bd54deebffd --- /dev/null +++ b/llvm/test/DebugInfo/PDB/Inputs/merge-ids-and-types-2.yaml @@ -0,0 +1,143 @@ +# In file 1 we set up some basic types and IDs to refer to them. In this file +# we will set up the same types. For some of them we will make them identical +# but re-order the records in the file to make sure they have different type +# indices and appear in different orders. In other cases we will make slight +# adjustments to the types, to ensure that they do not get merged in. +# +# For easy understanding, a semantic representation of the types we will set up +# is as follows: +# - int main(int, char**) // This record should share an LF_PROCEDURE and id +# // record with corresponding function from the +# // first file. +# - int main2(int, char**) // This record should share the LF_PROCEDURE +# // record but have a unique id record. +# - void foo(int, char**) // This record should have a unique LF_PROCEDURE +# // record, but the LF_ARGLIST record internally +# // should be shared. +# +# - struct FooBar { // Because the type of this record exactly matches +# // the corresponding file, its entire type record +# // hierarchy should be shared. +# public: +# void *FooMember; +# void FooMethod2(int); // Note that the *type* of this member should be +# // the same as the type of the record from the +# // first stream. But since it has a different +# // name, it will not share an id record. +# }; +TpiStream: + Records: + # TypeIndex: 4096 (0x1000) + # (int) + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116 ] + # TypeIndex: 4097 (0x1001) + # public void *FooMember + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_MEMBER + DataMember: + Attrs: 3 # public + Type: 1027 # void* + FieldOffset: 0 + Name: FooMember # FooMember + # TypeIndex: 4098 (0x1002) + # char** + - Kind: LF_POINTER + Pointer: + ReferentType: 1136 + Attrs: 32778 + # TypeIndex: 4099 (0x1003) + # (int, char**) + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116, 4098 ] + # TypeIndex: 4100 (0x1004) + # struct FooBar { + # public: + # void *FooMember; + # }; + - Kind: LF_STRUCTURE + Class: + MemberCount: 1 + Options: [ None, HasUniqueName ] + FieldList: 4097 + Name: FooBar + UniqueName: 'FooBar' + DerivationList: 0 + VTableShape: 0 + Size: 4 + # TypeIndex: 4101 (0x1005) + # void (int, char**) + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 # void + CallConv: NearC + Options: [ None ] + ParameterCount: 2 + ArgumentList: 4099 # (int, char**) + # TypeIndex: 4102 (0x1006) + # FooBar * + - Kind: LF_POINTER + Pointer: + ReferentType: 4100 # FooBar + Attrs: 32778 + # TypeIndex: 4103 (0x1007) + # int (int, char**) + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 # int + CallConv: NearC + Options: [ None ] + ParameterCount: 2 + ArgumentList: 4099 # (int, char**) + # TypeIndex: 4104 (0x1008) + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 # void + ClassType: 4100 # struct FooBar + ThisType: 4102 # FooBar * + CallConv: ThisCall + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4096 # (int) + ThisPointerAdjustment: 0 +IpiStream: + Records: + # TypeIndex: 4096 (0x1000) + # struct FooBar + - Kind: LF_UDT_MOD_SRC_LINE + UdtModSourceLine: + UDT: 4100 # struct FooBar + SourceFile: 0 # We don't support this yet + LineNumber: 0 + Module: 0 # We don't support this yet + # TypeIndex: 4097 (0x1001) + # int main2(int, char **) + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4103 # int main2(int, char**) + Name: main2 + # TypeIndex: 4098 (0x1002) + # void foo(int, char **) + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4101 # void main2(int, char**) + Name: foo + # TypeIndex: 4099 (0x1003) + # void FooBar::FooMethod2(int) + - Kind: LF_MFUNC_ID + MemberFuncId: + ClassType: 4100 # struct FooBar + FunctionType: 4104 # void FooBar::FooMethod2(int) + Name: FooMethod2 + # TypeIndex: 4100 (0x1004) + # int main(int, char **) + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4103 # int main(int, char**) + Name: main diff --git a/llvm/test/DebugInfo/PDB/Inputs/merge1.yaml b/llvm/test/DebugInfo/PDB/Inputs/merge-types-1.yaml similarity index 100% rename from llvm/test/DebugInfo/PDB/Inputs/merge1.yaml rename to llvm/test/DebugInfo/PDB/Inputs/merge-types-1.yaml diff --git a/llvm/test/DebugInfo/PDB/Inputs/merge2.yaml b/llvm/test/DebugInfo/PDB/Inputs/merge-types-2.yaml similarity index 100% rename from llvm/test/DebugInfo/PDB/Inputs/merge2.yaml rename to llvm/test/DebugInfo/PDB/Inputs/merge-types-2.yaml diff --git a/llvm/test/DebugInfo/PDB/pdbdump-merge-ids-and-types.test b/llvm/test/DebugInfo/PDB/pdbdump-merge-ids-and-types.test new file mode 100644 index 000000000000..ac32ce040b98 --- /dev/null +++ b/llvm/test/DebugInfo/PDB/pdbdump-merge-ids-and-types.test @@ -0,0 +1,65 @@ +; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-and-types-1.yaml +; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-and-types-2.yaml +; RUN: llvm-pdbdump merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb +; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-TYPES %s +; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=INTMAIN %s +; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=VOIDMAIN %s +; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-TYPES %s +; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-NAMES %s +; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-UDT %s + +TPI-TYPES: Type Info Stream (TPI) +TPI-TYPES: Record count: 9 +TPI-TYPES-DAG: TypeLeafKind: LF_POINTER +TPI-TYPES-DAG: TypeLeafKind: LF_FIELDLIST +TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST +TPI-TYPES-DAG: TypeLeafKind: LF_STRUCTURE +TPI-TYPES-DAG: TypeLeafKind: LF_MEMBER +TPI-TYPES-DAG: TypeLeafKind: LF_POINTER +TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST +TPI-TYPES-DAG: TypeLeafKind: LF_MFUNCTION +TPI-TYPES-DAG: TypeLeafKind: LF_PROCEDURE +TPI-TYPES-DAG: TypeLeafKind: LF_PROCEDURE +TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST + +; Both procedures should use the same arglist even though they have a different +; return type. +INTMAIN: ArgList ([[ID:.*]]) +INTMAIN-NEXT: TypeLeafKind: LF_ARGLIST +INTMAIN-NEXT: NumArgs: 2 +INTMAIN-NEXT: Arguments [ +INTMAIN-NEXT: ArgType: int +INTMAIN-NEXT: ArgType: char** +INTMAIN: TypeLeafKind: LF_PROCEDURE +INTMAIN: ReturnType: int +INTMAIN: NumParameters: 2 +INTMAIN-NEXT: ArgListType: (int, char**) ([[ID]]) + +VOIDMAIN: ArgList ([[ID:.*]]) +VOIDMAIN-NEXT: TypeLeafKind: LF_ARGLIST +VOIDMAIN-NEXT: NumArgs: 2 +VOIDMAIN-NEXT: Arguments [ +VOIDMAIN-NEXT: ArgType: int +VOIDMAIN-NEXT: ArgType: char** +VOIDMAIN: TypeLeafKind: LF_PROCEDURE +VOIDMAIN: ReturnType: void +VOIDMAIN: NumParameters: 2 +VOIDMAIN-NEXT: ArgListType: (int, char**) ([[ID]]) + +IPI-TYPES: Type Info Stream (IPI) +IPI-TYPES: Record count: 6 +IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID +IPI-TYPES-DAG: TypeLeafKind: LF_MFUNC_ID +IPI-TYPES-DAG: TypeLeafKind: LF_UDT_MOD_SRC_LINE +IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID +IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID +IPI-TYPES-DAG: TypeLeafKind: LF_MFUNC_ID + +IPI-NAMES-DAG: Name: main +IPI-NAMES-DAG: Name: FooMethod +IPI-NAMES-DAG: Name: main2 +IPI-NAMES-DAG: Name: foo +IPI-NAMES-DAG: Name: FooMethod2 + +IPI-UDT: TypeLeafKind: LF_UDT_MOD_SRC_LINE +IPI-UDT-NEXT: UDT: FooBar diff --git a/llvm/test/DebugInfo/PDB/pdbdump-mergeids.test b/llvm/test/DebugInfo/PDB/pdbdump-mergeids.test new file mode 100644 index 000000000000..6a4d19eba042 --- /dev/null +++ b/llvm/test/DebugInfo/PDB/pdbdump-mergeids.test @@ -0,0 +1,31 @@ +; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-1.yaml +; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-2.yaml +; RUN: llvm-pdbdump merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb +; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s +; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=SUBSTRS %s +; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-EMPTY %s + + +MERGED: Type Info Stream (IPI) +MERGED: Record count: 8 +MERGED-DAG: StringData: One +MERGED-DAG: StringData: Two +MERGED-DAG: StringData: SubOne +MERGED-DAG: StringData: SubTwo +MERGED-DAG: StringData: Main +MERGED-DAG: TypeLeafKind: LF_SUBSTR_LIST +MERGED-DAG: StringData: OnlyInFirst +MERGED-DAG: StringData: OnlyInSecond + +SUBSTRS: StringList +SUBSTRS: TypeLeafKind: LF_SUBSTR_LIST +SUBSTRS-NEXT: NumStrings: 2 +SUBSTRS-NEXT: Strings [ +SUBSTRS-NEXT: SubOne +SUBSTRS-NEXT: SubTwo +SUBSTRS: StringId +SUBSTRS-NEXT: TypeLeafKind: LF_STRING_ID +SUBSTRS-NEXT: Id: "SubOne" "SubTwo" +SUBSTRS-NEXT: StringData: Main + +TPI-EMPTY: Record count: 0 diff --git a/llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test b/llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test index 96f6316d4766..a26b92631828 100644 --- a/llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test +++ b/llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test @@ -1,5 +1,5 @@ -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge1.yaml -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge2.yaml +; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-types-1.yaml +; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-types-2.yaml ; RUN: llvm-pdbdump merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb ; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s ; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=ARGLIST %s diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp index 50ee5f4d0ac9..3394d3268dd5 100644 --- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -500,6 +500,7 @@ static void yamlToPdb(StringRef Path) { pdb::yaml::PdbInfoStream DefaultInfoStream; pdb::yaml::PdbDbiStream DefaultDbiStream; pdb::yaml::PdbTpiStream DefaultTpiStream; + pdb::yaml::PdbTpiStream DefaultIpiStream; const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream); @@ -601,11 +602,11 @@ static void yamlToPdb(StringRef Path) { for (const auto &R : Tpi.Records) TpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash); - const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultTpiStream); + const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultIpiStream); auto &IpiBuilder = Builder.getIpiBuilder(); IpiBuilder.setVersionHeader(Ipi.Version); for (const auto &R : Ipi.Records) - TpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash); + IpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash); ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile)); } @@ -852,18 +853,17 @@ static void mergePdbs() { for (const auto &Path : opts::merge::InputFilenames) { std::unique_ptr Session; auto &File = loadPDB(Path, Session); - SmallVector SourceToDest; + SmallVector TypeMap; + SmallVector IdMap; if (File.hasPDBTpiStream()) { - SourceToDest.clear(); auto &Tpi = ExitOnErr(File.getPDBTpiStream()); - ExitOnErr(codeview::mergeTypeStreams(MergedIpi, MergedTpi, SourceToDest, - nullptr, Tpi.typeArray())); + ExitOnErr(codeview::mergeTypeRecords(MergedTpi, TypeMap, nullptr, + Tpi.typeCollection())); } if (File.hasPDBIpiStream()) { - SourceToDest.clear(); auto &Ipi = ExitOnErr(File.getPDBIpiStream()); - ExitOnErr(codeview::mergeTypeStreams(MergedIpi, MergedTpi, SourceToDest, - nullptr, Ipi.typeArray())); + ExitOnErr(codeview::mergeIdRecords(MergedIpi, TypeMap, IdMap, + Ipi.typeCollection())); } } diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp index 78bfa558e4a3..96adf49ed690 100644 --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -1072,9 +1072,10 @@ void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVIDs, W.flush(); error(object_error::parse_failed); } + LazyRandomTypeCollection TypesAndIds(Types, 100); SmallVector SourceToDest; - if (auto EC = - mergeTypeStreams(CVIDs, CVTypes, SourceToDest, nullptr, Types)) + if (auto EC = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, nullptr, + TypesAndIds)) return error(std::move(EC)); } }