OLD | NEW |
| (Empty) |
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(MyClass* 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_LAZY_INSTANCE_H_ | |
69 #define V8_LAZY_INSTANCE_H_ | |
70 | |
71 #include "src/base/macros.h" | |
72 #include "src/once.h" | |
73 | |
74 namespace v8 { | |
75 namespace internal { | |
76 | |
77 #define LAZY_STATIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, { {} } } | |
78 #define LAZY_DYNAMIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, 0 } | |
79 | |
80 // Default to static mode. | |
81 #define LAZY_INSTANCE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER | |
82 | |
83 | |
84 template <typename T> | |
85 struct LeakyInstanceTrait { | |
86 static void Destroy(T* /* instance */) {} | |
87 }; | |
88 | |
89 | |
90 // Traits that define how an instance is allocated and accessed. | |
91 | |
92 | |
93 template <typename T> | |
94 struct StaticallyAllocatedInstanceTrait { | |
95 // 16-byte alignment fallback to be on the safe side here. | |
96 struct V8_ALIGNAS(T, 16) StorageType { | |
97 char x[sizeof(T)]; | |
98 }; | |
99 | |
100 STATIC_ASSERT(V8_ALIGNOF(StorageType) >= V8_ALIGNOF(T)); | |
101 | |
102 static T* MutableInstance(StorageType* storage) { | |
103 return reinterpret_cast<T*>(storage); | |
104 } | |
105 | |
106 template <typename ConstructTrait> | |
107 static void InitStorageUsingTrait(StorageType* storage) { | |
108 ConstructTrait::Construct(MutableInstance(storage)); | |
109 } | |
110 }; | |
111 | |
112 | |
113 template <typename T> | |
114 struct DynamicallyAllocatedInstanceTrait { | |
115 typedef T* StorageType; | |
116 | |
117 static T* MutableInstance(StorageType* storage) { | |
118 return *storage; | |
119 } | |
120 | |
121 template <typename CreateTrait> | |
122 static void InitStorageUsingTrait(StorageType* storage) { | |
123 *storage = CreateTrait::Create(); | |
124 } | |
125 }; | |
126 | |
127 | |
128 template <typename T> | |
129 struct DefaultConstructTrait { | |
130 // Constructs the provided object which was already allocated. | |
131 static void Construct(T* allocated_ptr) { | |
132 new(allocated_ptr) T(); | |
133 } | |
134 }; | |
135 | |
136 | |
137 template <typename T> | |
138 struct DefaultCreateTrait { | |
139 static T* Create() { | |
140 return new T(); | |
141 } | |
142 }; | |
143 | |
144 | |
145 struct ThreadSafeInitOnceTrait { | |
146 template <typename Function, typename Storage> | |
147 static void Init(OnceType* once, Function function, Storage storage) { | |
148 CallOnce(once, function, storage); | |
149 } | |
150 }; | |
151 | |
152 | |
153 // Initialization trait for users who don't care about thread-safety. | |
154 struct SingleThreadInitOnceTrait { | |
155 template <typename Function, typename Storage> | |
156 static void Init(OnceType* once, Function function, Storage storage) { | |
157 if (*once == ONCE_STATE_UNINITIALIZED) { | |
158 function(storage); | |
159 *once = ONCE_STATE_DONE; | |
160 } | |
161 } | |
162 }; | |
163 | |
164 | |
165 // TODO(pliard): Handle instances destruction (using global destructors). | |
166 template <typename T, typename AllocationTrait, typename CreateTrait, | |
167 typename InitOnceTrait, typename DestroyTrait /* not used yet. */> | |
168 struct LazyInstanceImpl { | |
169 public: | |
170 typedef typename AllocationTrait::StorageType StorageType; | |
171 | |
172 private: | |
173 static void InitInstance(StorageType* storage) { | |
174 AllocationTrait::template InitStorageUsingTrait<CreateTrait>(storage); | |
175 } | |
176 | |
177 void Init() const { | |
178 InitOnceTrait::Init( | |
179 &once_, | |
180 // Casts to void* are needed here to avoid breaking strict aliasing | |
181 // rules. | |
182 reinterpret_cast<void(*)(void*)>(&InitInstance), // NOLINT | |
183 reinterpret_cast<void*>(&storage_)); | |
184 } | |
185 | |
186 public: | |
187 T* Pointer() { | |
188 Init(); | |
189 return AllocationTrait::MutableInstance(&storage_); | |
190 } | |
191 | |
192 const T& Get() const { | |
193 Init(); | |
194 return *AllocationTrait::MutableInstance(&storage_); | |
195 } | |
196 | |
197 mutable OnceType once_; | |
198 // Note that the previous field, OnceType, is an AtomicWord which guarantees | |
199 // 4-byte alignment of the storage field below. If compiling with GCC (>4.2), | |
200 // the LAZY_ALIGN macro above will guarantee correctness for any alignment. | |
201 mutable StorageType storage_; | |
202 }; | |
203 | |
204 | |
205 template <typename T, | |
206 typename CreateTrait = DefaultConstructTrait<T>, | |
207 typename InitOnceTrait = ThreadSafeInitOnceTrait, | |
208 typename DestroyTrait = LeakyInstanceTrait<T> > | |
209 struct LazyStaticInstance { | |
210 typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, | |
211 CreateTrait, InitOnceTrait, DestroyTrait> type; | |
212 }; | |
213 | |
214 | |
215 template <typename T, | |
216 typename CreateTrait = DefaultConstructTrait<T>, | |
217 typename InitOnceTrait = ThreadSafeInitOnceTrait, | |
218 typename DestroyTrait = LeakyInstanceTrait<T> > | |
219 struct LazyInstance { | |
220 // A LazyInstance is a LazyStaticInstance. | |
221 typedef typename LazyStaticInstance<T, CreateTrait, InitOnceTrait, | |
222 DestroyTrait>::type type; | |
223 }; | |
224 | |
225 | |
226 template <typename T, | |
227 typename CreateTrait = DefaultCreateTrait<T>, | |
228 typename InitOnceTrait = ThreadSafeInitOnceTrait, | |
229 typename DestroyTrait = LeakyInstanceTrait<T> > | |
230 struct LazyDynamicInstance { | |
231 typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>, | |
232 CreateTrait, InitOnceTrait, DestroyTrait> type; | |
233 }; | |
234 | |
235 } } // namespace v8::internal | |
236 | |
237 #endif // V8_LAZY_INSTANCE_H_ | |
OLD | NEW |