diff --git a/lld/Common/CommonLinkerContext.cpp b/lld/Common/CommonLinkerContext.cpp --- a/lld/Common/CommonLinkerContext.cpp +++ b/lld/Common/CommonLinkerContext.cpp @@ -28,12 +28,29 @@ codegen::RegisterCodeGenFlags CGF; } +AllocContext *CommonLinkerContext::alloc() { + AllocContext *context = contextIndex.get(); + if (!context) { + // Context didn't exist yet for this thread, so create a new one. + context = new AllocContext; + contextIndex.set(context); + + llvm::sys::ScopedWriter lock(allContextsMutex); + allContexts.push_back(context); + } + return context; +} + 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(); + llvm::sys::ScopedWriter lock(allContextsMutex); + for (AllocContext *context : allContexts) { + for (auto &instance : context->instances) + instance.second->~SpecificAllocBase(); + delete context; + } lctx = nullptr; } @@ -48,4 +65,5 @@ if (lctx == nullptr) return; delete lctx; + lctx = nullptr; } diff --git a/lld/Common/Memory.cpp b/lld/Common/Memory.cpp --- a/lld/Common/Memory.cpp +++ b/lld/Common/Memory.cpp @@ -15,10 +15,10 @@ 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); + AllocContext *threadContext = context().alloc(); + auto &instance = threadContext->instances[tag]; + if (!instance) { + void *storage = threadContext->bAlloc.Allocate(size, align); instance = creator(storage); } return instance; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -554,9 +554,9 @@ } template Defined *makeDefined(T &&...args) { - return new (reinterpret_cast( - getSpecificAllocSingleton().Allocate())) - Defined(std::forward(args)...); + auto &bumpAllocator = SpecificAlloc::get().allocator; + void *objectStorage = bumpAllocator.Allocate(); + return new (objectStorage) Defined(std::forward(args)...); } void reportDuplicate(const Symbol &sym, const InputFile *newFile, diff --git a/lld/include/lld/Common/CommonLinkerContext.h b/lld/include/lld/Common/CommonLinkerContext.h --- a/lld/include/lld/Common/CommonLinkerContext.h +++ b/lld/include/lld/Common/CommonLinkerContext.h @@ -21,7 +21,9 @@ #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "llvm/Support/RWMutex.h" #include "llvm/Support/StringSaver.h" +#include "llvm/Support/ThreadLocal.h" namespace llvm { class raw_ostream; @@ -29,6 +31,13 @@ namespace lld { struct SpecificAllocBase; + +struct AllocContext { + llvm::BumpPtrAllocator bAlloc; + llvm::StringSaver saver{bAlloc}; + llvm::DenseMap instances; +}; + class CommonLinkerContext { public: CommonLinkerContext(); @@ -36,11 +45,18 @@ static void destroy(); - llvm::BumpPtrAllocator bAlloc; - llvm::StringSaver saver{bAlloc}; - llvm::DenseMap instances; - ErrorHandler e; + + // Returns the thread-local AllocContext. + AllocContext *alloc(); + +private: + llvm::sys::ThreadLocal contextIndex; + // Vector of the TLS context's addresses. + // We store the TLS variable's addresses so that we can reset the variable's + // value from another thread. + std::vector allContexts; + llvm::sys::RWMutex allContextsMutex; }; // Retrieve the global state. Currently only one state can exist per process, @@ -51,11 +67,12 @@ template T &context() { return static_cast(commonContext()); } - bool hasContext(); -inline llvm::StringSaver &saver() { return context().saver; } -inline llvm::BumpPtrAllocator &bAlloc() { return context().bAlloc; } +inline llvm::StringSaver &saver() { return context().alloc()->saver; } + +inline llvm::BumpPtrAllocator &bAlloc() { return context().alloc()->bAlloc; } + } // namespace lld #endif 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 @@ -33,11 +33,31 @@ }; // An arena of specific types T, created on-demand. -template struct SpecificAlloc : public SpecificAllocBase { +template class SpecificAlloc : public SpecificAllocBase { + // Ensure that users don't accidentally create instances on the stack. + SpecificAlloc() = default; + +public: static SpecificAllocBase *create(void *storage) { return new (storage) SpecificAlloc(); } - llvm::SpecificBumpPtrAllocator alloc; + + // Creates the arena on-demand on the first call; or returns it, if it was + // already created. + inline static SpecificAlloc &get() { + SpecificAllocBase *instance = SpecificAllocBase::getOrCreate( + &SpecificAlloc::tag, sizeof(SpecificAlloc), + alignof(SpecificAlloc), SpecificAlloc::create); + return *(SpecificAlloc *)instance; + } + + // Creates new instances of T off a (almost) contiguous arena/object pool. The + // instances are destroyed whenever lldMain() goes out of scope. + template T *make(U &&...args) { + return new (allocator.Allocate()) T(std::forward(args)...); + } + + llvm::SpecificBumpPtrAllocator allocator; static int tag; }; @@ -45,21 +65,10 @@ // 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. -template -inline llvm::SpecificBumpPtrAllocator &getSpecificAllocSingleton() { - SpecificAllocBase *instance = SpecificAllocBase::getOrCreate( - &SpecificAlloc::tag, sizeof(SpecificAlloc), - alignof(SpecificAlloc), SpecificAlloc::create); - return ((SpecificAlloc *)instance)->alloc; -} - // Creates new instances of T off a (almost) contiguous arena/object pool. The // instances are destroyed whenever lldMain() goes out of scope. template T *make(U &&... args) { - return new (getSpecificAllocSingleton().Allocate()) - T(std::forward(args)...); + return SpecificAlloc::get().make(std::forward(args)...); } } // namespace lld