diff options
Diffstat (limited to 'llvm/lib/DebugInfo/CodeView')
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp | 371 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp | 388 |
3 files changed, 413 insertions, 347 deletions
diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt index 556ebf78622..90193d07b95 100644 --- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -22,6 +22,7 @@ add_llvm_library(LLVMDebugInfoCodeView TypeDatabaseVisitor.cpp TypeDumpVisitor.cpp TypeIndex.cpp + TypeIndexDiscovery.cpp TypeRecordMapping.cpp TypeSerializer.cpp TypeStreamMerger.cpp diff --git a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp new file mode 100644 index 00000000000..11e2e215303 --- /dev/null +++ b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp @@ -0,0 +1,371 @@ +//===- TypeIndexDiscovery.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/TypeIndexDiscovery.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::codeview; + +static inline MethodKind getMethodKind(uint16_t Attrs) { + Attrs &= uint16_t(MethodOptions::MethodKindMask); + Attrs >>= 2; + return MethodKind(Attrs); +} + +static inline bool isIntroVirtual(uint16_t Attrs) { + MethodKind MK = getMethodKind(Attrs); + return MK == MethodKind::IntroducingVirtual || + MK == MethodKind::PureIntroducingVirtual; +} + +static inline PointerMode getPointerMode(uint32_t Attrs) { + return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) & + PointerRecord::PointerModeMask); +} + +static inline bool isMemberPointer(uint32_t Attrs) { + PointerMode Mode = getPointerMode(Attrs); + return Mode == PointerMode::PointerToDataMember || + Mode == PointerMode::PointerToDataMember; +} + +static inline uint32_t getEncodedIntegerLength(ArrayRef<uint8_t> Data) { + uint16_t N = support::endian::read16le(Data.data()); + if (N < LF_NUMERIC) + return 2; + + assert(N <= LF_UQUADWORD); + + constexpr uint32_t Sizes[] = { + 1, // LF_CHAR + 2, // LF_SHORT + 2, // LF_USHORT + 4, // LF_LONG + 4, // LF_ULONG + 4, // LF_REAL32 + 8, // LF_REAL64 + 10, // LF_REAL80 + 16, // LF_REAL128 + 8, // LF_QUADWORD + 8, // LF_UQUADWORD + }; + + return Sizes[N - LF_NUMERIC]; +} + +static inline uint32_t getCStringLength(ArrayRef<uint8_t> Data) { + const char *S = reinterpret_cast<const char *>(Data.data()); + return strlen(S) + 1; +} + +static void handleMethodOverloadList(ArrayRef<uint8_t> Content, + SmallVectorImpl<TiReference> &Refs) { + uint32_t Offset = 0; + + while (!Content.empty()) { + // Array of: + // 0: Attrs + // 2: Padding + // 4: TypeIndex + // if (isIntroVirtual()) + // 8: VFTableOffset + + // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an + // intro virtual. + uint32_t Len = 8; + + uint16_t Attrs = support::endian::read16le(Content.data()); + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + + if (LLVM_UNLIKELY(isIntroVirtual(Attrs))) + Len += 4; + Offset += Len; + Content = Content.drop_front(Len); + } +} + +static uint32_t handleBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + // 8: Encoded Integer + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8 + getEncodedIntegerLength(Data.drop_front(8)); +} + +static uint32_t handleEnumerator(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: Encoded Integer + // <next>: Name + uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4)); + return Size + getCStringLength(Data.drop_front(Size)); +} + +static uint32_t handleDataMember(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + // 8: Encoded Integer + // <next>: Name + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8)); + return Size + getCStringLength(Data.drop_front(Size)); +} + +static uint32_t handleOverloadedMethod(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + // 8: Name + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8 + getCStringLength(Data.drop_front(8)); +} + +static uint32_t handleOneMethod(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Attributes + // 4: Type + // if (isIntroVirtual) + // 8: VFTableOffset + // <next>: Name + uint32_t Size = 8; + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + + uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data()); + if (LLVM_UNLIKELY(isIntroVirtual(Attrs))) + Size += 4; + + return Size + getCStringLength(Data.drop_front(Size)); +} + +static uint32_t handleNestedType(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + // 8: Name + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8 + getCStringLength(Data.drop_front(8)); +} + +static uint32_t handleStaticDataMember(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + // 8: Name + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8 + getCStringLength(Data.drop_front(8)); +} + +static uint32_t handleVirtualBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset, + bool IsIndirect, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Attrs + // 4: TypeIndex + // 8: TypeIndex + // 12: Encoded Integer + // <next>: Encoded Integer + uint32_t Size = 12; + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2}); + Size += getEncodedIntegerLength(Data.drop_front(Size)); + Size += getEncodedIntegerLength(Data.drop_front(Size)); + return Size; +} + +static uint32_t handleVFPtr(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8; +} + +static uint32_t handleListContinuation(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8; +} + +static void handleFieldList(ArrayRef<uint8_t> Content, + SmallVectorImpl<TiReference> &Refs) { + uint32_t Offset = 0; + uint32_t ThisLen = 0; + while (!Content.empty()) { + TypeLeafKind Kind = + static_cast<TypeLeafKind>(support::endian::read16le(Content.data())); + switch (Kind) { + case LF_BCLASS: + ThisLen = handleBaseClass(Content, Offset, Refs); + break; + case LF_ENUMERATE: + ThisLen = handleEnumerator(Content, Offset, Refs); + break; + case LF_MEMBER: + ThisLen = handleDataMember(Content, Offset, Refs); + break; + case LF_METHOD: + ThisLen = handleOverloadedMethod(Content, Offset, Refs); + break; + case LF_ONEMETHOD: + ThisLen = handleOneMethod(Content, Offset, Refs); + break; + case LF_NESTTYPE: + ThisLen = handleNestedType(Content, Offset, Refs); + break; + case LF_STMEMBER: + ThisLen = handleStaticDataMember(Content, Offset, Refs); + break; + case LF_VBCLASS: + case LF_IVBCLASS: + ThisLen = + handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs); + break; + case LF_VFUNCTAB: + ThisLen = handleVFPtr(Content, Offset, Refs); + break; + case LF_INDEX: + ThisLen = handleListContinuation(Content, Offset, Refs); + break; + default: + return; + } + Content = Content.drop_front(ThisLen); + Offset += ThisLen; + if (!Content.empty()) { + uint8_t Pad = Content.front(); + if (Pad >= LF_PAD0) { + uint32_t Skip = Pad & 0x0F; + Content = Content.drop_front(Skip); + Offset += Skip; + } + } + } +} + +static void handlePointer(ArrayRef<uint8_t> Content, + SmallVectorImpl<TiReference> &Refs) { + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + + uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data()); + if (isMemberPointer(Attrs)) + Refs.push_back({TiRefKind::TypeRef, 8, 1}); +} + +static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind, + SmallVectorImpl<TiReference> &Refs) { + uint32_t Count; + // FIXME: In the future it would be nice if we could avoid hardcoding these + // values. One idea is to define some structures representing these types + // that would allow the use of offsetof(). + switch (Kind) { + case TypeLeafKind::LF_FUNC_ID: + Refs.push_back({TiRefKind::IndexRef, 0, 1}); + Refs.push_back({TiRefKind::TypeRef, 4, 1}); + break; + case TypeLeafKind::LF_MFUNC_ID: + Refs.push_back({TiRefKind::TypeRef, 0, 2}); + break; + case TypeLeafKind::LF_STRING_ID: + Refs.push_back({TiRefKind::IndexRef, 0, 1}); + break; + case TypeLeafKind::LF_SUBSTR_LIST: + Count = support::endian::read32le(Content.data()); + if (Count > 0) + Refs.push_back({TiRefKind::IndexRef, 4, Count}); + break; + case TypeLeafKind::LF_BUILDINFO: + Count = support::endian::read16le(Content.data()); + if (Count > 0) + Refs.push_back({TiRefKind::IndexRef, 2, Count}); + break; + case TypeLeafKind::LF_UDT_SRC_LINE: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + Refs.push_back({TiRefKind::IndexRef, 4, 1}); + break; + case TypeLeafKind::LF_UDT_MOD_SRC_LINE: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + break; + case TypeLeafKind::LF_MODIFIER: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + break; + case TypeLeafKind::LF_PROCEDURE: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + Refs.push_back({TiRefKind::TypeRef, 8, 1}); + break; + case TypeLeafKind::LF_MFUNCTION: + Refs.push_back({TiRefKind::TypeRef, 0, 3}); + Refs.push_back({TiRefKind::TypeRef, 16, 1}); + break; + case TypeLeafKind::LF_ARGLIST: + Count = support::endian::read32le(Content.data()); + if (Count > 0) + Refs.push_back({TiRefKind::TypeRef, 4, Count}); + break; + case TypeLeafKind::LF_ARRAY: + Refs.push_back({TiRefKind::TypeRef, 0, 2}); + break; + case TypeLeafKind::LF_CLASS: + case TypeLeafKind::LF_STRUCTURE: + case TypeLeafKind::LF_INTERFACE: + Refs.push_back({TiRefKind::TypeRef, 4, 3}); + break; + case TypeLeafKind::LF_UNION: + Refs.push_back({TiRefKind::TypeRef, 4, 1}); + break; + case TypeLeafKind::LF_ENUM: + Refs.push_back({TiRefKind::TypeRef, 4, 2}); + break; + case TypeLeafKind::LF_BITFIELD: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + break; + case TypeLeafKind::LF_VFTABLE: + Refs.push_back({TiRefKind::TypeRef, 0, 2}); + break; + case TypeLeafKind::LF_VTSHAPE: + break; + case TypeLeafKind::LF_METHODLIST: + handleMethodOverloadList(Content, Refs); + break; + case TypeLeafKind::LF_FIELDLIST: + handleFieldList(Content, Refs); + break; + case TypeLeafKind::LF_POINTER: + handlePointer(Content, Refs); + break; + default: + break; + } +} + +void llvm::codeview::discoverTypeIndices(const CVType &Type, + SmallVectorImpl<TiReference> &Refs) { + ::discoverTypeIndices(Type.content(), Type.kind(), Refs); +} + +void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData, + SmallVectorImpl<TiReference> &Refs) { + const RecordPrefix *P = + reinterpret_cast<const RecordPrefix *>(RecordData.data()); + TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind)); + ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs); +} diff --git a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp index c7f256b838a..261e89e1d3a 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" @@ -66,20 +67,8 @@ public: static const TypeIndex Untranslated; -/// TypeVisitorCallbacks overrides. -#define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; -#define MEMBER_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override; -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#include "llvm/DebugInfo/CodeView/TypeRecords.def" - - Error visitUnknownType(CVType &Record) override; - Error visitTypeBegin(CVType &Record) override; Error visitTypeEnd(CVType &Record) override; - Error visitMemberEnd(CVMemberRecord &Record) override; Error mergeTypesAndIds(TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes, const CVTypeArray &IdsAndTypes); @@ -96,29 +85,25 @@ private: bool remapTypeIndex(TypeIndex &Idx); bool remapItemIndex(TypeIndex &Idx); - bool remapIndices(RemappedType &Record, ArrayRef<uint32_t> TidOffs, - ArrayRef<uint32_t> IidOffs) { + bool remapIndices(RemappedType &Record, ArrayRef<TiReference> Refs) { auto OriginalData = Record.OriginalRecord.content(); bool Success = true; - for (auto Off : TidOffs) { - ArrayRef<uint8_t> Bytes = OriginalData.slice(Off, sizeof(TypeIndex)); - TypeIndex OldTI( - *reinterpret_cast<const support::ulittle32_t *>(Bytes.data())); - TypeIndex NewTI = OldTI; - bool ThisSuccess = remapTypeIndex(NewTI); - if (ThisSuccess && NewTI != OldTI) - Record.Mappings.emplace_back(Off, NewTI); - Success &= ThisSuccess; - } - for (auto Off : IidOffs) { - ArrayRef<uint8_t> Bytes = OriginalData.slice(Off, sizeof(TypeIndex)); - TypeIndex OldTI( - *reinterpret_cast<const support::ulittle32_t *>(Bytes.data())); - TypeIndex NewTI = OldTI; - bool ThisSuccess = remapItemIndex(NewTI); - if (ThisSuccess && NewTI != OldTI) - Record.Mappings.emplace_back(Off, NewTI); - Success &= ThisSuccess; + for (auto &Ref : Refs) { + uint32_t Offset = Ref.Offset; + ArrayRef<uint8_t> Bytes = + OriginalData.slice(Ref.Offset, sizeof(TypeIndex)); + ArrayRef<TypeIndex> TIs(reinterpret_cast<const TypeIndex *>(Bytes.data()), + Ref.Count); + for (auto TI : TIs) { + TypeIndex NewTI = TI; + bool ThisSuccess = (Ref.Kind == TiRefKind::IndexRef) + ? remapItemIndex(NewTI) + : remapTypeIndex(NewTI); + if (ThisSuccess && NewTI != TI) + Record.Mappings.emplace_back(Offset, NewTI); + Offset += sizeof(TypeIndex); + Success &= ThisSuccess; + } } return Success; } @@ -134,26 +119,6 @@ private: return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); } - template <typename RecordType> - Error writeKnownRecord(TypeTableBuilder &Dest, RecordType &R, - bool RemapSuccess) { - TypeIndex DestIdx = Untranslated; - if (RemapSuccess) - DestIdx = Dest.writeKnownType(R); - addMapping(DestIdx); - return Error::success(); - } - - template <typename RecordType> - Error writeKnownTypeRecord(RecordType &R, bool RemapSuccess) { - return writeKnownRecord(*DestTypeStream, R, RemapSuccess); - } - - template <typename RecordType> - Error writeKnownIdRecord(RecordType &R, bool RemapSuccess) { - return writeKnownRecord(*DestIdStream, R, RemapSuccess); - } - Error writeRecord(TypeTableBuilder &Dest, const RemappedType &Record, bool RemapSuccess) { TypeIndex DestIdx = Untranslated; @@ -178,15 +143,6 @@ private: return writeRecord(*DestIdStream, Record, RemapSuccess); } - template <typename RecordType> - Error writeMember(RecordType &R, bool RemapSuccess) { - if (RemapSuccess) - FieldListBuilder->writeMemberType(R); - else - HadUntranslatedMember = true; - return Error::success(); - } - Optional<Error> LastError; bool IsSecondPass = false; @@ -195,13 +151,10 @@ private: unsigned NumBadIndices = 0; - BumpPtrAllocator Allocator; - TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex}; TypeTableBuilder *DestIdStream = nullptr; TypeTableBuilder *DestTypeStream = nullptr; - std::unique_ptr<FieldListRecordBuilder> FieldListBuilder; TypeServerHandler *Handler = nullptr; // If we're only mapping id records, this array contains the mapping for @@ -217,7 +170,25 @@ private: const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated); -Error TypeStreamMerger::visitTypeBegin(CVType &Rec) { return Error::success(); } +Error TypeStreamMerger::visitTypeBegin(CVType &Rec) { + RemappedType R(Rec); + SmallVector<TiReference, 32> Refs; + discoverTypeIndices(Rec.RecordData, Refs); + bool Success = remapIndices(R, Refs); + switch (Rec.kind()) { + case TypeLeafKind::LF_FUNC_ID: + case TypeLeafKind::LF_MFUNC_ID: + case TypeLeafKind::LF_STRING_ID: + case TypeLeafKind::LF_SUBSTR_LIST: + case TypeLeafKind::LF_BUILDINFO: + case TypeLeafKind::LF_UDT_SRC_LINE: + case TypeLeafKind::LF_UDT_MOD_SRC_LINE: + return writeIdRecord(R, Success); + default: + return writeTypeRecord(R, Success); + } + return Error::success(); +} Error TypeStreamMerger::visitTypeEnd(CVType &Rec) { ++CurIndex; @@ -227,10 +198,6 @@ Error TypeStreamMerger::visitTypeEnd(CVType &Rec) { return Error::success(); } -Error TypeStreamMerger::visitMemberEnd(CVMemberRecord &Rec) { - return Error::success(); -} - void TypeStreamMerger::addMapping(TypeIndex Idx) { if (!IsSecondPass) { assert(IndexMap.size() == slotForIndex(CurIndex) && @@ -290,283 +257,6 @@ bool TypeStreamMerger::remapItemIndex(TypeIndex &Idx) { return remapIndex(Idx, IndexMap); } -//----------------------------------------------------------------------------// -// Item records -//----------------------------------------------------------------------------// - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, FuncIdRecord &R) { - assert(DestIdStream); - - RemappedType RR(CVR); - return writeIdRecord(RR, remapIndices(RR, {4}, {0})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &R) { - assert(DestIdStream); - - RemappedType RR(CVR); - return writeIdRecord(RR, remapIndices(RR, {0, 4}, {})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, StringIdRecord &R) { - assert(DestIdStream); - - RemappedType RR(CVR); - return writeIdRecord(RR, remapIndices(RR, {}, {0})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, StringListRecord &R) { - assert(DestIdStream); - - if (auto EC = TypeDeserializer::deserializeAs<StringListRecord>(CVR, R)) - return EC; - bool Success = true; - - for (TypeIndex &Id : R.StringIndices) - Success &= remapItemIndex(Id); - return writeKnownIdRecord(R, Success); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, BuildInfoRecord &R) { - assert(DestIdStream); - - if (auto EC = TypeDeserializer::deserializeAs(CVR, R)) - return EC; - - bool Success = true; - for (TypeIndex &Str : R.ArgIndices) - Success &= remapItemIndex(Str); - return writeKnownIdRecord(R, Success); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, UdtSourceLineRecord &R) { - assert(DestIdStream); - - RemappedType RR(CVR); - - // FIXME: Translate UdtSourceLineRecord into UdtModSourceLineRecords in the - // IPI stream. - return writeIdRecord(RR, remapIndices(RR, {0}, {4})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, - UdtModSourceLineRecord &R) { - assert(DestIdStream); - - RemappedType RR(CVR); - - // UdtModSourceLine Source File Ids are offsets into the global string table, - // not type indices. - // FIXME: We need to merge string table records for this to be valid. - return writeIdRecord(RR, remapIndices(RR, {0}, {})); -} - -//----------------------------------------------------------------------------// -// Type records -//----------------------------------------------------------------------------// - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ModifierRecord &R) { - assert(DestTypeStream); - - RemappedType RR(CVR); - return writeTypeRecord(RR, remapIndices(RR, {0}, {})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ProcedureRecord &R) { - assert(DestTypeStream); - - RemappedType RR(CVR); - return writeTypeRecord(RR, remapIndices(RR, {0, 8}, {})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, MemberFunctionRecord &R) { - assert(DestTypeStream); - - RemappedType RR(CVR); - return writeTypeRecord(RR, remapIndices(RR, {0, 4, 8, 16}, {})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ArgListRecord &R) { - assert(DestTypeStream); - - if (auto EC = TypeDeserializer::deserializeAs(CVR, R)) - return EC; - - bool Success = true; - for (TypeIndex &Arg : R.ArgIndices) - Success &= remapTypeIndex(Arg); - - return writeKnownTypeRecord(R, Success); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, PointerRecord &R) { - assert(DestTypeStream); - - // Pointer records have a different number of TypeIndex mappings depending - // on whether or not it is a pointer to member. - if (auto EC = TypeDeserializer::deserializeAs(CVR, R)) - return EC; - - bool Success = remapTypeIndex(R.ReferentType); - if (R.isPointerToMember()) - Success &= remapTypeIndex(R.MemberInfo->ContainingType); - return writeKnownTypeRecord(R, Success); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ArrayRecord &R) { - assert(DestTypeStream); - - RemappedType RR(CVR); - return writeTypeRecord(RR, remapIndices(RR, {0, 4}, {})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ClassRecord &R) { - assert(DestTypeStream); - - RemappedType RR(CVR); - return writeTypeRecord(RR, remapIndices(RR, {4, 8, 12}, {})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, UnionRecord &R) { - assert(DestTypeStream); - - RemappedType RR(CVR); - return writeTypeRecord(RR, remapIndices(RR, {4}, {})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, EnumRecord &R) { - assert(DestTypeStream); - - RemappedType RR(CVR); - return writeTypeRecord(RR, remapIndices(RR, {4, 8}, {})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, BitFieldRecord &R) { - assert(DestTypeStream); - - RemappedType RR(CVR); - return writeTypeRecord(RR, remapIndices(RR, {0}, {})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, VFTableShapeRecord &R) { - assert(DestTypeStream); - - return writeTypeRecord(CVR); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, TypeServer2Record &R) { - assert(DestTypeStream); - - return writeTypeRecord(CVR); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, LabelRecord &R) { - assert(DestTypeStream); - - return writeTypeRecord(CVR); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, VFTableRecord &R) { - assert(DestTypeStream); - - RemappedType RR(CVR); - return writeTypeRecord(RR, remapIndices(RR, {0, 4}, {})); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, - MethodOverloadListRecord &R) { - assert(DestTypeStream); - - if (auto EC = TypeDeserializer::deserializeAs(CVR, R)) - return EC; - - bool Success = true; - for (OneMethodRecord &Meth : R.Methods) - Success &= remapTypeIndex(Meth.Type); - return writeKnownTypeRecord(R, Success); -} - -Error TypeStreamMerger::visitKnownRecord(CVType &CVR, FieldListRecord &R) { - assert(DestTypeStream); - // Visit the members inside the field list. - HadUntranslatedMember = false; - if (!FieldListBuilder) - FieldListBuilder = - llvm::make_unique<FieldListRecordBuilder>(*DestTypeStream); - - FieldListBuilder->begin(); - if (auto EC = codeview::visitMemberRecordStream(CVR.content(), *this)) - return EC; - - // Write the record if we translated all field list members. - TypeIndex DestIdx = FieldListBuilder->end(!HadUntranslatedMember); - addMapping(HadUntranslatedMember ? Untranslated : DestIdx); - - return Error::success(); -} - -//----------------------------------------------------------------------------// -// Member records -//----------------------------------------------------------------------------// - -Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, - NestedTypeRecord &R) { - return writeMember(R, remapTypeIndex(R.Type)); -} - -Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, OneMethodRecord &R) { - bool Success = true; - Success &= remapTypeIndex(R.Type); - return writeMember(R, Success); -} - -Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, - OverloadedMethodRecord &R) { - return writeMember(R, remapTypeIndex(R.MethodList)); -} - -Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, - DataMemberRecord &R) { - return writeMember(R, remapTypeIndex(R.Type)); -} - -Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, - StaticDataMemberRecord &R) { - return writeMember(R, remapTypeIndex(R.Type)); -} - -Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, - EnumeratorRecord &R) { - return writeMember(R, true); -} - -Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, VFPtrRecord &R) { - return writeMember(R, remapTypeIndex(R.Type)); -} - -Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, BaseClassRecord &R) { - return writeMember(R, remapTypeIndex(R.Type)); -} - -Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, - VirtualBaseClassRecord &R) { - bool Success = true; - Success &= remapTypeIndex(R.BaseType); - Success &= remapTypeIndex(R.VBPtrType); - return writeMember(R, Success); -} - -Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, - ListContinuationRecord &R) { - return writeMember(R, remapTypeIndex(R.ContinuationIndex)); -} - -Error TypeStreamMerger::visitUnknownType(CVType &Rec) { - // We failed to translate a type. Translate this index as "not translated". - addMapping(TypeIndex(SimpleTypeKind::NotTranslated)); - return errorCorruptRecord(); -} - Error TypeStreamMerger::mergeTypeRecords(TypeTableBuilder &Dest, const CVTypeArray &Types) { DestTypeStream = &Dest; @@ -598,6 +288,10 @@ Error TypeStreamMerger::doit(const CVTypeArray &Types) { // We don't want to deserialize records. I guess this flag is poorly named, // but it really means "Don't deserialize records before switching on the // concrete type. + // FIXME: We can probably get even more speed here if we don't use the visitor + // pipeline here, but instead write the switch ourselves. I don't think it + // would buy us much since it's already pretty fast, but it's probably worth + // a few cycles. if (auto EC = codeview::visitTypeStream(Types, *this, VDS_BytesExternal, Handler)) return EC; |

