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 "src/base/macros.h" 72 #include "src/base/once.h" 73 74 namespace v8 { 75 namespace 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 84 template <typename T> 85 struct LeakyInstanceTrait { DestroyLeakyInstanceTrait86 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 MutableInstanceStaticallyAllocatedInstanceTrait102 static T* MutableInstance(StorageType* storage) { 103 return reinterpret_cast<T*>(storage); 104 } 105 106 template <typename ConstructTrait> InitStorageUsingTraitStaticallyAllocatedInstanceTrait107 static void InitStorageUsingTrait(StorageType* storage) { 108 ConstructTrait::Construct(storage); 109 } 110 }; 111 112 113 template <typename T> 114 struct DynamicallyAllocatedInstanceTrait { 115 typedef T* StorageType; 116 MutableInstanceDynamicallyAllocatedInstanceTrait117 static T* MutableInstance(StorageType* storage) { 118 return *storage; 119 } 120 121 template <typename CreateTrait> InitStorageUsingTraitDynamicallyAllocatedInstanceTrait122 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. ConstructDefaultConstructTrait131 static void Construct(void* allocated_ptr) { new (allocated_ptr) T(); } 132 }; 133 134 135 template <typename T> 136 struct DefaultCreateTrait { CreateDefaultCreateTrait137 static T* Create() { 138 return new T(); 139 } 140 }; 141 142 143 struct ThreadSafeInitOnceTrait { 144 template <typename Function, typename Storage> InitThreadSafeInitOnceTrait145 static void Init(OnceType* once, Function function, Storage storage) { 146 CallOnce(once, function, storage); 147 } 148 }; 149 150 151 // Initialization trait for users who don't care about thread-safety. 152 struct SingleThreadInitOnceTrait { 153 template <typename Function, typename Storage> InitSingleThreadInitOnceTrait154 static void Init(OnceType* once, Function function, Storage storage) { 155 if (*once == ONCE_STATE_UNINITIALIZED) { 156 function(storage); 157 *once = ONCE_STATE_DONE; 158 } 159 } 160 }; 161 162 163 // TODO(pliard): Handle instances destruction (using global destructors). 164 template <typename T, typename AllocationTrait, typename CreateTrait, 165 typename InitOnceTrait, typename DestroyTrait /* not used yet. */> 166 struct LazyInstanceImpl { 167 public: 168 typedef typename AllocationTrait::StorageType StorageType; 169 170 private: InitInstanceLazyInstanceImpl171 static void InitInstance(void* storage) { 172 AllocationTrait::template InitStorageUsingTrait<CreateTrait>( 173 static_cast<StorageType*>(storage)); 174 } 175 InitLazyInstanceImpl176 void Init() const { 177 InitOnceTrait::Init(&once_, &InitInstance, static_cast<void*>(&storage_)); 178 } 179 180 public: PointerLazyInstanceImpl181 T* Pointer() { 182 Init(); 183 return AllocationTrait::MutableInstance(&storage_); 184 } 185 GetLazyInstanceImpl186 const T& Get() const { 187 Init(); 188 return *AllocationTrait::MutableInstance(&storage_); 189 } 190 191 mutable OnceType once_; 192 // Note that the previous field, OnceType, is an AtomicWord which guarantees 193 // 4-byte alignment of the storage field below. If compiling with GCC (>4.2), 194 // the LAZY_ALIGN macro above will guarantee correctness for any alignment. 195 mutable StorageType storage_; 196 }; 197 198 199 template <typename T, 200 typename CreateTrait = DefaultConstructTrait<T>, 201 typename InitOnceTrait = ThreadSafeInitOnceTrait, 202 typename DestroyTrait = LeakyInstanceTrait<T> > 203 struct LazyStaticInstance { 204 typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, 205 CreateTrait, InitOnceTrait, DestroyTrait> type; 206 }; 207 208 209 template <typename T, 210 typename CreateTrait = DefaultConstructTrait<T>, 211 typename InitOnceTrait = ThreadSafeInitOnceTrait, 212 typename DestroyTrait = LeakyInstanceTrait<T> > 213 struct LazyInstance { 214 // A LazyInstance is a LazyStaticInstance. 215 typedef typename LazyStaticInstance<T, CreateTrait, InitOnceTrait, 216 DestroyTrait>::type type; 217 }; 218 219 220 template <typename T, 221 typename CreateTrait = DefaultCreateTrait<T>, 222 typename InitOnceTrait = ThreadSafeInitOnceTrait, 223 typename DestroyTrait = LeakyInstanceTrait<T> > 224 struct LazyDynamicInstance { 225 typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>, 226 CreateTrait, InitOnceTrait, DestroyTrait> type; 227 }; 228 229 } // namespace base 230 } // namespace v8 231 232 #endif // V8_BASE_LAZY_INSTANCE_H_ 233