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 // WARNING: This implementation of LazyInstance is NOT thread-safe by default. 69 // See ThreadSafeInitOnceTrait declared below for that. 70 // 71 // Notes for advanced users: 72 // LazyInstance can actually be used in two different ways: 73 // 74 // - "Static mode" which is the default mode since it is the most efficient 75 // (no extra heap allocation). In this mode, the instance is statically 76 // allocated (stored in the global data section at compile time). 77 // The macro LAZY_STATIC_INSTANCE_INITIALIZER (= LAZY_INSTANCE_INITIALIZER) 78 // must be used to initialize static lazy instances. 79 // 80 // - "Dynamic mode". In this mode, the instance is dynamically allocated and 81 // constructed (using new) by default. This mode is useful if you have to 82 // deal with some code already allocating the instance for you (e.g. 83 // OS::Mutex() which returns a new private OS-dependent subclass of Mutex). 84 // The macro LAZY_DYNAMIC_INSTANCE_INITIALIZER must be used to initialize 85 // dynamic lazy instances. 86 87 #ifndef V8_LAZY_INSTANCE_H_ 88 #define V8_LAZY_INSTANCE_H_ 89 90 #include "once.h" 91 92 namespace v8 { 93 namespace internal { 94 95 #define LAZY_STATIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, {} } 96 #define LAZY_DYNAMIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, 0 } 97 98 // Default to static mode. 99 #define LAZY_INSTANCE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER 100 101 102 template <typename T> 103 struct LeakyInstanceTrait { DestroyLeakyInstanceTrait104 static void Destroy(T* /* instance */) {} 105 }; 106 107 108 // Traits that define how an instance is allocated and accessed. 109 110 // TODO(kalmard): __alignof__ is only defined for GCC > 4.2. Fix alignment issue 111 // on MIPS with other compilers. 112 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) 113 #define LAZY_ALIGN(x) __attribute__((aligned(__alignof__(x)))) 114 #else 115 #define LAZY_ALIGN(x) 116 #endif 117 118 template <typename T> 119 struct StaticallyAllocatedInstanceTrait { 120 typedef char StorageType[sizeof(T)] LAZY_ALIGN(T); 121 MutableInstanceStaticallyAllocatedInstanceTrait122 static T* MutableInstance(StorageType* storage) { 123 return reinterpret_cast<T*>(storage); 124 } 125 126 template <typename ConstructTrait> InitStorageUsingTraitStaticallyAllocatedInstanceTrait127 static void InitStorageUsingTrait(StorageType* storage) { 128 ConstructTrait::Construct(MutableInstance(storage)); 129 } 130 }; 131 132 #undef LAZY_ALIGN 133 134 135 template <typename T> 136 struct DynamicallyAllocatedInstanceTrait { 137 typedef T* StorageType; 138 MutableInstanceDynamicallyAllocatedInstanceTrait139 static T* MutableInstance(StorageType* storage) { 140 return *storage; 141 } 142 143 template <typename CreateTrait> InitStorageUsingTraitDynamicallyAllocatedInstanceTrait144 static void InitStorageUsingTrait(StorageType* storage) { 145 *storage = CreateTrait::Create(); 146 } 147 }; 148 149 150 template <typename T> 151 struct DefaultConstructTrait { 152 // Constructs the provided object which was already allocated. ConstructDefaultConstructTrait153 static void Construct(T* allocated_ptr) { 154 new(allocated_ptr) T(); 155 } 156 }; 157 158 159 template <typename T> 160 struct DefaultCreateTrait { CreateDefaultCreateTrait161 static T* Create() { 162 return new T(); 163 } 164 }; 165 166 167 struct ThreadSafeInitOnceTrait { 168 template <typename Function, typename Storage> InitThreadSafeInitOnceTrait169 static void Init(OnceType* once, Function function, Storage storage) { 170 CallOnce(once, function, storage); 171 } 172 }; 173 174 175 // Initialization trait for users who don't care about thread-safety. 176 struct SingleThreadInitOnceTrait { 177 template <typename Function, typename Storage> InitSingleThreadInitOnceTrait178 static void Init(OnceType* once, Function function, Storage storage) { 179 if (*once == ONCE_STATE_UNINITIALIZED) { 180 function(storage); 181 *once = ONCE_STATE_DONE; 182 } 183 } 184 }; 185 186 187 // TODO(pliard): Handle instances destruction (using global destructors). 188 template <typename T, typename AllocationTrait, typename CreateTrait, 189 typename InitOnceTrait, typename DestroyTrait /* not used yet. */> 190 struct LazyInstanceImpl { 191 public: 192 typedef typename AllocationTrait::StorageType StorageType; 193 194 private: InitInstanceLazyInstanceImpl195 static void InitInstance(StorageType* storage) { 196 AllocationTrait::template InitStorageUsingTrait<CreateTrait>(storage); 197 } 198 InitLazyInstanceImpl199 void Init() const { 200 InitOnceTrait::Init( 201 &once_, 202 // Casts to void* are needed here to avoid breaking strict aliasing 203 // rules. 204 reinterpret_cast<void(*)(void*)>(&InitInstance), // NOLINT 205 reinterpret_cast<void*>(&storage_)); 206 } 207 208 public: PointerLazyInstanceImpl209 T* Pointer() { 210 Init(); 211 return AllocationTrait::MutableInstance(&storage_); 212 } 213 GetLazyInstanceImpl214 const T& Get() const { 215 Init(); 216 return *AllocationTrait::MutableInstance(&storage_); 217 } 218 219 mutable OnceType once_; 220 // Note that the previous field, OnceType, is an AtomicWord which guarantees 221 // 4-byte alignment of the storage field below. If compiling with GCC (>4.2), 222 // the LAZY_ALIGN macro above will guarantee correctness for any alignment. 223 mutable StorageType storage_; 224 }; 225 226 227 template <typename T, 228 typename CreateTrait = DefaultConstructTrait<T>, 229 typename InitOnceTrait = SingleThreadInitOnceTrait, 230 typename DestroyTrait = LeakyInstanceTrait<T> > 231 struct LazyStaticInstance { 232 typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, 233 CreateTrait, InitOnceTrait, DestroyTrait> type; 234 }; 235 236 237 template <typename T, 238 typename CreateTrait = DefaultConstructTrait<T>, 239 typename InitOnceTrait = SingleThreadInitOnceTrait, 240 typename DestroyTrait = LeakyInstanceTrait<T> > 241 struct LazyInstance { 242 // A LazyInstance is a LazyStaticInstance. 243 typedef typename LazyStaticInstance<T, CreateTrait, InitOnceTrait, 244 DestroyTrait>::type type; 245 }; 246 247 248 template <typename T, 249 typename CreateTrait = DefaultConstructTrait<T>, 250 typename InitOnceTrait = SingleThreadInitOnceTrait, 251 typename DestroyTrait = LeakyInstanceTrait<T> > 252 struct LazyDynamicInstance { 253 typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>, 254 CreateTrait, InitOnceTrait, DestroyTrait> type; 255 }; 256 257 } } // namespace v8::internal 258 259 #endif // V8_LAZY_INSTANCE_H_ 260