| // 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 v8::base |
| |
| #endif // V8_BASE_LAZY_INSTANCE_H_ |