| 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 |