| // Copyright 2012 the V8 project authors. All rights reserved. |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following |
| // disclaimer in the documentation and/or other materials provided |
| // with the distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived |
| // from this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // 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; |
| // |
| // WARNING: This implementation of LazyInstance is NOT thread-safe by default. |
| // See ThreadSafeInitOnceTrait declared below for that. |
| // |
| // 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_LAZY_INSTANCE_H_ |
| #define V8_LAZY_INSTANCE_H_ |
| |
| #include "once.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| #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. |
| |
| // TODO(kalmard): __alignof__ is only defined for GCC > 4.2. Fix alignment issue |
| // on MIPS with other compilers. |
| #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) |
| #define LAZY_ALIGN(x) __attribute__((aligned(__alignof__(x)))) |
| #else |
| #define LAZY_ALIGN(x) |
| #endif |
| |
| template <typename T> |
| struct StaticallyAllocatedInstanceTrait { |
| typedef char StorageType[sizeof(T)] LAZY_ALIGN(T); |
| |
| static T* MutableInstance(StorageType* storage) { |
| return reinterpret_cast<T*>(storage); |
| } |
| |
| template <typename ConstructTrait> |
| static void InitStorageUsingTrait(StorageType* storage) { |
| ConstructTrait::Construct(MutableInstance(storage)); |
| } |
| }; |
| |
| #undef LAZY_ALIGN |
| |
| |
| 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 = SingleThreadInitOnceTrait, |
| typename DestroyTrait = LeakyInstanceTrait<T> > |
| struct LazyStaticInstance { |
| typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, |
| CreateTrait, InitOnceTrait, DestroyTrait> type; |
| }; |
| |
| |
| template <typename T, |
| typename CreateTrait = DefaultConstructTrait<T>, |
| typename InitOnceTrait = SingleThreadInitOnceTrait, |
| 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 = DefaultConstructTrait<T>, |
| typename InitOnceTrait = SingleThreadInitOnceTrait, |
| typename DestroyTrait = LeakyInstanceTrait<T> > |
| struct LazyDynamicInstance { |
| typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>, |
| CreateTrait, InitOnceTrait, DestroyTrait> type; |
| }; |
| |
| } } // namespace v8::internal |
| |
| #endif // V8_LAZY_INSTANCE_H_ |