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