10b57cec5SDimitry Andric //===- Memory.h -------------------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines arena allocators.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric // Almost all large objects, such as files, sections or symbols, are
120b57cec5SDimitry Andric // used for the entire lifetime of the linker once they are created.
130b57cec5SDimitry Andric // This usage characteristic makes arena allocator an attractive choice
140b57cec5SDimitry Andric // where the entire linker is one arena. With an arena, newly created
150b57cec5SDimitry Andric // objects belong to the arena and freed all at once when everything is done.
160b57cec5SDimitry Andric // Arena allocators are efficient and easy to understand.
170b57cec5SDimitry Andric // Most objects are allocated using the arena allocators defined by this file.
180b57cec5SDimitry Andric //
190b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #ifndef LLD_COMMON_MEMORY_H
220b57cec5SDimitry Andric #define LLD_COMMON_MEMORY_H
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric #include "llvm/Support/Allocator.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric namespace lld {
2704eeddc0SDimitry Andric // A base class only used by the CommonLinkerContext to keep track of the
2804eeddc0SDimitry Andric // SpecificAlloc<> instances.
290b57cec5SDimitry Andric struct SpecificAllocBase {
300b57cec5SDimitry Andric   virtual ~SpecificAllocBase() = default;
3104eeddc0SDimitry Andric   static SpecificAllocBase *getOrCreate(void *tag, size_t size, size_t align,
3204eeddc0SDimitry Andric                                         SpecificAllocBase *(&creator)(void *));
330b57cec5SDimitry Andric };
340b57cec5SDimitry Andric 
3504eeddc0SDimitry Andric // An arena of specific types T, created on-demand.
360b57cec5SDimitry Andric template <class T> struct SpecificAlloc : public SpecificAllocBase {
createSpecificAlloc3704eeddc0SDimitry Andric   static SpecificAllocBase *create(void *storage) {
3804eeddc0SDimitry Andric     return new (storage) SpecificAlloc<T>();
3904eeddc0SDimitry Andric   }
400b57cec5SDimitry Andric   llvm::SpecificBumpPtrAllocator<T> alloc;
4104eeddc0SDimitry Andric   static int tag;
420b57cec5SDimitry Andric };
430b57cec5SDimitry Andric 
4404eeddc0SDimitry Andric // The address of this static member is only used as a key in
4504eeddc0SDimitry Andric // CommonLinkerContext::instances. Its value does not matter.
4604eeddc0SDimitry Andric template <class T> int SpecificAlloc<T>::tag = 0;
4704eeddc0SDimitry Andric 
4804eeddc0SDimitry Andric // Creates the arena on-demand on the first call; or returns it, if it was
4904eeddc0SDimitry Andric // already created.
505ffd83dbSDimitry Andric template <typename T>
getSpecificAllocSingleton()515ffd83dbSDimitry Andric inline llvm::SpecificBumpPtrAllocator<T> &getSpecificAllocSingleton() {
5204eeddc0SDimitry Andric   SpecificAllocBase *instance = SpecificAllocBase::getOrCreate(
5304eeddc0SDimitry Andric       &SpecificAlloc<T>::tag, sizeof(SpecificAlloc<T>),
5404eeddc0SDimitry Andric       alignof(SpecificAlloc<T>), SpecificAlloc<T>::create);
5504eeddc0SDimitry Andric   return ((SpecificAlloc<T> *)instance)->alloc;
565ffd83dbSDimitry Andric }
575ffd83dbSDimitry Andric 
5804eeddc0SDimitry Andric // Creates new instances of T off a (almost) contiguous arena/object pool. The
5904eeddc0SDimitry Andric // instances are destroyed whenever lldMain() goes out of scope.
make(U &&...args)600b57cec5SDimitry Andric template <typename T, typename... U> T *make(U &&... args) {
615ffd83dbSDimitry Andric   return new (getSpecificAllocSingleton<T>().Allocate())
625ffd83dbSDimitry Andric       T(std::forward<U>(args)...);
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric 
65bdd1243dSDimitry Andric template <typename T>
66bdd1243dSDimitry Andric inline llvm::SpecificBumpPtrAllocator<T> &
getSpecificAllocSingletonThreadLocal()67bdd1243dSDimitry Andric getSpecificAllocSingletonThreadLocal() {
68bdd1243dSDimitry Andric   thread_local SpecificAlloc<T> instance;
69bdd1243dSDimitry Andric   return instance.alloc;
70bdd1243dSDimitry Andric }
71bdd1243dSDimitry Andric 
72bdd1243dSDimitry Andric // Create a new instance of T off a thread-local SpecificAlloc, used by code
73bdd1243dSDimitry Andric // like parallel input section initialization. The use cases assume that the
74bdd1243dSDimitry Andric // return value outlives the containing parallelForEach (if exists), which is
75bdd1243dSDimitry Andric // currently guaranteed: when parallelForEach returns, the threads allocating
76bdd1243dSDimitry Andric // the TLS are not destroyed.
77bdd1243dSDimitry Andric //
78bdd1243dSDimitry Andric // Note: Some ports (e.g. ELF) have lots of global states which are currently
79bdd1243dSDimitry Andric // infeasible to remove, and context() just adds overhead with no benefit. The
80bdd1243dSDimitry Andric // allocation performance is of higher importance, so we simply use thread_local
81bdd1243dSDimitry Andric // allocators instead of doing context indirection and pthread_getspecific.
makeThreadLocal(U &&...args)82bdd1243dSDimitry Andric template <typename T, typename... U> T *makeThreadLocal(U &&...args) {
83bdd1243dSDimitry Andric   return new (getSpecificAllocSingletonThreadLocal<T>().Allocate())
84bdd1243dSDimitry Andric       T(std::forward<U>(args)...);
85bdd1243dSDimitry Andric }
86bdd1243dSDimitry Andric 
makeThreadLocalN(size_t n)87bdd1243dSDimitry Andric template <typename T> T *makeThreadLocalN(size_t n) {
88bdd1243dSDimitry Andric   return new (getSpecificAllocSingletonThreadLocal<T>().Allocate(n)) T[n];
89bdd1243dSDimitry Andric }
90bdd1243dSDimitry Andric 
910b57cec5SDimitry Andric } // namespace lld
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric #endif
94