Index: lld/COFF/PDB.cpp =================================================================== --- lld/COFF/PDB.cpp +++ lld/COFF/PDB.cpp @@ -14,7 +14,8 @@ #include "SymbolTable.h" #include "Symbols.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" @@ -133,12 +134,11 @@ if (Data.empty()) return; - TypeDatabase TDB(0); - TypeDumpVisitor TDV(TDB, &W, false); + LazyRandomTypeCollection Types(Data, 100); + TypeDumpVisitor TDV(Types, &W, false); // Use a default implementation that does not follow type servers and instead // just dumps the contents of the TypeServer2 record. - CVTypeDumper TypeDumper(TDB); - if (auto EC = TypeDumper.dump(Data, TDV)) + if (auto EC = codeview::visitTypeStream(Types, TDV)) fatal(EC, "CVTypeDumper::dump failed"); } Index: llvm/include/llvm/DebugInfo/CodeView/CVRecord.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/CVRecord.h +++ llvm/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -32,6 +32,10 @@ uint32_t length() const { return RecordData.size(); } Kind kind() const { return Type; } ArrayRef data() const { return RecordData; } + StringRef str_data() const { + return StringRef(reinterpret_cast(RecordData.data()), + RecordData.size()); + } ArrayRef content() const { return RecordData.drop_front(sizeof(RecordPrefix)); Index: llvm/include/llvm/DebugInfo/CodeView/CVTypeDumper.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/CVTypeDumper.h +++ /dev/null @@ -1,61 +0,0 @@ -//===-- CVTypeDumper.h - CodeView type info dumper --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEDUMPER_H -#define LLVM_DEBUGINFO_CODEVIEW_CVTYPEDUMPER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/Support/ScopedPrinter.h" - -namespace llvm { - -namespace codeview { - -class TypeServerHandler; - -/// Dumper for CodeView type streams found in COFF object files and PDB files. -class CVTypeDumper { -public: - explicit CVTypeDumper(TypeDatabase &TypeDB, - TypeServerHandler *Handler = nullptr) - : TypeDB(TypeDB), Handler(Handler) {} - - /// Dumps one type record. Returns false if there was a type parsing error, - /// and true otherwise. This should be called in order, since the dumper - /// maintains state about previous records which are necessary for cross - /// type references. - Error dump(const CVType &Record, TypeVisitorCallbacks &Dumper); - - /// Dumps the type records in Types. Returns false if there was a type stream - /// parse error, and true otherwise. - Error dump(const CVTypeArray &Types, TypeVisitorCallbacks &Dumper); - - /// Dumps the type records in Data. Returns false if there was a type stream - /// parse error, and true otherwise. Use this method instead of the - /// CVTypeArray overload when type records are laid out contiguously in - /// memory. - Error dump(ArrayRef Data, TypeVisitorCallbacks &Dumper); - - static void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, - TypeIndex TI, TypeDatabase &DB); - -private: - TypeDatabase &TypeDB; - TypeServerHandler *Handler; -}; - -} // end namespace codeview -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H Index: llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -10,42 +10,15 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H #define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H -#include "llvm/ADT/TinyPtrVector.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeServerHandler.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" #include "llvm/Support/Error.h" namespace llvm { namespace codeview { - -class CVTypeVisitor { -public: - explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks); - - void addTypeServerHandler(TypeServerHandler &Handler); - - Error visitTypeRecord(CVType &Record, TypeIndex Index); - Error visitTypeRecord(CVType &Record); - Error visitMemberRecord(CVMemberRecord Record); - - /// Visits the type records in Data. Sets the error flag on parse failures. - Error visitTypeStream(const CVTypeArray &Types); - Error visitTypeStream(CVTypeRange Types); - - Error visitFieldListMemberStream(ArrayRef FieldList); - Error visitFieldListMemberStream(BinaryStreamReader Reader); - -private: - Expected handleTypeServer(CVType &Record); - Error finishVisitation(CVType &Record); - - /// The interface to the class that gets notified of each visitation. - TypeVisitorCallbacks &Callbacks; - - TinyPtrVector Handlers; -}; +class TypeCollection; +class TypeServerHandler; +class TypeVisitorCallbacks; enum VisitorDataSource { VDS_BytesPresent, // The record bytes are passed into the the visitation @@ -76,6 +49,8 @@ TypeServerHandler *TS = nullptr); Error visitTypeStream(CVTypeRange Types, TypeVisitorCallbacks &Callbacks, TypeServerHandler *TS = nullptr); +Error visitTypeStream(TypeCollection &Types, TypeVisitorCallbacks &Callbacks, + TypeServerHandler *TS = nullptr); } // end namespace codeview } // end namespace llvm Index: llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h @@ -0,0 +1,103 @@ +//===- LazyRandomTypeCollection.h ---------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H +#define LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H + +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { + +class TypeDatabase; +class TypeVisitorCallbacks; + +/// \brief Provides amortized O(1) random access to a CodeView type stream. +/// Normally to access a type from a type stream, you must know its byte +/// offset into the type stream, because type records are variable-lengthed. +/// However, this is not the way we prefer to access them. For example, given +/// a symbol record one of the fields may be the TypeIndex of the symbol's +/// type record. Or given a type record such as an array type, there might +/// be a TypeIndex for the element type. Sequential access is perfect when +/// we're just dumping every entry, but it's very poor for real world usage. +/// +/// Type streams in PDBs contain an additional field which is a list of pairs +/// containing indices and their corresponding offsets, roughly every ~8KB of +/// record data. This general idea need not be confined to PDBs though. By +/// supplying such an array, the producer of a type stream can allow the +/// consumer much better access time, because the consumer can find the nearest +/// index in this array, and do a linear scan forward only from there. +/// +/// LazyRandomTypeCollection implements this algorithm, but additionally goes +/// one step further by caching offsets of every record that has been visited at +/// least once. This way, even repeated visits of the same record will never +/// require more than one linear scan. For a type stream of N elements divided +/// into M chunks of roughly equal size, this yields a worst case lookup time +/// of O(N/M) and an amortized time of O(1). +class LazyRandomTypeCollection : public TypeCollection { + typedef FixedStreamArray PartialOffsetArray; + +public: + explicit LazyRandomTypeCollection(uint32_t RecordCountHint); + LazyRandomTypeCollection(StringRef Data, uint32_t RecordCountHint); + LazyRandomTypeCollection(ArrayRef Data, uint32_t RecordCountHint); + LazyRandomTypeCollection(const CVTypeArray &Types, uint32_t RecordCountHint, + PartialOffsetArray PartialOffsets); + LazyRandomTypeCollection(const CVTypeArray &Types, uint32_t RecordCountHint); + + void reset(ArrayRef Data); + void reset(StringRef Data); + + CVType getType(TypeIndex Index) override; + StringRef getTypeName(TypeIndex Index) override; + bool contains(TypeIndex Index) override; + uint32_t size() override; + uint32_t capacity() override; + TypeIndex getFirst() override; + Optional getNext(TypeIndex Prev) override; + +private: + const TypeDatabase &database() const { return Database; } + Error ensureTypeExists(TypeIndex Index); + + Error visitRangeForType(TypeIndex TI); + Error fullScanForType(TypeIndex TI); + Error visitRange(TypeIndex Begin, uint32_t BeginOffset, TypeIndex End); + Error visitOneRecord(TypeIndex TI, uint32_t Offset, CVType &Record); + + /// Visited records get automatically added to the type database. + TypeDatabase Database; + + /// The type array to allow random access visitation of. + CVTypeArray Types; + + /// The database visitor which adds new records to the database. + TypeDatabaseVisitor DatabaseVisitor; + + /// A vector mapping type indices to type offset. For every record that has + /// been visited, contains the absolute offset of that record in the record + /// array. + std::vector KnownOffsets; + + /// An array of index offsets for the given type stream, allowing log(N) + /// lookups of a type record by index. Similar to KnownOffsets but only + /// contains offsets for some type indices, some of which may not have + /// ever been visited. + PartialOffsetArray PartialOffsets; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H Index: llvm/include/llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h +++ /dev/null @@ -1,88 +0,0 @@ -//===- RandomAccessTypeVisitor.h ------------------------------ *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H -#define LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H - -#include "llvm/ADT/TinyPtrVector.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/Support/Error.h" - -namespace llvm { -namespace codeview { - -class TypeDatabase; -class TypeServerHandler; -class TypeVisitorCallbacks; - -/// \brief Provides amortized O(1) random access to a CodeView type stream. -/// Normally to access a type from a type stream, you must know its byte -/// offset into the type stream, because type records are variable-lengthed. -/// However, this is not the way we prefer to access them. For example, given -/// a symbol record one of the fields may be the TypeIndex of the symbol's -/// type record. Or given a type record such as an array type, there might -/// be a TypeIndex for the element type. Sequential access is perfect when -/// we're just dumping every entry, but it's very poor for real world usage. -/// -/// Type streams in PDBs contain an additional field which is a list of pairs -/// containing indices and their corresponding offsets, roughly every ~8KB of -/// record data. This general idea need not be confined to PDBs though. By -/// supplying such an array, the producer of a type stream can allow the -/// consumer much better access time, because the consumer can find the nearest -/// index in this array, and do a linear scan forward only from there. -/// -/// RandomAccessTypeVisitor implements this algorithm, but additionally goes one -/// step further by caching offsets of every record that has been visited at -/// least once. This way, even repeated visits of the same record will never -/// require more than one linear scan. For a type stream of N elements divided -/// into M chunks of roughly equal size, this yields a worst case lookup time -/// of O(N/M) and an amortized time of O(1). -class RandomAccessTypeVisitor { - typedef FixedStreamArray PartialOffsetArray; - -public: - RandomAccessTypeVisitor(const CVTypeArray &Types, uint32_t NumRecords, - PartialOffsetArray PartialOffsets); - - Error visitTypeIndex(TypeIndex Index, TypeVisitorCallbacks &Callbacks); - - const TypeDatabase &database() const { return Database; } - -private: - Error visitRangeForType(TypeIndex TI); - Error visitRange(TypeIndex Begin, uint32_t BeginOffset, TypeIndex End); - - /// Visited records get automatically added to the type database. - TypeDatabase Database; - - /// The type array to allow random access visitation of. - const CVTypeArray &Types; - - /// The database visitor which adds new records to the database. - TypeDatabaseVisitor DatabaseVisitor; - - /// A vector mapping type indices to type offset. For every record that has - /// been visited, contains the absolute offset of that record in the record - /// array. - std::vector KnownOffsets; - - /// An array of index offsets for the given type stream, allowing log(N) - /// lookups of a type record by index. Similar to KnownOffsets but only - /// contains offsets for some type indices, some of which may not have - /// ever been visited. - PartialOffsetArray PartialOffsets; -}; - -} // end namespace codeview -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H Index: llvm/include/llvm/DebugInfo/CodeView/SymbolDumper.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/SymbolDumper.h +++ llvm/include/llvm/DebugInfo/CodeView/SymbolDumper.h @@ -20,15 +20,15 @@ class ScopedPrinter; namespace codeview { -class TypeDatabase; +class TypeCollection; /// Dumper for CodeView symbol streams found in COFF object files and PDB files. class CVSymbolDumper { public: - CVSymbolDumper(ScopedPrinter &W, TypeDatabase &TypeDB, + CVSymbolDumper(ScopedPrinter &W, TypeCollection &Types, std::unique_ptr ObjDelegate, bool PrintRecordBytes) - : W(W), TypeDB(TypeDB), ObjDelegate(std::move(ObjDelegate)), + : W(W), Types(Types), ObjDelegate(std::move(ObjDelegate)), PrintRecordBytes(PrintRecordBytes) {} /// Dumps one type record. Returns false if there was a type parsing error, @@ -43,7 +43,7 @@ private: ScopedPrinter &W; - TypeDatabase &TypeDB; + TypeCollection &Types; std::unique_ptr ObjDelegate; bool PrintRecordBytes; Index: llvm/include/llvm/DebugInfo/CodeView/TypeCollection.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/CodeView/TypeCollection.h @@ -0,0 +1,38 @@ +//===- TypeCollection.h - A collection of CodeView type records -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPECOLLECTION_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPECOLLECTION_H + +#include "llvm/ADT/StringRef.h" + +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" + +namespace llvm { +namespace codeview { +class TypeCollection { +public: + virtual ~TypeCollection() = default; + + bool empty() { return size() == 0; } + + virtual TypeIndex getFirst() = 0; + virtual Optional getNext(TypeIndex Prev) = 0; + + virtual CVType getType(TypeIndex Index) = 0; + virtual StringRef getTypeName(TypeIndex Index) = 0; + virtual bool contains(TypeIndex Index) = 0; + virtual uint32_t size() = 0; + virtual uint32_t capacity() = 0; +}; +} +} + +#endif Index: llvm/include/llvm/DebugInfo/CodeView/TypeDatabase.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeDatabase.h +++ llvm/include/llvm/DebugInfo/CodeView/TypeDatabase.h @@ -13,6 +13,7 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/TypeCollection.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/Support/Allocator.h" @@ -20,7 +21,7 @@ namespace llvm { namespace codeview { -class TypeDatabase { +class TypeDatabase : public TypeCollection { friend class RandomAccessTypeVisitor; public: @@ -41,19 +42,31 @@ CVType &getTypeRecord(TypeIndex Index); bool contains(TypeIndex Index) const; - uint32_t size() const; uint32_t capacity() const; bool empty() const; - TypeIndex getAppendIndex() const; + CVType getType(TypeIndex Index) override; + StringRef getTypeName(TypeIndex Index) override; + bool contains(TypeIndex Index) override; + uint32_t size() override; + uint32_t capacity() override; + + TypeIndex getFirst() override; + Optional getNext(TypeIndex Prev) override; + + Optional largestTypeIndexLessThan(TypeIndex TI) const; private: + TypeIndex getAppendIndex() const; + void grow(); + void grow(TypeIndex Index); BumpPtrAllocator Allocator; uint32_t Count = 0; + TypeIndex LargestTypeIndex; /// All user defined type records in .debug$T live in here. Type indices /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to Index: llvm/include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h +++ llvm/include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h @@ -12,7 +12,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringSet.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" @@ -22,17 +21,20 @@ namespace codeview { +class TypeCollection; + /// Dumper for CodeView type streams found in COFF object files and PDB files. class TypeDumpVisitor : public TypeVisitorCallbacks { public: - TypeDumpVisitor(TypeDatabase &TypeDB, ScopedPrinter *W, bool PrintRecordBytes) - : W(W), PrintRecordBytes(PrintRecordBytes), TypeDB(TypeDB) {} + TypeDumpVisitor(TypeCollection &TpiTypes, ScopedPrinter *W, + bool PrintRecordBytes) + : W(W), PrintRecordBytes(PrintRecordBytes), TpiTypes(TpiTypes) {} /// When dumping types from an IPI stream in a PDB, a type index may refer to /// a type or an item ID. The dumper will lookup the "name" of the index in /// the item database if appropriate. If ItemDB is null, it will use TypeDB, /// which is correct when dumping types from an object file (/Z7). - void setItemDB(TypeDatabase &DB) { ItemDB = &DB; } + void setIpiTypes(TypeCollection &Types) { IpiTypes = &Types; } void printTypeIndex(StringRef FieldName, TypeIndex TI) const; @@ -66,14 +68,16 @@ /// Get the database of indices for the stream that we are dumping. If ItemDB /// is set, then we must be dumping an item (IPI) stream. This will also /// always get the appropriate DB for printing item names. - TypeDatabase &getSourceDB() const { return ItemDB ? *ItemDB : TypeDB; } + TypeCollection &getSourceTypes() const { + return IpiTypes ? *IpiTypes : TpiTypes; + } ScopedPrinter *W; bool PrintRecordBytes = false; - TypeDatabase &TypeDB; - TypeDatabase *ItemDB = nullptr; + TypeCollection &TpiTypes; + TypeCollection *IpiTypes = nullptr; }; } // end namespace codeview Index: llvm/include/llvm/DebugInfo/CodeView/TypeIndex.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeIndex.h +++ llvm/include/llvm/DebugInfo/CodeView/TypeIndex.h @@ -15,8 +15,13 @@ #include namespace llvm { + +class ScopedPrinter; + namespace codeview { +class TypeCollection; + enum class SimpleTypeKind : uint32_t { None = 0x0000, // uncharacterized type (no type) Void = 0x0003, // void @@ -238,6 +243,11 @@ return Result; } + friend inline uint32_t operator-(const TypeIndex &A, const TypeIndex &B) { + assert(A >= B); + return A.toArrayIndex() - B.toArrayIndex(); + } + private: support::ulittle32_t Index; }; @@ -249,6 +259,9 @@ TypeIndex Type; support::ulittle32_t Offset; }; + +void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, TypeIndex TI, + TypeCollection &Types); } } Index: llvm/include/llvm/DebugInfo/CodeView/TypeTableCollection.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/CodeView/TypeTableCollection.h @@ -0,0 +1,42 @@ +//===- TypeTableCollection.h ---------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPETABLECOLLECTION_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPETABLECOLLECTION_H + +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" + +namespace llvm { +namespace codeview { + +class TypeTableCollection : public TypeCollection { +public: + explicit TypeTableCollection(ArrayRef> Records); + + TypeIndex getFirst() override; + Optional getNext(TypeIndex Prev) override; + + CVType getType(TypeIndex Index) override; + StringRef getTypeName(TypeIndex Index) override; + bool contains(TypeIndex Index) override; + uint32_t size() override; + uint32_t capacity() override; + +private: + bool hasCapacityFor(TypeIndex Index) const; + void ensureTypeExists(TypeIndex Index); + + ArrayRef> Records; + TypeDatabase Database; +}; +} +} + +#endif Index: llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h +++ llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h @@ -17,8 +17,6 @@ namespace codeview { class TypeVisitorCallbacks { - friend class CVTypeVisitor; - public: virtual ~TypeVisitorCallbacks() = default; Index: llvm/include/llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h +++ llvm/include/llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h @@ -13,7 +13,6 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeServerHandler.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.h" Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -13,7 +13,6 @@ #include "CodeViewDebug.h" #include "llvm/ADT/TinyPtrVector.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Line.h" @@ -23,6 +22,7 @@ #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeTableCollection.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" #include "llvm/IR/Constants.h" #include "llvm/MC/MCAsmInfo.h" @@ -469,17 +469,21 @@ CommentPrefix += ' '; } - TypeDatabase TypeDB(TypeTable.records().size()); - CVTypeDumper CVTD(TypeDB); - TypeTable.ForEachRecord([&](TypeIndex Index, ArrayRef Record) { + TypeTableCollection Table(TypeTable.records()); + Optional B = Table.getFirst(); + do { + // This will fail if the record data is invalid. + CVType Record = Table.getType(*B); + if (OS.isVerboseAsm()) { // Emit a block comment describing the type record for readability. SmallString<512> CommentBlock; raw_svector_ostream CommentOS(CommentBlock); ScopedPrinter SP(CommentOS); SP.setPrefix(CommentPrefix); - TypeDumpVisitor TDV(TypeDB, &SP, false); - Error E = CVTD.dump(Record, TDV); + TypeDumpVisitor TDV(Table, &SP, false); + + Error E = codeview::visitTypeRecord(Record, *B, TDV); if (E) { logAllUnhandledErrors(std::move(E), errs(), "error: "); llvm_unreachable("produced malformed type record"); @@ -489,29 +493,9 @@ // newline. OS.emitRawComment( CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim()); - } else { -#ifndef NDEBUG - // Assert that the type data is valid even if we aren't dumping - // comments. The MSVC linker doesn't do much type record validation, - // so the first link of an invalid type record can succeed while - // subsequent links will fail with LNK1285. - BinaryByteStream Stream(Record, llvm::support::little); - CVTypeArray Types; - BinaryStreamReader Reader(Stream); - Error E = Reader.readArray(Types, Reader.getLength()); - if (!E) { - TypeVisitorCallbacks C; - E = codeview::visitTypeStream(Types, C); - } - if (E) { - logAllUnhandledErrors(std::move(E), errs(), "error: "); - llvm_unreachable("produced malformed type record"); - } -#endif } - StringRef S(reinterpret_cast(Record.data()), Record.size()); - OS.EmitBinaryData(S); - }); + OS.EmitBinaryData(Record.str_data()); + } while (B = Table.getNext(*B)); } namespace { Index: llvm/lib/DebugInfo/CodeView/CMakeLists.txt =================================================================== --- llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -2,10 +2,10 @@ CodeViewError.cpp CodeViewRecordIO.cpp CVSymbolVisitor.cpp - CVTypeDumper.cpp CVTypeVisitor.cpp EnumTables.cpp Formatters.cpp + LazyRandomTypeCollection.cpp Line.cpp ModuleDebugFileChecksumFragment.cpp ModuleDebugFragment.cpp @@ -13,7 +13,6 @@ ModuleDebugFragmentVisitor.cpp ModuleDebugInlineeLinesFragment.cpp ModuleDebugLineFragment.cpp - RandomAccessTypeVisitor.cpp RecordSerialization.cpp StringTable.cpp SymbolRecordMapping.cpp @@ -22,10 +21,12 @@ TypeDatabase.cpp TypeDatabaseVisitor.cpp TypeDumpVisitor.cpp + TypeIndex.cpp TypeRecordMapping.cpp TypeSerializer.cpp TypeStreamMerger.cpp - + TypeTableCollection.cpp + ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView ) Index: llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp +++ /dev/null @@ -1,61 +0,0 @@ -//===-- CVTypeDumper.cpp - CodeView type info dumper ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/Support/BinaryByteStream.h" - -using namespace llvm; -using namespace llvm::codeview; - -Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) { - TypeDatabaseVisitor DBV(TypeDB); - TypeVisitorCallbackPipeline Pipeline; - Pipeline.addCallbackToPipeline(DBV); - Pipeline.addCallbackToPipeline(Dumper); - - CVType RecordCopy = Record; - return codeview::visitTypeRecord(RecordCopy, Pipeline, VDS_BytesPresent, - Handler); -} - -Error CVTypeDumper::dump(const CVTypeArray &Types, - TypeVisitorCallbacks &Dumper) { - TypeDatabaseVisitor DBV(TypeDB); - TypeVisitorCallbackPipeline Pipeline; - Pipeline.addCallbackToPipeline(DBV); - Pipeline.addCallbackToPipeline(Dumper); - - return codeview::visitTypeStream(Types, Pipeline, Handler); -} - -Error CVTypeDumper::dump(ArrayRef Data, TypeVisitorCallbacks &Dumper) { - BinaryByteStream Stream(Data, llvm::support::little); - CVTypeArray Types; - BinaryStreamReader Reader(Stream); - if (auto EC = Reader.readArray(Types, Reader.getLength())) - return EC; - - return dump(Types, Dumper); -} - -void CVTypeDumper::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, - TypeIndex TI, TypeDatabase &DB) { - StringRef TypeName; - if (!TI.isNoneType()) - TypeName = DB.getTypeName(TI); - if (!TypeName.empty()) - Printer.printHex(FieldName, TypeName, TI.getIndex()); - else - Printer.printHex(FieldName, TI.getIndex()); -} Index: llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -9,7 +9,9 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/ADT/TinyPtrVector.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/TypeCollection.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" @@ -22,8 +24,6 @@ using namespace llvm; using namespace llvm::codeview; -CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) - : Callbacks(Callbacks) {} template static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) { @@ -66,6 +66,67 @@ return R; } +static Error visitMemberRecord(CVMemberRecord &Record, + TypeVisitorCallbacks &Callbacks) { + if (auto EC = Callbacks.visitMemberBegin(Record)) + return EC; + + switch (Record.Kind) { + default: + if (auto EC = Callbacks.visitUnknownMember(Record)) + return EC; + break; +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + case EnumName: { \ + if (auto EC = visitKnownMember(Record, Callbacks)) \ + return EC; \ + break; \ + } +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ + MEMBER_RECORD(EnumVal, EnumVal, AliasName) +#define TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/TypeRecords.def" + } + + if (auto EC = Callbacks.visitMemberEnd(Record)) + return EC; + + return Error::success(); +} + +namespace { + +class CVTypeVisitor { +public: + explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks); + + void addTypeServerHandler(TypeServerHandler &Handler); + + Error visitTypeRecord(CVType &Record, TypeIndex Index); + Error visitTypeRecord(CVType &Record); + + /// Visits the type records in Data. Sets the error flag on parse failures. + Error visitTypeStream(const CVTypeArray &Types); + Error visitTypeStream(CVTypeRange Types); + Error visitTypeStream(TypeCollection &Types); + + Error visitMemberRecord(CVMemberRecord Record); + Error visitFieldListMemberStream(BinaryStreamReader &Stream); + +private: + Expected handleTypeServer(CVType &Record); + Error finishVisitation(CVType &Record); + + /// The interface to the class that gets notified of each visitation. + TypeVisitorCallbacks &Callbacks; + + TinyPtrVector Handlers; +}; + +CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) + : Callbacks(Callbacks) {} + void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) { Handlers.push_back(&Handler); } @@ -144,35 +205,6 @@ return finishVisitation(Record); } -static Error visitMemberRecord(CVMemberRecord &Record, - TypeVisitorCallbacks &Callbacks) { - if (auto EC = Callbacks.visitMemberBegin(Record)) - return EC; - - switch (Record.Kind) { - default: - if (auto EC = Callbacks.visitUnknownMember(Record)) - return EC; - break; -#define MEMBER_RECORD(EnumName, EnumVal, Name) \ - case EnumName: { \ - if (auto EC = visitKnownMember(Record, Callbacks)) \ - return EC; \ - break; \ - } -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ - MEMBER_RECORD(EnumVal, EnumVal, AliasName) -#define TYPE_RECORD(EnumName, EnumVal, Name) -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#include "llvm/DebugInfo/CodeView/TypeRecords.def" - } - - if (auto EC = Callbacks.visitMemberEnd(Record)) - return EC; - - return Error::success(); -} - Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) { return ::visitMemberRecord(Record, Callbacks); } @@ -194,12 +226,17 @@ return Error::success(); } -Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) { - FieldListDeserializer Deserializer(Reader); - TypeVisitorCallbackPipeline Pipeline; - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(Callbacks); +Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) { + Optional I = Types.getFirst(); + do { + CVType Type = Types.getType(*I); + if (auto EC = visitTypeRecord(Type, *I)) + return EC; + } while (I = Types.getNext(*I)); + return Error::success(); +} +Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) { TypeLeafKind Leaf; while (!Reader.empty()) { if (auto EC = Reader.readEnum(Leaf)) @@ -207,20 +244,13 @@ CVMemberRecord Record; Record.Kind = Leaf; - if (auto EC = ::visitMemberRecord(Record, Pipeline)) + if (auto EC = ::visitMemberRecord(Record, Callbacks)) return EC; } return Error::success(); } -Error CVTypeVisitor::visitFieldListMemberStream(ArrayRef Data) { - BinaryByteStream S(Data, llvm::support::little); - BinaryStreamReader SR(S); - return visitFieldListMemberStream(SR); -} - -namespace { struct FieldListVisitHelper { FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef Data, VisitorDataSource Source) @@ -241,11 +271,8 @@ }; struct VisitHelper { - VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source, - TypeServerHandler *TS) + VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source) : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) { - if (TS) - Visitor.addTypeServerHandler(*TS); if (Source == VDS_BytesPresent) { Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Callbacks); @@ -262,29 +289,57 @@ TypeVisitorCallbacks &Callbacks, VisitorDataSource Source, TypeServerHandler *TS) { - VisitHelper Helper(Callbacks, Source, TS); - return Helper.Visitor.visitTypeRecord(Record, Index); + VisitHelper V(Callbacks, Source); + if (TS) + V.Visitor.addTypeServerHandler(*TS); + return V.Visitor.visitTypeRecord(Record, Index); } Error llvm::codeview::visitTypeRecord(CVType &Record, TypeVisitorCallbacks &Callbacks, VisitorDataSource Source, TypeServerHandler *TS) { - VisitHelper Helper(Callbacks, Source, TS); - return Helper.Visitor.visitTypeRecord(Record); + VisitHelper V(Callbacks, Source); + if (TS) + V.Visitor.addTypeServerHandler(*TS); + return V.Visitor.visitTypeRecord(Record); } -Error llvm::codeview::visitMemberRecordStream(ArrayRef FieldList, - TypeVisitorCallbacks &Callbacks) { - CVTypeVisitor Visitor(Callbacks); - return Visitor.visitFieldListMemberStream(FieldList); +Error llvm::codeview::visitTypeStream(const CVTypeArray &Types, + TypeVisitorCallbacks &Callbacks, + TypeServerHandler *TS) { + VisitHelper V(Callbacks, VDS_BytesPresent); + if (TS) + V.Visitor.addTypeServerHandler(*TS); + return V.Visitor.visitTypeStream(Types); +} + +Error llvm::codeview::visitTypeStream(CVTypeRange Types, + TypeVisitorCallbacks &Callbacks, + TypeServerHandler *TS) { + VisitHelper V(Callbacks, VDS_BytesPresent); + if (TS) + V.Visitor.addTypeServerHandler(*TS); + return V.Visitor.visitTypeStream(Types); +} + +Error llvm::codeview::visitTypeStream(TypeCollection &Types, + TypeVisitorCallbacks &Callbacks, + TypeServerHandler *TS) { + // When the internal visitor calls Types.getType(Index) the interface is + // required to return a CVType with the bytes filled out. So we can assume + // that the bytes will be present when individual records are visited. + VisitHelper V(Callbacks, VDS_BytesPresent); + if (TS) + V.Visitor.addTypeServerHandler(*TS); + return V.Visitor.visitTypeStream(Types); } Error llvm::codeview::visitMemberRecord(CVMemberRecord Record, TypeVisitorCallbacks &Callbacks, VisitorDataSource Source) { - FieldListVisitHelper Helper(Callbacks, Record.Data, Source); - return Helper.Visitor.visitMemberRecord(Record); + FieldListVisitHelper V(Callbacks, Record.Data, Source); + return V.Visitor.visitMemberRecord(Record); } Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind, @@ -296,16 +351,8 @@ return visitMemberRecord(R, Callbacks, VDS_BytesPresent); } -Error llvm::codeview::visitTypeStream(const CVTypeArray &Types, - TypeVisitorCallbacks &Callbacks, - TypeServerHandler *TS) { - VisitHelper Helper(Callbacks, VDS_BytesPresent, TS); - return Helper.Visitor.visitTypeStream(Types); -} - -Error llvm::codeview::visitTypeStream(CVTypeRange Types, - TypeVisitorCallbacks &Callbacks, - TypeServerHandler *TS) { - VisitHelper Helper(Callbacks, VDS_BytesPresent, TS); - return Helper.Visitor.visitTypeStream(Types); +Error llvm::codeview::visitMemberRecordStream(ArrayRef FieldList, + TypeVisitorCallbacks &Callbacks) { + FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent); + return V.Visitor.visitFieldListMemberStream(V.Reader); } Index: llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp =================================================================== --- /dev/null +++ llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp @@ -0,0 +1,226 @@ +//===- LazyRandomTypeCollection.cpp ---------------------------- *- C++--*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeServerHandler.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" + +using namespace llvm; +using namespace llvm::codeview; + +static void error(Error &&EC) { + assert(!static_cast(EC)); + if (EC) + consumeError(std::move(EC)); +} + +LazyRandomTypeCollection::LazyRandomTypeCollection(uint32_t RecordCountHint) + : LazyRandomTypeCollection(CVTypeArray(), RecordCountHint, + PartialOffsetArray()) {} + +LazyRandomTypeCollection::LazyRandomTypeCollection( + const CVTypeArray &Types, uint32_t RecordCountHint, + PartialOffsetArray PartialOffsets) + : Database(RecordCountHint), Types(Types), DatabaseVisitor(Database), + PartialOffsets(PartialOffsets) { + KnownOffsets.resize(Database.capacity()); +} + +LazyRandomTypeCollection::LazyRandomTypeCollection(ArrayRef Data, + uint32_t RecordCountHint) + : LazyRandomTypeCollection(RecordCountHint) { + reset(Data); +} + +LazyRandomTypeCollection::LazyRandomTypeCollection(StringRef Data, + uint32_t RecordCountHint) + : LazyRandomTypeCollection( + makeArrayRef(Data.bytes_begin(), Data.bytes_end()), RecordCountHint) { +} + +LazyRandomTypeCollection::LazyRandomTypeCollection(const CVTypeArray &Types, + uint32_t NumRecords) + : LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {} + +void LazyRandomTypeCollection::reset(StringRef Data) { + reset(makeArrayRef(Data.bytes_begin(), Data.bytes_end())); +} + +void LazyRandomTypeCollection::reset(ArrayRef Data) { + PartialOffsets = PartialOffsetArray(); + + BinaryStreamReader Reader(Data, support::little); + error(Reader.readArray(Types, Reader.getLength())); + + KnownOffsets.resize(Database.capacity()); +} + +CVType LazyRandomTypeCollection::getType(TypeIndex Index) { + error(ensureTypeExists(Index)); + return Database.getTypeRecord(Index); +} + +StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) { + if (!Index.isSimple()) { + // Try to make sure the type exists. Even if it doesn't though, it may be + // because we're dumping a symbol stream with no corresponding type stream + // present, in which case we still want to be able to print + // for the type names. + consumeError(ensureTypeExists(Index)); + } + + return Database.getTypeName(Index); +} + +bool LazyRandomTypeCollection::contains(TypeIndex Index) { + return Database.contains(Index); +} + +uint32_t LazyRandomTypeCollection::size() { return Database.size(); } + +uint32_t LazyRandomTypeCollection::capacity() { return Database.capacity(); } + +Error LazyRandomTypeCollection::ensureTypeExists(TypeIndex TI) { + if (!Database.contains(TI)) { + if (auto EC = visitRangeForType(TI)) + return EC; + } + return Error::success(); +} + +Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) { + if (PartialOffsets.empty()) + return fullScanForType(TI); + + auto Next = std::upper_bound(PartialOffsets.begin(), PartialOffsets.end(), TI, + [](TypeIndex Value, const TypeIndexOffset &IO) { + return Value < IO.Type; + }); + + assert(Next != PartialOffsets.begin()); + auto Prev = std::prev(Next); + + TypeIndex TIB = Prev->Type; + if (Database.contains(TIB)) { + // They've asked us to fetch a type index, but the entry we found in the + // partial offsets array has already been visited. Since we visit an entire + // block every time, that means this record should have been previously + // discovered. Ultimately, this means this is a request for a non-existant + // type index. + return make_error("Invalid type index"); + } + + TypeIndex TIE; + if (Next == PartialOffsets.end()) { + TIE = TypeIndex::fromArrayIndex(Database.capacity()); + } else { + TIE = Next->Type; + } + + if (auto EC = visitRange(TIB, Prev->Offset, TIE)) + return EC; + return Error::success(); +} + +TypeIndex LazyRandomTypeCollection::getFirst() { + TypeIndex TI = TypeIndex::fromArrayIndex(0); + error(ensureTypeExists(TI)); + return TI; +} + +Optional LazyRandomTypeCollection::getNext(TypeIndex Prev) { + // We can't be sure how long this type stream is, given that the initial count + // given to the constructor is just a hint. So just try to make sure the next + // record exists, and if anything goes wrong, we must be at the end. + if (auto EC = ensureTypeExists(Prev + 1)) { + consumeError(std::move(EC)); + return None; + } + + return Prev + 1; +} + +Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) { + assert(PartialOffsets.empty()); + + TypeIndex CurrentTI = TypeIndex::fromArrayIndex(0); + uint32_t Offset = 0; + auto Begin = Types.begin(); + + if (!Database.empty()) { + // In the case of type streams which we don't know the number of records of, + // it's possible to search for a type index triggering a full scan, but then + // later additional records are added since we didn't know how many there + // would be until we did a full visitation, then you try to access the new + // type triggering another full scan. To avoid this, we assume that if the + // database has some records, this must be what's going on. So we ask the + // database for the largest type index less than the one we're searching for + // and only do the forward scan from there. + auto Prev = Database.largestTypeIndexLessThan(TI); + assert(Prev.hasValue() && "Empty database with valid types?"); + Offset = KnownOffsets[Prev->toArrayIndex()]; + CurrentTI = *Prev; + ++CurrentTI; + Begin = Types.at(Offset); + ++Begin; + Offset = Begin.offset(); + } + + auto End = Types.end(); + while (Begin != End) { + if (auto EC = visitOneRecord(CurrentTI, Offset, *Begin)) + return EC; + + Offset += Begin.getRecordLength(); + ++Begin; + ++CurrentTI; + } + if (CurrentTI <= TI) { + return make_error("Type Index does not exist!"); + } + return Error::success(); +} + +Error LazyRandomTypeCollection::visitRange(TypeIndex Begin, + uint32_t BeginOffset, + TypeIndex End) { + + auto RI = Types.at(BeginOffset); + assert(RI != Types.end()); + + while (Begin != End) { + if (auto EC = visitOneRecord(Begin, BeginOffset, *RI)) + return EC; + + BeginOffset += RI.getRecordLength(); + ++Begin; + ++RI; + } + + return Error::success(); +} + +Error LazyRandomTypeCollection::visitOneRecord(TypeIndex TI, uint32_t Offset, + CVType &Record) { + assert(!Database.contains(TI)); + if (auto EC = codeview::visitTypeRecord(Record, TI, DatabaseVisitor)) + return EC; + // Keep the KnownOffsets array the same size as the Database's capacity. Since + // we don't always know how many records are in the type stream, we need to be + // prepared for the database growing and receicing a type index that can't fit + // in our current buffer. + if (KnownOffsets.size() < Database.capacity()) + KnownOffsets.resize(Database.capacity()); + KnownOffsets[TI.toArrayIndex()] = Offset; + return Error::success(); +} Index: llvm/lib/DebugInfo/CodeView/RandomAccessTypeVisitor.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/RandomAccessTypeVisitor.cpp +++ /dev/null @@ -1,89 +0,0 @@ -//===- RandomAccessTypeVisitor.cpp ---------------------------- *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h" - -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/DebugInfo/CodeView/TypeServerHandler.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" - -using namespace llvm; -using namespace llvm::codeview; - -RandomAccessTypeVisitor::RandomAccessTypeVisitor( - const CVTypeArray &Types, uint32_t NumRecords, - PartialOffsetArray PartialOffsets) - : Database(NumRecords), Types(Types), DatabaseVisitor(Database), - PartialOffsets(PartialOffsets) { - - KnownOffsets.resize(Database.capacity()); -} - -Error RandomAccessTypeVisitor::visitTypeIndex(TypeIndex TI, - TypeVisitorCallbacks &Callbacks) { - assert(TI.toArrayIndex() < Database.capacity()); - - if (!Database.contains(TI)) { - if (auto EC = visitRangeForType(TI)) - return EC; - } - - assert(Database.contains(TI)); - auto &Record = Database.getTypeRecord(TI); - return codeview::visitTypeRecord(Record, TI, Callbacks); -} - -Error RandomAccessTypeVisitor::visitRangeForType(TypeIndex TI) { - if (PartialOffsets.empty()) { - TypeIndex TIB(TypeIndex::FirstNonSimpleIndex); - TypeIndex TIE = TIB + Database.capacity(); - return visitRange(TIB, 0, TIE); - } - - auto Next = std::upper_bound(PartialOffsets.begin(), PartialOffsets.end(), TI, - [](TypeIndex Value, const TypeIndexOffset &IO) { - return Value < IO.Type; - }); - - assert(Next != PartialOffsets.begin()); - auto Prev = std::prev(Next); - - TypeIndex TIB = Prev->Type; - TypeIndex TIE; - if (Next == PartialOffsets.end()) { - TIE = TypeIndex::fromArrayIndex(Database.capacity()); - } else { - TIE = Next->Type; - } - - if (auto EC = visitRange(TIB, Prev->Offset, TIE)) - return EC; - return Error::success(); -} - -Error RandomAccessTypeVisitor::visitRange(TypeIndex Begin, uint32_t BeginOffset, - TypeIndex End) { - - auto RI = Types.at(BeginOffset); - assert(RI != Types.end()); - - while (Begin != End) { - assert(!Database.contains(Begin)); - if (auto EC = codeview::visitTypeRecord(*RI, Begin, DatabaseVisitor)) - return EC; - KnownOffsets[Begin.toArrayIndex()] = BeginOffset; - - BeginOffset += RI.getRecordLength(); - ++Begin; - ++RI; - } - - return Error::success(); -} Index: llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -11,7 +11,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" #include "llvm/DebugInfo/CodeView/StringTable.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" @@ -33,9 +32,9 @@ /// the visitor out of SymbolDumper.h. class CVSymbolDumperImpl : public SymbolVisitorCallbacks { public: - CVSymbolDumperImpl(TypeDatabase &TypeDB, SymbolDumpDelegate *ObjDelegate, + CVSymbolDumperImpl(TypeCollection &Types, SymbolDumpDelegate *ObjDelegate, ScopedPrinter &W, bool PrintRecordBytes) - : TypeDB(TypeDB), ObjDelegate(ObjDelegate), W(W), + : Types(Types), ObjDelegate(ObjDelegate), W(W), PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {} /// CVSymbolVisitor overrides. @@ -54,7 +53,7 @@ void printLocalVariableAddrGap(ArrayRef Gaps); void printTypeIndex(StringRef FieldName, TypeIndex TI); - TypeDatabase &TypeDB; + TypeCollection &Types; SymbolDumpDelegate *ObjDelegate; ScopedPrinter &W; @@ -83,7 +82,7 @@ } void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) { - CVTypeDumper::printTypeIndex(W, FieldName, TI, TypeDB); + codeview::printTypeIndex(W, FieldName, TI, Types); } Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) { @@ -670,7 +669,7 @@ Error CVSymbolDumper::dump(CVRecord &Record) { SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(ObjDelegate.get()); - CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes); + CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); @@ -681,7 +680,7 @@ Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) { SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(ObjDelegate.get()); - CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes); + CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); Index: llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp +++ llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp @@ -72,16 +72,20 @@ } TypeIndex TypeDatabase::appendType(StringRef Name, const CVType &Data) { - TypeIndex TI; - TI = getAppendIndex(); - if (TI.toArrayIndex() >= capacity()) + LargestTypeIndex = getAppendIndex(); + if (LargestTypeIndex.toArrayIndex() >= capacity()) grow(); - recordType(Name, TI, Data); - return TI; + recordType(Name, LargestTypeIndex, Data); + return LargestTypeIndex; } void TypeDatabase::recordType(StringRef Name, TypeIndex Index, const CVType &Data) { + LargestTypeIndex = empty() ? Index : std::max(Index, LargestTypeIndex); + + if (LargestTypeIndex.toArrayIndex() >= capacity()) + grow(Index); + uint32_t AI = Index.toArrayIndex(); assert(!contains(Index)); @@ -144,19 +148,65 @@ uint32_t TypeDatabase::capacity() const { return TypeRecords.size(); } -void TypeDatabase::grow() { - TypeRecords.emplace_back(); - CVUDTNames.emplace_back(); - ValidRecords.resize(ValidRecords.size() + 1); +CVType TypeDatabase::getType(TypeIndex Index) { return getTypeRecord(Index); } + +StringRef TypeDatabase::getTypeName(TypeIndex Index) { + return static_cast(this)->getTypeName(Index); +} + +bool TypeDatabase::contains(TypeIndex Index) { + return static_cast(this)->contains(Index); +} + +uint32_t TypeDatabase::size() { + return static_cast(this)->size(); +} + +uint32_t TypeDatabase::capacity() { + return static_cast(this)->capacity(); +} + +void TypeDatabase::grow() { grow(LargestTypeIndex + 1); } + +void TypeDatabase::grow(TypeIndex NewIndex) { + uint32_t NewSize = NewIndex.toArrayIndex() + 1; + + if (NewSize <= capacity()) + return; + + uint32_t NewCapacity = NewSize * 3 / 2; + + TypeRecords.resize(NewCapacity); + CVUDTNames.resize(NewCapacity); + ValidRecords.resize(NewCapacity); } bool TypeDatabase::empty() const { return size() == 0; } +Optional TypeDatabase::largestTypeIndexLessThan(TypeIndex TI) const { + uint32_t AI = TI.toArrayIndex(); + int N = ValidRecords.find_prev(AI); + if (N == -1) + return None; + return TypeIndex::fromArrayIndex(N); +} + TypeIndex TypeDatabase::getAppendIndex() const { if (empty()) return TypeIndex::fromArrayIndex(0); - int Index = ValidRecords.find_last(); - assert(Index != -1); - return TypeIndex::fromArrayIndex(Index) + 1; + return LargestTypeIndex + 1; +} + +TypeIndex TypeDatabase::getFirst() { + int N = ValidRecords.find_first(); + assert(N != -1); + return TypeIndex::fromArrayIndex(N); +} + +Optional TypeDatabase::getNext(TypeIndex Prev) { + int N = ValidRecords.find_next(Prev.toArrayIndex()); + if (N == -1) + return None; + return TypeIndex::fromArrayIndex(N); } Index: llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp +++ llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -10,15 +10,13 @@ #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/ADT/SmallString.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/Formatters.h" +#include "llvm/DebugInfo/CodeView/TypeCollection.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ScopedPrinter.h" @@ -165,16 +163,15 @@ } void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const { - CVTypeDumper::printTypeIndex(*W, FieldName, TI, TypeDB); + codeview::printTypeIndex(*W, FieldName, TI, TpiTypes); } void TypeDumpVisitor::printItemIndex(StringRef FieldName, TypeIndex TI) const { - CVTypeDumper::printTypeIndex(*W, FieldName, TI, getSourceDB()); + codeview::printTypeIndex(*W, FieldName, TI, getSourceTypes()); } Error TypeDumpVisitor::visitTypeBegin(CVType &Record) { - TypeIndex TI = getSourceDB().getAppendIndex(); - return visitTypeBegin(Record, TI); + return visitTypeBegin(Record, TypeIndex::fromArrayIndex(TpiTypes.size())); } Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) { Index: llvm/lib/DebugInfo/CodeView/TypeIndex.cpp =================================================================== --- /dev/null +++ llvm/lib/DebugInfo/CodeView/TypeIndex.cpp @@ -0,0 +1,27 @@ +//===-- TypeIndex.cpp - CodeView type index ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeIndex.h" + +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace llvm::codeview; + +void llvm::codeview::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, + TypeIndex TI, TypeCollection &Types) { + StringRef TypeName; + if (!TI.isNoneType()) + TypeName = Types.getTypeName(TI); + if (!TypeName.empty()) + Printer.printHex(FieldName, TypeName, TI.getIndex()); + else + Printer.printHex(FieldName, TI.getIndex()); +} Index: llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -11,11 +11,9 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" #include "llvm/Support/Error.h" #include "llvm/Support/ScopedPrinter.h" Index: llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp =================================================================== --- /dev/null +++ llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp @@ -0,0 +1,82 @@ +//===- TypeTableCollection.cpp -------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeTableCollection.h" + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" + +using namespace llvm; +using namespace llvm::codeview; + +static void error(Error &&EC) { + assert(!static_cast(EC)); + if (EC) + consumeError(std::move(EC)); +} + +TypeTableCollection::TypeTableCollection( + ArrayRef> Records) + : Records(Records), Database(Records.size()) {} + +TypeIndex TypeTableCollection::getFirst() { + assert(!empty()); + return TypeIndex::fromArrayIndex(0); +} + +Optional TypeTableCollection::getNext(TypeIndex Prev) { + ++Prev; + assert(Prev.toArrayIndex() <= size()); + if (Prev.toArrayIndex() == size()) + return None; + return Prev; +} + +void TypeTableCollection::ensureTypeExists(TypeIndex Index) { + assert(hasCapacityFor(Index)); + + if (Database.contains(Index)) + return; + + BinaryByteStream Bytes(Records[Index.toArrayIndex()], support::little); + + CVType Type; + uint32_t Len; + error(VarStreamArrayExtractor::extract(Bytes, Len, Type)); + + TypeDatabaseVisitor DBV(Database); + error(codeview::visitTypeRecord(Type, Index, DBV)); + assert(Database.contains(Index)); +} + +CVType TypeTableCollection::getType(TypeIndex Index) { + ensureTypeExists(Index); + return Database.getTypeRecord(Index); +} + +StringRef TypeTableCollection::getTypeName(TypeIndex Index) { + if (!Index.isSimple()) + ensureTypeExists(Index); + return Database.getTypeName(Index); +} + +bool TypeTableCollection::contains(TypeIndex Index) { + return Database.contains(Index); +} + +uint32_t TypeTableCollection::size() { return Records.size(); } + +uint32_t TypeTableCollection::capacity() { return Records.size(); } + +bool TypeTableCollection::hasCapacityFor(TypeIndex Index) const { + return Index.toArrayIndex() < Records.size(); +} Index: llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp +++ llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp @@ -21,6 +21,7 @@ #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" Index: llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp +++ llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -9,10 +9,7 @@ #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" Index: llvm/tools/llvm-pdbdump/Analyze.cpp =================================================================== --- llvm/tools/llvm-pdbdump/Analyze.cpp +++ llvm/tools/llvm-pdbdump/Analyze.cpp @@ -14,7 +14,6 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" Index: llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h =================================================================== --- llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h +++ llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h @@ -17,7 +17,7 @@ namespace llvm { class ScopedPrinter; namespace codeview { -class TypeDatabase; +class TypeCollection; } namespace pdb { @@ -26,8 +26,8 @@ /// Dumps records on a single line, and ignores member records. class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks { public: - CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB, ScopedPrinter *W); - CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB, + CompactTypeDumpVisitor(codeview::TypeCollection &Types, ScopedPrinter *W); + CompactTypeDumpVisitor(codeview::TypeCollection &Types, codeview::TypeIndex FirstTI, ScopedPrinter *W); /// Paired begin/end actions for all types. Receives all record data, @@ -40,7 +40,7 @@ codeview::TypeIndex TI; uint32_t Offset; - codeview::TypeDatabase &TypeDB; + codeview::TypeCollection &Types; }; } // end namespace pdb Index: llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp =================================================================== --- llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp +++ llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp @@ -29,15 +29,15 @@ return StringRef(); } -CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB, +CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types, ScopedPrinter *W) - : CompactTypeDumpVisitor(TypeDB, TypeIndex(TypeIndex::FirstNonSimpleIndex), + : CompactTypeDumpVisitor(Types, TypeIndex(TypeIndex::FirstNonSimpleIndex), W) {} -CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB, +CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types, TypeIndex FirstTI, ScopedPrinter *W) - : W(W), TI(FirstTI), Offset(0), TypeDB(TypeDB) {} + : W(W), TI(FirstTI), Offset(0), Types(Types) {} Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) { return Error::success(); @@ -46,7 +46,7 @@ Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) { uint32_t I = TI.getIndex(); StringRef Leaf = getLeafName(Record.Type); - StringRef Name = TypeDB.getTypeName(TI); + StringRef Name = Types.getTypeName(TI); W->printString( llvm::formatv("Index: {0:x} ({1:N} bytes, offset {2:N}) {3} \"{4}\"", I, Record.length(), Offset, Leaf, Name) Index: llvm/tools/llvm-pdbdump/LLVMOutputStyle.h =================================================================== --- llvm/tools/llvm-pdbdump/LLVMOutputStyle.h +++ llvm/tools/llvm-pdbdump/LLVMOutputStyle.h @@ -21,6 +21,11 @@ namespace llvm { class BitVector; + +namespace codeview { +class LazyRandomTypeCollection; +} + namespace pdb { class LLVMOutputStyle : public OutputStyle { public: @@ -29,7 +34,8 @@ Error dump() override; private: - Error buildTypeDatabase(uint32_t SN); + Expected + initializeTypeDatabase(uint32_t SN); Error dumpFileHeaders(); Error dumpStreamSummary(); @@ -54,8 +60,8 @@ PDBFile &File; ScopedPrinter P; - Optional TypeDB; - Optional ItemDB; + std::unique_ptr TpiTypes; + std::unique_ptr IpiTypes; SmallVector StreamPurposes; }; } Index: llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -14,9 +14,9 @@ #include "StreamUtil.h" #include "llvm-pdbdump.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h" @@ -25,7 +25,6 @@ #include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" @@ -84,7 +83,7 @@ class C13RawVisitor : public C13DebugFragmentVisitor { public: - C13RawVisitor(ScopedPrinter &P, PDBFile &F, TypeDatabase &IPI) + C13RawVisitor(ScopedPrinter &P, PDBFile &F, LazyRandomTypeCollection &IPI) : C13DebugFragmentVisitor(F), P(P), IPI(IPI) {} Error handleLines() override { @@ -160,7 +159,7 @@ if (auto EC = printFileName("FileName", L.Header->FileID)) return EC; - if (auto EC = dumpTypeRecord("Function", IPI, L.Header->Inlinee)) + if (auto EC = dumpTypeRecord("Function", L.Header->Inlinee)) return EC; P.printNumber("SourceLine", L.Header->SourceLineNum); if (IL.hasExtraFiles()) { @@ -176,11 +175,11 @@ } private: - Error dumpTypeRecord(StringRef Label, TypeDatabase &DB, TypeIndex Index) { - CompactTypeDumpVisitor CTDV(DB, Index, &P); + Error dumpTypeRecord(StringRef Label, TypeIndex Index) { + CompactTypeDumpVisitor CTDV(IPI, Index, &P); DictScope D(P, Label); - if (DB.contains(Index)) { - CVType &Type = DB.getTypeRecord(Index); + if (IPI.contains(Index)) { + CVType Type = IPI.getType(Index); if (auto EC = codeview::visitTypeRecord(Type, CTDV)) return EC; } else { @@ -199,7 +198,7 @@ } ScopedPrinter &P; - TypeDatabase &IPI; + LazyRandomTypeCollection &IPI; }; } @@ -609,14 +608,19 @@ VerLabel = "IPI Version"; } - if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash) - return Error::success(); - auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream(); if (!Tpi) return Tpi.takeError(); + auto ExpectedTypes = initializeTypeDatabase(StreamIdx); + if (!ExpectedTypes) + return ExpectedTypes.takeError(); + auto &Types = *ExpectedTypes; + + if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash) + return Error::success(); + std::unique_ptr StreamScope; std::unique_ptr RecordScope; @@ -624,25 +628,19 @@ P.printNumber(VerLabel, Tpi->getTpiVersion()); P.printNumber("Record count", Tpi->getNumTypeRecords()); - Optional &StreamDB = (StreamIdx == StreamTPI) ? TypeDB : ItemDB; - std::vector> Visitors; - if (!StreamDB.hasValue()) { - StreamDB.emplace(Tpi->getNumTypeRecords()); - Visitors.push_back(make_unique(*StreamDB)); - } // If we're in dump mode, add a dumper with the appropriate detail level. if (DumpRecords) { std::unique_ptr Dumper; if (opts::raw::CompactRecords) - Dumper = make_unique(*StreamDB, &P); + Dumper = make_unique(Types, &P); else { - assert(TypeDB.hasValue()); + assert(TpiTypes); - auto X = make_unique(*TypeDB, &P, false); + auto X = make_unique(*TpiTypes, &P, false); if (StreamIdx == StreamIPI) - X->setItemDB(*ItemDB); + X->setIpiTypes(*IpiTypes); Dumper = std::move(X); } Visitors.push_back(std::move(Dumper)); @@ -660,23 +658,17 @@ if (DumpRecords || DumpRecordBytes) RecordScope = llvm::make_unique(P, "Records"); - bool HadError = false; - - TypeIndex T(TypeIndex::FirstNonSimpleIndex); - for (auto Type : Tpi->types(&HadError)) { + Optional I = Types.getFirst(); + do { std::unique_ptr OneRecordScope; if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords) OneRecordScope = llvm::make_unique(P, ""); - if (auto EC = codeview::visitTypeRecord(Type, Pipeline)) + auto T = Types.getType(*I); + if (auto EC = codeview::visitTypeRecord(T, *I, Pipeline)) return EC; - - ++T; - } - if (HadError) - return make_error(raw_error_code::corrupt_file, - "TPI stream contained corrupt record"); + } while (I = Types.getNext(*I)); if (DumpTpiHash) { DictScope DD(P, "Hash"); @@ -711,35 +703,26 @@ return Error::success(); } -Error LLVMOutputStyle::buildTypeDatabase(uint32_t SN) { - assert(SN == StreamIPI || SN == StreamTPI); - - auto &DB = (SN == StreamIPI) ? ItemDB : TypeDB; - - if (DB.hasValue()) - return Error::success(); - +Expected +LLVMOutputStyle::initializeTypeDatabase(uint32_t SN) { + auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes; auto Tpi = (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream(); - if (!Tpi) return Tpi.takeError(); - DB.emplace(Tpi->getNumTypeRecords()); - - TypeDatabaseVisitor DBV(*DB); - - auto HashValues = Tpi->getHashValues(); - if (HashValues.empty()) - return codeview::visitTypeStream(Tpi->typeArray(), DBV); - - TypeVisitorCallbackPipeline Pipeline; - Pipeline.addCallbackToPipeline(DBV); - - TpiHashVerifier HashVerifier(HashValues, Tpi->getNumHashBuckets()); - Pipeline.addCallbackToPipeline(HashVerifier); + if (!TypeCollection) { + // Initialize the type collection, even if we're not going to dump it. This + // way if some other part of the dumper decides it wants to use some or all + // of the records for whatever purposes, it can still access them lazily. + auto &Types = Tpi->typeArray(); + uint32_t Count = Tpi->getNumTypeRecords(); + auto Offsets = Tpi->getTypeIndexOffsets(); + TypeCollection = + llvm::make_unique(Types, Count, Offsets); + } - return codeview::visitTypeStream(Tpi->typeArray(), Pipeline); + return *TypeCollection; } Error LLVMOutputStyle::dumpDbiStream() { @@ -814,11 +797,13 @@ return EC; if (ShouldDumpSymbols) { - if (auto EC = buildTypeDatabase(StreamTPI)) - return EC; + auto ExpectedTypes = initializeTypeDatabase(StreamTPI); + if (!ExpectedTypes) + return ExpectedTypes.takeError(); + auto &Types = *ExpectedTypes; ListScope SS(P, "Symbols"); - codeview::CVSymbolDumper SD(P, *TypeDB, nullptr, false); + codeview::CVSymbolDumper SD(P, Types, nullptr, false); bool HadError = false; for (auto S : ModS.symbols(&HadError)) { DictScope LL(P, ""); @@ -839,10 +824,11 @@ } if (opts::raw::DumpLineInfo) { ListScope SS(P, "LineInfo"); - if (auto EC = buildTypeDatabase(StreamIPI)) - return EC; - - C13RawVisitor V(P, File, *ItemDB); + auto ExpectedTypes = initializeTypeDatabase(StreamIPI); + if (!ExpectedTypes) + return ExpectedTypes.takeError(); + auto &IpiItems = *ExpectedTypes; + C13RawVisitor V(P, File, IpiItems); if (auto EC = codeview::visitModuleDebugFragments( ModS.linesAndChecksums(), V)) return EC; @@ -960,10 +946,12 @@ P.printList("Section Offsets", Publics->getSectionOffsets(), printSectionOffset); ListScope L(P, "Symbols"); - if (auto EC = buildTypeDatabase(StreamTPI)) - return EC; + auto ExpectedTypes = initializeTypeDatabase(StreamTPI); + if (!ExpectedTypes) + return ExpectedTypes.takeError(); + auto &Tpi = *ExpectedTypes; - codeview::CVSymbolDumper SD(P, *TypeDB, nullptr, false); + codeview::CVSymbolDumper SD(P, Tpi, nullptr, false); bool HadError = false; for (auto S : Publics->getSymbols(&HadError)) { DictScope DD(P, ""); Index: llvm/tools/llvm-pdbdump/PdbYaml.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PdbYaml.cpp +++ llvm/tools/llvm-pdbdump/PdbYaml.cpp @@ -19,7 +19,6 @@ #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolSerializer.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeSerializer.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" @@ -371,7 +370,6 @@ void MappingContextTraits:: mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj, pdb::yaml::SerializationContext &Context) { - if (IO.outputting()) { // For PDB to Yaml, deserialize into a high level record type, then dump it. consumeError(codeview::visitTypeRecord(Obj.Record, Context.Dumper)); Index: llvm/tools/llvm-pdbdump/YAMLOutputStyle.h =================================================================== --- llvm/tools/llvm-pdbdump/YAMLOutputStyle.h +++ llvm/tools/llvm-pdbdump/YAMLOutputStyle.h @@ -13,7 +13,6 @@ #include "OutputStyle.h" #include "PdbYaml.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/YAMLTraits.h" Index: llvm/tools/llvm-pdbdump/YamlTypeDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/YamlTypeDumper.cpp +++ llvm/tools/llvm-pdbdump/YamlTypeDumper.cpp @@ -13,7 +13,6 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeSerializer.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" Index: llvm/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/COFFDumper.cpp +++ llvm/tools/llvm-readobj/COFFDumper.cpp @@ -22,8 +22,9 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" @@ -34,18 +35,20 @@ #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" +#include "llvm/DebugInfo/CodeView/TypeTableCollection.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/COFF.h" -#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" @@ -70,7 +73,7 @@ public: friend class COFFObjectDumpDelegate; COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer) - : ObjDumper(Writer), Obj(Obj), Writer(Writer), TypeDB(100) {} + : ObjDumper(Writer), Obj(Obj), Writer(Writer), Types(100) {} void printFileHeaders() override; void printSections() override; @@ -106,7 +109,7 @@ void printFileNameForOffset(StringRef Label, uint32_t FileOffset); void printTypeIndex(StringRef FieldName, TypeIndex TI) { // Forward to CVTypeDumper for simplicity. - CVTypeDumper::printTypeIndex(Writer, FieldName, TI, TypeDB); + codeview::printTypeIndex(Writer, FieldName, TI, Types); } void printCodeViewSymbolsSubsection(StringRef Subsection, @@ -159,7 +162,8 @@ StringTableRef CVStringTable; ScopedPrinter &Writer; - TypeDatabase TypeDB; + BinaryByteStream TypeContents; + LazyRandomTypeCollection Types; }; class COFFObjectDumpDelegate : public SymbolDumpDelegate { @@ -975,9 +979,7 @@ Subsection.bytes_end()); auto CODD = llvm::make_unique(*this, Section, Obj, SectionContents); - - CVSymbolDumper CVSD(W, TypeDB, std::move(CODD), - opts::CodeViewSubsectionBytes); + CVSymbolDumper CVSD(W, Types, std::move(CODD), opts::CodeViewSubsectionBytes); CVSymbolArray Symbols; BinaryStreamReader Reader(BinaryData, llvm::support::little); if (auto EC = Reader.readArray(Symbols, Reader.getLength())) { @@ -1093,12 +1095,11 @@ if (Magic != COFF::DEBUG_SECTION_MAGIC) return error(object_error::parse_failed); - CVTypeDumper CVTD(TypeDB); - TypeDumpVisitor TDV(TypeDB, &W, opts::CodeViewSubsectionBytes); - if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()}, TDV)) { - W.flush(); - error(llvm::errorToErrorCode(std::move(EC))); - } + Types.reset(Data); + + TypeDumpVisitor TDV(Types, &W, opts::CodeViewSubsectionBytes); + error(codeview::visitTypeStream(Types, TDV)); + W.flush(); } void COFFDumper::printSections() { @@ -1638,35 +1639,22 @@ TypeBuf.append(Record.begin(), Record.end()); }); - TypeDatabase TypeDB(CVTypes.records().size()); + TypeTableCollection TpiTypes(CVTypes.records()); { ListScope S(Writer, "MergedTypeStream"); - CVTypeDumper CVTD(TypeDB); - TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes); - if (auto EC = CVTD.dump( - {TypeBuf.str().bytes_begin(), TypeBuf.str().bytes_end()}, TDV)) { - Writer.flush(); - error(std::move(EC)); - } + TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes); + error(codeview::visitTypeStream(TpiTypes, TDV)); + Writer.flush(); } // Flatten the id stream and print it next. The ID stream refers to names from // the type stream. - SmallString<0> IDBuf; - IDTable.ForEachRecord([&](TypeIndex TI, ArrayRef Record) { - IDBuf.append(Record.begin(), Record.end()); - }); - + TypeTableCollection IpiTypes(IDTable.records()); { ListScope S(Writer, "MergedIDStream"); - TypeDatabase IDDB(IDTable.records().size()); - CVTypeDumper CVTD(IDDB); - TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes); - TDV.setItemDB(IDDB); - if (auto EC = CVTD.dump( - {IDBuf.str().bytes_begin(), IDBuf.str().bytes_end()}, TDV)) { - Writer.flush(); - error(std::move(EC)); - } + TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes); + TDV.setIpiTypes(IpiTypes); + error(codeview::visitTypeStream(IpiTypes, TDV)); + Writer.flush(); } } Index: llvm/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp =================================================================== --- llvm/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp +++ llvm/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp @@ -11,14 +11,12 @@ #include "llvm/ADT/SmallBitVector.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" #include "llvm/DebugInfo/CodeView/TypeSerializer.h" #include "llvm/DebugInfo/CodeView/TypeServerHandler.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/Support/Allocator.h" @@ -130,20 +128,16 @@ void SetUp() override { TestState = llvm::make_unique(); - - TestState->Pipeline.addCallbackToPipeline(TestState->Deserializer); - TestState->Pipeline.addCallbackToPipeline(TestState->Callbacks); } void TearDown() override { TestState.reset(); } protected: - bool ValidateDatabaseRecord(const RandomAccessTypeVisitor &Visitor, - uint32_t Index) { + bool ValidateDatabaseRecord(LazyRandomTypeCollection &Types, uint32_t Index) { TypeIndex TI = TypeIndex::fromArrayIndex(Index); - if (!Visitor.database().contains(TI)) + if (!Types.contains(TI)) return false; - if (GlobalState->TypeVector[Index] != Visitor.database().getTypeRecord(TI)) + if (GlobalState->TypeVector[Index] != Types.getType(TI)) return false; return true; } @@ -184,8 +178,6 @@ struct PerTestState { FixedStreamArray Offsets; - TypeVisitorCallbackPipeline Pipeline; - TypeDeserializer Deserializer; MockCallbacks Callbacks; }; @@ -218,21 +210,22 @@ TEST_F(RandomAccessVisitorTest, MultipleVisits) { TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8}); - RandomAccessTypeVisitor Visitor(GlobalState->TypeArray, - GlobalState->TypeVector.size(), - TestState->Offsets); + LazyRandomTypeCollection Types(GlobalState->TypeArray, + GlobalState->TypeVector.size(), + TestState->Offsets); std::vector IndicesToVisit = {5, 5, 5}; for (uint32_t I : IndicesToVisit) { TypeIndex TI = TypeIndex::fromArrayIndex(I); - EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline)); + CVType T = Types.getType(TI); + EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks)); } // [0,8) should be present - EXPECT_EQ(8u, Visitor.database().size()); + EXPECT_EQ(8u, Types.size()); for (uint32_t I = 0; I < 8; ++I) - EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I)); + EXPECT_TRUE(ValidateDatabaseRecord(Types, I)); // 5, 5, 5 EXPECT_EQ(3u, TestState->Callbacks.count()); @@ -248,19 +241,19 @@ std::vector IndicesToVisit = {7, 4, 2}; - RandomAccessTypeVisitor Visitor(GlobalState->TypeArray, - GlobalState->TypeVector.size(), - TestState->Offsets); - + LazyRandomTypeCollection Types(GlobalState->TypeArray, + GlobalState->TypeVector.size(), + TestState->Offsets); for (uint32_t I : IndicesToVisit) { TypeIndex TI = TypeIndex::fromArrayIndex(I); - EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline)); + CVType T = Types.getType(TI); + EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks)); } // [0, 7] - EXPECT_EQ(8u, Visitor.database().size()); + EXPECT_EQ(8u, Types.size()); for (uint32_t I = 0; I < 8; ++I) - EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I)); + EXPECT_TRUE(ValidateDatabaseRecord(Types, I)); // 2, 4, 7 EXPECT_EQ(3u, TestState->Callbacks.count()); @@ -276,19 +269,19 @@ std::vector IndicesToVisit = {2, 4, 7}; - RandomAccessTypeVisitor Visitor(GlobalState->TypeArray, - GlobalState->TypeVector.size(), - TestState->Offsets); - + LazyRandomTypeCollection Types(GlobalState->TypeArray, + GlobalState->TypeVector.size(), + TestState->Offsets); for (uint32_t I : IndicesToVisit) { TypeIndex TI = TypeIndex::fromArrayIndex(I); - EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline)); + CVType T = Types.getType(TI); + EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks)); } // [0, 7] - EXPECT_EQ(8u, Visitor.database().size()); + EXPECT_EQ(8u, Types.size()); for (uint32_t I = 0; I < 8; ++I) - EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I)); + EXPECT_TRUE(ValidateDatabaseRecord(Types, I)); // 2, 4, 7 EXPECT_EQ(3u, TestState->Callbacks.count()); @@ -305,19 +298,20 @@ std::vector IndicesToVisit = {0, 1, 2}; - RandomAccessTypeVisitor Visitor(GlobalState->TypeArray, - GlobalState->TypeVector.size(), - TestState->Offsets); + LazyRandomTypeCollection Types(GlobalState->TypeArray, + GlobalState->TypeVector.size(), + TestState->Offsets); for (uint32_t I : IndicesToVisit) { TypeIndex TI = TypeIndex::fromArrayIndex(I); - EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline)); + CVType T = Types.getType(TI); + EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks)); } // [0, 8) should be visited. - EXPECT_EQ(8u, Visitor.database().size()); + EXPECT_EQ(8u, Types.size()); for (uint32_t I = 0; I < 8; ++I) - EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I)); + EXPECT_TRUE(ValidateDatabaseRecord(Types, I)); // [0, 2] EXPECT_EQ(3u, TestState->Callbacks.count()); @@ -333,19 +327,20 @@ std::vector IndicesToVisit = {5, 7}; - RandomAccessTypeVisitor Visitor(GlobalState->TypeArray, - GlobalState->TypeVector.size(), - TestState->Offsets); + LazyRandomTypeCollection Types(GlobalState->TypeArray, + GlobalState->TypeVector.size(), + TestState->Offsets); for (uint32_t I : IndicesToVisit) { TypeIndex TI = TypeIndex::fromArrayIndex(I); - EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline)); + CVType T = Types.getType(TI); + EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks)); } // [4, 9) - EXPECT_EQ(5u, Visitor.database().size()); + EXPECT_EQ(5u, Types.size()); for (uint32_t I = 4; I < 9; ++I) - EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I)); + EXPECT_TRUE(ValidateDatabaseRecord(Types, I)); // 5, 7 EXPECT_EQ(2u, TestState->Callbacks.count());