diff --git a/lld/Common/Memory.cpp b/lld/Common/Memory.cpp --- a/lld/Common/Memory.cpp +++ b/lld/Common/Memory.cpp @@ -12,6 +12,8 @@ using namespace llvm; using namespace lld; +bool lld::ThreadSafeAlloc = false; + SpecificAllocBase * lld::SpecificAllocBase::getOrCreate(void *tag, size_t size, size_t align, SpecificAllocBase *(&creator)(void *)) { diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1107,6 +1107,7 @@ if (errorCount()) return false; + lld::ThreadSafeAlloc = true; if (args.hasArg(OPT_pagezero_size)) { uint64_t pagezeroSize = args::getHex(args, OPT_pagezero_size, 0); 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,8 +22,13 @@ #define LLD_COMMON_MEMORY_H #include "llvm/Support/Allocator.h" +#include namespace lld { + +// Set to "true" for a thread-safe (but ~2.74% slower) allocator. +extern bool ThreadSafeAlloc; + // A base class only used by the CommonLinkerContext to keep track of the // SpecificAlloc<> instances. struct SpecificAllocBase { @@ -39,6 +44,8 @@ } llvm::SpecificBumpPtrAllocator alloc; static int tag; + + std::mutex mutex; }; // The address of this static member is only used as a key in @@ -48,18 +55,35 @@ // Creates the arena on-demand on the first call; or returns it, if it was // already created. template -inline llvm::SpecificBumpPtrAllocator &getSpecificAllocSingleton() { +inline SpecificAlloc *getSpecificAllocSingletonHelper() { SpecificAllocBase *instance = SpecificAllocBase::getOrCreate( &SpecificAlloc::tag, sizeof(SpecificAlloc), alignof(SpecificAlloc), SpecificAlloc::create); - return ((SpecificAlloc *)instance)->alloc; + return (SpecificAlloc *)instance; +} + +template +inline llvm::SpecificBumpPtrAllocator &getSpecificAllocSingleton() { + return getSpecificAllocSingletonHelper()->alloc; +} + +template inline T *DoAlloc() { + { + auto *allocator = getSpecificAllocSingletonHelper(); + // TODO: maybe make the flag a compile-time config to avoid this branch. + if (ThreadSafeAlloc) { + std::lock_guard lock(allocator->mutex); + return allocator->alloc.Allocate(); + } else { + return allocator->alloc.Allocate(); + } + } } // 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 new (DoAlloc()) T(std::forward(args)...); } } // namespace lld