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 // WARNING: This implementation of LazyInstance is NOT thread-safe by default.
     69 // See ThreadSafeInitOnceTrait declared below for that.
     70 //
     71 // Notes for advanced users:
     72 // LazyInstance can actually be used in two different ways:
     73 //
     74 // - "Static mode" which is the default mode since it is the most efficient
     75 //   (no extra heap allocation). In this mode, the instance is statically
     76 //   allocated (stored in the global data section at compile time).
     77 //   The macro LAZY_STATIC_INSTANCE_INITIALIZER (= LAZY_INSTANCE_INITIALIZER)
     78 //   must be used to initialize static lazy instances.
     79 //
     80 // - "Dynamic mode". In this mode, the instance is dynamically allocated and
     81 //   constructed (using new) by default. This mode is useful if you have to
     82 //   deal with some code already allocating the instance for you (e.g.
     83 //   OS::Mutex() which returns a new private OS-dependent subclass of Mutex).
     84 //   The macro LAZY_DYNAMIC_INSTANCE_INITIALIZER must be used to initialize
     85 //   dynamic lazy instances.
     86 
     87 #ifndef V8_LAZY_INSTANCE_H_
     88 #define V8_LAZY_INSTANCE_H_
     89 
     90 #include "once.h"
     91 
     92 namespace v8 {
     93 namespace internal {
     94 
     95 #define LAZY_STATIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, {} }
     96 #define LAZY_DYNAMIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, 0 }
     97 
     98 // Default to static mode.
     99 #define LAZY_INSTANCE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
    100 
    101 
    102 template <typename T>
    103 struct LeakyInstanceTrait {
    104   static void Destroy(T* /* instance */) {}
    105 };
    106 
    107 
    108 // Traits that define how an instance is allocated and accessed.
    109 
    110 // TODO(kalmard): __alignof__ is only defined for GCC > 4.2. Fix alignment issue
    111 // on MIPS with other compilers.
    112 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2))
    113 #define LAZY_ALIGN(x) __attribute__((aligned(__alignof__(x))))
    114 #else
    115 #define LAZY_ALIGN(x)
    116 #endif
    117 
    118 template <typename T>
    119 struct StaticallyAllocatedInstanceTrait {
    120   typedef char StorageType[sizeof(T)] LAZY_ALIGN(T);
    121 
    122   static T* MutableInstance(StorageType* storage) {
    123     return reinterpret_cast<T*>(storage);
    124   }
    125 
    126   template <typename ConstructTrait>
    127   static void InitStorageUsingTrait(StorageType* storage) {
    128     ConstructTrait::Construct(MutableInstance(storage));
    129   }
    130 };
    131 
    132 #undef LAZY_ALIGN
    133 
    134 
    135 template <typename T>
    136 struct DynamicallyAllocatedInstanceTrait {
    137   typedef T* StorageType;
    138 
    139   static T* MutableInstance(StorageType* storage) {
    140     return *storage;
    141   }
    142 
    143   template <typename CreateTrait>
    144   static void InitStorageUsingTrait(StorageType* storage) {
    145     *storage = CreateTrait::Create();
    146   }
    147 };
    148 
    149 
    150 template <typename T>
    151 struct DefaultConstructTrait {
    152   // Constructs the provided object which was already allocated.
    153   static void Construct(T* allocated_ptr) {
    154     new(allocated_ptr) T();
    155   }
    156 };
    157 
    158 
    159 template <typename T>
    160 struct DefaultCreateTrait {
    161   static T* Create() {
    162     return new T();
    163   }
    164 };
    165 
    166 
    167 struct ThreadSafeInitOnceTrait {
    168   template <typename Function, typename Storage>
    169   static void Init(OnceType* once, Function function, Storage storage) {
    170     CallOnce(once, function, storage);
    171   }
    172 };
    173 
    174 
    175 // Initialization trait for users who don't care about thread-safety.
    176 struct SingleThreadInitOnceTrait {
    177   template <typename Function, typename Storage>
    178   static void Init(OnceType* once, Function function, Storage storage) {
    179     if (*once == ONCE_STATE_UNINITIALIZED) {
    180       function(storage);
    181       *once = ONCE_STATE_DONE;
    182     }
    183   }
    184 };
    185 
    186 
    187 // TODO(pliard): Handle instances destruction (using global destructors).
    188 template <typename T, typename AllocationTrait, typename CreateTrait,
    189           typename InitOnceTrait, typename DestroyTrait  /* not used yet. */>
    190 struct LazyInstanceImpl {
    191  public:
    192   typedef typename AllocationTrait::StorageType StorageType;
    193 
    194  private:
    195   static void InitInstance(StorageType* storage) {
    196     AllocationTrait::template InitStorageUsingTrait<CreateTrait>(storage);
    197   }
    198 
    199   void Init() const {
    200     InitOnceTrait::Init(
    201         &once_,
    202         // Casts to void* are needed here to avoid breaking strict aliasing
    203         // rules.
    204         reinterpret_cast<void(*)(void*)>(&InitInstance),  // NOLINT
    205         reinterpret_cast<void*>(&storage_));
    206   }
    207 
    208  public:
    209   T* Pointer() {
    210     Init();
    211     return AllocationTrait::MutableInstance(&storage_);
    212   }
    213 
    214   const T& Get() const {
    215     Init();
    216     return *AllocationTrait::MutableInstance(&storage_);
    217   }
    218 
    219   mutable OnceType once_;
    220   // Note that the previous field, OnceType, is an AtomicWord which guarantees
    221   // 4-byte alignment of the storage field below. If compiling with GCC (>4.2),
    222   // the LAZY_ALIGN macro above will guarantee correctness for any alignment.
    223   mutable StorageType storage_;
    224 };
    225 
    226 
    227 template <typename T,
    228           typename CreateTrait = DefaultConstructTrait<T>,
    229           typename InitOnceTrait = SingleThreadInitOnceTrait,
    230           typename DestroyTrait = LeakyInstanceTrait<T> >
    231 struct LazyStaticInstance {
    232   typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>,
    233       CreateTrait, InitOnceTrait, DestroyTrait> type;
    234 };
    235 
    236 
    237 template <typename T,
    238           typename CreateTrait = DefaultConstructTrait<T>,
    239           typename InitOnceTrait = SingleThreadInitOnceTrait,
    240           typename DestroyTrait = LeakyInstanceTrait<T> >
    241 struct LazyInstance {
    242   // A LazyInstance is a LazyStaticInstance.
    243   typedef typename LazyStaticInstance<T, CreateTrait, InitOnceTrait,
    244       DestroyTrait>::type type;
    245 };
    246 
    247 
    248 template <typename T,
    249           typename CreateTrait = DefaultConstructTrait<T>,
    250           typename InitOnceTrait = SingleThreadInitOnceTrait,
    251           typename DestroyTrait = LeakyInstanceTrait<T> >
    252 struct LazyDynamicInstance {
    253   typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>,
    254       CreateTrait, InitOnceTrait, DestroyTrait> type;
    255 };
    256 
    257 } }  // namespace v8::internal
    258 
    259 #endif  // V8_LAZY_INSTANCE_H_
    260