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