Index: llvm/trunk/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h @@ -76,6 +76,11 @@ Error visitRange(TypeIndex Begin, uint32_t BeginOffset, TypeIndex End); Error visitOneRecord(TypeIndex TI, uint32_t Offset, CVType &Record); + BumpPtrAllocator Allocator; + StringSaver NameStorage; + + SmallVector TypeNames; + /// Visited records get automatically added to the type database. TypeDatabase Database; Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeName.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeName.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeName.h @@ -0,0 +1,22 @@ +//===- TypeName.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_TYPENAME_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPENAME_H + +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" + +namespace llvm { +namespace codeview { +std::string computeTypeName(TypeCollection &Types, TypeIndex Index); +} +} // namespace llvm + +#endif Index: llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt +++ llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt @@ -29,6 +29,7 @@ TypeDumpVisitor.cpp TypeIndex.cpp TypeIndexDiscovery.cpp + TypeName.cpp TypeRecordMapping.cpp TypeSerializer.cpp TypeStreamMerger.cpp Index: llvm/trunk/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp @@ -12,6 +12,7 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeName.h" #include "llvm/DebugInfo/CodeView/TypeServerHandler.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" @@ -31,8 +32,8 @@ LazyRandomTypeCollection::LazyRandomTypeCollection( const CVTypeArray &Types, uint32_t RecordCountHint, PartialOffsetArray PartialOffsets) - : Database(RecordCountHint), Types(Types), DatabaseVisitor(Database), - PartialOffsets(PartialOffsets) { + : NameStorage(Allocator), Database(RecordCountHint), Types(Types), + DatabaseVisitor(Database), PartialOffsets(PartialOffsets) { KnownOffsets.resize(Database.capacity()); } @@ -71,15 +72,18 @@ } 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)); - } + if (Index.isNoneType() || Index.isSimple()) + return TypeIndex::simpleTypeName(Index); - return Database.getTypeName(Index); + uint32_t I = Index.toArrayIndex(); + if (I >= TypeNames.size()) + TypeNames.resize(I + 1); + + if (TypeNames[I].data() == nullptr) { + StringRef Result = NameStorage.save(computeTypeName(*this, Index)); + TypeNames[I] = Result; + } + return TypeNames[I]; } bool LazyRandomTypeCollection::contains(TypeIndex Index) { Index: llvm/trunk/lib/DebugInfo/CodeView/TypeName.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeName.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeName.cpp @@ -0,0 +1,243 @@ +//===- TypeName.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/TypeName.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; + +namespace { +class TypeNameComputer : public TypeVisitorCallbacks { + /// The type collection. Used to calculate names of nested types. + TypeCollection &Types; + TypeIndex CurrentTypeIndex = TypeIndex::None(); + + /// Name of the current type. Only valid before visitTypeEnd. + SmallString<256> Name; + +public: + explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {} + + StringRef name() const { return Name; } + + /// 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; + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" +}; +} // namespace + +Error TypeNameComputer::visitTypeBegin(CVType &Record) { + llvm_unreachable("Must call visitTypeBegin with a TypeIndex!"); + return Error::success(); +} + +Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) { + // Reset Name to the empty string. If the visitor sets it, we know it. + Name = ""; + CurrentTypeIndex = Index; + return Error::success(); +} + +Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); } + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + FieldListRecord &FieldList) { + Name = ""; + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVRecord &CVR, + StringIdRecord &String) { + Name = String.getString(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { + auto Indices = Args.getIndices(); + uint32_t Size = Indices.size(); + Name = "("; + for (uint32_t I = 0; I < Size; ++I) { + assert(Indices[I] < CurrentTypeIndex); + + Name.append(Types.getTypeName(Indices[I])); + if (I + 1 != Size) + Name.append(", "); + } + Name.push_back(')'); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + StringListRecord &Strings) { + auto Indices = Strings.getIndices(); + uint32_t Size = Indices.size(); + Name = "\""; + for (uint32_t I = 0; I < Size; ++I) { + Name.append(Types.getTypeName(Indices[I])); + if (I + 1 != Size) + Name.append("\" \""); + } + Name.push_back('\"'); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) { + Name = Class.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) { + Name = Union.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { + Name = Enum.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { + Name = AT.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { + Name = VFT.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { + Name = Id.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { + StringRef Ret = Types.getTypeName(Proc.getReturnType()); + StringRef Params = Types.getTypeName(Proc.getArgumentList()); + Name = formatv("{0} {1}", Ret, Params).sstr<256>(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + MemberFunctionRecord &MF) { + StringRef Ret = Types.getTypeName(MF.getReturnType()); + StringRef Class = Types.getTypeName(MF.getClassType()); + StringRef Params = Types.getTypeName(MF.getArgumentList()); + Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { + Name = Func.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { + Name = TS.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { + + if (Ptr.isPointerToMember()) { + const MemberPointerInfo &MI = Ptr.getMemberInfo(); + + StringRef Pointee = Types.getTypeName(Ptr.getReferentType()); + StringRef Class = Types.getTypeName(MI.getContainingType()); + Name = formatv("{0} {1}::*", Pointee, Class); + } else { + if (Ptr.isConst()) + Name.append("const "); + if (Ptr.isVolatile()) + Name.append("volatile "); + if (Ptr.isUnaligned()) + Name.append("__unaligned "); + + Name.append(Types.getTypeName(Ptr.getReferentType())); + + if (Ptr.getMode() == PointerMode::LValueReference) + Name.append("&"); + else if (Ptr.getMode() == PointerMode::RValueReference) + Name.append("&&"); + else if (Ptr.getMode() == PointerMode::Pointer) + Name.append("*"); + } + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { + uint16_t Mods = static_cast(Mod.getModifiers()); + + SmallString<256> TypeName; + if (Mods & uint16_t(ModifierOptions::Const)) + Name.append("const "); + if (Mods & uint16_t(ModifierOptions::Volatile)) + Name.append("volatile "); + if (Mods & uint16_t(ModifierOptions::Unaligned)) + Name.append("__unaligned "); + Name.append(Types.getTypeName(Mod.getModifiedType())); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Shape) { + Name = formatv("", Shape.getEntryCount()); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord( + CVType &CVR, UdtModSourceLineRecord &ModSourceLine) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &SourceLine) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + MethodOverloadListRecord &Overloads) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) { + return Error::success(); +} + +std::string llvm::codeview::computeTypeName(TypeCollection &Types, + TypeIndex Index) { + TypeNameComputer Computer(Types); + CVType Record = Types.getType(Index); + if (auto EC = visitTypeRecord(Record, Index, Computer)) { + consumeError(std::move(EC)); + return ""; + } + return Computer.name(); +} Index: llvm/trunk/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp =================================================================== --- llvm/trunk/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp +++ llvm/trunk/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp @@ -351,3 +351,54 @@ for (auto &I : enumerate(IndicesToVisit)) EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value())); } + +TEST_F(RandomAccessVisitorTest, CrossChunkName) { + TypeTableBuilder Builder(GlobalState->Allocator); + + // TypeIndex 0 + ClassRecord Class(TypeRecordKind::Class); + Class.Name = "FooClass"; + Class.Options = ClassOptions::None; + Class.MemberCount = 0; + Class.DerivationList = TypeIndex::fromArrayIndex(0); + Class.FieldList = TypeIndex::fromArrayIndex(0); + Class.VTableShape = TypeIndex::fromArrayIndex(0); + TypeIndex IndexZero = Builder.writeKnownType(Class); + + // TypeIndex 1 refers to type index 0. + ModifierRecord Modifier(TypeRecordKind::Modifier); + Modifier.ModifiedType = TypeIndex::fromArrayIndex(0); + Modifier.Modifiers = ModifierOptions::Const; + TypeIndex IndexOne = Builder.writeKnownType(Modifier); + + // set up a type stream that refers to the above two serialized records. + std::vector TypeArray; + TypeArray.push_back( + CVType(static_cast(Class.Kind), Builder.records()[0])); + TypeArray.push_back( + CVType(static_cast(Modifier.Kind), Builder.records()[1])); + BinaryItemStream ItemStream(llvm::support::little); + ItemStream.setItems(TypeArray); + VarStreamArray TypeStream(ItemStream); + + // Figure out the byte offset of the second item. + auto ItemOneIter = TypeStream.begin(); + ++ItemOneIter; + + // Set up a partial offsets buffer that contains the first and second items + // in separate chunks. + std::vector TIO; + TIO.push_back({IndexZero, ulittle32_t(0u)}); + TIO.push_back({IndexOne, ulittle32_t(ItemOneIter.offset())}); + ArrayRef Buffer(reinterpret_cast(TIO.data()), + TIO.size() * sizeof(TypeIndexOffset)); + + BinaryStreamReader Reader(Buffer, llvm::support::little); + FixedStreamArray PartialOffsets; + ASSERT_THAT_ERROR(Reader.readArray(PartialOffsets, 2), Succeeded()); + + LazyRandomTypeCollection Types(TypeStream, 2, PartialOffsets); + + StringRef Name = Types.getTypeName(IndexOne); + EXPECT_EQ("const FooClass", Name); +} \ No newline at end of file