Index: llvm/trunk/include/llvm/DebugInfo/CodeView/CVRecord.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/CVRecord.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -14,6 +14,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" @@ -50,6 +51,13 @@ Optional Hash; }; +template struct RemappedRecord { + explicit RemappedRecord(const CVRecord &R) : OriginalRecord(R) {} + + CVRecord OriginalRecord; + SmallVector, 8> Mappings; +}; + } // end namespace codeview template Index: llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -46,6 +46,7 @@ TypeVisitorCallbacks &Callbacks); Error visitTypeStream(const CVTypeArray &Types, TypeVisitorCallbacks &Callbacks, + VisitorDataSource Source = VDS_BytesPresent, TypeServerHandler *TS = nullptr); Error visitTypeStream(CVTypeRange Types, TypeVisitorCallbacks &Callbacks, TypeServerHandler *TS = nullptr); Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDeserializer.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDeserializer.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDeserializer.h @@ -40,6 +40,17 @@ public: TypeDeserializer() = default; + template static Error deserializeAs(CVType &CVT, T &Record) { + MappingInfo I(CVT.content()); + if (auto EC = I.Mapping.visitTypeBegin(CVT)) + return EC; + if (auto EC = I.Mapping.visitKnownRecord(CVT, Record)) + return EC; + if (auto EC = I.Mapping.visitTypeEnd(CVT)) + return EC; + return Error::success(); + } + Error visitTypeBegin(CVType &Record) override { assert(!Mapping && "Already in a type mapping!"); Mapping = llvm::make_unique(Record.content()); Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -35,6 +35,7 @@ using support::ulittle32_t; typedef CVRecord CVType; +typedef RemappedRecord RemappedType; struct CVMemberRecord { TypeLeafKind Kind; Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializer.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializer.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializer.h @@ -63,6 +63,15 @@ /// Private type record hashing implementation details are handled here. std::unique_ptr Hasher; + /// Contains a list of all records indexed by TypeIndex.toArrayIndex(). + SmallVector, 2> SeenRecords; + + /// Temporary storage that we use to copy a record's data while re-writing + /// its type indices. + SmallVector RemapStorage; + + TypeIndex nextTypeIndex() const; + bool isInFieldList() const; MutableArrayRef getCurrentSubRecordData(); MutableArrayRef getCurrentRecordData(); @@ -72,11 +81,12 @@ addPadding(MutableArrayRef Record); public: - explicit TypeSerializer(BumpPtrAllocator &Storage); + explicit TypeSerializer(BumpPtrAllocator &Storage, bool Hash = true); ~TypeSerializer(); ArrayRef> records() const; - TypeIndex insertRecordBytes(ArrayRef Record); + TypeIndex insertRecordBytes(ArrayRef &Record); + TypeIndex insertRecord(const RemappedType &Record); Expected visitTypeEndGetIndex(CVType &Record); Error visitTypeBegin(CVType &Record) override; Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h @@ -68,6 +68,10 @@ return Serializer.insertRecordBytes(Record); } + TypeIndex writeSerializedRecord(const RemappedType &Record) { + return Serializer.insertRecord(Record); + } + template void ForEachRecord(TFunc Func) { uint32_t Index = TypeIndex::FirstNonSimpleIndex; @@ -88,7 +92,7 @@ public: explicit FieldListRecordBuilder(TypeTableBuilder &TypeTable) - : TypeTable(TypeTable), TempSerializer(Allocator) { + : TypeTable(TypeTable), TempSerializer(Allocator, false) { Type.Type = TypeLeafKind::LF_FIELDLIST; } Index: llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -45,24 +45,9 @@ } static Expected deserializeTypeServerRecord(CVType &Record) { - class StealTypeServerVisitor : public TypeVisitorCallbacks { - public: - explicit StealTypeServerVisitor(TypeServer2Record &TR) : TR(TR) {} - - Error visitKnownRecord(CVType &CVR, TypeServer2Record &Record) override { - TR = Record; - return Error::success(); - } - - private: - TypeServer2Record &TR; - }; - TypeServer2Record R(TypeRecordKind::TypeServer2); - StealTypeServerVisitor Thief(R); - if (auto EC = visitTypeRecord(Record, Thief)) + if (auto EC = TypeDeserializer::deserializeAs(Record, R)) return std::move(EC); - return R; } @@ -308,8 +293,9 @@ Error llvm::codeview::visitTypeStream(const CVTypeArray &Types, TypeVisitorCallbacks &Callbacks, + VisitorDataSource Source, TypeServerHandler *TS) { - VisitHelper V(Callbacks, VDS_BytesPresent); + VisitHelper V(Callbacks, Source); if (TS) V.Visitor.addTypeServerHandler(*TS); return V.Visitor.visitTypeStream(Types); Index: llvm/trunk/lib/DebugInfo/CodeView/TypeSerializer.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeSerializer.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeSerializer.cpp @@ -75,29 +75,23 @@ /// entries are small and easy to rehash. DenseSet HashedRecords; - SmallVector, 2> SeenRecords; - - TypeIndex NextTypeIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex); - public: TypeHasher(BumpPtrAllocator &RecordStorage) : RecordStorage(RecordStorage) {} - ArrayRef> records() const { return SeenRecords; } - /// Takes the bytes of type record, inserts them into the hash table, saves /// them, and returns a pointer to an identical stable type record along with /// its type index in the destination stream. - TypeIndex getOrCreateRecord(ArrayRef &Record); + TypeIndex getOrCreateRecord(ArrayRef &Record, TypeIndex TI); }; -TypeIndex TypeHasher::getOrCreateRecord(ArrayRef &Record) { +TypeIndex TypeHasher::getOrCreateRecord(ArrayRef &Record, + TypeIndex TI) { assert(Record.size() < UINT32_MAX && "Record too big"); assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!"); // Compute the hash up front so we can store it in the key. HashedType TempHashedType = {hash_value(Record), Record.data(), - unsigned(Record.size()), NextTypeIndex}; - + unsigned(Record.size()), TI}; auto Result = HashedRecords.insert(HashedTypePtr(&TempHashedType)); HashedType *&Hashed = Result.first->Ptr; @@ -111,20 +105,15 @@ memcpy(Stable, Record.data(), Record.size()); Hashed->Data = Stable; assert(Hashed->Size == Record.size()); - - // This was a new record, so increment our next type index. - ++NextTypeIndex; } // Update the caller's copy of Record to point a stable copy. Record = ArrayRef(Hashed->Data, Hashed->Size); + return Hashed->Index; +} - if (Result.second) { - // FIXME: Can we record these in a more efficient way? - SeenRecords.push_back(Record); - } - - return TypeIndex(Hashed->Index); +TypeIndex TypeSerializer::nextTypeIndex() const { + return TypeIndex::fromArrayIndex(SeenRecords.size()); } bool TypeSerializer::isInFieldList() const { @@ -166,26 +155,68 @@ return MutableArrayRef(Record.data(), Record.size() + N); } -TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage) +TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage, bool Hash) : RecordStorage(Storage), RecordBuffer(MaxRecordLength * 2), Stream(RecordBuffer, llvm::support::little), Writer(Stream), - Mapping(Writer), Hasher(make_unique(Storage)) { + Mapping(Writer) { // RecordBuffer needs to be able to hold enough data so that if we are 1 // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes, // we won't overflow. + if (Hash) + Hasher = make_unique(Storage); } TypeSerializer::~TypeSerializer() = default; ArrayRef> TypeSerializer::records() const { - return Hasher->records(); + return SeenRecords; } -TypeIndex TypeSerializer::insertRecordBytes(ArrayRef Record) { +TypeIndex TypeSerializer::insertRecordBytes(ArrayRef &Record) { assert(!TypeKind.hasValue() && "Already in a type mapping!"); assert(Writer.getOffset() == 0 && "Stream has data already!"); - return Hasher->getOrCreateRecord(Record); + if (Hasher) { + TypeIndex ActualTI = Hasher->getOrCreateRecord(Record, nextTypeIndex()); + if (nextTypeIndex() == ActualTI) + SeenRecords.push_back(Record); + return ActualTI; + } + + TypeIndex NewTI = nextTypeIndex(); + uint8_t *Stable = RecordStorage.Allocate(Record.size()); + memcpy(Stable, Record.data(), Record.size()); + Record = ArrayRef(Stable, Record.size()); + SeenRecords.push_back(Record); + return NewTI; +} + +TypeIndex TypeSerializer::insertRecord(const RemappedType &Record) { + assert(!TypeKind.hasValue() && "Already in a type mapping!"); + assert(Writer.getOffset() == 0 && "Stream has data already!"); + + TypeIndex TI; + ArrayRef OriginalData = Record.OriginalRecord.RecordData; + if (Record.Mappings.empty()) { + // This record did not remap any type indices. Just write it. + return insertRecordBytes(OriginalData); + } + + // At least one type index was remapped. Before we can hash it we have to + // copy the full record bytes, re-write each type index, then hash the copy. + // We do this in temporary storage since only the DenseMap can decide whether + // this record already exists, and if it does we don't want the memory to + // stick around. + RemapStorage.resize(OriginalData.size()); + ::memcpy(&RemapStorage[0], OriginalData.data(), OriginalData.size()); + uint8_t *ContentBegin = RemapStorage.data() + sizeof(RecordPrefix); + for (const auto &M : Record.Mappings) { + // First 4 bytes of every record are the record prefix, but the mapping + // offset is relative to the content which starts after. + *(TypeIndex *)(ContentBegin + M.first) = M.second; + } + auto RemapRef = makeArrayRef(RemapStorage); + return insertRecordBytes(RemapRef); } Error TypeSerializer::visitTypeBegin(CVType &Record) { @@ -221,7 +252,12 @@ Record.Type = *TypeKind; Record.RecordData = ThisRecordData; - TypeIndex InsertedTypeIndex = Hasher->getOrCreateRecord(Record.RecordData); + + // insertRecordBytes assumes we're not in a mapping, so do this first. + TypeKind.reset(); + Writer.setOffset(0); + + TypeIndex InsertedTypeIndex = insertRecordBytes(Record.RecordData); // Write out each additional segment in reverse order, and update each // record's continuation index to point to the previous one. @@ -231,11 +267,9 @@ reinterpret_cast(CIBytes.data()); assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder"); *CI = InsertedTypeIndex.getIndex(); - InsertedTypeIndex = Hasher->getOrCreateRecord(X); + InsertedTypeIndex = insertRecordBytes(X); } - TypeKind.reset(); - Writer.setOffset(0); FieldListSegments.clear(); CurrentSegment.SubRecords.clear(); Index: llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -11,6 +11,7 @@ #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" @@ -95,6 +96,33 @@ bool remapTypeIndex(TypeIndex &Idx); bool remapItemIndex(TypeIndex &Idx); + bool remapIndices(RemappedType &Record, ArrayRef TidOffs, + ArrayRef IidOffs) { + auto OriginalData = Record.OriginalRecord.content(); + bool Success = true; + for (auto Off : TidOffs) { + ArrayRef Bytes = OriginalData.slice(Off, sizeof(TypeIndex)); + TypeIndex OldTI( + *reinterpret_cast(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 Bytes = OriginalData.slice(Off, sizeof(TypeIndex)); + TypeIndex OldTI( + *reinterpret_cast(Bytes.data())); + TypeIndex NewTI = OldTI; + bool ThisSuccess = remapItemIndex(NewTI); + if (ThisSuccess && NewTI != OldTI) + Record.Mappings.emplace_back(Off, NewTI); + Success &= ThisSuccess; + } + return Success; + } + bool remapIndex(TypeIndex &Idx, ArrayRef Map); size_t slotForIndex(TypeIndex Idx) const { @@ -107,23 +135,49 @@ } template - Error writeRecord(RecordType &R, bool RemapSuccess) { + Error writeKnownRecord(TypeTableBuilder &Dest, RecordType &R, + bool RemapSuccess) { TypeIndex DestIdx = Untranslated; if (RemapSuccess) - DestIdx = DestTypeStream->writeKnownType(R); + DestIdx = Dest.writeKnownType(R); addMapping(DestIdx); return Error::success(); } template - Error writeIdRecord(RecordType &R, bool RemapSuccess) { + Error writeKnownTypeRecord(RecordType &R, bool RemapSuccess) { + return writeKnownRecord(*DestTypeStream, R, RemapSuccess); + } + + template + Error writeKnownIdRecord(RecordType &R, bool RemapSuccess) { + return writeKnownRecord(*DestIdStream, R, RemapSuccess); + } + + Error writeRecord(TypeTableBuilder &Dest, const RemappedType &Record, + bool RemapSuccess) { TypeIndex DestIdx = Untranslated; if (RemapSuccess) - DestIdx = DestIdStream->writeKnownType(R); + DestIdx = Dest.writeSerializedRecord(Record); addMapping(DestIdx); return Error::success(); } + Error writeTypeRecord(const CVType &Record) { + TypeIndex DestIdx = + DestTypeStream->writeSerializedRecord(Record.RecordData); + addMapping(DestIdx); + return Error::success(); + } + + Error writeTypeRecord(const RemappedType &Record, bool RemapSuccess) { + return writeRecord(*DestTypeStream, Record, RemapSuccess); + } + + Error writeIdRecord(const RemappedType &Record, bool RemapSuccess) { + return writeRecord(*DestIdStream, Record, RemapSuccess); + } + template Error writeMember(RecordType &R, bool RemapSuccess) { if (RemapSuccess) @@ -163,12 +217,10 @@ const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated); -Error TypeStreamMerger::visitTypeBegin(CVRecord &Rec) { - return Error::success(); -} +Error TypeStreamMerger::visitTypeBegin(CVType &Rec) { return Error::success(); } -Error TypeStreamMerger::visitTypeEnd(CVRecord &Rec) { - CurIndex = TypeIndex(CurIndex.getIndex() + 1); +Error TypeStreamMerger::visitTypeEnd(CVType &Rec) { + ++CurIndex; if (!IsSecondPass) assert(IndexMap.size() == slotForIndex(CurIndex) && "visitKnownRecord should add one index map entry"); @@ -242,184 +294,206 @@ // Item records //----------------------------------------------------------------------------// -Error TypeStreamMerger::visitKnownRecord(CVType &, FuncIdRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, FuncIdRecord &R) { assert(DestIdStream); - bool Success = true; - Success &= remapItemIndex(R.ParentScope); - Success &= remapTypeIndex(R.FunctionType); - return writeIdRecord(R, Success); + + RemappedType RR(CVR); + return writeIdRecord(RR, remapIndices(RR, {4}, {0})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFuncIdRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &R) { assert(DestIdStream); - bool Success = true; - Success &= remapTypeIndex(R.ClassType); - Success &= remapTypeIndex(R.FunctionType); - return writeIdRecord(R, Success); + + RemappedType RR(CVR); + return writeIdRecord(RR, remapIndices(RR, {0, 4}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, StringIdRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, StringIdRecord &R) { assert(DestIdStream); - return writeIdRecord(R, remapItemIndex(R.Id)); + + RemappedType RR(CVR); + return writeIdRecord(RR, remapIndices(RR, {}, {0})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, StringListRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, StringListRecord &R) { assert(DestIdStream); + + if (auto EC = TypeDeserializer::deserializeAs(CVR, R)) + return EC; bool Success = true; - for (TypeIndex &Str : R.StringIndices) - Success &= remapItemIndex(Str); - return writeIdRecord(R, Success); + + for (TypeIndex &Id : R.StringIndices) + Success &= remapItemIndex(Id); + return writeKnownIdRecord(R, Success); } -Error TypeStreamMerger::visitKnownRecord(CVType &, BuildInfoRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, BuildInfoRecord &R) { assert(DestIdStream); + + if (auto EC = TypeDeserializer::deserializeAs(CVR, R)) + return EC; + bool Success = true; - for (TypeIndex &Arg : R.ArgIndices) - Success &= remapItemIndex(Arg); - return writeIdRecord(R, Success); + for (TypeIndex &Str : R.ArgIndices) + Success &= remapItemIndex(Str); + return writeKnownIdRecord(R, Success); } -Error TypeStreamMerger::visitKnownRecord(CVType &, UdtSourceLineRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, UdtSourceLineRecord &R) { assert(DestIdStream); - bool Success = true; - Success &= remapTypeIndex(R.UDT); - Success &= remapItemIndex(R.SourceFile); + + RemappedType RR(CVR); + // FIXME: Translate UdtSourceLineRecord into UdtModSourceLineRecords in the // IPI stream. - return writeIdRecord(R, Success); + return writeIdRecord(RR, remapIndices(RR, {0}, {4})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, UdtModSourceLineRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, + UdtModSourceLineRecord &R) { assert(DestIdStream); - bool Success = true; - Success &= remapTypeIndex(R.UDT); - // UdtModSourceLine Source File Ids are offsets into the global string table. + + 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. - // Success &= remapItemIndex(R.SourceFile); - return writeIdRecord(R, Success); + return writeIdRecord(RR, remapIndices(RR, {0}, {})); } //----------------------------------------------------------------------------// // Type records //----------------------------------------------------------------------------// -Error TypeStreamMerger::visitKnownRecord(CVType &, ModifierRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ModifierRecord &R) { assert(DestTypeStream); - return writeRecord(R, remapTypeIndex(R.ModifiedType)); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, ProcedureRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ProcedureRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.ReturnType); - Success &= remapTypeIndex(R.ArgumentList); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0, 8}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFunctionRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, MemberFunctionRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.ReturnType); - Success &= remapTypeIndex(R.ClassType); - Success &= remapTypeIndex(R.ThisType); - Success &= remapTypeIndex(R.ArgumentList); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0, 4, 8, 16}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &Type, ArgListRecord &R) { +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); - if (auto EC = writeRecord(R, Success)) - return EC; - return Error::success(); + + return writeKnownTypeRecord(R, Success); } -Error TypeStreamMerger::visitKnownRecord(CVType &, PointerRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, PointerRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.ReferentType); + + // 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 writeRecord(R, Success); + return writeKnownTypeRecord(R, Success); } -Error TypeStreamMerger::visitKnownRecord(CVType &, ArrayRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ArrayRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.ElementType); - Success &= remapTypeIndex(R.IndexType); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0, 4}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, ClassRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ClassRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.FieldList); - Success &= remapTypeIndex(R.DerivationList); - Success &= remapTypeIndex(R.VTableShape); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {4, 8, 12}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, UnionRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, UnionRecord &R) { assert(DestTypeStream); - return writeRecord(R, remapTypeIndex(R.FieldList)); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {4}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, EnumRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, EnumRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.FieldList); - Success &= remapTypeIndex(R.UnderlyingType); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {4, 8}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, BitFieldRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, BitFieldRecord &R) { assert(DestTypeStream); - return writeRecord(R, remapTypeIndex(R.Type)); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableShapeRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, VFTableShapeRecord &R) { assert(DestTypeStream); - return writeRecord(R, true); + + return writeTypeRecord(CVR); } -Error TypeStreamMerger::visitKnownRecord(CVType &, TypeServer2Record &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, TypeServer2Record &R) { assert(DestTypeStream); - return writeRecord(R, true); + + return writeTypeRecord(CVR); } -Error TypeStreamMerger::visitKnownRecord(CVType &, LabelRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, LabelRecord &R) { assert(DestTypeStream); - return writeRecord(R, true); + + return writeTypeRecord(CVR); } -Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, VFTableRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.CompleteClass); - Success &= remapTypeIndex(R.OverriddenVFTable); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0, 4}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, +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 writeRecord(R, Success); + return writeKnownTypeRecord(R, Success); } -Error TypeStreamMerger::visitKnownRecord(CVType &, FieldListRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, FieldListRecord &R) { assert(DestTypeStream); // Visit the members inside the field list. HadUntranslatedMember = false; FieldListBuilder = llvm::make_unique(*DestTypeStream); FieldListBuilder->begin(); - if (auto EC = codeview::visitMemberRecordStream(R.Data, *this)) + if (auto EC = codeview::visitMemberRecordStream(CVR.content(), *this)) return EC; // Write the record if we translated all field list members. @@ -524,7 +598,11 @@ Error TypeStreamMerger::doit(const CVTypeArray &Types) { LastError = Error::success(); - if (auto EC = codeview::visitTypeStream(Types, *this, Handler)) + // 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. + if (auto EC = + codeview::visitTypeStream(Types, *this, VDS_BytesExternal, Handler)) return EC; // If we found bad indices but no other errors, try doing another pass and see @@ -540,7 +618,8 @@ NumBadIndices = 0; CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex); - if (auto EC = codeview::visitTypeStream(Types, *this, Handler)) + if (auto EC = + codeview::visitTypeStream(Types, *this, VDS_BytesExternal, Handler)) return EC; assert(NumBadIndices <= BadIndicesRemaining && Index: llvm/trunk/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp @@ -57,7 +57,13 @@ if (!ExpectedTpi) return ExpectedTpi.takeError(); - if (auto EC = codeview::visitTypeStream(ExpectedTpi->typeArray(), Callbacks)) + // For handling a type server, we should be using whatever the callback array + // was + // that is being used for the original file. We shouldn't allow the visitor + // to + // arbitrarily stick a deserializer in there. + if (auto EC = codeview::visitTypeStream(ExpectedTpi->typeArray(), Callbacks, + VDS_BytesExternal)) return std::move(EC); return true;