summaryrefslogtreecommitdiffstats
path: root/llvm/lib/DebugInfo/CodeView
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2017-05-25 23:36:16 +0000
committerZachary Turner <zturner@google.com>2017-05-25 23:36:16 +0000
commitfed467eefb75e4af9ca1b534019eb5780aaf0984 (patch)
tree3bf789aa6b9aac17d8fc3992632e38276223e5ac /llvm/lib/DebugInfo/CodeView
parentd3bc3e01386f53924e66a1216364ab4acd784356 (diff)
downloadbcm5719-llvm-fed467eefb75e4af9ca1b534019eb5780aaf0984.tar.gz
bcm5719-llvm-fed467eefb75e4af9ca1b534019eb5780aaf0984.zip
[CV Type Merging] Find nested type indices faster.
Merging two type streams is one of the most time consuming parts of generating a PDB, and as such it needs to be as fast as possible. The visitor abstractions used for interoperating nicely with many different types of inputs and outputs have been used widely and help greatly for testability and implementing tools, but the abstractions build up and get in the way of performance. This patch removes all of the visitation stuff from the type stream merger, essentially re-inventing the leaf / member switch and loop, but at a very low level. This allows us many other optimizations, such as not actually deserializing *any* records (even member records which don't describe their own length), as the operation of "figure out how long this record is" is somewhat faster than "figure out how long this record *and* get all its fields out". Furthermore, whereas before we had to deserialize, re-write type indices, then re-serialize, now we don't have to do any of those 3 steps. We just find out where the type indices are and pull them directly out of the byte stream and re-write them. This is worth a 50-60% performance increase. On top of all other optimizations that have been applied this week, I now get the following numbers when linking lld.exe and lld.pdb MSVC: 25.67s Before This Patch: 18.59s After This Patch: 8.92s So this is a huge performance win. Differential Revision: https://reviews.llvm.org/D33564 llvm-svn: 303935
Diffstat (limited to 'llvm/lib/DebugInfo/CodeView')
-rw-r--r--llvm/lib/DebugInfo/CodeView/CMakeLists.txt1
-rw-r--r--llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp371
-rw-r--r--llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp388
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;
OpenPOWER on IntegriCloud