1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 // The LazyInstance<Type, Traits> class manages a single instance of Type, 29 // which will be lazily created on the first time it's accessed. This class is 30 // useful for places you would normally use a function-level static, but you 31 // need to have guaranteed thread-safety. The Type constructor will only ever 32 // be called once, even if two threads are racing to create the object. Get() 33 // and Pointer() will always return the same, completely initialized instance. 34 // 35 // LazyInstance is completely thread safe, assuming that you create it safely. 36 // The class was designed to be POD initialized, so it shouldn't require a 37 // static constructor. It really only makes sense to declare a LazyInstance as 38 // a global variable using the LAZY_INSTANCE_INITIALIZER initializer. 39 // 40 // LazyInstance is similar to Singleton, except it does not have the singleton 41 // property. You can have multiple LazyInstance's of the same type, and each 42 // will manage a unique instance. It also preallocates the space for Type, as 43 // to avoid allocating the Type instance on the heap. This may help with the 44 // performance of creating the instance, and reducing heap fragmentation. This 45 // requires that Type be a complete type so we can determine the size. See 46 // notes for advanced users below for more explanations. 47 // 48 // Example usage: 49 // static LazyInstance<MyClass>::type my_instance = LAZY_INSTANCE_INITIALIZER; 50 // void SomeMethod() { 51 // my_instance.Get().SomeMethod(); // MyClass::SomeMethod() 52 // 53 // MyClass* ptr = my_instance.Pointer(); 54 // ptr->DoDoDo(); // MyClass::DoDoDo 55 // } 56 // 57 // Additionally you can override the way your instance is constructed by 58 // providing your own trait: 59 // Example usage: 60 // struct MyCreateTrait { 61 // static void Construct(MyClass* allocated_ptr) { 62 // new (allocated_ptr) MyClass(/* extra parameters... */); 63 // } 64 // }; 65 // static LazyInstance<MyClass, MyCreateTrait>::type my_instance = 66 // LAZY_INSTANCE_INITIALIZER; 67 // 68 // WARNINGS: 69 // - This implementation of LazyInstance is NOT THREAD-SAFE by default. See 70 // ThreadSafeInitOnceTrait declared below for that. 71 // - Lazy initialization comes with a cost. Make sure that you don't use it on 72 // critical path. Consider adding your initialization code to a function 73 // which is explicitly called once. 74 // 75 // Notes for advanced users: 76 // LazyInstance can actually be used in two different ways: 77 // 78 // - "Static mode" which is the default mode since it is the most efficient 79 // (no extra heap allocation). In this mode, the instance is statically 80 // allocated (stored in the global data section at compile time). 81 // The macro LAZY_STATIC_INSTANCE_INITIALIZER (= LAZY_INSTANCE_INITIALIZER) 82 // must be used to initialize static lazy instances. 83 // 84 // - "Dynamic mode". In this mode, the instance is dynamically allocated and 85 // constructed (using new) by default. This mode is useful if you have to 86 // deal with some code already allocating the instance for you (e.g. 87 // OS::Mutex() which returns a new private OS-dependent subclass of Mutex). 88 // The macro LAZY_DYNAMIC_INSTANCE_INITIALIZER must be used to initialize 89 // dynamic lazy instances. 90 91 #ifndef V8_LAZY_INSTANCE_H_ 92 #define V8_LAZY_INSTANCE_H_ 93 94 #include "checks.h" 95 #include "once.h" 96 97 namespace v8 { 98 namespace internal { 99 100 #define LAZY_STATIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, { {} } } 101 #define LAZY_DYNAMIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, 0 } 102 103 // Default to static mode. 104 #define LAZY_INSTANCE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER 105 106 107 template <typename T> 108 struct LeakyInstanceTrait { 109 static void Destroy(T* /* instance */) {} 110 }; 111 112 113 // Traits that define how an instance is allocated and accessed. 114 115 116 template <typename T> 117 struct StaticallyAllocatedInstanceTrait { 118 // 16-byte alignment fallback to be on the safe side here. 119 struct V8_ALIGNAS(T, 16) StorageType { 120 char x[sizeof(T)]; 121 }; 122 123 STATIC_ASSERT(V8_ALIGNOF(StorageType) >= V8_ALIGNOF(T)); 124 125 static T* MutableInstance(StorageType* storage) { 126 return reinterpret_cast<T*>(storage); 127 } 128 129 template <typename ConstructTrait> 130 static void InitStorageUsingTrait(StorageType* storage) { 131 ConstructTrait::Construct(MutableInstance(storage)); 132 } 133 }; 134 135 136 template <typename T> 137 struct DynamicallyAllocatedInstanceTrait { 138 typedef T* StorageType; 139 140 static T* MutableInstance(StorageType* storage) { 141 return *storage; 142 } 143 144 template <typename CreateTrait> 145 static void InitStorageUsingTrait(StorageType* storage) { 146 *storage = CreateTrait::Create(); 147 } 148 }; 149 150 151 template <typename T> 152 struct DefaultConstructTrait { 153 // Constructs the provided object which was already allocated. 154 static void Construct(T* allocated_ptr) { 155 new(allocated_ptr) T(); 156 } 157 }; 158 159 160 template <typename T> 161 struct DefaultCreateTrait { 162 static T* Create() { 163 return new T(); 164 } 165 }; 166 167 168 struct ThreadSafeInitOnceTrait { 169 template <typename Function, typename Storage> 170 static void Init(OnceType* once, Function function, Storage storage) { 171 CallOnce(once, function, storage); 172 } 173 }; 174 175 176 // Initialization trait for users who don't care about thread-safety. 177 struct SingleThreadInitOnceTrait { 178 template <typename Function, typename Storage> 179 static void Init(OnceType* once, Function function, Storage storage) { 180 if (*once == ONCE_STATE_UNINITIALIZED) { 181 function(storage); 182 *once = ONCE_STATE_DONE; 183 } 184 } 185 }; 186 187 188 // TODO(pliard): Handle instances destruction (using global destructors). 189 template <typename T, typename AllocationTrait, typename CreateTrait, 190 typename InitOnceTrait, typename DestroyTrait /* not used yet. */> 191 struct LazyInstanceImpl { 192 public: 193 typedef typename AllocationTrait::StorageType StorageType; 194 195 private: 196 static void InitInstance(StorageType* storage) { 197 AllocationTrait::template InitStorageUsingTrait<CreateTrait>(storage); 198 } 199 200 void Init() const { 201 InitOnceTrait::Init( 202 &once_, 203 // Casts to void* are needed here to avoid breaking strict aliasing 204 // rules. 205 reinterpret_cast<void(*)(void*)>(&InitInstance), // NOLINT 206 reinterpret_cast<void*>(&storage_)); 207 } 208 209 public: 210 T* Pointer() { 211 Init(); 212 return AllocationTrait::MutableInstance(&storage_); 213 } 214 215 const T& Get() const { 216 Init(); 217 return *AllocationTrait::MutableInstance(&storage_); 218 } 219 220 mutable OnceType once_; 221 // Note that the previous field, OnceType, is an AtomicWord which guarantees 222 // 4-byte alignment of the storage field below. If compiling with GCC (>4.2), 223 // the LAZY_ALIGN macro above will guarantee correctness for any alignment. 224 mutable StorageType storage_; 225 }; 226 227 228 template <typename T, 229 typename CreateTrait = DefaultConstructTrait<T>, 230 typename InitOnceTrait = SingleThreadInitOnceTrait, 231 typename DestroyTrait = LeakyInstanceTrait<T> > 232 struct LazyStaticInstance { 233 typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, 234 CreateTrait, InitOnceTrait, DestroyTrait> type; 235 }; 236 237 238 template <typename T, 239 typename CreateTrait = DefaultConstructTrait<T>, 240 typename InitOnceTrait = SingleThreadInitOnceTrait, 241 typename DestroyTrait = LeakyInstanceTrait<T> > 242 struct LazyInstance { 243 // A LazyInstance is a LazyStaticInstance. 244 typedef typename LazyStaticInstance<T, CreateTrait, InitOnceTrait, 245 DestroyTrait>::type type; 246 }; 247 248 249 template <typename T, 250 typename CreateTrait = DefaultCreateTrait<T>, 251 typename InitOnceTrait = SingleThreadInitOnceTrait, 252 typename DestroyTrait = LeakyInstanceTrait<T> > 253 struct LazyDynamicInstance { 254 typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>, 255 CreateTrait, InitOnceTrait, DestroyTrait> type; 256 }; 257 258 } } // namespace v8::internal 259 260 #endif // V8_LAZY_INSTANCE_H_ 261