• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- llvm/Support/ManagedStatic.h - Static Global wrapper ----*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the ManagedStatic class and the llvm_shutdown() function.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_SUPPORT_MANAGEDSTATIC_H
15 #define LLVM_SUPPORT_MANAGEDSTATIC_H
16 
17 #include "llvm/Support/Compiler.h"
18 #include <atomic>
19 #include <cstddef>
20 
21 namespace llvm {
22 
23 /// object_creator - Helper method for ManagedStatic.
24 template<class C>
object_creator()25 LLVM_LIBRARY_VISIBILITY void* object_creator() {
26   return new C();
27 }
28 
29 /// object_deleter - Helper method for ManagedStatic.
30 ///
31 template <typename T> struct LLVM_LIBRARY_VISIBILITY object_deleter {
callobject_deleter32   static void call(void *Ptr) { delete (T *)Ptr; }
33 };
34 template <typename T, size_t N>
35 struct LLVM_LIBRARY_VISIBILITY object_deleter<T[N]> {
36   static void call(void *Ptr) { delete[](T *)Ptr; }
37 };
38 
39 // If the current compiler is MSVC 2017 or earlier, then we have to work around
40 // a bug where MSVC emits code to perform dynamic initialization even if the
41 // class has a constexpr constructor. Instead, fall back to the C++98 strategy
42 // where there are no constructors or member initializers. We can remove this
43 // when MSVC 2019 (19.20+) is our minimum supported version.
44 #if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1920
45 #define LLVM_AVOID_CONSTEXPR_CTOR
46 #endif
47 
48 /// ManagedStaticBase - Common base class for ManagedStatic instances.
49 class ManagedStaticBase {
50 protected:
51 #ifndef LLVM_AVOID_CONSTEXPR_CTOR
52   mutable std::atomic<void *> Ptr{};
53   mutable void (*DeleterFn)(void *) = nullptr;
54   mutable const ManagedStaticBase *Next = nullptr;
55 #else
56   // This should only be used as a static variable, which guarantees that this
57   // will be zero initialized.
58   mutable std::atomic<void *> Ptr;
59   mutable void (*DeleterFn)(void *);
60   mutable const ManagedStaticBase *Next;
61 #endif
62 
63   void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const;
64 
65 public:
66 #ifndef LLVM_AVOID_CONSTEXPR_CTOR
67   constexpr ManagedStaticBase() = default;
68 #endif
69 
70   /// isConstructed - Return true if this object has not been created yet.
71   bool isConstructed() const { return Ptr != nullptr; }
72 
73   void destroy() const;
74 };
75 
76 /// ManagedStatic - This transparently changes the behavior of global statics to
77 /// be lazily constructed on demand (good for reducing startup times of dynamic
78 /// libraries that link in LLVM components) and for making destruction be
79 /// explicit through the llvm_shutdown() function call.
80 ///
81 template<class C>
82 class ManagedStatic : public ManagedStaticBase {
83 public:
84   // Accessors.
85   C &operator*() {
86     void *Tmp = Ptr.load(std::memory_order_acquire);
87     if (!Tmp)
88       RegisterManagedStatic(object_creator<C>, object_deleter<C>::call);
89 
90     return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
91   }
92 
93   C *operator->() { return &**this; }
94 
95   const C &operator*() const {
96     void *Tmp = Ptr.load(std::memory_order_acquire);
97     if (!Tmp)
98       RegisterManagedStatic(object_creator<C>, object_deleter<C>::call);
99 
100     return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
101   }
102 
103   const C *operator->() const { return &**this; }
104 };
105 
106 /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.
107 void llvm_shutdown();
108 
109 /// llvm_shutdown_obj - This is a simple helper class that calls
110 /// llvm_shutdown() when it is destroyed.
111 struct llvm_shutdown_obj {
112   llvm_shutdown_obj() = default;
113   ~llvm_shutdown_obj() { llvm_shutdown(); }
114 };
115 
116 } // end namespace llvm
117 
118 #endif // LLVM_SUPPORT_MANAGEDSTATIC_H
119