// 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 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::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::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 #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 struct LeakyInstanceTrait { static void Destroy(T* /* instance */) {} }; // Traits that define how an instance is allocated and accessed. template struct StaticallyAllocatedInstanceTrait { using StorageType = typename std::aligned_storage::type; static T* MutableInstance(StorageType* storage) { return reinterpret_cast(storage); } template static void InitStorageUsingTrait(StorageType* storage) { ConstructTrait::Construct(storage); } }; template struct DynamicallyAllocatedInstanceTrait { using StorageType = T*; static T* MutableInstance(StorageType* storage) { return *storage; } template static void InitStorageUsingTrait(StorageType* storage) { *storage = CreateTrait::Create(); } }; template struct DefaultConstructTrait { // Constructs the provided object which was already allocated. static void Construct(void* allocated_ptr) { new (allocated_ptr) T(); } }; template struct DefaultCreateTrait { static T* Create() { return new T(); } }; struct ThreadSafeInitOnceTrait { template 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 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 struct LazyInstanceImpl { public: using StorageType = typename AllocationTrait::StorageType; private: static void InitInstance(void* storage) { AllocationTrait::template InitStorageUsingTrait( static_cast(storage)); } void Init() const { InitOnceTrait::Init(&once_, &InitInstance, static_cast(&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 InitOnceTrait = ThreadSafeInitOnceTrait, typename DestroyTrait = LeakyInstanceTrait > struct LazyStaticInstance { using type = LazyInstanceImpl, CreateTrait, InitOnceTrait, DestroyTrait>; }; template , typename InitOnceTrait = ThreadSafeInitOnceTrait, typename DestroyTrait = LeakyInstanceTrait > struct LazyInstance { // A LazyInstance is a LazyStaticInstance. using type = typename LazyStaticInstance::type; }; template , typename InitOnceTrait = ThreadSafeInitOnceTrait, typename DestroyTrait = LeakyInstanceTrait > struct LazyDynamicInstance { using type = LazyInstanceImpl, CreateTrait, InitOnceTrait, DestroyTrait>; }; // LeakyObject wraps an object of type T, which is initialized in the // constructor but never destructed. Thus LeakyObject is trivially // destructible and can be used in static (lazily initialized) variables. template class LeakyObject { public: template explicit LeakyObject(Args&&... args) { new (&storage_) T(std::forward(args)...); } T* get() { return reinterpret_cast(&storage_); } private: typename std::aligned_storage::type storage_; DISALLOW_COPY_AND_ASSIGN(LeakyObject); }; // Define a function which returns a pointer to a lazily initialized and never // destructed object of type T. #define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName, ...) \ T* FunctionName() { \ static ::v8::base::LeakyObject object{__VA_ARGS__}; \ return object.get(); \ } } // namespace base } // namespace v8 #endif // V8_BASE_LAZY_INSTANCE_H_