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 92namespace v8 { 93namespace 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 102template <typename T> 103struct 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 118template <typename T> 119struct 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 135template <typename T> 136struct 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 150template <typename T> 151struct 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 159template <typename T> 160struct DefaultCreateTrait { 161 static T* Create() { 162 return new T(); 163 } 164}; 165 166 167struct 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. 176struct 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). 188template <typename T, typename AllocationTrait, typename CreateTrait, 189 typename InitOnceTrait, typename DestroyTrait /* not used yet. */> 190struct 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 227template <typename T, 228 typename CreateTrait = DefaultConstructTrait<T>, 229 typename InitOnceTrait = SingleThreadInitOnceTrait, 230 typename DestroyTrait = LeakyInstanceTrait<T> > 231struct LazyStaticInstance { 232 typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, 233 CreateTrait, InitOnceTrait, DestroyTrait> type; 234}; 235 236 237template <typename T, 238 typename CreateTrait = DefaultConstructTrait<T>, 239 typename InitOnceTrait = SingleThreadInitOnceTrait, 240 typename DestroyTrait = LeakyInstanceTrait<T> > 241struct LazyInstance { 242 // A LazyInstance is a LazyStaticInstance. 243 typedef typename LazyStaticInstance<T, CreateTrait, InitOnceTrait, 244 DestroyTrait>::type type; 245}; 246 247 248template <typename T, 249 typename CreateTrait = DefaultConstructTrait<T>, 250 typename InitOnceTrait = SingleThreadInitOnceTrait, 251 typename DestroyTrait = LeakyInstanceTrait<T> > 252struct 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