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 @@ -70,7 +70,7 @@ const RecordPrefix *Prefix = reinterpret_cast(StreamBuffer.data()); - uint16_t RealLen = Prefix->RecordLen + 2; + size_t RealLen = Prefix->RecordLen + 2; if (StreamBuffer.size() < RealLen) return make_error(cv_error_code::corrupt_record); Index: llvm/trunk/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h @@ -69,9 +69,22 @@ ArrayRef> records() const; ArrayRef hashes() const; - using CreateRecord = llvm::function_ref()>; + template + TypeIndex insertRecordAs(GloballyHashedType Hash, size_t RecordSize, + CreateFunc Create) { + auto Result = HashedRecords.try_emplace(Hash, nextTypeIndex()); + + if (LLVM_UNLIKELY(Result.second)) { + uint8_t *Stable = RecordStorage.Allocate(RecordSize); + MutableArrayRef Data(Stable, RecordSize); + SeenRecords.push_back(Create(Data)); + SeenHashes.push_back(Hash); + } + + // Update the caller's copy of Record to point a stable copy. + return Result.first->second; + } - TypeIndex insertRecordAs(GloballyHashedType Hash, CreateRecord Create); TypeIndex insertRecordBytes(ArrayRef Data); TypeIndex insertRecord(ContinuationRecordBuilder &Builder); Index: llvm/trunk/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp @@ -55,9 +55,12 @@ CVType GlobalTypeTableBuilder::getType(TypeIndex Index) { CVType Type; Type.RecordData = SeenRecords[Index.toArrayIndex()]; - const RecordPrefix *P = - reinterpret_cast(Type.RecordData.data()); - Type.Type = static_cast(uint16_t(P->RecordKind)); + if (!Type.RecordData.empty()) { + assert(Type.RecordData.size() >= sizeof(RecordPrefix)); + const RecordPrefix *P = + reinterpret_cast(Type.RecordData.data()); + Type.Type = static_cast(uint16_t(P->RecordKind)); + } return Type; } @@ -89,31 +92,15 @@ SeenRecords.clear(); } -static inline ArrayRef stabilize(BumpPtrAllocator &Alloc, - ArrayRef Data) { - uint8_t *Stable = Alloc.Allocate(Data.size()); - memcpy(Stable, Data.data(), Data.size()); - return makeArrayRef(Stable, Data.size()); -} - -TypeIndex GlobalTypeTableBuilder::insertRecordAs(GloballyHashedType Hash, - CreateRecord Create) { - auto Result = HashedRecords.try_emplace(Hash, nextTypeIndex()); - - if (Result.second) { - ArrayRef RecordData = stabilize(RecordStorage, Create()); - SeenRecords.push_back(RecordData); - SeenHashes.push_back(Hash); - } - - // Update the caller's copy of Record to point a stable copy. - return Result.first->second; -} - TypeIndex GlobalTypeTableBuilder::insertRecordBytes(ArrayRef Record) { GloballyHashedType GHT = GloballyHashedType::hashType(Record, SeenHashes, SeenHashes); - return insertRecordAs(GHT, [Record]() { return Record; }); + return insertRecordAs(GHT, Record.size(), + [Record](MutableArrayRef Data) { + assert(Data.size() == Record.size()); + ::memcpy(Data.data(), Record.data(), Record.size()); + return Data; + }); } TypeIndex Index: llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -20,6 +20,11 @@ using namespace llvm; using namespace llvm::codeview; +static inline size_t slotForIndex(TypeIndex Idx) { + assert(!Idx.isSimple() && "simple type indices have no slots"); + return Idx.getIndex() - TypeIndex::FirstNonSimpleIndex; +} + namespace { /// Implementation of CodeView type stream merging. @@ -94,8 +99,22 @@ void addMapping(TypeIndex Idx); - bool remapTypeIndex(TypeIndex &Idx); - bool remapItemIndex(TypeIndex &Idx); + inline bool remapTypeIndex(TypeIndex &Idx) { + // If we're mapping a pure index stream, then IndexMap only contains + // mappings from OldIdStream -> NewIdStream, in which case we will need to + // use the special mapping from OldTypeStream -> NewTypeStream which was + // computed externally. Regardless, we use this special map if and only if + // we are doing an id-only mapping. + if (!hasTypeStream()) + return remapIndex(Idx, TypeLookup); + + assert(TypeLookup.empty()); + return remapIndex(Idx, IndexMap); + } + inline bool remapItemIndex(TypeIndex &Idx) { + assert(hasIdStream()); + return remapIndex(Idx, IndexMap); + } bool hasTypeStream() const { return (UseGlobalHashes) ? (!!DestGlobalTypeStream) : (!!DestTypeStream); @@ -105,17 +124,34 @@ return (UseGlobalHashes) ? (!!DestGlobalIdStream) : (!!DestIdStream); } - ArrayRef serializeRemapped(const RemappedType &Record); + ArrayRef remapIndices(const CVType &OriginalType, + MutableArrayRef Storage); - bool remapIndices(RemappedType &Record, ArrayRef Refs); + inline bool remapIndex(TypeIndex &Idx, ArrayRef Map) { + if (LLVM_LIKELY(remapIndexSimple(Idx, Map))) + return true; + + return remapIndexFallback(Idx, Map); + } + + inline bool remapIndexSimple(TypeIndex &Idx, ArrayRef Map) const { + // Simple types are unchanged. + if (Idx.isSimple()) + return true; + + // Check if this type index refers to a record we've already translated + // successfully. If it refers to a type later in the stream or a record we + // had to defer, defer it until later pass. + unsigned MapPos = slotForIndex(Idx); + if (LLVM_UNLIKELY(MapPos >= Map.size() || Map[MapPos] == Untranslated)) + return false; - bool remapIndex(TypeIndex &Idx, ArrayRef Map); - - size_t slotForIndex(TypeIndex Idx) const { - assert(!Idx.isSimple() && "simple type indices have no slots"); - return Idx.getIndex() - TypeIndex::FirstNonSimpleIndex; + Idx = Map[MapPos]; + return true; } + bool remapIndexFallback(TypeIndex &Idx, ArrayRef Map); + Error errorCorruptRecord() const { return llvm::make_error(cv_error_code::corrupt_record); } @@ -153,27 +189,6 @@ } // end anonymous namespace -ArrayRef -TypeStreamMerger::serializeRemapped(const RemappedType &Record) { - TypeIndex TI; - ArrayRef OriginalData = Record.OriginalRecord.RecordData; - if (Record.Mappings.empty()) - return OriginalData; - - // At least one type index was remapped. We copy the full record bytes, - // re-write each type index, then return that. - 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 RemapRef; -} - const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated); static bool isIdRecord(TypeLeafKind K) { @@ -202,19 +217,9 @@ } } -bool TypeStreamMerger::remapIndex(TypeIndex &Idx, ArrayRef Map) { - // Simple types are unchanged. - if (Idx.isSimple()) - return true; - - // Check if this type index refers to a record we've already translated - // successfully. If it refers to a type later in the stream or a record we - // had to defer, defer it until later pass. - unsigned MapPos = slotForIndex(Idx); - if (MapPos < Map.size() && Map[MapPos] != Untranslated) { - Idx = Map[MapPos]; - return true; - } +bool TypeStreamMerger::remapIndexFallback(TypeIndex &Idx, + ArrayRef Map) { + size_t MapPos = slotForIndex(Idx); // If this is the second pass and this index isn't in the map, then it points // outside the current type stream, and this is a corrupt record. @@ -232,24 +237,6 @@ return false; } -bool TypeStreamMerger::remapTypeIndex(TypeIndex &Idx) { - // If we're mapping a pure index stream, then IndexMap only contains mappings - // from OldIdStream -> NewIdStream, in which case we will need to use the - // special mapping from OldTypeStream -> NewTypeStream which was computed - // externally. Regardless, we use this special map if and only if we are - // doing an id-only mapping. - if (!hasTypeStream()) - return remapIndex(Idx, TypeLookup); - - assert(TypeLookup.empty()); - return remapIndex(Idx, IndexMap); -} - -bool TypeStreamMerger::remapItemIndex(TypeIndex &Idx) { - assert(hasIdStream()); - return remapIndex(Idx, IndexMap); -} - // Local hashing entry points Error TypeStreamMerger::mergeTypeRecords(MergingTypeTableBuilder &Dest, const CVTypeArray &Types) { @@ -355,28 +342,25 @@ } Error TypeStreamMerger::remapType(const CVType &Type) { - auto DoSerialize = [this, Type]() -> ArrayRef { - RemappedType R(Type); - SmallVector Refs; - discoverTypeIndices(Type.RecordData, Refs); - if (!remapIndices(R, Refs)) - return {}; - return serializeRemapped(R); + auto DoSerialize = + [this, Type](MutableArrayRef Storage) -> ArrayRef { + return remapIndices(Type, Storage); }; TypeIndex DestIdx = Untranslated; - if (UseGlobalHashes) { + if (LLVM_LIKELY(UseGlobalHashes)) { GlobalTypeTableBuilder &Dest = isIdRecord(Type.kind()) ? *DestGlobalIdStream : *DestGlobalTypeStream; GloballyHashedType H = GlobalHashes[CurIndex.toArrayIndex()]; - DestIdx = Dest.insertRecordAs(H, DoSerialize); + DestIdx = Dest.insertRecordAs(H, Type.RecordData.size(), DoSerialize); } else { MergingTypeTableBuilder &Dest = isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream; - auto Data = DoSerialize(); - if (!Data.empty()) - DestIdx = Dest.insertRecordBytes(Data); + RemapStorage.resize(Type.RecordData.size()); + ArrayRef Result = DoSerialize(RemapStorage); + if (!Result.empty()) + DestIdx = Dest.insertRecordBytes(Result); } addMapping(DestIdx); @@ -386,27 +370,32 @@ return Error::success(); } -bool TypeStreamMerger::remapIndices(RemappedType &Record, - ArrayRef Refs) { - ArrayRef OriginalData = Record.OriginalRecord.content(); - bool Success = true; +ArrayRef +TypeStreamMerger::remapIndices(const CVType &OriginalType, + MutableArrayRef Storage) { + SmallVector Refs; + discoverTypeIndices(OriginalType.RecordData, Refs); + if (Refs.empty()) + return OriginalType.RecordData; + + ::memcpy(Storage.data(), OriginalType.RecordData.data(), + OriginalType.RecordData.size()); + + uint8_t *DestContent = Storage.data() + sizeof(RecordPrefix); + for (auto &Ref : Refs) { - uint32_t Offset = Ref.Offset; - ArrayRef Bytes = OriginalData.slice(Ref.Offset, sizeof(TypeIndex)); - ArrayRef TIs(reinterpret_cast(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; + TypeIndex *DestTIs = + reinterpret_cast(DestContent + Ref.Offset); + + for (size_t I = 0; I < Ref.Count; ++I) { + TypeIndex &TI = DestTIs[I]; + bool Success = (Ref.Kind == TiRefKind::IndexRef) ? remapItemIndex(TI) + : remapTypeIndex(TI); + if (LLVM_UNLIKELY(!Success)) + return {}; } } - return Success; + return Storage; } Error llvm::codeview::mergeTypeRecords(MergingTypeTableBuilder &Dest,