Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 // The LazyInstance<Type, Traits> class manages a single instance of Type,
     29 // which will be lazily created on the first time it's accessed.  This class is
     30 // useful for places you would normally use a function-level static, but you
     31 // need to have guaranteed thread-safety.  The Type constructor will only ever
     32 // be called once, even if two threads are racing to create the object.  Get()
     33 // and Pointer() will always return the same, completely initialized instance.
     34 //
     35 // LazyInstance is completely thread safe, assuming that you create it safely.
     36 // The class was designed to be POD initialized, so it shouldn't require a
     37 // static constructor.  It really only makes sense to declare a LazyInstance as
     38 // a global variable using the LAZY_INSTANCE_INITIALIZER initializer.
     39 //
     40 // LazyInstance is similar to Singleton, except it does not have the singleton
     41 // property.  You can have multiple LazyInstance's of the same type, and each
     42 // will manage a unique instance.  It also preallocates the space for Type, as
     43 // to avoid allocating the Type instance on the heap.  This may help with the
     44 // performance of creating the instance, and reducing heap fragmentation.  This
     45 // requires that Type be a complete type so we can determine the size. See
     46 // notes for advanced users below for more explanations.
     47 //
     48 // Example usage:
     49 //   static LazyInstance<MyClass>::type my_instance = LAZY_INSTANCE_INITIALIZER;
     50 //   void SomeMethod() {
     51 //     my_instance.Get().SomeMethod();  // MyClass::SomeMethod()
     52 //
     53 //     MyClass* ptr = my_instance.Pointer();
     54 //     ptr->DoDoDo();  // MyClass::DoDoDo
     55 //   }
     56 //
     57 // Additionally you can override the way your instance is constructed by
     58 // providing your own trait:
     59 // Example usage:
     60 //   struct MyCreateTrait {
     61 //     static void Construct(MyClass* allocated_ptr) {
     62 //       new (allocated_ptr) MyClass(/* extra parameters... */);
     63 //     }
     64 //   };
     65 //   static LazyInstance<MyClass, MyCreateTrait>::type my_instance =
     66 //      LAZY_INSTANCE_INITIALIZER;
     67 //
     68 // WARNINGS:
     69 // - This implementation of LazyInstance is NOT THREAD-SAFE by default. See
     70 //   ThreadSafeInitOnceTrait declared below for that.
     71 // - Lazy initialization comes with a cost. Make sure that you don't use it on
     72 //   critical path. Consider adding your initialization code to a function
     73 //   which is explicitly called once.
     74 //
     75 // Notes for advanced users:
     76 // LazyInstance can actually be used in two different ways:
     77 //
     78 // - "Static mode" which is the default mode since it is the most efficient
     79 //   (no extra heap allocation). In this mode, the instance is statically
     80 //   allocated (stored in the global data section at compile time).
     81 //   The macro LAZY_STATIC_INSTANCE_INITIALIZER (= LAZY_INSTANCE_INITIALIZER)
     82 //   must be used to initialize static lazy instances.
     83 //
     84 // - "Dynamic mode". In this mode, the instance is dynamically allocated and
     85 //   constructed (using new) by default. This mode is useful if you have to
     86 //   deal with some code already allocating the instance for you (e.g.
     87 //   OS::Mutex() which returns a new private OS-dependent subclass of Mutex).
     88 //   The macro LAZY_DYNAMIC_INSTANCE_INITIALIZER must be used to initialize
     89 //   dynamic lazy instances.
     90 
     91 #ifndef V8_LAZY_INSTANCE_H_
     92 #define V8_LAZY_INSTANCE_H_
     93 
     94 #include "checks.h"
     95 #include "once.h"
     96 
     97 namespace v8 {
     98 namespace internal {
     99 
    100 #define LAZY_STATIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, { {} } }
    101 #define LAZY_DYNAMIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, 0 }
    102 
    103 // Default to static mode.
    104 #define LAZY_INSTANCE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
    105 
    106 
    107 template <typename T>
    108 struct LeakyInstanceTrait {
    109   static void Destroy(T* /* instance */) {}
    110 };
    111 
    112 
    113 // Traits that define how an instance is allocated and accessed.
    114 
    115 
    116 template <typename T>
    117 struct StaticallyAllocatedInstanceTrait {
    118   // 16-byte alignment fallback to be on the safe side here.
    119   struct V8_ALIGNAS(T, 16) StorageType {
    120     char x[sizeof(T)];
    121   };
    122 
    123   STATIC_ASSERT(V8_ALIGNOF(StorageType) >= V8_ALIGNOF(T));
    124 
    125   static T* MutableInstance(StorageType* storage) {
    126     return reinterpret_cast<T*>(storage);
    127   }
    128 
    129   template <typename ConstructTrait>
    130   static void InitStorageUsingTrait(StorageType* storage) {
    131     ConstructTrait::Construct(MutableInstance(storage));
    132   }
    133 };
    134 
    135 
    136 template <typename T>
    137 struct DynamicallyAllocatedInstanceTrait {
    138   typedef T* StorageType;
    139 
    140   static T* MutableInstance(StorageType* storage) {
    141     return *storage;
    142   }
    143 
    144   template <typename CreateTrait>
    145   static void InitStorageUsingTrait(StorageType* storage) {
    146     *storage = CreateTrait::Create();
    147   }
    148 };
    149 
    150 
    151 template <typename T>
    152 struct DefaultConstructTrait {
    153   // Constructs the provided object which was already allocated.
    154   static void Construct(T* allocated_ptr) {
    155     new(allocated_ptr) T();
    156   }
    157 };
    158 
    159 
    160 template <typename T>
    161 struct DefaultCreateTrait {
    162   static T* Create() {
    163     return new T();
    164   }
    165 };
    166 
    167 
    168 struct ThreadSafeInitOnceTrait {
    169   template <typename Function, typename Storage>
    170   static void Init(OnceType* once, Function function, Storage storage) {
    171     CallOnce(once, function, storage);
    172   }
    173 };
    174 
    175 
    176 // Initialization trait for users who don't care about thread-safety.
    177 struct SingleThreadInitOnceTrait {
    178   template <typename Function, typename Storage>
    179   static void Init(OnceType* once, Function function, Storage storage) {
    180     if (*once == ONCE_STATE_UNINITIALIZED) {
    181       function(storage);
    182       *once = ONCE_STATE_DONE;
    183     }
    184   }
    185 };
    186 
    187 
    188 // TODO(pliard): Handle instances destruction (using global destructors).
    189 template <typename T, typename AllocationTrait, typename CreateTrait,
    190           typename InitOnceTrait, typename DestroyTrait  /* not used yet. */>
    191 struct LazyInstanceImpl {
    192  public:
    193   typedef typename AllocationTrait::StorageType StorageType;
    194 
    195  private:
    196   static void InitInstance(StorageType* storage) {
    197     AllocationTrait::template InitStorageUsingTrait<CreateTrait>(storage);
    198   }
    199 
    200   void Init() const {
    201     InitOnceTrait::Init(
    202         &once_,
    203         // Casts to void* are needed here to avoid breaking strict aliasing
    204         // rules.
    205         reinterpret_cast<void(*)(void*)>(&InitInstance),  // NOLINT
    206         reinterpret_cast<void*>(&storage_));
    207   }
    208 
    209  public:
    210   T* Pointer() {
    211     Init();
    212     return AllocationTrait::MutableInstance(&storage_);
    213   }
    214 
    215   const T& Get() const {
    216     Init();
    217     return *AllocationTrait::MutableInstance(&storage_);
    218   }
    219 
    220   mutable OnceType once_;
    221   // Note that the previous field, OnceType, is an AtomicWord which guarantees
    222   // 4-byte alignment of the storage field below. If compiling with GCC (>4.2),
    223   // the LAZY_ALIGN macro above will guarantee correctness for any alignment.
    224   mutable StorageType storage_;
    225 };
    226 
    227 
    228 template <typename T,
    229           typename CreateTrait = DefaultConstructTrait<T>,
    230           typename InitOnceTrait = SingleThreadInitOnceTrait,
    231           typename DestroyTrait = LeakyInstanceTrait<T> >
    232 struct LazyStaticInstance {
    233   typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>,
    234       CreateTrait, InitOnceTrait, DestroyTrait> type;
    235 };
    236 
    237 
    238 template <typename T,
    239           typename CreateTrait = DefaultConstructTrait<T>,
    240           typename InitOnceTrait = SingleThreadInitOnceTrait,
    241           typename DestroyTrait = LeakyInstanceTrait<T> >
    242 struct LazyInstance {
    243   // A LazyInstance is a LazyStaticInstance.
    244   typedef typename LazyStaticInstance<T, CreateTrait, InitOnceTrait,
    245       DestroyTrait>::type type;
    246 };
    247 
    248 
    249 template <typename T,
    250           typename CreateTrait = DefaultCreateTrait<T>,
    251           typename InitOnceTrait = SingleThreadInitOnceTrait,
    252           typename DestroyTrait = LeakyInstanceTrait<T> >
    253 struct LazyDynamicInstance {
    254   typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>,
    255       CreateTrait, InitOnceTrait, DestroyTrait> type;
    256 };
    257 
    258 } }  // namespace v8::internal
    259 
    260 #endif  // V8_LAZY_INSTANCE_H_
    261