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_BASE_LAZY_INSTANCE_H_ 69#define V8_BASE_LAZY_INSTANCE_H_ 70 71#include "src/base/macros.h" 72#include "src/base/once.h" 73 74namespace v8 { 75namespace base { 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 84template <typename T> 85struct LeakyInstanceTrait { 86 static void Destroy(T* /* instance */) {} 87}; 88 89 90// Traits that define how an instance is allocated and accessed. 91 92 93template <typename T> 94struct 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 113template <typename T> 114struct 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 128template <typename T> 129struct 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 137template <typename T> 138struct DefaultCreateTrait { 139 static T* Create() { 140 return new T(); 141 } 142}; 143 144 145struct 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. 154struct 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). 166template <typename T, typename AllocationTrait, typename CreateTrait, 167 typename InitOnceTrait, typename DestroyTrait /* not used yet. */> 168struct 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 205template <typename T, 206 typename CreateTrait = DefaultConstructTrait<T>, 207 typename InitOnceTrait = ThreadSafeInitOnceTrait, 208 typename DestroyTrait = LeakyInstanceTrait<T> > 209struct LazyStaticInstance { 210 typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, 211 CreateTrait, InitOnceTrait, DestroyTrait> type; 212}; 213 214 215template <typename T, 216 typename CreateTrait = DefaultConstructTrait<T>, 217 typename InitOnceTrait = ThreadSafeInitOnceTrait, 218 typename DestroyTrait = LeakyInstanceTrait<T> > 219struct LazyInstance { 220 // A LazyInstance is a LazyStaticInstance. 221 typedef typename LazyStaticInstance<T, CreateTrait, InitOnceTrait, 222 DestroyTrait>::type type; 223}; 224 225 226template <typename T, 227 typename CreateTrait = DefaultCreateTrait<T>, 228 typename InitOnceTrait = ThreadSafeInitOnceTrait, 229 typename DestroyTrait = LeakyInstanceTrait<T> > 230struct LazyDynamicInstance { 231 typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>, 232 CreateTrait, InitOnceTrait, DestroyTrait> type; 233}; 234 235} // namespace base 236} // namespace v8 237 238#endif // V8_BASE_LAZY_INSTANCE_H_ 239