forked from OSchip/llvm-project
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