xref: /llvm-project/llvm/include/llvm/Support/Registry.h (revision b735c66da9c9ae752b88941d466895a0b696c75e)
1 //=== Registry.h - Linker-supported plugin registries -----------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Defines a registry template for discovering pluggable modules.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_SUPPORT_REGISTRY_H
14 #define LLVM_SUPPORT_REGISTRY_H
15 
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/iterator_range.h"
19 #include "llvm/Support/Compiler.h"
20 #include "llvm/Support/DynamicLibrary.h"
21 #include <memory>
22 
23 namespace llvm {
24   /// A simple registry entry which provides only a name, description, and
25   /// no-argument constructor.
26   template <typename T>
27   class SimpleRegistryEntry {
28     StringRef Name, Desc;
29     std::unique_ptr<T> (*Ctor)();
30 
31   public:
32     SimpleRegistryEntry(StringRef N, StringRef D, std::unique_ptr<T> (*C)())
33         : Name(N), Desc(D), Ctor(C) {}
34 
35     StringRef getName() const { return Name; }
36     StringRef getDesc() const { return Desc; }
37     std::unique_ptr<T> instantiate() const { return Ctor(); }
38   };
39 
40   /// A global registry used in conjunction with static constructors to make
41   /// pluggable components (like targets or garbage collectors) "just work" when
42   /// linked with an executable.
43   template <typename T>
44   class Registry {
45   public:
46     typedef T type;
47     typedef SimpleRegistryEntry<T> entry;
48 
49     class node;
50     class iterator;
51 
52   private:
53     Registry() = delete;
54 
55     friend class node;
56     // These must be must two separate declarations to workaround a 20 year
57     // old MSVC bug with dllexport and multiple static fields in the same
58     // declaration causing error C2487 "member of dll interface class may not
59     // be declared with dll interface".
60     // https://developercommunity.visualstudio.com/t/c2487-in-dllexport-class-with-static-members/69878
61     static node *Head;
62     static node *Tail;
63 
64   public:
65     /// Node in linked list of entries.
66     ///
67     class node {
68       friend class iterator;
69       friend Registry<T>;
70 
71       node *Next;
72       const entry& Val;
73 
74     public:
75       node(const entry &V) : Next(nullptr), Val(V) {}
76     };
77 
78     /// Add a node to the Registry: this is the interface between the plugin and
79     /// the executable.
80     ///
81     /// This function is exported by the executable and called by the plugin to
82     /// add a node to the executable's registry. Therefore it's not defined here
83     /// to avoid it being instantiated in the plugin and is instead defined in
84     /// the executable (see LLVM_INSTANTIATE_REGISTRY below).
85     static void add_node(node *N) {
86       if (Tail)
87         Tail->Next = N;
88       else
89         Head = N;
90       Tail = N;
91     }
92 
93     /// Iterators for registry entries.
94     ///
95     class iterator
96         : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag,
97                                             const entry> {
98       const node *Cur;
99 
100     public:
101       explicit iterator(const node *N) : Cur(N) {}
102 
103       bool operator==(const iterator &That) const { return Cur == That.Cur; }
104       iterator &operator++() { Cur = Cur->Next; return *this; }
105       const entry &operator*() const { return Cur->Val; }
106     };
107 
108     // begin is not defined here in order to avoid usage of an undefined static
109     // data member, instead it's instantiated by LLVM_INSTANTIATE_REGISTRY.
110     static iterator begin() { return iterator(Head); }
111     static iterator end()   { return iterator(nullptr); }
112 
113     static iterator_range<iterator> entries() {
114       return make_range(begin(), end());
115     }
116 
117     /// A static registration template. Use like such:
118     ///
119     ///   Registry<Collector>::Add<FancyGC>
120     ///   X("fancy-gc", "Newfangled garbage collector.");
121     ///
122     /// Use of this template requires that:
123     ///
124     ///  1. The registered subclass has a default constructor.
125     template <typename V>
126     class Add {
127       entry Entry;
128       node Node;
129 
130       static std::unique_ptr<T> CtorFn() { return std::make_unique<V>(); }
131 
132     public:
133       Add(StringRef Name, StringRef Desc)
134           : Entry(Name, Desc, CtorFn), Node(Entry) {
135         add_node(&Node);
136       }
137     };
138   };
139 
140 } // end namespace llvm
141 
142 #ifdef _WIN32
143 /// Instantiate a registry class.
144 #define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS)                              \
145   namespace llvm {                                                             \
146   template <typename T>                                                        \
147   typename Registry<T>::node *Registry<T>::Head = nullptr;                     \
148   template <typename T>                                                        \
149   typename Registry<T>::node *Registry<T>::Tail = nullptr;                     \
150   template class LLVM_ABI_EXPORT Registry<REGISTRY_CLASS::type>;               \
151   }
152 #else
153 #define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS)                              \
154   namespace llvm {                                                             \
155   template <typename T>                                                        \
156   typename Registry<T>::node *Registry<T>::Head = nullptr;                     \
157   template <typename T>                                                        \
158   typename Registry<T>::node *Registry<T>::Tail = nullptr;                     \
159   template class Registry<REGISTRY_CLASS::type>;                               \
160   }
161 #endif
162 
163 #endif // LLVM_SUPPORT_REGISTRY_H
164