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 { DestroyLeakyInstanceTrait88 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 MutableInstanceStaticallyAllocatedInstanceTrait100 static T* MutableInstance(StorageType* storage) { 101 return reinterpret_cast<T*>(storage); 102 } 103 104 template <typename ConstructTrait> InitStorageUsingTraitStaticallyAllocatedInstanceTrait105 static void InitStorageUsingTrait(StorageType* storage) { 106 ConstructTrait::Construct(storage); 107 } 108 }; 109 110 111 template <typename T> 112 struct DynamicallyAllocatedInstanceTrait { 113 using StorageType = T*; 114 MutableInstanceDynamicallyAllocatedInstanceTrait115 static T* MutableInstance(StorageType* storage) { 116 return *storage; 117 } 118 119 template <typename CreateTrait> InitStorageUsingTraitDynamicallyAllocatedInstanceTrait120 static void InitStorageUsingTrait(StorageType* storage) { 121 *storage = CreateTrait::Create(); 122 } 123 }; 124 125 126 template <typename T> 127 struct DefaultConstructTrait { 128 // Constructs the provided object which was already allocated. ConstructDefaultConstructTrait129 static void Construct(void* allocated_ptr) { new (allocated_ptr) T(); } 130 }; 131 132 133 template <typename T> 134 struct DefaultCreateTrait { CreateDefaultCreateTrait135 static T* Create() { 136 return new T(); 137 } 138 }; 139 140 141 struct ThreadSafeInitOnceTrait { 142 template <typename Function, typename Storage> InitThreadSafeInitOnceTrait143 static void Init(OnceType* once, Function function, Storage storage) { 144 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> InitSingleThreadInitOnceTrait152 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: InitInstanceLazyInstanceImpl169 static void InitInstance(void* storage) { 170 AllocationTrait::template InitStorageUsingTrait<CreateTrait>( 171 static_cast<StorageType*>(storage)); 172 } 173 InitLazyInstanceImpl174 void Init() const { 175 InitOnceTrait::Init(&once_, &InitInstance, static_cast<void*>(&storage_)); 176 } 177 178 public: PointerLazyInstanceImpl179 T* Pointer() { 180 Init(); 181 return AllocationTrait::MutableInstance(&storage_); 182 } 183 GetLazyInstanceImpl184 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> LeakyObject(Args &&...args)234 explicit LeakyObject(Args&&... args) { 235 new (&storage_) T(std::forward<Args>(args)...); 236 } 237 238 LeakyObject(const LeakyObject&) = delete; 239 LeakyObject& operator=(const LeakyObject&) = delete; 240 get()241 T* get() { return reinterpret_cast<T*>(&storage_); } 242 243 private: 244 typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_; 245 }; 246 247 // Define a function which returns a pointer to a lazily initialized and never 248 // destructed object of type T. 249 #define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName, ...) \ 250 T* FunctionName() { \ 251 static ::v8::base::LeakyObject<T> object{__VA_ARGS__}; \ 252 return object.get(); \ 253 } 254 255 } // namespace base 256 } // namespace v8 257 258 #endif // V8_BASE_LAZY_INSTANCE_H_ 259