diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -47,14 +47,7 @@ // Make sure this comes before MSVCSetupApi.h #include -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnon-virtual-dtor" -#endif #include "MSVCSetupApi.h" -#ifdef __clang__ -#pragma clang diagnostic pop -#endif #include "llvm/Support/COM.h" _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); _COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2)); diff --git a/lld/COFF/COFFLinkerContext.h b/lld/COFF/COFFLinkerContext.h --- a/lld/COFF/COFFLinkerContext.h +++ b/lld/COFF/COFFLinkerContext.h @@ -15,13 +15,12 @@ #include "InputFiles.h" #include "SymbolTable.h" #include "Writer.h" -#include "lld/Common/CommonLinkerContext.h" #include "lld/Common/Timer.h" namespace lld { namespace coff { -class COFFLinkerContext : public CommonLinkerContext { +class COFFLinkerContext { public: COFFLinkerContext(); COFFLinkerContext(const COFFLinkerContext &) = delete; diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -12,6 +12,7 @@ #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" @@ -429,7 +430,7 @@ return; warn("some relocations in " + file->getName() + " are not sorted"); MutableArrayRef newRelocs( - bAlloc().Allocate(relocsSize), relocsSize); + bAlloc.Allocate(relocsSize), relocsSize); memcpy(newRelocs.data(), relocsData, relocsSize * sizeof(coff_relocation)); llvm::sort(newRelocs, cmpByVa); setRelocs(newRelocs); diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp --- a/lld/COFF/DLL.cpp +++ b/lld/COFF/DLL.cpp @@ -659,14 +659,14 @@ // Add a syntentic symbol for this load thunk, using the "__imp_load" // prefix, in case this thunk needs to be added to the list of valid // call targets for Control Flow Guard. - StringRef symName = saver().save("__imp_load_" + extName); + StringRef symName = saver.save("__imp_load_" + extName); s->loadThunkSym = cast(ctx.symtab.addSynthetic(symName, t)); } } thunks.push_back(tm); StringRef tmName = - saver().save("__tailMerge_" + syms[0]->getDLLName().lower()); + saver.save("__tailMerge_" + syms[0]->getDLLName().lower()); ctx.symtab.addSynthetic(tmName, tm); // Terminate with null values. addresses.push_back(make(8)); diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -19,7 +19,9 @@ #include "Writer.h" #include "lld/Common/Args.h" #include "lld/Common/Driver.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Filesystem.h" +#include "lld/Common/Memory.h" #include "lld/Common/Timer.h" #include "lld/Common/Version.h" #include "llvm/ADT/Optional.h" @@ -61,22 +63,34 @@ std::unique_ptr config; std::unique_ptr driver; -bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) { - // This driver-specific context will be freed later by lldMain(). - auto *ctx = new COFFLinkerContext; +bool link(ArrayRef args, bool canExitEarly, raw_ostream &stdoutOS, + raw_ostream &stderrOS) { + lld::stdoutOS = &stdoutOS; + lld::stderrOS = &stderrOS; - ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); - ctx->e.logName = args::getFilenameWithoutExe(args[0]); - ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now" - " (use /errorlimit:0 to see all errors)"; + errorHandler().cleanupCallback = []() { freeArena(); }; + errorHandler().logName = args::getFilenameWithoutExe(args[0]); + errorHandler().errorLimitExceededMsg = + "too many errors emitted, stopping now" + " (use /errorlimit:0 to see all errors)"; + errorHandler().exitEarly = canExitEarly; + stderrOS.enable_colors(stderrOS.has_colors()); + + COFFLinkerContext ctx; config = std::make_unique(); - driver = std::make_unique(*ctx); + driver = std::make_unique(ctx); driver->linkerMain(args); - return errorCount() == 0; + // Call exit() if we can to avoid calling destructors. + if (canExitEarly) + exitLld(errorCount() ? 1 : 0); + + bool ret = errorCount() == 0; + if (!canExitEarly) + errorHandler().reset(); + return ret; } // Parse options of the form "old;new". @@ -146,7 +160,7 @@ static StringRef mangle(StringRef sym) { assert(config->machine != IMAGE_FILE_MACHINE_UNKNOWN); if (config->machine == I386) - return saver().save("_" + sym); + return saver.save("_" + sym); return sym; } @@ -342,9 +356,9 @@ Export exp = parseExport(e); if (config->machine == I386 && config->mingw) { if (!isDecorated(exp.name)) - exp.name = saver().save("_" + exp.name); + exp.name = saver.save("_" + exp.name); if (!exp.extName.empty() && !isDecorated(exp.extName)) - exp.extName = saver().save("_" + exp.extName); + exp.extName = saver.save("_" + exp.extName); } exp.directives = true; config->exports.push_back(exp); @@ -426,11 +440,11 @@ SmallString<128> path = dir; sys::path::append(path, filename); if (sys::fs::exists(path.str())) - return saver().save(path.str()); + return saver.save(path.str()); if (!hasExt) { path.append(".obj"); if (sys::fs::exists(path.str())) - return saver().save(path.str()); + return saver.save(path.str()); } } return filename; @@ -467,7 +481,7 @@ SmallString<128> s = filename; sys::path::replace_extension(s, ".a"); - StringRef libName = saver().save("lib" + s.str()); + StringRef libName = saver.save("lib" + s.str()); return doFindFile(libName); } @@ -476,7 +490,7 @@ // Add ".lib" to Filename if that has no file extension. bool hasExt = filename.contains('.'); if (!hasExt) - filename = saver().save(filename + ".lib"); + filename = saver.save(filename + ".lib"); StringRef ret = doFindFile(filename); // For MinGW, if the find above didn't turn up anything, try // looking for a MinGW formatted library name. @@ -509,7 +523,7 @@ Optional envOpt = Process::GetEnv("LIB"); if (!envOpt.hasValue()) return; - StringRef env = saver().save(*envOpt); + StringRef env = saver.save(*envOpt); while (!env.empty()) { StringRef path; std::tie(path, env) = env.split(';'); @@ -857,8 +871,8 @@ driver->takeBuffer(std::move(mb)); if (config->outputFile.empty()) - config->outputFile = std::string(saver().save(m.OutputFile)); - config->importName = std::string(saver().save(m.ImportName)); + config->outputFile = std::string(saver.save(m.OutputFile)); + config->importName = std::string(saver.save(m.ImportName)); if (m.ImageBase) config->imageBase = m.ImageBase; if (m.StackReserve) @@ -886,14 +900,14 @@ // DLL instead. This is supported by both MS and GNU linkers. if (!e1.ExtName.empty() && e1.ExtName != e1.Name && StringRef(e1.Name).contains('.')) { - e2.name = saver().save(e1.ExtName); - e2.forwardTo = saver().save(e1.Name); + e2.name = saver.save(e1.ExtName); + e2.forwardTo = saver.save(e1.Name); config->exports.push_back(e2); continue; } - e2.name = saver().save(e1.Name); - e2.extName = saver().save(e1.ExtName); - e2.aliasTarget = saver().save(e1.AliasTarget); + e2.name = saver.save(e1.Name); + e2.extName = saver.save(e1.ExtName); + e2.aliasTarget = saver.save(e1.AliasTarget); e2.ordinal = e1.Ordinal; e2.noname = e1.Noname; e2.data = e1.Data; @@ -1890,9 +1904,9 @@ Export e = parseExport(arg->getValue()); if (config->machine == I386) { if (!isDecorated(e.name)) - e.name = saver().save("_" + e.name); + e.name = saver.save("_" + e.name); if (!e.extName.empty() && !isDecorated(e.extName)) - e.extName = saver().save("_" + e.extName); + e.extName = saver.save("_" + e.extName); } config->exports.push_back(e); } diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -48,17 +48,17 @@ class Executor { public: - explicit Executor(StringRef s) : prog(saver().save(s)) {} - void add(StringRef s) { args.push_back(saver().save(s)); } - void add(std::string &s) { args.push_back(saver().save(s)); } - void add(Twine s) { args.push_back(saver().save(s)); } - void add(const char *s) { args.push_back(saver().save(s)); } + explicit Executor(StringRef s) : prog(saver.save(s)) {} + void add(StringRef s) { args.push_back(saver.save(s)); } + void add(std::string &s) { args.push_back(saver.save(s)); } + void add(Twine s) { args.push_back(saver.save(s)); } + void add(const char *s) { args.push_back(saver.save(s)); } void run() { ErrorOr exeOrErr = sys::findProgramByName(prog); if (auto ec = exeOrErr.getError()) fatal("unable to find " + prog + " in PATH: " + ec.message()); - StringRef exe = saver().save(*exeOrErr); + StringRef exe = saver.save(*exeOrErr); args.insert(args.begin(), exe); if (sys::ExecuteAndWait(args[0], args) != 0) @@ -636,14 +636,14 @@ sym = sym.substr(0, sym.find('@', 1)); if (!sym.startswith("@")) { if (prefix && !sym.startswith("_")) - return saver().save("_" + sym); + return saver.save("_" + sym); return sym; } // For fastcall, remove the leading @ and replace it with an // underscore, if prefixes are used. sym = sym.substr(1); if (prefix) - sym = saver().save("_" + sym); + sym = saver.save("_" + sym); return sym; } @@ -854,7 +854,7 @@ argv.data() + argv.size()); if (!args.hasArg(OPT_lldignoreenv)) addLINK(expandedArgv); - cl::ExpandResponseFiles(saver(), getQuotingStyle(args), expandedArgv); + cl::ExpandResponseFiles(saver, getQuotingStyle(args), expandedArgv); args = optTable.ParseArgs(makeArrayRef(expandedArgv).drop_front(), missingIndex, missingCount); @@ -901,7 +901,7 @@ // Handle /EXPORT and /INCLUDE in a fast path. These directives can appear for // potentially every symbol in the object, so they must be handled quickly. SmallVector tokens; - cl::TokenizeWindowsCommandLineNoCopy(s, saver(), tokens); + cl::TokenizeWindowsCommandLineNoCopy(s, saver, tokens); for (StringRef tok : tokens) { if (tok.startswith_insensitive("/export:") || tok.startswith_insensitive("-export:")) @@ -914,7 +914,7 @@ // already copied quoted arguments for us, so those do not need to be // copied again. bool HasNul = tok.end() != s.end() && tok.data()[tok.size()] == '\0'; - rest.push_back(HasNul ? tok.data() : saver().save(tok).data()); + rest.push_back(HasNul ? tok.data() : saver.save(tok).data()); } } @@ -948,7 +948,7 @@ std::vector ArgParser::tokenize(StringRef s) { SmallVector tokens; - cl::TokenizeWindowsCommandLine(s, saver(), tokens); + cl::TokenizeWindowsCommandLine(s, saver, tokens); return std::vector(tokens.begin(), tokens.end()); } diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -15,6 +15,8 @@ #include "SymbolTable.h" #include "Symbols.h" #include "lld/Common/DWARF.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm-c/lto.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" @@ -903,7 +905,7 @@ Optional> ret = dwarf->getVariableLoc(var); if (!ret) return None; - return std::make_pair(saver().save(ret->first), ret->second); + return std::make_pair(saver.save(ret->first), ret->second); } // Used only for DWARF debug info, which is not common (except in MinGW @@ -938,8 +940,8 @@ fatal("broken import library"); // Read names and create an __imp_ symbol. - StringRef name = saver().save(StringRef(buf + sizeof(*hdr))); - StringRef impName = saver().save("__imp_" + name); + StringRef name = saver.save(StringRef(buf + sizeof(*hdr))); + StringRef impName = saver.save("__imp_" + name); const char *nameStart = buf + sizeof(coff_import_header) + name.size() + 1; dllName = std::string(StringRef(nameStart)); StringRef extName; @@ -993,12 +995,11 @@ // into consideration at LTO time (which very likely causes undefined // symbols later in the link stage). So we append file offset to make // filename unique. - MemoryBufferRef mbref(mb.getBuffer(), - saver().save(archiveName.empty() - ? path - : archiveName + - sys::path::filename(path) + - utostr(offsetInArchive))); + MemoryBufferRef mbref( + mb.getBuffer(), + saver.save(archiveName.empty() ? path + : archiveName + sys::path::filename(path) + + utostr(offsetInArchive))); obj = check(lto::InputFile::create(mbref)); } @@ -1034,7 +1035,6 @@ } // namespace void BitcodeFile::parse() { - llvm::StringSaver &saver = lld::saver(); std::vector> comdat(obj->getComdatTable().size()); for (size_t i = 0; i != obj->getComdatTable().size(); ++i) // FIXME: Check nodeduplicate @@ -1156,11 +1156,11 @@ s->nameType = ImportNameType::IMPORT_NAME; if (coffObj->getMachine() == I386) { - s->symbolName = symbolName = saver().save("_" + symbolName); + s->symbolName = symbolName = saver.save("_" + symbolName); s->nameType = ImportNameType::IMPORT_NAME_NOPREFIX; } - StringRef impName = saver().save("__imp_" + symbolName); + StringRef impName = saver.save("__imp_" + symbolName); ctx.symtab.addLazyDLLSymbol(this, s, impName); if (code) ctx.symtab.addLazyDLLSymbol(this, s, symbolName); @@ -1179,7 +1179,7 @@ size_t impSize = s->dllName.size() + s->symbolName.size() + 2; // +2 for NULs size_t size = sizeof(coff_import_header) + impSize; - char *buf = bAlloc().Allocate(size); + char *buf = bAlloc.Allocate(size); memset(buf, 0, size); char *p = buf; auto *imp = reinterpret_cast(p); diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -11,7 +11,7 @@ #include "InputFiles.h" #include "Symbols.h" #include "lld/Common/Args.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Strings.h" #include "lld/Common/TargetOptionsCommandFlags.h" #include "llvm/ADT/STLExtras.h" @@ -209,8 +209,8 @@ // - foo.exe.lto.1.obj // - ... StringRef ltoObjName = - saver().save(Twine(config->outputFile) + ".lto" + - (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".obj"); + saver.save(Twine(config->outputFile) + ".lto" + + (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".obj"); // Get the native object contents either from the cache or from memory. Do // not use the cached MemoryBuffer directly, or the PDB will not be diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp --- a/lld/COFF/MinGW.cpp +++ b/lld/COFF/MinGW.cpp @@ -11,6 +11,7 @@ #include "Driver.h" #include "InputFiles.h" #include "SymbolTable.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Object/COFF.h" @@ -183,8 +184,8 @@ static StringRef mangle(Twine sym) { assert(config->machine != IMAGE_FILE_MACHINE_UNKNOWN); if (config->machine == I386) - return saver().save("_" + sym); - return saver().save(sym); + return saver.save("_" + sym); + return saver.save(sym); } // Handles -wrap option. @@ -248,7 +249,7 @@ // referenced it or not, though.) if (imp) { DefinedLocalImport *wrapimp = make( - saver().save("__imp_" + w.wrap->getName()), d); + saver.save("__imp_" + w.wrap->getName()), d); ctx.symtab.localImportChunks.push_back(wrapimp->getChunk()); map[imp] = wrapimp; } diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp --- a/lld/COFF/PDB.cpp +++ b/lld/COFF/PDB.cpp @@ -16,6 +16,7 @@ #include "Symbols.h" #include "TypeMerger.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Timer.h" #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" @@ -74,7 +75,7 @@ public: PDBLinker(COFFLinkerContext &ctx) - : builder(bAlloc()), tMerger(ctx, bAlloc()), ctx(ctx) { + : builder(bAlloc), tMerger(ctx, bAlloc), ctx(ctx) { // This isn't strictly necessary, but link.exe usually puts an empty string // as the first "valid" string in the string table, so we do the same in // order to maintain as much byte-for-byte compatibility as possible. @@ -500,7 +501,7 @@ case SymbolKind::S_LPROCREF: { // sym is a temporary object, so we have to copy and reallocate the record // to stabilize it. - uint8_t *mem = bAlloc().Allocate(sym.length()); + uint8_t *mem = bAlloc.Allocate(sym.length()); memcpy(mem, sym.data().data(), sym.length()); builder.addGlobalSymbol(CVSymbol(makeArrayRef(mem, sym.length()))); break; @@ -1002,7 +1003,7 @@ // Allocate memory for a .debug$S / .debug$F section and relocate it. static ArrayRef relocateDebugChunk(SectionChunk &debugChunk) { - uint8_t *buffer = bAlloc().Allocate(debugChunk.getSize()); + uint8_t *buffer = bAlloc.Allocate(debugChunk.getSize()); assert(debugChunk.getOutputSectionIdx() == 0 && "debug sections should not be in output sections"); debugChunk.writeTo(buffer); @@ -1416,7 +1417,6 @@ ebs.Fields.push_back(path); ebs.Fields.push_back("cmd"); ebs.Fields.push_back(argStr); - llvm::BumpPtrAllocator &bAlloc = lld::bAlloc(); mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( ons, bAlloc, CodeViewContainer::Pdb)); mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( @@ -1448,7 +1448,7 @@ cgs.Characteristics |= llvm::COFF::IMAGE_SCN_MEM_WRITE; mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( - cgs, bAlloc(), CodeViewContainer::Pdb)); + cgs, bAlloc, CodeViewContainer::Pdb)); } static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &mod, @@ -1461,7 +1461,7 @@ sym.Rva = os.getRVA(); sym.SectionNumber = os.sectionIndex; mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( - sym, bAlloc(), CodeViewContainer::Pdb)); + sym, bAlloc, CodeViewContainer::Pdb)); // Skip COFF groups in MinGW because it adds a significant footprint to the // PDB, due to each function being in its own section @@ -1536,7 +1536,6 @@ ts.Segment = thunkOS->sectionIndex; ts.Offset = thunkChunk->getRVA() - thunkOS->getRVA(); - llvm::BumpPtrAllocator &bAlloc = lld::bAlloc(); mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol( ons, bAlloc, CodeViewContainer::Pdb)); mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol( diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -134,7 +134,7 @@ const DILineInfo &lineInfo = *optionalLineInfo; if (lineInfo.FileName == DILineInfo::BadString) return None; - return std::make_pair(saver().save(lineInfo.FileName), lineInfo.Line); + return std::make_pair(saver.save(lineInfo.FileName), lineInfo.Line); } static Optional> diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -485,7 +485,7 @@ MutableArrayRef newRelocs; if (originalRelocs.data() == curRelocs.data()) { newRelocs = makeMutableArrayRef( - bAlloc().Allocate(originalRelocs.size()), + bAlloc.Allocate(originalRelocs.size()), originalRelocs.size()); } else { newRelocs = makeMutableArrayRef( diff --git a/lld/Common/CMakeLists.txt b/lld/Common/CMakeLists.txt --- a/lld/Common/CMakeLists.txt +++ b/lld/Common/CMakeLists.txt @@ -28,7 +28,6 @@ add_lld_library(lldCommon Args.cpp - CommonLinkerContext.cpp DWARF.cpp ErrorHandler.cpp Filesystem.cpp diff --git a/lld/Common/CommonLinkerContext.cpp b/lld/Common/CommonLinkerContext.cpp deleted file mode 100644 --- a/lld/Common/CommonLinkerContext.cpp +++ /dev/null @@ -1,45 +0,0 @@ -//===- CommonLinkerContext.cpp --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lld/Common/CommonLinkerContext.h" -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" - -using namespace llvm; -using namespace lld; - -// Reference to the current LLD instance. This is a temporary situation, until -// we pass this context everywhere by reference, or we make it a thread_local, -// as in https://reviews.llvm.org/D108850?id=370678 where each thread can be -// associated with a LLD instance. Only then will LLD be free of global -// state. -static CommonLinkerContext *lctx; - -CommonLinkerContext::CommonLinkerContext() { lctx = this; } - -CommonLinkerContext::~CommonLinkerContext() { - assert(lctx); - // Explicitly call the destructors since we created the objects with placement - // new in SpecificAlloc::create(). - for (auto &it : instances) - it.second->~SpecificAllocBase(); - lctx = nullptr; -} - -CommonLinkerContext &lld::commonContext() { - assert(lctx); - return *lctx; -} - -bool lld::hasContext() { return lctx != nullptr; } - -void CommonLinkerContext::destroy() { - if (lctx == nullptr) - return; - delete lctx; -} diff --git a/lld/Common/ErrorHandler.cpp b/lld/Common/ErrorHandler.cpp --- a/lld/Common/ErrorHandler.cpp +++ b/lld/Common/ErrorHandler.cpp @@ -10,7 +10,6 @@ #include "llvm/Support/Parallel.h" -#include "lld/Common/CommonLinkerContext.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" @@ -19,69 +18,51 @@ #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" +#include #include using namespace llvm; using namespace lld; +// The functions defined in this file can be called from multiple threads, +// but lld::outs() or lld::errs() are not thread-safe. We protect them using a +// mutex. +static std::mutex mu; + +// We want to separate multi-line messages with a newline. `sep` is "\n" +// if the last messages was multi-line. Otherwise "". +static StringRef sep; + static StringRef getSeparator(const Twine &msg) { if (StringRef(msg.str()).contains('\n')) return "\n"; return ""; } -ErrorHandler::~ErrorHandler() { - if (cleanupCallback) - cleanupCallback(); -} - -void ErrorHandler::initialize(llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, - bool disableOutput) { - this->stdoutOS = &stdoutOS; - this->stderrOS = &stderrOS; - stderrOS.enable_colors(stderrOS.has_colors()); - this->exitEarly = exitEarly; - this->disableOutput = disableOutput; -} +raw_ostream *lld::stdoutOS; +raw_ostream *lld::stderrOS; -void ErrorHandler::flushStreams() { - std::lock_guard lock(mu); - outs().flush(); - errs().flush(); +ErrorHandler &lld::errorHandler() { + static ErrorHandler handler; + return handler; } -ErrorHandler &lld::errorHandler() { return context().e; } - raw_ostream &lld::outs() { - ErrorHandler &e = errorHandler(); - return e.outs(); -} - -raw_ostream &lld::errs() { - ErrorHandler &e = errorHandler(); - return e.errs(); -} - -raw_ostream &ErrorHandler::outs() { - if (disableOutput) + if (errorHandler().disableOutput) return llvm::nulls(); return stdoutOS ? *stdoutOS : llvm::outs(); } -raw_ostream &ErrorHandler::errs() { - if (disableOutput) +raw_ostream &lld::errs() { + if (errorHandler().disableOutput) return llvm::nulls(); return stderrOS ? *stderrOS : llvm::errs(); } void lld::exitLld(int val) { - if (hasContext()) { - ErrorHandler &e = errorHandler(); - // Delete any temporary file, while keeping the memory mapping open. - if (e.outputBuffer) - e.outputBuffer->discard(); - } + // Delete any temporary file, while keeping the memory mapping open. + if (errorHandler().outputBuffer) + errorHandler().outputBuffer->discard(); // Re-throw a possible signal or exception once/if it was catched by // safeLldMain(). @@ -94,9 +75,11 @@ if (!CrashRecoveryContext::GetCurrent()) llvm_shutdown(); - if (hasContext()) - lld::errorHandler().flushStreams(); - + { + std::lock_guard lock(mu); + lld::outs().flush(); + lld::errs().flush(); + } // When running inside safeLldMain(), restore the control flow back to the // CrashRecoveryContext. Otherwise simply use _exit(), meanning no cleanup, // since we want to avoid further crashes on shutdown. diff --git a/lld/Common/Memory.cpp b/lld/Common/Memory.cpp --- a/lld/Common/Memory.cpp +++ b/lld/Common/Memory.cpp @@ -7,19 +7,16 @@ //===----------------------------------------------------------------------===// #include "lld/Common/Memory.h" -#include "lld/Common/CommonLinkerContext.h" using namespace llvm; using namespace lld; -SpecificAllocBase * -lld::SpecificAllocBase::getOrCreate(void *tag, size_t size, size_t align, - SpecificAllocBase *(&creator)(void *)) { - auto &instances = context().instances; - auto &instance = instances[tag]; - if (instance == nullptr) { - void *storage = context().bAlloc.Allocate(size, align); - instance = creator(storage); - } - return instance; +BumpPtrAllocator lld::bAlloc; +StringSaver lld::saver{bAlloc}; +std::vector lld::SpecificAllocBase::instances; + +void lld::freeArena() { + for (SpecificAllocBase *alloc : SpecificAllocBase::instances) + alloc->reset(); + bAlloc.Reset(); } diff --git a/lld/Common/TargetOptionsCommandFlags.cpp b/lld/Common/TargetOptionsCommandFlags.cpp --- a/lld/Common/TargetOptionsCommandFlags.cpp +++ b/lld/Common/TargetOptionsCommandFlags.cpp @@ -7,9 +7,12 @@ //===----------------------------------------------------------------------===// #include "lld/Common/TargetOptionsCommandFlags.h" + #include "llvm/CodeGen/CommandFlags.h" #include "llvm/Target/TargetOptions.h" +static llvm::codegen::RegisterCodeGenFlags CGF; + llvm::TargetOptions lld::initTargetOptionsFromCodeGenFlags() { return llvm::codegen::InitTargetOptionsFromCodeGenFlags(llvm::Triple()); } diff --git a/lld/ELF/AArch64ErrataFix.cpp b/lld/ELF/AArch64ErrataFix.cpp --- a/lld/ELF/AArch64ErrataFix.cpp +++ b/lld/ELF/AArch64ErrataFix.cpp @@ -32,7 +32,7 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "llvm/Support/Endian.h" #include @@ -396,9 +396,9 @@ patchee(p), patcheeOffset(off) { this->parent = p->getParent(); patchSym = addSyntheticLocal( - saver().save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, - 0, getSize(), *this); - addSyntheticLocal(saver().save("$x"), STT_NOTYPE, 0, 0, *this); + saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0, + getSize(), *this); + addSyntheticLocal(saver.save("$x"), STT_NOTYPE, 0, 0, *this); } uint64_t Patch843419Section::getLDSTAddr() const { diff --git a/lld/ELF/ARMErrataFix.cpp b/lld/ELF/ARMErrataFix.cpp --- a/lld/ELF/ARMErrataFix.cpp +++ b/lld/ELF/ARMErrataFix.cpp @@ -20,7 +20,7 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "llvm/Support/Endian.h" #include @@ -139,9 +139,9 @@ patchee(p), patcheeOffset(off), instr(instr), isARM(isARM) { parent = p->getParent(); patchSym = addSyntheticLocal( - saver().save("__CortexA8657417_" + utohexstr(getBranchAddr())), STT_FUNC, + saver.save("__CortexA8657417_" + utohexstr(getBranchAddr())), STT_FUNC, isARM ? 0 : 1, getSize(), *this); - addSyntheticLocal(saver().save(isARM ? "$a" : "$t"), STT_NOTYPE, 0, 0, *this); + addSyntheticLocal(saver.save(isARM ? "$a" : "$t"), STT_NOTYPE, 0, 0, *this); } uint64_t Patch657417Section::getBranchAddr() const { diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -11,7 +11,8 @@ #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/Support/Endian.h" using namespace llvm; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -84,15 +84,14 @@ else error(msg); } +bool elf::link(ArrayRef args, bool canExitEarly, + raw_ostream &stdoutOS, raw_ostream &stderrOS) { + lld::stdoutOS = &stdoutOS; + lld::stderrOS = &stderrOS; -bool elf::link(ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, - bool disableOutput) { - // This driver-specific context will be freed later by lldMain(). - auto *ctx = new CommonLinkerContext; + errorHandler().cleanupCallback = []() { + freeArena(); - ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); - ctx->e.cleanupCallback = []() { inputSections.clear(); outputSections.clear(); memoryBuffers.clear(); @@ -114,9 +113,13 @@ SharedFile::vernauxNum = 0; }; - ctx->e.logName = args::getFilenameWithoutExe(args[0]); - ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use " - "-error-limit=0 to see all errors)"; + + errorHandler().logName = args::getFilenameWithoutExe(args[0]); + errorHandler().errorLimitExceededMsg = + "too many errors emitted, stopping now (use " + "-error-limit=0 to see all errors)"; + errorHandler().exitEarly = canExitEarly; + stderrOS.enable_colors(stderrOS.has_colors()); config = std::make_unique(); driver = std::make_unique(); @@ -130,7 +133,15 @@ driver->linkerMain(args); - return errorCount() == 0; + // Exit immediately if we don't need to return to the caller. + // This saves time because the overhead of calling destructors + // for all globally-allocated objects is not negligible. + int hasError = errorCount() ? 1 : 0; + if (canExitEarly) + exitLld(hasError); + else + errorHandler().reset(); + return !hasError; } // Parses a linker -m option. @@ -1239,7 +1250,7 @@ // Parse LTO options. if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq)) - parseClangOption(saver().save("-mcpu=" + StringRef(arg->getValue())), + parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())), arg->getSpelling()); for (opt::Arg *arg : args.filtered(OPT_plugin_opt_eq_minus)) @@ -2055,9 +2066,9 @@ if (!sym || (sym->isLazy() && !sym->isUsedInRegularObj)) continue; - Symbol *real = addUnusedUndefined(saver().save("__real_" + name)); + Symbol *real = addUnusedUndefined(saver.save("__real_" + name)); Symbol *wrap = - addUnusedUndefined(saver().save("__wrap_" + name), sym->binding); + addUnusedUndefined(saver.save("__wrap_" + name), sym->binding); v.push_back({sym, real, wrap}); // We want to tell LTO not to inline symbols to be overwritten diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp --- a/lld/ELF/DriverUtils.cpp +++ b/lld/ELF/DriverUtils.cpp @@ -14,7 +14,8 @@ #include "Config.h" #include "Driver.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "lld/Common/Reproduce.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/Triple.h" @@ -99,7 +100,7 @@ for (size_t i = 0, e = args.size(); i != e; ++i) { StringRef s = args[i]; if ((s == "-plugin-opt" || s == "--plugin-opt") && i + 1 != e) { - v.push_back(saver().save(s + "=" + args[i + 1]).data()); + v.push_back(saver.save(s + "=" + args[i + 1]).data()); ++i; } else { v.push_back(args[i]); @@ -122,7 +123,7 @@ // Expand response files (arguments in the form of @) // and then parse the argument again. - cl::ExpandResponseFiles(saver(), getQuotingStyle(args), vec); + cl::ExpandResponseFiles(saver, getQuotingStyle(args), vec); concatLTOPluginOptions(vec); args = this->ParseArgs(vec, missingIndex, missingCount); diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -15,8 +15,9 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" -#include "lld/Common/CommonLinkerContext.h" #include "lld/Common/DWARF.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/STLExtras.h" #include "llvm/LTO/LTO.h" @@ -110,7 +111,7 @@ // The --chroot option changes our virtual root directory. // This is useful when you are dealing with files created by --reproduce. if (!config->chroot.empty() && path.startswith("/")) - path = saver().save(config->chroot + path); + path = saver.save(config->chroot + path); log(path); config->dependencyFiles.insert(llvm::CachedHashString(path)); @@ -1507,8 +1508,8 @@ } StringRef verName = stringTable.data() + verneeds[idx]; versionedNameBuffer.clear(); - name = saver().save( - (name + "@" + verName).toStringRef(versionedNameBuffer)); + name = + saver.save((name + "@" + verName).toStringRef(versionedNameBuffer)); } Symbol *s = symtab.addSymbol( Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()}); @@ -1553,7 +1554,7 @@ versionedNameBuffer.clear(); name = (name + "@" + verName).toStringRef(versionedNameBuffer); auto *s = symtab.addSymbol( - SharedSymbol{*this, saver().save(name), sym.getBinding(), sym.st_other, + SharedSymbol{*this, saver.save(name), sym.getBinding(), sym.st_other, sym.getType(), sym.st_value, sym.st_size, alignment}); if (s->file == this) s->verdefIndex = idx; @@ -1638,9 +1639,9 @@ // symbols later in the link stage). So we append file offset to make // filename unique. StringRef name = archiveName.empty() - ? saver().save(path) - : saver().save(archiveName + "(" + path::filename(path) + - " at " + utostr(offsetInArchive) + ")"); + ? saver.save(path) + : saver.save(archiveName + "(" + path::filename(path) + + " at " + utostr(offsetInArchive) + ")"); MemoryBufferRef mbref(mb.getBuffer(), name); obj = CHECK(lto::InputFile::create(mbref), this); @@ -1672,7 +1673,7 @@ uint8_t visibility = mapVisibility(objSym.getVisibility()); if (!sym) - sym = symtab->insert(saver().save(objSym.getName())); + sym = symtab->insert(saver.save(objSym.getName())); int c = objSym.getComdatIndex(); if (objSym.isUndefined() || (c != -1 && !keptComdats[c])) { @@ -1718,7 +1719,7 @@ symbols.resize(obj->symbols().size()); for (auto it : llvm::enumerate(obj->symbols())) if (!it.value().isUndefined()) { - auto *sym = symtab.insert(saver().save(it.value().getName())); + auto *sym = symtab.insert(saver.save(it.value().getName())); sym->resolve(LazyObject{*this}); symbols[it.index()] = sym; } @@ -1739,8 +1740,6 @@ if (!isAlnum(s[i])) s[i] = '_'; - llvm::StringSaver &saver = lld::saver(); - symtab->addSymbol(Defined{nullptr, saver.save(s + "_start"), STB_GLOBAL, STV_DEFAULT, STT_OBJECT, 0, 0, section}); symtab->addSymbol(Defined{nullptr, saver.save(s + "_end"), STB_GLOBAL, diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -15,7 +15,9 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" -#include "lld/Common/CommonLinkerContext.h" +#include "Thunks.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" @@ -121,7 +123,7 @@ { static std::mutex mu; std::lock_guard lock(mu); - uncompressedBuf = bAlloc().Allocate(size); + uncompressedBuf = bAlloc.Allocate(size); } if (Error e = zlib::uncompress(toStringRef(rawData), uncompressedBuf, size)) @@ -215,7 +217,7 @@ // Restore the original section name. // (e.g. ".zdebug_info" -> ".debug_info") - name = saver().save("." + name.substr(2)); + name = saver.save("." + name.substr(2)); return; } diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -19,7 +19,7 @@ #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" @@ -60,8 +60,8 @@ if (InputSectionBase *rel = isec->getRelocatedSection()) { OutputSection *out = rel->getOutputSection(); if (s->type == SHT_RELA) - return saver().save(".rela" + out->name); - return saver().save(".rel" + out->name); + return saver.save(".rela" + out->name); + return saver.save(".rel" + out->name); } } diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -26,7 +26,7 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Object/ELF.h" @@ -306,8 +306,8 @@ // As a workaround for glibc libc.a before 2.34 // (https://sourceware.org/PR27492), retain __libc_atexit and similar // sections regardless of zStartStopGC. - cNamedSections[saver().save("__start_" + sec->name)].push_back(sec); - cNamedSections[saver().save("__stop_" + sec->name)].push_back(sec); + cNamedSections[saver.save("__start_" + sec->name)].push_back(sec); + cNamedSections[saver.save("__stop_" + sec->name)].push_back(sec); } } diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -20,7 +20,7 @@ #include "SymbolTable.h" #include "Symbols.h" #include "Target.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/Memory.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" @@ -289,7 +289,7 @@ SmallString<128> pathData; StringRef path = (config->sysroot + s).toStringRef(pathData); if (sys::fs::exists(path)) - driver->addFile(saver().save(path), /*withLOption=*/false); + driver->addFile(saver.save(path), /*withLOption=*/false); else setError("cannot find " + s + " inside " + config->sysroot); return; @@ -303,7 +303,7 @@ if (config->sysroot.empty()) driver->addFile(s.substr(1), /*withLOption=*/false); else - driver->addFile(saver().save(config->sysroot + "/" + s.substr(1)), + driver->addFile(saver.save(config->sysroot + "/" + s.substr(1)), /*withLOption=*/false); } else if (s.startswith("-l")) { // Case 3: search in the list of library paths. @@ -326,7 +326,7 @@ } else { // Finally, search in the list of library paths. if (Optional path = findFromSearchPaths(s)) - driver->addFile(saver().save(*path), /*withLOption=*/true); + driver->addFile(saver.save(*path), /*withLOption=*/true); else setError("unable to find " + s); } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -25,8 +25,9 @@ #include "Target.h" #include "Thunks.h" #include "Writer.h" -#include "lld/Common/CommonLinkerContext.h" #include "lld/Common/DWARF.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "lld/Common/Version.h" #include "llvm/ADT/SetOperations.h" @@ -71,7 +72,7 @@ // This is only for testing. StringRef s = getenv("LLD_VERSION"); if (s.empty()) - s = saver().save(Twine("Linker: ") + getLLDVersion()); + s = saver.save(Twine("Linker: ") + getLLDVersion()); // +1 to include the terminating '\0'. return {(const uint8_t *)s.data(), s.size() + 1}; @@ -255,7 +256,7 @@ InputSection *elf::createInterpSection() { // StringSaver guarantees that the returned string ends with '\0'. - StringRef s = saver().save(config->dynamicLinker); + StringRef s = saver.save(config->dynamicLinker); ArrayRef contents = {(const uint8_t *)s.data(), s.size() + 1}; return make(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents, diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -27,7 +27,8 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" @@ -432,7 +433,7 @@ } void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__AArch64AbsLongThunk_" + destination.getName()), + addSymbol(saver.save("__AArch64AbsLongThunk_" + destination.getName()), STT_FUNC, 0, isec); addSymbol("$x", STT_NOTYPE, 0, isec); addSymbol("$d", STT_NOTYPE, 8, isec); @@ -458,8 +459,8 @@ } void AArch64ADRPThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__AArch64ADRPThunk_" + destination.getName()), - STT_FUNC, 0, isec); + addSymbol(saver.save("__AArch64ADRPThunk_" + destination.getName()), STT_FUNC, + 0, isec); addSymbol("$x", STT_NOTYPE, 0, isec); } @@ -558,7 +559,7 @@ } void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__ARMv7ABSLongThunk_" + destination.getName()), + addSymbol(saver.save("__ARMv7ABSLongThunk_" + destination.getName()), STT_FUNC, 0, isec); addSymbol("$a", STT_NOTYPE, 0, isec); } @@ -576,7 +577,7 @@ } void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__Thumbv7ABSLongThunk_" + destination.getName()), + addSymbol(saver.save("__Thumbv7ABSLongThunk_" + destination.getName()), STT_FUNC, 1, isec); addSymbol("$t", STT_NOTYPE, 0, isec); } @@ -597,8 +598,8 @@ } void ARMV7PILongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__ARMV7PILongThunk_" + destination.getName()), - STT_FUNC, 0, isec); + addSymbol(saver.save("__ARMV7PILongThunk_" + destination.getName()), STT_FUNC, + 0, isec); addSymbol("$a", STT_NOTYPE, 0, isec); } @@ -618,7 +619,7 @@ } void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__ThumbV7PILongThunk_" + destination.getName()), + addSymbol(saver.save("__ThumbV7PILongThunk_" + destination.getName()), STT_FUNC, 1, isec); addSymbol("$t", STT_NOTYPE, 0, isec); } @@ -633,7 +634,7 @@ } void ARMV5ABSLongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__ARMv5ABSLongThunk_" + destination.getName()), + addSymbol(saver.save("__ARMv5ABSLongThunk_" + destination.getName()), STT_FUNC, 0, isec); addSymbol("$a", STT_NOTYPE, 0, isec); addSymbol("$d", STT_NOTYPE, 4, isec); @@ -659,8 +660,8 @@ } void ARMV5PILongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__ARMV5PILongThunk_" + destination.getName()), - STT_FUNC, 0, isec); + addSymbol(saver.save("__ARMV5PILongThunk_" + destination.getName()), STT_FUNC, + 0, isec); addSymbol("$a", STT_NOTYPE, 0, isec); addSymbol("$d", STT_NOTYPE, 12, isec); } @@ -689,7 +690,7 @@ } void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__Thumbv6MABSLongThunk_" + destination.getName()), + addSymbol(saver.save("__Thumbv6MABSLongThunk_" + destination.getName()), STT_FUNC, 1, isec); addSymbol("$t", STT_NOTYPE, 0, isec); addSymbol("$d", STT_NOTYPE, 8, isec); @@ -715,7 +716,7 @@ } void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__Thumbv6MPILongThunk_" + destination.getName()), + addSymbol(saver.save("__Thumbv6MPILongThunk_" + destination.getName()), STT_FUNC, 1, isec); addSymbol("$t", STT_NOTYPE, 0, isec); addSymbol("$d", STT_NOTYPE, 12, isec); @@ -733,7 +734,7 @@ } void MipsThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0, + addSymbol(saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0, isec); } @@ -757,7 +758,7 @@ void MicroMipsThunk::addSymbols(ThunkSection &isec) { Defined *d = - addSymbol(saver().save("__microLA25Thunk_" + destination.getName()), + addSymbol(saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec); d->stOther |= STO_MIPS_MICROMIPS; } @@ -782,7 +783,7 @@ void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) { Defined *d = - addSymbol(saver().save("__microLA25Thunk_" + destination.getName()), + addSymbol(saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec); d->stOther |= STO_MIPS_MICROMIPS; } @@ -843,7 +844,7 @@ else os << ".plt_pic32."; os << destination.getName(); - addSymbol(saver().save(os.str()), STT_FUNC, 0, isec); + addSymbol(saver.save(os.str()), STT_FUNC, 0, isec); } bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec, @@ -852,7 +853,7 @@ } void PPC32LongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__LongThunk_" + destination.getName()), STT_FUNC, 0, + addSymbol(saver.save("__LongThunk_" + destination.getName()), STT_FUNC, 0, isec); } @@ -896,8 +897,8 @@ } void PPC64PltCallStub::addSymbols(ThunkSection &isec) { - Defined *s = addSymbol(saver().save("__plt_" + destination.getName()), - STT_FUNC, 0, isec); + Defined *s = addSymbol(saver.save("__plt_" + destination.getName()), STT_FUNC, + 0, isec); s->needsTocRestore = true; s->file = destination.file; } @@ -947,7 +948,7 @@ } void PPC64R2SaveStub::addSymbols(ThunkSection &isec) { - Defined *s = addSymbol(saver().save("__toc_save_" + destination.getName()), + Defined *s = addSymbol(saver.save("__toc_save_" + destination.getName()), STT_FUNC, 0, isec); s->needsTocRestore = true; } @@ -983,7 +984,7 @@ } void PPC64R12SetupStub::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__gep_setup_" + destination.getName()), STT_FUNC, 0, + addSymbol(saver.save("__gep_setup_" + destination.getName()), STT_FUNC, 0, isec); } @@ -1019,7 +1020,7 @@ } void PPC64PCRelPLTStub::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__plt_pcrel_" + destination.getName()), STT_FUNC, 0, + addSymbol(saver.save("__plt_pcrel_" + destination.getName()), STT_FUNC, 0, isec); } @@ -1035,7 +1036,7 @@ } void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__long_branch_" + destination.getName()), STT_FUNC, 0, + addSymbol(saver.save("__long_branch_" + destination.getName()), STT_FUNC, 0, isec); } diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -20,8 +20,8 @@ #include "SyntheticSections.h" #include "Target.h" #include "lld/Common/Arrays.h" -#include "lld/Common/CommonLinkerContext.h" #include "lld/Common/Filesystem.h" +#include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Parallel.h" @@ -2208,9 +2208,9 @@ StringRef s = sec->name; if (!isValidCIdentifier(s)) return; - addOptionalRegular(saver().save("__start_" + s), sec, 0, + addOptionalRegular(saver.save("__start_" + s), sec, 0, config->zStartStopVisibility); - addOptionalRegular(saver().save("__stop_" + s), sec, -1, + addOptionalRegular(saver.save("__stop_" + s), sec, -1, config->zStartStopVisibility); } diff --git a/lld/MachO/ConcatOutputSection.cpp b/lld/MachO/ConcatOutputSection.cpp --- a/lld/MachO/ConcatOutputSection.cpp +++ b/lld/MachO/ConcatOutputSection.cpp @@ -13,7 +13,8 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/TimeProfiler.h" @@ -321,8 +322,8 @@ // get written are happy. thunkInfo.isec->live = true; - StringRef thunkName = saver().save(funcSym->getName() + ".thunk." + - std::to_string(thunkInfo.sequence++)); + StringRef thunkName = saver.save(funcSym->getName() + ".thunk." + + std::to_string(thunkInfo.sequence++)); r.referent = thunkInfo.sym = symtab->addDefined( thunkName, /*file=*/nullptr, thunkInfo.isec, /*value=*/0, /*size=*/thunkSize, /*isWeakDef=*/false, /*isPrivateExtern=*/true, diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -129,7 +129,7 @@ // only append suffix if realpath() succeeds Twine suffixed = location + suffix; if (fs::exists(suffixed)) - return resolvedFrameworks[key] = saver().save(suffixed.str()); + return resolvedFrameworks[key] = saver.save(suffixed.str()); } // Suffix lookup failed, fall through to the no-suffix case. } @@ -166,7 +166,7 @@ path::append(buffer, path); // Do not warn about paths that are computed via the syslib roots if (fs::is_directory(buffer)) { - paths.push_back(saver().save(buffer.str())); + paths.push_back(saver.save(buffer.str())); found = true; } } @@ -184,7 +184,7 @@ SmallString<261> buffer(root); path::append(buffer, path); if (fs::is_directory(buffer)) - paths.push_back(saver().save(buffer.str())); + paths.push_back(saver.save(buffer.str())); } } return paths; @@ -1069,14 +1069,14 @@ symtab->addUndefined("dyld_stub_binder", /*file=*/nullptr, /*isWeak=*/false); } -bool macho::link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, - bool disableOutput) { - // This driver-specific context will be freed later by lldMain(). - auto *ctx = new CommonLinkerContext; +bool macho::link(ArrayRef argsArr, bool canExitEarly, + raw_ostream &stdoutOS, raw_ostream &stderrOS) { + lld::stdoutOS = &stdoutOS; + lld::stderrOS = &stderrOS; + + errorHandler().cleanupCallback = []() { + freeArena(); - ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); - ctx->e.cleanupCallback = []() { resolvedFrameworks.clear(); resolvedLibraries.clear(); cachedReads.clear(); @@ -1098,15 +1098,17 @@ InputFile::resetIdCount(); }; - ctx->e.logName = args::getFilenameWithoutExe(argsArr[0]); + errorHandler().logName = args::getFilenameWithoutExe(argsArr[0]); + stderrOS.enable_colors(stderrOS.has_colors()); MachOOptTable parser; InputArgList args = parser.parse(argsArr.slice(1)); - ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now " - "(use --error-limit=0 to see all errors)"; - ctx->e.errorLimit = args::getInteger(args, OPT_error_limit_eq, 20); - ctx->e.verbose = args.hasArg(OPT_verbose); + errorHandler().errorLimitExceededMsg = + "too many errors emitted, stopping now " + "(use --error-limit=0 to see all errors)"; + errorHandler().errorLimit = args::getInteger(args, OPT_error_limit_eq, 20); + errorHandler().verbose = args.hasArg(OPT_verbose); if (args.hasArg(OPT_help_hidden)) { parser.printHelp(argsArr[0], /*showHidden=*/true); @@ -1171,7 +1173,7 @@ // these are meaningful for our text based stripping if (config->osoPrefix.equals(".") || config->osoPrefix.endswith(sep)) expanded += sep; - config->osoPrefix = saver().save(expanded.str()); + config->osoPrefix = saver.save(expanded.str()); } } @@ -1459,7 +1461,7 @@ // Parse LTO options. if (const Arg *arg = args.getLastArg(OPT_mcpu)) - parseClangOption(saver().save("-mcpu=" + StringRef(arg->getValue())), + parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())), arg->getSpelling()); for (const Arg *arg : args.filtered(OPT_mllvm)) @@ -1556,5 +1558,11 @@ timeTraceProfilerCleanup(); } - return errorCount() == 0; + + if (canExitEarly) + exitLld(errorCount() ? 1 : 0); + + bool ret = errorCount() == 0; + errorHandler().reset(); + return ret; } diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -13,7 +13,8 @@ #include "Target.h" #include "lld/Common/Args.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "lld/Common/Reproduce.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseMap.h" @@ -81,7 +82,7 @@ // Expand response files (arguments in the form of @) // and then parse the argument again. - cl::ExpandResponseFiles(saver(), cl::TokenizeGNUCommandLine, vec); + cl::ExpandResponseFiles(saver, cl::TokenizeGNUCommandLine, vec); InputArgList args = ParseArgs(vec, missingIndex, missingCount); // Handle -fatal_warnings early since it converts missing argument warnings @@ -190,12 +191,12 @@ bool tbdExists = fs::exists(tbdPath); searchedDylib(tbdPath, tbdExists); if (tbdExists) - return saver().save(tbdPath.str()); + return saver.save(tbdPath.str()); bool dylibExists = fs::exists(dylibPath); searchedDylib(dylibPath, dylibExists); if (dylibExists) - return saver().save(dylibPath); + return saver.save(dylibPath); return {}; } @@ -260,7 +261,7 @@ bool exists = fs::exists(location); searchedDylib(location, exists); if (exists) - return saver().save(location.str()); + return saver.save(location.str()); } } return {}; diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -56,8 +56,9 @@ #include "SyntheticSections.h" #include "Target.h" -#include "lld/Common/CommonLinkerContext.h" #include "lld/Common/DWARF.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "lld/Common/Reproduce.h" #include "llvm/ADT/iterator.h" #include "llvm/BinaryFormat/MachO.h" @@ -209,8 +210,6 @@ return cachedReads[key] = mbref; } - llvm::BumpPtrAllocator &bAlloc = lld::bAlloc(); - // Object files and archive files may be fat files, which contain multiple // real files for different CPU ISAs. Here, we search for a file that matches // with the current link target and returns it as a MemoryBufferRef. @@ -242,7 +241,7 @@ } InputFile::InputFile(Kind kind, const InterfaceFile &interface) - : id(idCount++), fileKind(kind), name(saver().save(interface.getPath())) {} + : id(idCount++), fileKind(kind), name(saver.save(interface.getPath())) {} // Some sections comprise of fixed-size records, so instead of splitting them at // symbol boundaries, we split them based on size. Records are distinct from @@ -1200,7 +1199,7 @@ // Find all the $ld$* symbols to process first. parseTrie(buf + c->export_off, c->export_size, [&](const Twine &name, uint64_t flags) { - StringRef savedName = saver().save(name); + StringRef savedName = saver.save(name); if (handleLDSymbol(savedName)) return; entries.push_back({savedName, flags}); @@ -1275,7 +1274,7 @@ umbrella = this; this->umbrella = umbrella; - installName = saver().save(interface.getInstallName()); + installName = saver.save(interface.getInstallName()); compatibilityVersion = interface.getCompatibilityVersion().rawValue(); currentVersion = interface.getCurrentVersion().rawValue(); @@ -1294,7 +1293,7 @@ exportingFile = isImplicitlyLinked(installName) ? this : umbrella; auto addSymbol = [&](const Twine &name) -> void { - StringRef savedName = saver().save(name); + StringRef savedName = saver.save(name); if (exportingFile->hiddenSymbols.contains(CachedHashStringRef(savedName))) return; @@ -1413,7 +1412,7 @@ config->platformInfo.minimum >= end) return; - this->installName = saver().save(installName); + this->installName = saver.save(installName); if (!compatVersion.empty()) { VersionTuple cVersion; @@ -1435,7 +1434,7 @@ if (!condition.consume_front("os") || version.tryParse(condition)) warn("failed to parse os version, symbol '" + originalName + "' ignored"); else if (version == config->platformInfo.minimum) - this->installName = saver().save(installName); + this->installName = saver.save(installName); } void DylibFile::handleLDHideSymbol(StringRef name, StringRef originalName) { @@ -1540,7 +1539,7 @@ static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym, BitcodeFile &file) { - StringRef name = saver().save(objSym.getName()); + StringRef name = saver.save(objSym.getName()); if (objSym.isUndefined()) return symtab->addUndefined(name, &file, /*isWeakRef=*/objSym.isWeak()); @@ -1582,12 +1581,11 @@ // So, we append the archive name to disambiguate two members with the same // name from multiple different archives, and offset within the archive to // disambiguate two members of the same name from a single archive. - MemoryBufferRef mbref(mb.getBuffer(), - saver().save(archiveName.empty() - ? path - : archiveName + - sys::path::filename(path) + - utostr(offsetInArchive))); + MemoryBufferRef mbref( + mb.getBuffer(), + saver.save(archiveName.empty() ? path + : archiveName + sys::path::filename(path) + + utostr(offsetInArchive))); obj = check(lto::InputFile::create(mbref)); if (lazy) @@ -1611,7 +1609,7 @@ const lto::InputFile::Symbol &objSym = it.value(); if (!objSym.isUndefined()) { symbols[it.index()] = - symtab->addLazyObject(saver().save(objSym.getName()), *this); + symtab->addLazyObject(saver.save(objSym.getName()), *this); if (!lazy) break; } diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp --- a/lld/MachO/LTO.cpp +++ b/lld/MachO/LTO.cpp @@ -14,7 +14,7 @@ #include "Target.h" #include "lld/Common/Args.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Strings.h" #include "lld/Common/TargetOptionsCommandFlags.h" #include "llvm/LTO/Config.h" @@ -148,7 +148,7 @@ modTime = getModTime(filePath); } ret.push_back(make( - MemoryBufferRef(buf[i], saver().save(filePath.str())), modTime, "")); + MemoryBufferRef(buf[i], saver.save(filePath.str())), modTime, "")); } for (std::unique_ptr &file : files) if (file) diff --git a/lld/MachO/SectionPriorities.cpp b/lld/MachO/SectionPriorities.cpp --- a/lld/MachO/SectionPriorities.cpp +++ b/lld/MachO/SectionPriorities.cpp @@ -17,7 +17,6 @@ #include "Symbols.h" #include "Target.h" #include "lld/Common/Args.h" -#include "lld/Common/CommonLinkerContext.h" #include "lld/Common/ErrorHandler.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" @@ -255,8 +254,8 @@ if (f->archiveName.empty()) filename = path::filename(f->getName()); else - filename = saver().save(path::filename(f->archiveName) + "(" + - path::filename(f->getName()) + ")"); + filename = saver.save(path::filename(f->archiveName) + "(" + + path::filename(f->getName()) + ")"); return std::max(entry.objectFiles.lookup(filename), entry.anyObjectFile); } @@ -338,7 +337,7 @@ // This first builds a call graph based on the profile data then merges sections // according to the C³ heuristic. All clusters are then sorted by a density // metric to further improve locality. -static DenseMap computeCallGraphProfileOrder() { +DenseMap computeCallGraphProfileOrder() { TimeTraceScope timeScope("Call graph profile sort"); return CallGraphSort().run(); } diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -16,7 +16,8 @@ #include "SymbolTable.h" #include "Symbols.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/EndianStream.h" @@ -833,7 +834,7 @@ if (!dir.endswith(sep)) dir += sep; stab.strx = stringTableSection.addString( - saver().save(dir + compileUnit->getUnitDIE().getShortName())); + saver.save(dir + compileUnit->getUnitDIE().getShortName())); stabs.emplace_back(std::move(stab)); } @@ -855,7 +856,7 @@ if (!file->archiveName.empty()) path.append({"(", file->getName(), ")"}); - StringRef adjustedPath = saver().save(path.str()); + StringRef adjustedPath = saver.save(path.str()); adjustedPath.consume_front(config->osoPrefix); stab.strx = stringTableSection.addString(adjustedPath); diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -22,7 +22,8 @@ #include "UnwindInfoSection.h" #include "lld/Common/Arrays.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/LEB128.h" @@ -610,7 +611,7 @@ } static void prepareSymbolRelocation(Symbol *sym, const InputSection *isec, - const lld::macho::Reloc &r) { + const Reloc &r) { assert(sym->isLive()); const RelocAttrs &relocAttrs = target->getRelocAttrs(r.type); @@ -643,7 +644,7 @@ continue; for (auto it = isec->relocs.begin(); it != isec->relocs.end(); ++it) { - lld::macho::Reloc &r = *it; + Reloc &r = *it; if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) { // Skip over the following UNSIGNED relocation -- it's just there as the // minuend, and doesn't have the usual UNSIGNED semantics. We don't want @@ -1170,7 +1171,7 @@ // This section contains space for just a single word, and will be used by // dyld to cache an address to the image loader it uses. - uint8_t *arr = bAlloc().Allocate(target->wordSize); + uint8_t *arr = bAlloc.Allocate(target->wordSize); memset(arr, 0, target->wordSize); in.imageLoaderCache = makeSyntheticInputSection( segment_names::data, section_names::data, S_REGULAR, diff --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp --- a/lld/MinGW/Driver.cpp +++ b/lld/MinGW/Driver.cpp @@ -100,7 +100,7 @@ unsigned missingCount; SmallVector vec(argv.data(), argv.data() + argv.size()); - cl::ExpandResponseFiles(saver(), getQuotingStyle(), vec); + cl::ExpandResponseFiles(saver, getQuotingStyle(), vec); opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount); if (missingCount) @@ -154,11 +154,12 @@ // Convert Unix-ish command line arguments to Windows-ish ones and // then call coff::link. -bool mingw::link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, - bool disableOutput) { - auto *ctx = new CommonLinkerContext; - ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); +bool mingw::link(ArrayRef argsArr, bool canExitEarly, + raw_ostream &stdoutOS, raw_ostream &stderrOS) { + lld::stdoutOS = &stdoutOS; + lld::stderrOS = &stderrOS; + + stderrOS.enable_colors(stderrOS.has_colors()); MinGWOptTable parser; opt::InputArgList args = parser.parse(argsArr.slice(1)); @@ -446,9 +447,5 @@ // Pass the actual binary name, to make error messages be printed with // the right prefix. vec[0] = argsArr[0]; - - // The context will be re-created in the COFF driver. - lld::CommonLinkerContext::destroy(); - - return coff::link(vec, stdoutOS, stderrOS, exitEarly, disableOutput); + return coff::link(vec, canExitEarly, stdoutOS, stderrOS); } diff --git a/lld/include/lld/Common/CommonLinkerContext.h b/lld/include/lld/Common/CommonLinkerContext.h deleted file mode 100644 --- a/lld/include/lld/Common/CommonLinkerContext.h +++ /dev/null @@ -1,65 +0,0 @@ -//===- CommonLinkerContext.h ------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Entry point for all global state in lldCommon. The objective is for LLD to be -// used "as a library" in a thread-safe manner. -// -// Instead of program-wide globals or function-local statics, we prefer -// aggregating all "global" states into a heap-based structure -// (CommonLinkerContext). This also achieves deterministic initialization & -// shutdown for all "global" states. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COMMON_COMMONLINKINGCONTEXT_H -#define LLD_COMMON_COMMONLINKINGCONTEXT_H - -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" -#include "llvm/CodeGen/CommandFlags.h" -#include "llvm/Support/StringSaver.h" - -namespace llvm { -class raw_ostream; -} // namespace llvm - -namespace lld { -struct SpecificAllocBase; -class CommonLinkerContext { -public: - CommonLinkerContext(); - virtual ~CommonLinkerContext(); - - static void destroy(); - - llvm::BumpPtrAllocator bAlloc; - llvm::StringSaver saver{bAlloc}; - llvm::DenseMap instances; - - ErrorHandler e; - -private: - llvm::codegen::RegisterCodeGenFlags cgf; -}; - -// Retrieve the global state. Currently only one state can exist per process, -// but in the future we plan on supporting an arbitrary number of LLD instances -// in a single process. -CommonLinkerContext &commonContext(); - -template T &context() { - return static_cast(commonContext()); -} - -bool hasContext(); - -inline llvm::StringSaver &saver() { return context().saver; } -inline llvm::BumpPtrAllocator &bAlloc() { return context().bAlloc; } -} // namespace lld - -#endif diff --git a/lld/include/lld/Common/Driver.h b/lld/include/lld/Common/Driver.h --- a/lld/include/lld/Common/Driver.h +++ b/lld/include/lld/Common/Driver.h @@ -9,7 +9,6 @@ #ifndef LLD_COMMON_DRIVER_H #define LLD_COMMON_DRIVER_H -#include "lld/Common/CommonLinkerContext.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/raw_ostream.h" @@ -29,28 +28,28 @@ llvm::raw_ostream &stderrOS); namespace coff { -bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); +bool link(llvm::ArrayRef args, bool canExitEarly, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); } namespace mingw { -bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); +bool link(llvm::ArrayRef args, bool canExitEarly, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); } namespace elf { -bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); +bool link(llvm::ArrayRef args, bool canExitEarly, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); } namespace macho { -bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); +bool link(llvm::ArrayRef args, bool canExitEarly, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); } namespace wasm { -bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); +bool link(llvm::ArrayRef args, bool canExitEarly, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); } } diff --git a/lld/include/lld/Common/ErrorHandler.h b/lld/include/lld/Common/ErrorHandler.h --- a/lld/include/lld/Common/ErrorHandler.h +++ b/lld/include/lld/Common/ErrorHandler.h @@ -73,7 +73,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileOutputBuffer.h" -#include namespace llvm { class DiagnosticInfo; @@ -82,6 +81,11 @@ namespace lld { +// We wrap stdout and stderr so that you can pass alternative stdout/stderr as +// arguments to lld::*::link() functions. +extern llvm::raw_ostream *stdoutOS; +extern llvm::raw_ostream *stderrOS; + llvm::raw_ostream &outs(); llvm::raw_ostream &errs(); @@ -89,11 +93,6 @@ class ErrorHandler { public: - ~ErrorHandler(); - - void initialize(llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, - bool exitEarly, bool disableOutput); - uint64_t errorCount = 0; uint64_t errorLimit = 20; StringRef errorLimitExceededMsg = "too many errors emitted, stopping now"; @@ -113,9 +112,11 @@ void message(const Twine &msg, llvm::raw_ostream &s); void warn(const Twine &msg); - raw_ostream &outs(); - raw_ostream &errs(); - void flushStreams(); + void reset() { + if (cleanupCallback) + cleanupCallback(); + *this = ErrorHandler(); + } std::unique_ptr outputBuffer; @@ -125,19 +126,6 @@ std::string getLocation(const Twine &msg); void reportDiagnostic(StringRef location, Colors c, StringRef diagKind, const Twine &msg); - - // We want to separate multi-line messages with a newline. `sep` is "\n" - // if the last messages was multi-line. Otherwise "". - llvm::StringRef sep; - - // We wrap stdout and stderr so that you can pass alternative stdout/stderr as - // arguments to lld::*::link() functions. Since lld::outs() or lld::errs() can - // be indirectly called from multiple threads, we protect them using a mutex. - // In the future, we plan on supporting several concurent linker contexts, - // which explains why the mutex is not a global but part of this context. - std::mutex mu; - llvm::raw_ostream *stdoutOS{}; - llvm::raw_ostream *stderrOS{}; }; /// Returns the default error handler. diff --git a/lld/include/lld/Common/Memory.h b/lld/include/lld/Common/Memory.h --- a/lld/include/lld/Common/Memory.h +++ b/lld/include/lld/Common/Memory.h @@ -22,41 +22,42 @@ #define LLD_COMMON_MEMORY_H #include "llvm/Support/Allocator.h" +#include "llvm/Support/StringSaver.h" +#include namespace lld { -// A base class only used by the CommonLinkerContext to keep track of the -// SpecificAlloc<> instances. + +// Use this arena if your object doesn't have a destructor. +extern llvm::BumpPtrAllocator bAlloc; +extern llvm::StringSaver saver; + +void freeArena(); + +// These two classes are hack to keep track of all +// SpecificBumpPtrAllocator instances. struct SpecificAllocBase { + SpecificAllocBase() { instances.push_back(this); } virtual ~SpecificAllocBase() = default; - static SpecificAllocBase *getOrCreate(void *tag, size_t size, size_t align, - SpecificAllocBase *(&creator)(void *)); + virtual void reset() = 0; + static std::vector instances; }; -// An arena of specific types T, created on-demand. template struct SpecificAlloc : public SpecificAllocBase { - static SpecificAllocBase *create(void *storage) { - return new (storage) SpecificAlloc(); - } + void reset() override { alloc.DestroyAll(); } llvm::SpecificBumpPtrAllocator alloc; - static int tag; }; -// The address of this static member is only used as a key in -// CommonLinkerContext::instances. Its value does not matter. -template int SpecificAlloc::tag = 0; - -// Creates the arena on-demand on the first call; or returns it, if it was -// already created. +// Use a static local for these singletons so they are only registered if an +// object of this instance is ever constructed. Otherwise we will create and +// register ELF allocators for COFF and the reverse. template inline llvm::SpecificBumpPtrAllocator &getSpecificAllocSingleton() { - SpecificAllocBase *instance = SpecificAllocBase::getOrCreate( - &SpecificAlloc::tag, sizeof(SpecificAlloc), - alignof(SpecificAlloc), SpecificAlloc::create); - return ((SpecificAlloc *)instance)->alloc; + static SpecificAlloc instance; + return instance.alloc; } -// Creates new instances of T off a (almost) contiguous arena/object pool. The -// instances are destroyed whenever lldMain() goes out of scope. +// Use this arena if your object has a destructor. +// Your destructor will be invoked from freeArena(). template T *make(U &&... args) { return new (getSpecificAllocSingleton().Allocate()) T(std::forward(args)...); diff --git a/lld/include/lld/Core/LinkingContext.h b/lld/include/lld/Core/LinkingContext.h --- a/lld/include/lld/Core/LinkingContext.h +++ b/lld/include/lld/Core/LinkingContext.h @@ -9,7 +9,6 @@ #ifndef LLD_CORE_LINKING_CONTEXT_H #define LLD_CORE_LINKING_CONTEXT_H -#include "lld/Common/CommonLinkerContext.h" #include "lld/Core/Node.h" #include "lld/Core/Reader.h" #include "llvm/ADT/ArrayRef.h" @@ -35,7 +34,7 @@ /// The base class LinkingContext contains the options needed by core linking. /// Subclasses of LinkingContext have additional options needed by specific /// Writers. -class LinkingContext : public CommonLinkerContext { +class LinkingContext { public: virtual ~LinkingContext(); diff --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp --- a/lld/tools/lld/lld.cpp +++ b/lld/tools/lld/lld.cpp @@ -87,8 +87,6 @@ // Expand response files (arguments in the form of @) // to allow detecting the -m argument from arguments in them. SmallVector expandedArgs(v.data(), v.data() + v.size()); - BumpPtrAllocator a; - StringSaver saver(a); cl::ExpandResponseFiles(saver, getDefaultQuotingStyle(), expandedArgs); for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) { if (StringRef(*it) != "-m") @@ -136,42 +134,27 @@ return parseProgname(arg0); } -bool inTestOutputDisabled = false; - /// Universal linker main(). This linker emulates the gnu, darwin, or /// windows linker based on the argv[0] or -flavor option. static int lldMain(int argc, const char **argv, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly = true) { std::vector args(argv, argv + argc); - auto link = [&args]() { - Flavor f = parseFlavor(args); - if (f == Gnu && isPETarget(args)) - return mingw::link; - else if (f == Gnu) - return elf::link; - else if (f == WinLink) - return coff::link; - else if (f == Darwin) - return macho::link; - else if (f == Wasm) - return lld::wasm::link; - else - die("lld is a generic driver.\n" - "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld" - " (WebAssembly) instead"); - }; - // Run the driver. If an error occurs, false will be returned. - bool r = link()(args, stdoutOS, stderrOS, exitEarly, inTestOutputDisabled); - - // Call exit() if we can to avoid calling destructors. - if (exitEarly) - exitLld(!r ? 1 : 0); - - // Delete the global context and clear the global context pointer, so that it - // cannot be accessed anymore. - CommonLinkerContext::destroy(); - - return !r ? 1 : 0; + switch (parseFlavor(args)) { + case Gnu: + if (isPETarget(args)) + return !mingw::link(args, exitEarly, stdoutOS, stderrOS); + return !elf::link(args, exitEarly, stdoutOS, stderrOS); + case WinLink: + return !coff::link(args, exitEarly, stdoutOS, stderrOS); + case Darwin: + return !macho::link(args, exitEarly, stdoutOS, stderrOS); + case Wasm: + return !lld::wasm::link(args, exitEarly, stdoutOS, stderrOS); + default: + die("lld is a generic driver.\n" + "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld" + " (WebAssembly) instead"); + } } // Similar to lldMain except that exceptions are caught. @@ -193,7 +176,7 @@ // Cleanup memory and reset everything back in pristine condition. This path // is only taken when LLD is in test, or when it is used as a library. llvm::CrashRecoveryContext crc; - if (!crc.RunSafely([&]() { CommonLinkerContext::destroy(); })) { + if (!crc.RunSafely([&]() { errorHandler().reset(); })) { // The memory is corrupted beyond any possible recovery. return {r, /*canRunAgain=*/false}; } @@ -224,7 +207,8 @@ for (unsigned i = inTestVerbosity(); i > 0; --i) { // Disable stdout/stderr for all iterations but the last one. - inTestOutputDisabled = (i != 1); + if (i != 1) + errorHandler().disableOutput = true; // Execute one iteration. auto r = safeLldMain(argc, argv, llvm::outs(), llvm::errs()); diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -81,15 +81,18 @@ }; } // anonymous namespace -bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) { - // This driver-specific context will be freed later by lldMain(). - auto *ctx = new CommonLinkerContext; +bool link(ArrayRef args, bool canExitEarly, raw_ostream &stdoutOS, + raw_ostream &stderrOS) { + lld::stdoutOS = &stdoutOS; + lld::stderrOS = &stderrOS; - ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); - ctx->e.logName = args::getFilenameWithoutExe(args[0]); - ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use " - "-error-limit=0 to see all errors)"; + errorHandler().cleanupCallback = []() { freeArena(); }; + + errorHandler().logName = args::getFilenameWithoutExe(args[0]); + errorHandler().errorLimitExceededMsg = + "too many errors emitted, stopping now (use " + "-error-limit=0 to see all errors)"; + stderrOS.enable_colors(stderrOS.has_colors()); config = make(); symtab = make(); @@ -97,7 +100,13 @@ initLLVM(); LinkerDriver().linkerMain(args); - return errorCount() == 0; + // Exit immediately if we don't need to return to the caller. + // This saves time because the overhead of calling destructors + // for all globally-allocated objects is not negligible. + if (canExitEarly) + exitLld(errorCount() ? 1 : 0); + + return !errorCount(); } // Create prefix string literals used in Options.td @@ -180,7 +189,7 @@ // Expand response files (arguments in the form of @) // and then parse the argument again. - cl::ExpandResponseFiles(saver(), getQuotingStyle(args), vec); + cl::ExpandResponseFiles(saver, getQuotingStyle(args), vec); args = this->ParseArgs(vec, missingIndex, missingCount); handleColorDiagnostics(args); @@ -750,8 +759,8 @@ if (!sym) continue; - Symbol *real = addUndefined(saver().save("__real_" + name)); - Symbol *wrap = addUndefined(saver().save("__wrap_" + name)); + Symbol *real = addUndefined(saver.save("__real_" + name)); + Symbol *wrap = addUndefined(saver.save("__wrap_" + name)); v.push_back({sym, real, wrap}); // We want to tell LTO not to inline symbols to be overwritten diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -12,7 +12,8 @@ #include "InputElement.h" #include "OutputSegment.h" #include "SymbolTable.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "lld/Common/Reproduce.h" #include "llvm/Object/Binary.h" #include "llvm/Object/Wasm.h" @@ -720,7 +721,7 @@ static Symbol *createBitcodeSymbol(const std::vector &keptComdats, const lto::InputFile::Symbol &objSym, BitcodeFile &f) { - StringRef name = saver().save(objSym.getName()); + StringRef name = saver.save(objSym.getName()); uint32_t flags = objSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0; flags |= mapVisibility(objSym.getVisibility()); @@ -755,9 +756,9 @@ // symbols later in the link stage). So we append file offset to make // filename unique. StringRef name = archiveName.empty() - ? saver().save(path) - : saver().save(archiveName + "(" + path::filename(path) + - " at " + utostr(offsetInArchive) + ")"); + ? saver.save(path) + : saver.save(archiveName + "(" + path::filename(path) + + " at " + utostr(offsetInArchive) + ")"); MemoryBufferRef mbref(mb.getBuffer(), name); obj = check(lto::InputFile::create(mbref)); diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -11,7 +11,8 @@ #include "InputChunks.h" #include "InputElement.h" #include "WriterUtils.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/ADT/SetVector.h" #define DEBUG_TYPE "lld" @@ -842,7 +843,7 @@ void SymbolTable::replaceWithUndefined(Symbol *sym) { // Add a synthetic dummy for weak undefined functions. These dummies will // be GC'd if not used as the target of any "call" instructions. - StringRef debugName = saver().save("undefined_weak:" + toString(*sym)); + StringRef debugName = saver.save("undefined_weak:" + toString(*sym)); replaceWithUnreachable(sym, *sym->getSignature(), debugName); // Hide our dummy to prevent export. sym->setHidden(true); @@ -940,8 +941,7 @@ if (symbol != defined) { auto *f = cast(symbol); reportFunctionSignatureMismatch(symName, f, defined, false); - StringRef debugName = - saver().save("signature_mismatch:" + toString(*f)); + StringRef debugName = saver.save("signature_mismatch:" + toString(*f)); replaceWithUnreachable(f, *f->signature, debugName); } } diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -17,7 +17,8 @@ #include "SymbolTable.h" #include "SyntheticSections.h" #include "WriterUtils.h" -#include "lld/Common/CommonLinkerContext.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallSet.h" @@ -189,7 +190,7 @@ else if (sec->type == WASM_SEC_CODE) name = "reloc.CODE"; else if (sec->type == WASM_SEC_CUSTOM) - name = saver().save("reloc." + sec->name); + name = saver.save("reloc." + sec->name); else llvm_unreachable( "relocations only supported for code, data, or custom sections"); @@ -388,8 +389,8 @@ LLVM_DEBUG(dbgs() << "addStartStopSymbols: " << name << "\n"); uint64_t start = seg->startVA; uint64_t stop = start + seg->size; - symtab->addOptionalDataSymbol(saver().save("__start_" + name), start); - symtab->addOptionalDataSymbol(saver().save("__stop_" + name), stop); + symtab->addOptionalDataSymbol(saver.save("__start_" + name), start); + symtab->addOptionalDataSymbol(saver.save("__stop_" + name), stop); } void Writer::addSections() { @@ -957,7 +958,7 @@ writeUleb128(os, bodyContent.size(), "function size"); os << bodyContent; } - ArrayRef body = arrayRefFromStringRef(saver().save(functionBody)); + ArrayRef body = arrayRefFromStringRef(saver.save(functionBody)); cast(func->function)->setBody(body); } diff --git a/llvm/include/llvm/DebugInfo/PDB/DIA/DIASupport.h b/llvm/include/llvm/DebugInfo/PDB/DIA/DIASupport.h --- a/llvm/include/llvm/DebugInfo/PDB/DIA/DIASupport.h +++ b/llvm/include/llvm/DebugInfo/PDB/DIA/DIASupport.h @@ -27,14 +27,7 @@ // DIA headers must come after windows headers. #include -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnon-virtual-dtor" -#endif #include -#ifdef __clang__ -#pragma clang diagnostic pop -#endif #include #endif // LLVM_DEBUGINFO_PDB_DIA_DIASUPPORT_H diff --git a/mlir/lib/Dialect/GPU/Transforms/SerializeToHsaco.cpp b/mlir/lib/Dialect/GPU/Transforms/SerializeToHsaco.cpp --- a/mlir/lib/Dialect/GPU/Transforms/SerializeToHsaco.cpp +++ b/mlir/lib/Dialect/GPU/Transforms/SerializeToHsaco.cpp @@ -440,8 +440,7 @@ // Invoke lld. Expect a true return value from lld. if (!lld::elf::link({"ld.lld", "-shared", tempIsaBinaryFilename.c_str(), "-o", tempHsacoFilename.c_str()}, - llvm::outs(), llvm::errs(), /*exitEarly=*/true, - /*disableOutput=*/false)) { + /*canExitEarly=*/false, llvm::outs(), llvm::errs())) { emitError(loc, "lld invocation error"); return {}; }