From f6bd0a8f2bc4b62f7f7800a7dd1de6ba764b56c6 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 4 Aug 2022 11:09:40 -0700 Subject: [PATCH] [ELF] Add makeThreadLocal/makeThreadLocalN and remove InputFile::localSymStorage makeThreadLocal/makeThreadLocalN are moved from D130810 ([ELF] Parallelize input section initialization) here to make D130810 more focused on the refactor: * COFF has some needs for multiple linker contexts. D108850 partially removed global states from lldCommon but left the global variable `lctx`. * To the best of my knowledge, all multiple-linker-context feature requests to ELF are more from user convenience, with no very strong argument. * In practice, ELF port is very difficult to remove global states without introducing significant performance regression/hurting code readability. * Per-thread allocators from D122922/D123879 are too expensive and will not really benefit ELF. This patch adds a simple thread_local based makeThreadLocal to lld/Common/Memory.h. It will enable further optimization in ELF. --- lld/ELF/InputFiles.cpp | 3 +-- lld/ELF/InputFiles.h | 3 --- lld/include/lld/Common/Memory.h | 26 ++++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 378023a..560e24f 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1066,8 +1066,7 @@ void ObjFile::initializeSymbols(const object::ELFFile &obj) { template void ObjFile::initializeLocalSymbols() { if (!firstGlobal) return; - localSymStorage = std::make_unique(firstGlobal); - SymbolUnion *locals = localSymStorage.get(); + SymbolUnion *locals = makeThreadLocalN(firstGlobal); ArrayRef eSyms = this->getELFSyms(); for (size_t i = 0, end = firstGlobal; i != end; ++i) { diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index a24e664..dd9f732 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -304,9 +304,6 @@ private: // If the section does not exist (which is common), the array is empty. ArrayRef shndxTable; - // Storage for local symbols. - std::unique_ptr localSymStorage; - // Debugging information to retrieve source file and line for error // reporting. Linker may find reasonable number of errors in a // single object file, so we cache debugging information in order to diff --git a/lld/include/lld/Common/Memory.h b/lld/include/lld/Common/Memory.h index 0b2f474..c7612a0 100644 --- a/lld/include/lld/Common/Memory.h +++ b/lld/include/lld/Common/Memory.h @@ -62,6 +62,32 @@ template T *make(U &&... args) { T(std::forward(args)...); } +template +inline llvm::SpecificBumpPtrAllocator & +getSpecificAllocSingletonThreadLocal() { + thread_local SpecificAlloc instance; + return instance.alloc; +} + +// Create a new instance of T off a thread-local SpecificAlloc, used by code +// like parallel input section initialization. The use cases assume that the +// return value outlives the containing parallelForEach (if exists), which is +// currently guaranteed: when parallelForEach returns, the threads allocating +// the TLS are not destroyed. +// +// Note: Some ports (e.g. ELF) have lots of global states which are currently +// infeasible to remove, and context() just adds overhead with no benefit. The +// allocation performance is of higher importance, so we simply use thread_local +// allocators instead of doing context indirection and pthread_getspecific. +template T *makeThreadLocal(U &&...args) { + return new (getSpecificAllocSingletonThreadLocal().Allocate()) + T(std::forward(args)...); +} + +template T *makeThreadLocalN(size_t n) { + return new (getSpecificAllocSingletonThreadLocal().Allocate(n)) T[n]; +} + } // namespace lld #endif -- 2.7.4