Speed up iteration of CodeView record streams.
There's some abstraction overhead in the underlying mechanisms that were being used, and it was leading to an abundance of small but not-free copies being made. This showed up on a profile. Eliminating this and going back to a low-level byte-based implementation speeds up lld with /DEBUG between 10 and 15%. Differential Revision: https://reviews.llvm.org/D42148 llvm-svn: 322871
This commit is contained in:
parent
964ea50ff8
commit
1bc2ce6b9b
|
@ -677,54 +677,61 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjFile *File,
|
|||
BinaryStreamRef SymData) {
|
||||
// FIXME: Improve error recovery by warning and skipping records when
|
||||
// possible.
|
||||
CVSymbolArray Syms;
|
||||
BinaryStreamReader Reader(SymData);
|
||||
ExitOnErr(Reader.readArray(Syms, Reader.getLength()));
|
||||
ArrayRef<uint8_t> SymsBuffer;
|
||||
cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer));
|
||||
SmallVector<SymbolScope, 4> Scopes;
|
||||
for (CVSymbol Sym : Syms) {
|
||||
// Discover type index references in the record. Skip it if we don't know
|
||||
// where they are.
|
||||
SmallVector<TiReference, 32> TypeRefs;
|
||||
if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
|
||||
log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind()));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Copy the symbol record so we can mutate it.
|
||||
MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
|
||||
auto EC = forEachCodeViewRecord<CVSymbol>(
|
||||
SymsBuffer, [&](const CVSymbol &Sym) -> llvm::Error {
|
||||
// Discover type index references in the record. Skip it if we don't
|
||||
// know where they are.
|
||||
SmallVector<TiReference, 32> TypeRefs;
|
||||
if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
|
||||
log("ignoring unknown symbol record with kind 0x" +
|
||||
utohexstr(Sym.kind()));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
// Re-map all the type index references.
|
||||
MutableArrayRef<uint8_t> Contents =
|
||||
NewData.drop_front(sizeof(RecordPrefix));
|
||||
remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap, TypeRefs);
|
||||
// Copy the symbol record so we can mutate it.
|
||||
MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
|
||||
|
||||
// An object file may have S_xxx_ID symbols, but these get converted to
|
||||
// "real" symbols in a PDB.
|
||||
translateIdSymbols(NewData, IDTable);
|
||||
// Re-map all the type index references.
|
||||
MutableArrayRef<uint8_t> Contents =
|
||||
NewData.drop_front(sizeof(RecordPrefix));
|
||||
remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap,
|
||||
TypeRefs);
|
||||
|
||||
// If this record refers to an offset in the object file's string table,
|
||||
// add that item to the global PDB string table and re-write the index.
|
||||
recordStringTableReferences(Sym.kind(), Contents, StringTableRefs);
|
||||
// An object file may have S_xxx_ID symbols, but these get converted to
|
||||
// "real" symbols in a PDB.
|
||||
translateIdSymbols(NewData, IDTable);
|
||||
|
||||
SymbolKind NewKind = symbolKind(NewData);
|
||||
// If this record refers to an offset in the object file's string table,
|
||||
// add that item to the global PDB string table and re-write the index.
|
||||
recordStringTableReferences(Sym.kind(), Contents, StringTableRefs);
|
||||
|
||||
// Fill in "Parent" and "End" fields by maintaining a stack of scopes.
|
||||
CVSymbol NewSym(NewKind, NewData);
|
||||
if (symbolOpensScope(NewKind))
|
||||
scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym);
|
||||
else if (symbolEndsScope(NewKind))
|
||||
scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
|
||||
SymbolKind NewKind = symbolKind(NewData);
|
||||
|
||||
// Add the symbol to the globals stream if necessary. Do this before adding
|
||||
// the symbol to the module since we may need to get the next symbol offset,
|
||||
// and writing to the module's symbol stream will update that offset.
|
||||
if (symbolGoesInGlobalsStream(NewSym))
|
||||
addGlobalSymbol(GsiBuilder, *File, NewSym);
|
||||
// Fill in "Parent" and "End" fields by maintaining a stack of scopes.
|
||||
CVSymbol NewSym(NewKind, NewData);
|
||||
if (symbolOpensScope(NewKind))
|
||||
scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(),
|
||||
NewSym);
|
||||
else if (symbolEndsScope(NewKind))
|
||||
scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
|
||||
|
||||
// Add the symbol to the module.
|
||||
if (symbolGoesInModuleStream(NewSym))
|
||||
File->ModuleDBI->addSymbol(NewSym);
|
||||
}
|
||||
// Add the symbol to the globals stream if necessary. Do this before
|
||||
// adding the symbol to the module since we may need to get the next
|
||||
// symbol offset, and writing to the module's symbol stream will update
|
||||
// that offset.
|
||||
if (symbolGoesInGlobalsStream(NewSym))
|
||||
addGlobalSymbol(GsiBuilder, *File, NewSym);
|
||||
|
||||
// Add the symbol to the module.
|
||||
if (symbolGoesInModuleStream(NewSym))
|
||||
File->ModuleDBI->addSymbol(NewSym);
|
||||
return Error::success();
|
||||
});
|
||||
cantFail(std::move(EC));
|
||||
}
|
||||
|
||||
// Allocate memory for a .debug$S section and relocate it.
|
||||
|
|
|
@ -61,6 +61,30 @@ template <typename Kind> struct RemappedRecord {
|
|||
SmallVector<std::pair<uint32_t, TypeIndex>, 8> Mappings;
|
||||
};
|
||||
|
||||
template <typename Record, typename Func>
|
||||
Error forEachCodeViewRecord(ArrayRef<uint8_t> StreamBuffer, Func F) {
|
||||
while (!StreamBuffer.empty()) {
|
||||
if (StreamBuffer.size() < sizeof(RecordPrefix))
|
||||
return make_error<CodeViewError>(cv_error_code::corrupt_record);
|
||||
|
||||
const RecordPrefix *Prefix =
|
||||
reinterpret_cast<const RecordPrefix *>(StreamBuffer.data());
|
||||
|
||||
uint16_t RealLen = Prefix->RecordLen + 2;
|
||||
if (StreamBuffer.size() < RealLen)
|
||||
return make_error<CodeViewError>(cv_error_code::corrupt_record);
|
||||
|
||||
ArrayRef<uint8_t> Data = StreamBuffer.take_front(RealLen);
|
||||
StreamBuffer = StreamBuffer.drop_front(RealLen);
|
||||
|
||||
Record R(static_cast<decltype(Record::Type)>((uint16_t)Prefix->RecordKind),
|
||||
Data);
|
||||
if (auto EC = F(R))
|
||||
return EC;
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Read a complete record from a stream at a random offset.
|
||||
template <typename Kind>
|
||||
inline Expected<CVRecord<Kind>> readCVRecordFromStream(BinaryStreamRef Stream,
|
||||
|
|
|
@ -346,10 +346,12 @@ Error TypeStreamMerger::doit(const CVTypeArray &Types) {
|
|||
}
|
||||
|
||||
Error TypeStreamMerger::remapAllTypes(const CVTypeArray &Types) {
|
||||
for (const CVType &Type : Types)
|
||||
if (auto EC = remapType(Type))
|
||||
return EC;
|
||||
return Error::success();
|
||||
BinaryStreamRef Stream = Types.getUnderlyingStream();
|
||||
ArrayRef<uint8_t> Buffer;
|
||||
cantFail(Stream.readBytes(0, Stream.getLength(), Buffer));
|
||||
|
||||
return forEachCodeViewRecord<CVType>(
|
||||
Buffer, [this](const CVType &T) { return remapType(T); });
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::remapType(const CVType &Type) {
|
||||
|
|
Loading…
Reference in New Issue