| // 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(void* 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(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(void* 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(void* storage) { | |
| AllocationTrait::template InitStorageUsingTrait<CreateTrait>( | |
| static_cast<StorageType*>(storage)); | |
| } | |
| void Init() const { | |
| InitOnceTrait::Init(&once_, &InitInstance, static_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_ |