// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // The LazyInstance<Type, Traits> class manages a single instance of Type, // which will be lazily created on the first time it's accessed. This class is // useful for places you would normally use a function-level static, but you // need to have guaranteed thread-safety. The Type constructor will only ever // be called once, even if two threads are racing to create the object. Get() // and Pointer() will always return the same, completely initialized instance. // // LazyInstance is completely thread safe, assuming that you create it safely. // The class was designed to be POD initialized, so it shouldn't require a // static constructor. It really only makes sense to declare a LazyInstance as // a global variable using the LAZY_INSTANCE_INITIALIZER initializer. // // LazyInstance is similar to Singleton, except it does not have the singleton // property. You can have multiple LazyInstance's of the same type, and each // will manage a unique instance. It also preallocates the space for Type, as // to avoid allocating the Type instance on the heap. This may help with the // performance of creating the instance, and reducing heap fragmentation. This // requires that Type be a complete type so we can determine the size. See // notes for advanced users below for more explanations. // // Example usage: // static LazyInstance<MyClass>::type my_instance = LAZY_INSTANCE_INITIALIZER; // void SomeMethod() { // my_instance.Get().SomeMethod(); // MyClass::SomeMethod() // // MyClass* ptr = my_instance.Pointer(); // ptr->DoDoDo(); // MyClass::DoDoDo // } // // Additionally you can override the way your instance is constructed by // providing your own trait: // Example usage: // struct MyCreateTrait { // static void Construct(MyClass* allocated_ptr) { // new (allocated_ptr) MyClass(/* extra parameters... */); // } // }; // static LazyInstance<MyClass, MyCreateTrait>::type my_instance = // LAZY_INSTANCE_INITIALIZER; // // WARNINGS: // - This implementation of LazyInstance IS THREAD-SAFE by default. See // SingleThreadInitOnceTrait if you don't care about thread safety. // - Lazy initialization comes with a cost. Make sure that you don't use it on // critical path. Consider adding your initialization code to a function // which is explicitly called once. // // Notes for advanced users: // LazyInstance can actually be used in two different ways: // // - "Static mode" which is the default mode since it is the most efficient // (no extra heap allocation). In this mode, the instance is statically // allocated (stored in the global data section at compile time). // The macro LAZY_STATIC_INSTANCE_INITIALIZER (= LAZY_INSTANCE_INITIALIZER) // must be used to initialize static lazy instances. // // - "Dynamic mode". In this mode, the instance is dynamically allocated and // constructed (using new) by default. This mode is useful if you have to // deal with some code already allocating the instance for you (e.g. // OS::Mutex() which returns a new private OS-dependent subclass of Mutex). // The macro LAZY_DYNAMIC_INSTANCE_INITIALIZER must be used to initialize // dynamic lazy instances. #ifndef V8_BASE_LAZY_INSTANCE_H_ #define V8_BASE_LAZY_INSTANCE_H_ #include "src/base/macros.h" #include "src/base/once.h" namespace v8 { namespace base { #define LAZY_STATIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, { {} } } #define LAZY_DYNAMIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, 0 } // Default to static mode. #define LAZY_INSTANCE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER template <typename T> struct LeakyInstanceTrait { static void Destroy(T* /* instance */) {} }; // Traits that define how an instance is allocated and accessed. template <typename T> struct StaticallyAllocatedInstanceTrait { // 16-byte alignment fallback to be on the safe side here. struct V8_ALIGNAS(T, 16) StorageType { char x[sizeof(T)]; }; STATIC_ASSERT(V8_ALIGNOF(StorageType) >= V8_ALIGNOF(T)); static T* MutableInstance(StorageType* storage) { return reinterpret_cast<T*>(storage); } template <typename ConstructTrait> static void InitStorageUsingTrait(StorageType* storage) { ConstructTrait::Construct(MutableInstance(storage)); } }; template <typename T> struct DynamicallyAllocatedInstanceTrait { typedef T* StorageType; static T* MutableInstance(StorageType* storage) { return *storage; } template <typename CreateTrait> static void InitStorageUsingTrait(StorageType* storage) { *storage = CreateTrait::Create(); } }; template <typename T> struct DefaultConstructTrait { // Constructs the provided object which was already allocated. static void Construct(T* allocated_ptr) { new(allocated_ptr) T(); } }; template <typename T> struct DefaultCreateTrait { static T* Create() { return new T(); } }; struct ThreadSafeInitOnceTrait { template <typename Function, typename Storage> static void Init(OnceType* once, Function function, Storage storage) { CallOnce(once, function, storage); } }; // Initialization trait for users who don't care about thread-safety. struct SingleThreadInitOnceTrait { template <typename Function, typename Storage> static void Init(OnceType* once, Function function, Storage storage) { if (*once == ONCE_STATE_UNINITIALIZED) { function(storage); *once = ONCE_STATE_DONE; } } }; // TODO(pliard): Handle instances destruction (using global destructors). template <typename T, typename AllocationTrait, typename CreateTrait, typename InitOnceTrait, typename DestroyTrait /* not used yet. */> struct LazyInstanceImpl { public: typedef typename AllocationTrait::StorageType StorageType; private: static void InitInstance(StorageType* storage) { AllocationTrait::template InitStorageUsingTrait<CreateTrait>(storage); } void Init() const { InitOnceTrait::Init( &once_, // Casts to void* are needed here to avoid breaking strict aliasing // rules. reinterpret_cast<void(*)(void*)>(&InitInstance), // NOLINT reinterpret_cast<void*>(&storage_)); } public: T* Pointer() { Init(); return AllocationTrait::MutableInstance(&storage_); } const T& Get() const { Init(); return *AllocationTrait::MutableInstance(&storage_); } mutable OnceType once_; // Note that the previous field, OnceType, is an AtomicWord which guarantees // 4-byte alignment of the storage field below. If compiling with GCC (>4.2), // the LAZY_ALIGN macro above will guarantee correctness for any alignment. mutable StorageType storage_; }; template <typename T, typename CreateTrait = DefaultConstructTrait<T>, typename InitOnceTrait = ThreadSafeInitOnceTrait, typename DestroyTrait = LeakyInstanceTrait<T> > struct LazyStaticInstance { typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, CreateTrait, InitOnceTrait, DestroyTrait> type; }; template <typename T, typename CreateTrait = DefaultConstructTrait<T>, typename InitOnceTrait = ThreadSafeInitOnceTrait, typename DestroyTrait = LeakyInstanceTrait<T> > struct LazyInstance { // A LazyInstance is a LazyStaticInstance. typedef typename LazyStaticInstance<T, CreateTrait, InitOnceTrait, DestroyTrait>::type type; }; template <typename T, typename CreateTrait = DefaultCreateTrait<T>, typename InitOnceTrait = ThreadSafeInitOnceTrait, typename DestroyTrait = LeakyInstanceTrait<T> > struct LazyDynamicInstance { typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>, CreateTrait, InitOnceTrait, DestroyTrait> type; }; } // namespace base } // namespace v8 #endif // V8_BASE_LAZY_INSTANCE_H_