• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
DestroyLeakyInstanceTrait104   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 
MutableInstanceStaticallyAllocatedInstanceTrait122   static T* MutableInstance(StorageType* storage) {
123     return reinterpret_cast<T*>(storage);
124   }
125 
126   template <typename ConstructTrait>
InitStorageUsingTraitStaticallyAllocatedInstanceTrait127   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 
MutableInstanceDynamicallyAllocatedInstanceTrait139   static T* MutableInstance(StorageType* storage) {
140     return *storage;
141   }
142 
143   template <typename CreateTrait>
InitStorageUsingTraitDynamicallyAllocatedInstanceTrait144   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.
ConstructDefaultConstructTrait153   static void Construct(T* allocated_ptr) {
154     new(allocated_ptr) T();
155   }
156 };
157 
158 
159 template <typename T>
160 struct DefaultCreateTrait {
CreateDefaultCreateTrait161   static T* Create() {
162     return new T();
163   }
164 };
165 
166 
167 struct ThreadSafeInitOnceTrait {
168   template <typename Function, typename Storage>
InitThreadSafeInitOnceTrait169   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>
InitSingleThreadInitOnceTrait178   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:
InitInstanceLazyInstanceImpl195   static void InitInstance(StorageType* storage) {
196     AllocationTrait::template InitStorageUsingTrait<CreateTrait>(storage);
197   }
198 
InitLazyInstanceImpl199   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:
PointerLazyInstanceImpl209   T* Pointer() {
210     Init();
211     return AllocationTrait::MutableInstance(&storage_);
212   }
213 
GetLazyInstanceImpl214   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