Line data Source code
1 : // Copyright 2012 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : // The LazyInstance<Type, Traits> class manages a single instance of Type,
6 : // which will be lazily created on the first time it's accessed. This class is
7 : // useful for places you would normally use a function-level static, but you
8 : // need to have guaranteed thread-safety. The Type constructor will only ever
9 : // be called once, even if two threads are racing to create the object. Get()
10 : // and Pointer() will always return the same, completely initialized instance.
11 : //
12 : // LazyInstance is completely thread safe, assuming that you create it safely.
13 : // The class was designed to be POD initialized, so it shouldn't require a
14 : // static constructor. It really only makes sense to declare a LazyInstance as
15 : // a global variable using the LAZY_INSTANCE_INITIALIZER initializer.
16 : //
17 : // LazyInstance is similar to Singleton, except it does not have the singleton
18 : // property. You can have multiple LazyInstance's of the same type, and each
19 : // will manage a unique instance. It also preallocates the space for Type, as
20 : // to avoid allocating the Type instance on the heap. This may help with the
21 : // performance of creating the instance, and reducing heap fragmentation. This
22 : // requires that Type be a complete type so we can determine the size. See
23 : // notes for advanced users below for more explanations.
24 : //
25 : // Example usage:
26 : // static LazyInstance<MyClass>::type my_instance = LAZY_INSTANCE_INITIALIZER;
27 : // void SomeMethod() {
28 : // my_instance.Get().SomeMethod(); // MyClass::SomeMethod()
29 : //
30 : // MyClass* ptr = my_instance.Pointer();
31 : // ptr->DoDoDo(); // MyClass::DoDoDo
32 : // }
33 : //
34 : // Additionally you can override the way your instance is constructed by
35 : // providing your own trait:
36 : // Example usage:
37 : // struct MyCreateTrait {
38 : // static void Construct(void* allocated_ptr) {
39 : // new (allocated_ptr) MyClass(/* extra parameters... */);
40 : // }
41 : // };
42 : // static LazyInstance<MyClass, MyCreateTrait>::type my_instance =
43 : // LAZY_INSTANCE_INITIALIZER;
44 : //
45 : // WARNINGS:
46 : // - This implementation of LazyInstance IS THREAD-SAFE by default. See
47 : // SingleThreadInitOnceTrait if you don't care about thread safety.
48 : // - Lazy initialization comes with a cost. Make sure that you don't use it on
49 : // critical path. Consider adding your initialization code to a function
50 : // which is explicitly called once.
51 : //
52 : // Notes for advanced users:
53 : // LazyInstance can actually be used in two different ways:
54 : //
55 : // - "Static mode" which is the default mode since it is the most efficient
56 : // (no extra heap allocation). In this mode, the instance is statically
57 : // allocated (stored in the global data section at compile time).
58 : // The macro LAZY_STATIC_INSTANCE_INITIALIZER (= LAZY_INSTANCE_INITIALIZER)
59 : // must be used to initialize static lazy instances.
60 : //
61 : // - "Dynamic mode". In this mode, the instance is dynamically allocated and
62 : // constructed (using new) by default. This mode is useful if you have to
63 : // deal with some code already allocating the instance for you (e.g.
64 : // OS::Mutex() which returns a new private OS-dependent subclass of Mutex).
65 : // The macro LAZY_DYNAMIC_INSTANCE_INITIALIZER must be used to initialize
66 : // dynamic lazy instances.
67 :
68 : #ifndef V8_BASE_LAZY_INSTANCE_H_
69 : #define V8_BASE_LAZY_INSTANCE_H_
70 :
71 : #include <type_traits>
72 :
73 : #include "src/base/macros.h"
74 : #include "src/base/once.h"
75 :
76 : namespace v8 {
77 : namespace base {
78 :
79 : #define LAZY_STATIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, { {} } }
80 : #define LAZY_DYNAMIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, 0 }
81 :
82 : // Default to static mode.
83 : #define LAZY_INSTANCE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
84 :
85 :
86 : template <typename T>
87 : struct LeakyInstanceTrait {
88 : static void Destroy(T* /* instance */) {}
89 : };
90 :
91 :
92 : // Traits that define how an instance is allocated and accessed.
93 :
94 :
95 : template <typename T>
96 : struct StaticallyAllocatedInstanceTrait {
97 : using StorageType =
98 : typename std::aligned_storage<sizeof(T), alignof(T)>::type;
99 :
100 : static T* MutableInstance(StorageType* storage) {
101 : return reinterpret_cast<T*>(storage);
102 : }
103 :
104 : template <typename ConstructTrait>
105 : static void InitStorageUsingTrait(StorageType* storage) {
106 60084 : ConstructTrait::Construct(storage);
107 : }
108 : };
109 :
110 :
111 : template <typename T>
112 : struct DynamicallyAllocatedInstanceTrait {
113 : using StorageType = T*;
114 :
115 : static T* MutableInstance(StorageType* storage) {
116 : return *storage;
117 : }
118 :
119 : template <typename CreateTrait>
120 : static void InitStorageUsingTrait(StorageType* storage) {
121 866 : *storage = CreateTrait::Create();
122 : }
123 : };
124 :
125 :
126 : template <typename T>
127 : struct DefaultConstructTrait {
128 : // Constructs the provided object which was already allocated.
129 402426 : static void Construct(void* allocated_ptr) { new (allocated_ptr) T(); }
130 : };
131 :
132 :
133 : template <typename T>
134 : struct DefaultCreateTrait {
135 : static T* Create() {
136 : return new T();
137 : }
138 : };
139 :
140 :
141 : struct ThreadSafeInitOnceTrait {
142 : template <typename Function, typename Storage>
143 : static void Init(OnceType* once, Function function, Storage storage) {
144 76018120 : CallOnce(once, function, storage);
145 : }
146 : };
147 :
148 :
149 : // Initialization trait for users who don't care about thread-safety.
150 : struct SingleThreadInitOnceTrait {
151 : template <typename Function, typename Storage>
152 : static void Init(OnceType* once, Function function, Storage storage) {
153 : if (*once == ONCE_STATE_UNINITIALIZED) {
154 : function(storage);
155 : *once = ONCE_STATE_DONE;
156 : }
157 : }
158 : };
159 :
160 :
161 : // TODO(pliard): Handle instances destruction (using global destructors).
162 : template <typename T, typename AllocationTrait, typename CreateTrait,
163 : typename InitOnceTrait, typename DestroyTrait /* not used yet. */>
164 : struct LazyInstanceImpl {
165 : public:
166 : using StorageType = typename AllocationTrait::StorageType;
167 :
168 : private:
169 343568 : static void InitInstance(void* storage) {
170 : AllocationTrait::template InitStorageUsingTrait<CreateTrait>(
171 : static_cast<StorageType*>(storage));
172 343568 : }
173 :
174 : void Init() const {
175 15968 : InitOnceTrait::Init(&once_, &InitInstance, static_cast<void*>(&storage_));
176 : }
177 :
178 : public:
179 15968 : T* Pointer() {
180 : Init();
181 15968 : return AllocationTrait::MutableInstance(&storage_);
182 : }
183 :
184 : const T& Get() const {
185 : Init();
186 : return *AllocationTrait::MutableInstance(&storage_);
187 : }
188 :
189 : mutable OnceType once_;
190 : // Note that the previous field, OnceType, is an AtomicWord which guarantees
191 : // 4-byte alignment of the storage field below. If compiling with GCC (>4.2),
192 : // the LAZY_ALIGN macro above will guarantee correctness for any alignment.
193 : mutable StorageType storage_;
194 : };
195 :
196 :
197 : template <typename T,
198 : typename CreateTrait = DefaultConstructTrait<T>,
199 : typename InitOnceTrait = ThreadSafeInitOnceTrait,
200 : typename DestroyTrait = LeakyInstanceTrait<T> >
201 : struct LazyStaticInstance {
202 : using type = LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>,
203 : CreateTrait, InitOnceTrait, DestroyTrait>;
204 : };
205 :
206 :
207 : template <typename T,
208 : typename CreateTrait = DefaultConstructTrait<T>,
209 : typename InitOnceTrait = ThreadSafeInitOnceTrait,
210 : typename DestroyTrait = LeakyInstanceTrait<T> >
211 : struct LazyInstance {
212 : // A LazyInstance is a LazyStaticInstance.
213 : using type = typename LazyStaticInstance<T, CreateTrait, InitOnceTrait,
214 : DestroyTrait>::type;
215 : };
216 :
217 :
218 : template <typename T,
219 : typename CreateTrait = DefaultCreateTrait<T>,
220 : typename InitOnceTrait = ThreadSafeInitOnceTrait,
221 : typename DestroyTrait = LeakyInstanceTrait<T> >
222 : struct LazyDynamicInstance {
223 : using type = LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>,
224 : CreateTrait, InitOnceTrait, DestroyTrait>;
225 : };
226 :
227 : // LeakyObject<T> wraps an object of type T, which is initialized in the
228 : // constructor but never destructed. Thus LeakyObject<T> is trivially
229 : // destructible and can be used in static (lazily initialized) variables.
230 : template <typename T>
231 : class LeakyObject {
232 : public:
233 : template <typename... Args>
234 267 : explicit LeakyObject(Args&&... args) {
235 337080 : new (&storage_) T(std::forward<Args>(args)...);
236 267 : }
237 :
238 : T* get() { return reinterpret_cast<T*>(&storage_); }
239 :
240 : private:
241 : typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
242 :
243 : DISALLOW_COPY_AND_ASSIGN(LeakyObject);
244 : };
245 :
246 : // Define a function which returns a pointer to a lazily initialized and never
247 : // destructed object of type T.
248 : #define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName, ...) \
249 : T* FunctionName() { \
250 : static ::v8::base::LeakyObject<T> object{__VA_ARGS__}; \
251 : return object.get(); \
252 : }
253 :
254 : } // namespace base
255 : } // namespace v8
256 :
257 : #endif // V8_BASE_LAZY_INSTANCE_H_
|