mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 13:11:39 +01:00
5419400ae8
The Registry class constructs a linked list of nodes whose storage is inside static variables and nodes are added via static initializers. The trick is that those static initializers are in both the LLVM code base, and some random plugin that might get loaded in at runtime. The existing code tries to use C++ templates and their ODR rules to get a single definition of the registry for each type, but, experimentally, this doesn't quite work as designed. (Well, the entire structure doesn't. It might not actually be an ODR problem.) Previously, when I tried moving the GCStrategy class (along with it's registry) from CodeGen to IR, I ran into a problem where asking the GCStrategyRegistry a question would return inconsistent results depending on whether you asked from CodeGen (where the static initializers still were) or Transforms. My best guess is that this is a result of either a) an order of initialization error, or b) we ended up with two copies of the registry being created. I remember at the time having convinced myself it was probably (b), but I don't have any of my notes around from that investigation any more. See http://reviews.llvm.org/rL226311 for the original patch in question. This patch tries to remove the possibility of (b) above. (a) was already fixed in change 258109. Differential Revision: http://reviews.llvm.org/D16170 llvm-svn: 258157
131 lines
3.7 KiB
C++
131 lines
3.7 KiB
C++
//=== Registry.h - Linker-supported plugin registries -----------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Defines a registry template for discovering pluggable modules.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_SUPPORT_REGISTRY_H
|
|
#define LLVM_SUPPORT_REGISTRY_H
|
|
|
|
#include "llvm/ADT/iterator_range.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include <memory>
|
|
|
|
namespace llvm {
|
|
/// A simple registry entry which provides only a name, description, and
|
|
/// no-argument constructor.
|
|
template <typename T>
|
|
class SimpleRegistryEntry {
|
|
const char *Name, *Desc;
|
|
std::unique_ptr<T> (*Ctor)();
|
|
|
|
public:
|
|
SimpleRegistryEntry(const char *N, const char *D, std::unique_ptr<T> (*C)())
|
|
: Name(N), Desc(D), Ctor(C)
|
|
{}
|
|
|
|
const char *getName() const { return Name; }
|
|
const char *getDesc() const { return Desc; }
|
|
std::unique_ptr<T> instantiate() const { return Ctor(); }
|
|
};
|
|
|
|
/// A global registry used in conjunction with static constructors to make
|
|
/// pluggable components (like targets or garbage collectors) "just work" when
|
|
/// linked with an executable.
|
|
template <typename T>
|
|
class Registry {
|
|
public:
|
|
typedef SimpleRegistryEntry<T> entry;
|
|
|
|
class node;
|
|
class iterator;
|
|
|
|
private:
|
|
Registry() = delete;
|
|
|
|
friend class node;
|
|
static node *Head, *Tail;
|
|
|
|
public:
|
|
/// Node in linked list of entries.
|
|
///
|
|
class node {
|
|
friend class iterator;
|
|
|
|
node *Next;
|
|
const entry& Val;
|
|
|
|
public:
|
|
node(const entry& V) : Next(nullptr), Val(V) {
|
|
if (Tail)
|
|
Tail->Next = this;
|
|
else
|
|
Head = this;
|
|
Tail = this;
|
|
}
|
|
};
|
|
|
|
/// Iterators for registry entries.
|
|
///
|
|
class iterator {
|
|
const node *Cur;
|
|
|
|
public:
|
|
explicit iterator(const node *N) : Cur(N) {}
|
|
|
|
bool operator==(const iterator &That) const { return Cur == That.Cur; }
|
|
bool operator!=(const iterator &That) const { return Cur != That.Cur; }
|
|
iterator &operator++() { Cur = Cur->Next; return *this; }
|
|
const entry &operator*() const { return Cur->Val; }
|
|
const entry *operator->() const { return &Cur->Val; }
|
|
};
|
|
|
|
static iterator begin() { return iterator(Head); }
|
|
static iterator end() { return iterator(nullptr); }
|
|
|
|
static iterator_range<iterator> entries() {
|
|
return make_range(begin(), end());
|
|
}
|
|
|
|
/// A static registration template. Use like such:
|
|
///
|
|
/// Registry<Collector>::Add<FancyGC>
|
|
/// X("fancy-gc", "Newfangled garbage collector.");
|
|
///
|
|
/// Use of this template requires that:
|
|
///
|
|
/// 1. The registered subclass has a default constructor.
|
|
template <typename V>
|
|
class Add {
|
|
entry Entry;
|
|
node Node;
|
|
|
|
static std::unique_ptr<T> CtorFn() { return make_unique<V>(); }
|
|
|
|
public:
|
|
Add(const char *Name, const char *Desc)
|
|
: Entry(Name, Desc, CtorFn), Node(Entry) {}
|
|
};
|
|
};
|
|
|
|
// Use this macro to stamp out definitions for required static symbols in an
|
|
// appropriate source file. This is required to avoid getting multiple
|
|
// definitions of the Registry's fields in different translation or linkage
|
|
// units.
|
|
#define DEFINE_REGISTRY(T) \
|
|
template <> \
|
|
typename Registry<T>::node *Registry<T>::Head = nullptr; \
|
|
template <> \
|
|
typename Registry<T>::node *Registry<T>::Tail = nullptr;
|
|
} // end namespace llvm
|
|
|
|
#endif // LLVM_SUPPORT_REGISTRY_H
|