Home | History | Annotate | Line # | Download | only in Support
      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     static node *Head, *Tail;
     57 
     58   public:
     59     /// Node in linked list of entries.
     60     ///
     61     class node {
     62       friend class iterator;
     63       friend Registry<T>;
     64 
     65       node *Next;
     66       const entry& Val;
     67 
     68     public:
     69       node(const entry &V) : Next(nullptr), Val(V) {}
     70     };
     71 
     72     /// Add a node to the Registry: this is the interface between the plugin and
     73     /// the executable.
     74     ///
     75     /// This function is exported by the executable and called by the plugin to
     76     /// add a node to the executable's registry. Therefore it's not defined here
     77     /// to avoid it being instantiated in the plugin and is instead defined in
     78     /// the executable (see LLVM_INSTANTIATE_REGISTRY below).
     79     static void add_node(node *N);
     80 
     81     /// Iterators for registry entries.
     82     ///
     83     class iterator
     84         : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag,
     85                                             const entry> {
     86       const node *Cur;
     87 
     88     public:
     89       explicit iterator(const node *N) : Cur(N) {}
     90 
     91       bool operator==(const iterator &That) const { return Cur == That.Cur; }
     92       iterator &operator++() { Cur = Cur->Next; return *this; }
     93       const entry &operator*() const { return Cur->Val; }
     94     };
     95 
     96     // begin is not defined here in order to avoid usage of an undefined static
     97     // data member, instead it's instantiated by LLVM_INSTANTIATE_REGISTRY.
     98     static iterator begin();
     99     static iterator end()   { return iterator(nullptr); }
    100 
    101     static iterator_range<iterator> entries() {
    102       return make_range(begin(), end());
    103     }
    104 
    105     /// A static registration template. Use like such:
    106     ///
    107     ///   Registry<Collector>::Add<FancyGC>
    108     ///   X("fancy-gc", "Newfangled garbage collector.");
    109     ///
    110     /// Use of this template requires that:
    111     ///
    112     ///  1. The registered subclass has a default constructor.
    113     template <typename V>
    114     class Add {
    115       entry Entry;
    116       node Node;
    117 
    118       static std::unique_ptr<T> CtorFn() { return std::make_unique<V>(); }
    119 
    120     public:
    121       Add(StringRef Name, StringRef Desc)
    122           : Entry(Name, Desc, CtorFn), Node(Entry) {
    123         add_node(&Node);
    124       }
    125     };
    126   };
    127 } // end namespace llvm
    128 
    129 /// Instantiate a registry class.
    130 ///
    131 /// This provides template definitions of add_node, begin, and the Head and Tail
    132 /// pointers, then explicitly instantiates them. We could explicitly specialize
    133 /// them, instead of the two-step process of define then instantiate, but
    134 /// strictly speaking that's not allowed by the C++ standard (we would need to
    135 /// have explicit specialization declarations in all translation units where the
    136 /// specialization is used) so we don't.
    137 #define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
    138   namespace llvm { \
    139   template<typename T> typename Registry<T>::node *Registry<T>::Head = nullptr;\
    140   template<typename T> typename Registry<T>::node *Registry<T>::Tail = nullptr;\
    141   template<typename T> \
    142   void Registry<T>::add_node(typename Registry<T>::node *N) { \
    143     if (Tail) \
    144       Tail->Next = N; \
    145     else \
    146       Head = N; \
    147     Tail = N; \
    148   } \
    149   template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \
    150     return iterator(Head); \
    151   } \
    152   template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \
    153   template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Tail; \
    154   template \
    155   void Registry<REGISTRY_CLASS::type>::add_node(REGISTRY_CLASS::node*); \
    156   template REGISTRY_CLASS::iterator Registry<REGISTRY_CLASS::type>::begin(); \
    157   }
    158 
    159 #endif // LLVM_SUPPORT_REGISTRY_H
    160