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 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(MutableInstance(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(T* allocated_ptr) { 132 new(allocated_ptr) T(); 133 } 134 }; 135 136 137 template <typename T> 138 struct DefaultCreateTrait { CreateDefaultCreateTrait139 static T* Create() { 140 return new T(); 141 } 142 }; 143 144 145 struct ThreadSafeInitOnceTrait { 146 template <typename Function, typename Storage> InitThreadSafeInitOnceTrait147 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> InitSingleThreadInitOnceTrait156 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: InitInstanceLazyInstanceImpl173 static void InitInstance(StorageType* storage) { 174 AllocationTrait::template InitStorageUsingTrait<CreateTrait>(storage); 175 } 176 InitLazyInstanceImpl177 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: PointerLazyInstanceImpl187 T* Pointer() { 188 Init(); 189 return AllocationTrait::MutableInstance(&storage_); 190 } 191 GetLazyInstanceImpl192 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 base 236 } // namespace v8 237 238 #endif // V8_BASE_LAZY_INSTANCE_H_ 239