Index: llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -26,6 +26,7 @@ void addTypeServerHandler(TypeServerHandler &Handler); + Error visitTypeRecord(CVType &Record, TypeIndex Index); Error visitTypeRecord(CVType &Record); Error visitMemberRecord(CVMemberRecord &Record); @@ -37,6 +38,9 @@ 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; Index: llvm/include/llvm/DebugInfo/CodeView/TypeDatabase.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeDatabase.h +++ llvm/include/llvm/DebugInfo/CodeView/TypeDatabase.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASE_H #define LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASE_H +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" @@ -20,6 +21,8 @@ namespace llvm { namespace codeview { class TypeDatabase { + friend class RandomAccessTypeVisitor; + public: explicit TypeDatabase(uint32_t ExpectedSize); @@ -41,7 +44,9 @@ uint32_t size() const; -private: +protected: + uint32_t zeroIndex(TypeIndex Index) const; + BumpPtrAllocator Allocator; /// All user defined type records in .debug$T live in here. Type indices @@ -52,7 +57,29 @@ StringSaver TypeNameStorage; }; + +class RandomAccessTypeDatabase : private TypeDatabase { +public: + explicit RandomAccessTypeDatabase(uint32_t ExpectedSize); + + /// Records the name of a type, and reserves its type index. + void recordType(StringRef Name, TypeIndex Index, const CVType &Data); + + using TypeDatabase::saveTypeName; + + StringRef getTypeName(TypeIndex Index) const; + + const CVType &getTypeRecord(TypeIndex Index) const; + CVType &getTypeRecord(TypeIndex Index); + + bool containsTypeIndex(TypeIndex Index) const; + + uint32_t size() const; + +private: + BitVector ValidRecords; +}; } } #endif \ No newline at end of file Index: llvm/include/llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h +++ llvm/include/llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h @@ -10,6 +10,8 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASEVISITOR_H #define LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASEVISITOR_H +#include "llvm/ADT/PointerUnion.h" + #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" @@ -21,11 +23,14 @@ /// Dumper for CodeView type streams found in COFF object files and PDB files. class TypeDatabaseVisitor : public TypeVisitorCallbacks { public: - explicit TypeDatabaseVisitor(TypeDatabase &TypeDB) : TypeDB(TypeDB) {} + explicit TypeDatabaseVisitor(TypeDatabase &TypeDB) : TypeDB(&TypeDB) {} + explicit TypeDatabaseVisitor(RandomAccessTypeDatabase &TypeDB) + : TypeDB(&TypeDB) {} /// Paired begin/end actions for all types. Receives all record data, /// including the fixed-length record prefix. Error visitTypeBegin(CVType &Record) override; + Error visitTypeBegin(CVType &Record, TypeIndex Index) override; Error visitTypeEnd(CVType &Record) override; Error visitMemberBegin(CVMemberRecord &Record) override; Error visitMemberEnd(CVMemberRecord &Record) override; @@ -39,12 +44,18 @@ #include "TypeRecords.def" private: + StringRef getTypeName(TypeIndex Index) const; + StringRef saveTypeName(StringRef Name); + bool IsInFieldList = false; /// Name of the current type. Only valid before visitTypeEnd. StringRef Name; + /// Current type index. Only valid before visitTypeEnd, and if we are + /// visiting a random access type database. + TypeIndex CurrentTypeIndex; - TypeDatabase &TypeDB; + PointerUnion TypeDB; }; } // end namespace codeview Index: llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h +++ llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h @@ -47,6 +47,14 @@ return Error::success(); } + Error visitTypeBegin(CVType &Record, TypeIndex Index) override { + for (auto Visitor : Pipeline) { + if (auto EC = Visitor->visitTypeBegin(Record, Index)) + return EC; + } + return Error::success(); + } + Error visitTypeEnd(CVType &Record) override { for (auto Visitor : Pipeline) { if (auto EC = Visitor->visitTypeEnd(Record)) Index: llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h +++ llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h @@ -26,8 +26,15 @@ virtual Error visitUnknownType(CVType &Record) { return Error::success(); } /// Paired begin/end actions for all types. Receives all record data, /// including the fixed-length record prefix. visitTypeBegin() should return - /// the type of the Record, or an error if it cannot be determined. + /// the type of the Record, or an error if it cannot be determined. Exactly + /// one of the two visitTypeBegin methods will be called, depending on whether + /// records are being visited sequentially or randomly. An implementation + /// should be prepared to handle both (or assert if it can't handle random + /// access visitation). virtual Error visitTypeBegin(CVType &Record) { return Error::success(); } + virtual Error visitTypeBegin(CVType &Record, TypeIndex Index) { + return Error::success(); + } virtual Error visitTypeEnd(CVType &Record) { return Error::success(); } virtual Error visitUnknownMember(CVMemberRecord &Record) { Index: llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -76,7 +76,7 @@ Handlers.push_back(&Handler); } -Error CVTypeVisitor::visitTypeRecord(CVType &Record) { +Expected CVTypeVisitor::handleTypeServer(CVType &Record) { if (Record.Type == TypeLeafKind::LF_TYPESERVER2 && !Handlers.empty()) { auto TS = deserializeTypeServerRecord(Record); if (!TS) @@ -90,16 +90,16 @@ // If the handler processed the record, return success. if (*ExpectedResult) - return Error::success(); + return true; // Otherwise keep searching for a handler, eventually falling out and // using the default record handler. } } + return false; +} - if (auto EC = Callbacks.visitTypeBegin(Record)) - return EC; - +Error CVTypeVisitor::finishVisitation(CVType &Record) { switch (Record.Type) { default: if (auto EC = Callbacks.visitUnknownType(Record)) @@ -124,6 +124,32 @@ return Error::success(); } +Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) { + auto ExpectedResult = handleTypeServer(Record); + if (!ExpectedResult) + return ExpectedResult.takeError(); + if (*ExpectedResult) + return Error::success(); + + if (auto EC = Callbacks.visitTypeBegin(Record, Index)) + return EC; + + return finishVisitation(Record); +} + +Error CVTypeVisitor::visitTypeRecord(CVType &Record) { + auto ExpectedResult = handleTypeServer(Record); + if (!ExpectedResult) + return ExpectedResult.takeError(); + if (*ExpectedResult) + return Error::success(); + + if (auto EC = Callbacks.visitTypeBegin(Record)) + return EC; + + return finishVisitation(Record); +} + static Error visitMemberRecord(CVMemberRecord &Record, TypeVisitorCallbacks &Callbacks) { if (auto EC = Callbacks.visitMemberBegin(Record)) Index: llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp +++ llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp @@ -112,16 +112,60 @@ } const CVType &TypeDatabase::getTypeRecord(TypeIndex Index) const { - return TypeRecords[Index.getIndex() - TypeIndex::FirstNonSimpleIndex]; + return TypeRecords[zeroIndex(Index)]; } CVType &TypeDatabase::getTypeRecord(TypeIndex Index) { - return TypeRecords[Index.getIndex() - TypeIndex::FirstNonSimpleIndex]; + return TypeRecords[zeroIndex(Index)]; } bool TypeDatabase::containsTypeIndex(TypeIndex Index) const { - uint32_t I = Index.getIndex() - TypeIndex::FirstNonSimpleIndex; - return I < CVUDTNames.size(); + return zeroIndex(Index) < CVUDTNames.size(); } uint32_t TypeDatabase::size() const { return CVUDTNames.size(); } + +uint32_t TypeDatabase::zeroIndex(TypeIndex Index) const { + return Index.getIndex() - TypeIndex::FirstNonSimpleIndex; +} + +RandomAccessTypeDatabase::RandomAccessTypeDatabase(uint32_t ExpectedSize) + : TypeDatabase(ExpectedSize) { + ValidRecords.resize(ExpectedSize); + CVUDTNames.resize(ExpectedSize); + TypeRecords.resize(ExpectedSize); +} + +void RandomAccessTypeDatabase::recordType(StringRef Name, TypeIndex Index, + const CVType &Data) { + assert(!containsTypeIndex(Index)); + uint32_t ZI = Index.getIndex() - TypeIndex::FirstNonSimpleIndex; + + CVUDTNames[ZI] = Name; + TypeRecords[ZI] = Data; + ValidRecords.set(ZI); +} + +StringRef RandomAccessTypeDatabase::getTypeName(TypeIndex Index) const { + assert(containsTypeIndex(Index)); + return TypeDatabase::getTypeName(Index); +} + +const CVType &RandomAccessTypeDatabase::getTypeRecord(TypeIndex Index) const { + assert(containsTypeIndex(Index)); + return TypeDatabase::getTypeRecord(Index); +} + +CVType &RandomAccessTypeDatabase::getTypeRecord(TypeIndex Index) { + assert(containsTypeIndex(Index)); + return TypeDatabase::getTypeRecord(Index); +} + +bool RandomAccessTypeDatabase::containsTypeIndex(TypeIndex Index) const { + if (Index.isSimple()) + return true; + + return ValidRecords.test(zeroIndex(Index)); +} + +uint32_t RandomAccessTypeDatabase::size() const { return ValidRecords.count(); } Index: llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp +++ llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp @@ -15,7 +15,9 @@ using namespace llvm::codeview; -Error TypeDatabaseVisitor::visitTypeBegin(CVRecord &Record) { +Error TypeDatabaseVisitor::visitTypeBegin(CVType &Record) { + assert(TypeDB.is()); + assert(!IsInFieldList); // Reset Name to the empty string. If the visitor sets it, we know it. Name = ""; @@ -28,6 +30,34 @@ return Error::success(); } +StringRef TypeDatabaseVisitor::getTypeName(TypeIndex Index) const { + if (auto DB = TypeDB.get()) + return DB->getTypeName(Index); + else if (auto DB = TypeDB.get()) + return DB->getTypeName(Index); + + llvm_unreachable("Invalid TypeDB Kind!"); +} + +StringRef TypeDatabaseVisitor::saveTypeName(StringRef Name) { + if (auto DB = TypeDB.get()) + return DB->saveTypeName(Name); + else if (auto DB = TypeDB.get()) + return DB->saveTypeName(Name); + + llvm_unreachable("Invalid TypeDB Kind!"); +} + +Error TypeDatabaseVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) { + assert(TypeDB.is()); + + if (auto EC = visitTypeBegin(Record)) + return EC; + + CurrentTypeIndex = Index; + return Error::success(); +} + Error TypeDatabaseVisitor::visitTypeEnd(CVType &CVR) { if (CVR.Type == LF_FIELDLIST) { assert(IsInFieldList); @@ -39,7 +69,11 @@ // CVUDTNames is indexed by type index, and must have one entry for every // type. Field list members are not recorded, and are only referenced by // their containing field list record. - TypeDB.recordType(Name, CVR); + if (auto DB = TypeDB.get()) + DB->recordType(Name, CVR); + else if (auto DB = TypeDB.get()) + DB->recordType(Name, CurrentTypeIndex, CVR); + return Error::success(); } @@ -73,13 +107,13 @@ uint32_t Size = Indices.size(); SmallString<256> TypeName("("); for (uint32_t I = 0; I < Size; ++I) { - StringRef ArgTypeName = TypeDB.getTypeName(Indices[I]); + StringRef ArgTypeName = getTypeName(Indices[I]); TypeName.append(ArgTypeName); if (I + 1 != Size) TypeName.append(", "); } TypeName.push_back(')'); - Name = TypeDB.saveTypeName(TypeName); + Name = saveTypeName(TypeName); return Error::success(); } @@ -89,13 +123,13 @@ uint32_t Size = Indices.size(); SmallString<256> TypeName("\""); for (uint32_t I = 0; I < Size; ++I) { - StringRef ArgTypeName = TypeDB.getTypeName(Indices[I]); + StringRef ArgTypeName = getTypeName(Indices[I]); TypeName.append(ArgTypeName); if (I + 1 != Size) TypeName.append("\" \""); } TypeName.push_back('\"'); - Name = TypeDB.saveTypeName(TypeName); + Name = saveTypeName(TypeName); return Error::success(); } @@ -132,26 +166,26 @@ Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { - StringRef ReturnTypeName = TypeDB.getTypeName(Proc.getReturnType()); - StringRef ArgListTypeName = TypeDB.getTypeName(Proc.getArgumentList()); + StringRef ReturnTypeName = getTypeName(Proc.getReturnType()); + StringRef ArgListTypeName = getTypeName(Proc.getArgumentList()); SmallString<256> TypeName(ReturnTypeName); TypeName.push_back(' '); TypeName.append(ArgListTypeName); - Name = TypeDB.saveTypeName(TypeName); + Name = saveTypeName(TypeName); return Error::success(); } Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, MemberFunctionRecord &MF) { - StringRef ReturnTypeName = TypeDB.getTypeName(MF.getReturnType()); - StringRef ClassTypeName = TypeDB.getTypeName(MF.getClassType()); - StringRef ArgListTypeName = TypeDB.getTypeName(MF.getArgumentList()); + StringRef ReturnTypeName = getTypeName(MF.getReturnType()); + StringRef ClassTypeName = getTypeName(MF.getClassType()); + StringRef ArgListTypeName = getTypeName(MF.getArgumentList()); SmallString<256> TypeName(ReturnTypeName); TypeName.push_back(' '); TypeName.append(ClassTypeName); TypeName.append("::"); TypeName.append(ArgListTypeName); - Name = TypeDB.saveTypeName(TypeName); + Name = saveTypeName(TypeName); return Error::success(); } @@ -171,13 +205,13 @@ if (Ptr.isPointerToMember()) { const MemberPointerInfo &MI = Ptr.getMemberInfo(); - StringRef PointeeName = TypeDB.getTypeName(Ptr.getReferentType()); - StringRef ClassName = TypeDB.getTypeName(MI.getContainingType()); + StringRef PointeeName = getTypeName(Ptr.getReferentType()); + StringRef ClassName = getTypeName(MI.getContainingType()); SmallString<256> TypeName(PointeeName); TypeName.push_back(' '); TypeName.append(ClassName); TypeName.append("::*"); - Name = TypeDB.saveTypeName(TypeName); + Name = saveTypeName(TypeName); } else { SmallString<256> TypeName; if (Ptr.isConst()) @@ -187,7 +221,7 @@ if (Ptr.isUnaligned()) TypeName.append("__unaligned "); - TypeName.append(TypeDB.getTypeName(Ptr.getReferentType())); + TypeName.append(getTypeName(Ptr.getReferentType())); if (Ptr.getMode() == PointerMode::LValueReference) TypeName.append("&"); @@ -197,7 +231,7 @@ TypeName.append("*"); if (!TypeName.empty()) - Name = TypeDB.saveTypeName(TypeName); + Name = saveTypeName(TypeName); } return Error::success(); } @@ -205,7 +239,7 @@ Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { uint16_t Mods = static_cast(Mod.getModifiers()); - StringRef ModifiedName = TypeDB.getTypeName(Mod.getModifiedType()); + StringRef ModifiedName = getTypeName(Mod.getModifiedType()); SmallString<256> TypeName; if (Mods & uint16_t(ModifierOptions::Const)) TypeName.append("const "); @@ -214,14 +248,14 @@ if (Mods & uint16_t(ModifierOptions::Unaligned)) TypeName.append("__unaligned "); TypeName.append(ModifiedName); - Name = TypeDB.saveTypeName(TypeName); + Name = saveTypeName(TypeName); return Error::success(); } Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, VFTableShapeRecord &Shape) { - Name = TypeDB.saveTypeName(""); + Name = + saveTypeName(""); return Error::success(); }