1 /* 2 * Copyright (C) 2008, 2009 Paul Pedriana <ppedriana (at) ea.com>. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifndef FastAllocBase_h 30 #define FastAllocBase_h 31 32 // Provides customizable overrides of fastMalloc/fastFree and operator new/delete 33 // 34 // Provided functionality: 35 // namespace WTF { 36 // class FastAllocBase; 37 // 38 // T* fastNew<T>(); 39 // T* fastNew<T>(arg); 40 // T* fastNew<T>(arg, arg); 41 // T* fastNewArray<T>(count); 42 // void fastDelete(T* p); 43 // void fastDeleteArray(T* p); 44 // void fastNonNullDelete(T* p); 45 // void fastNonNullDeleteArray(T* p); 46 // } 47 // 48 // FastDelete assumes that the underlying 49 // 50 // Example usage: 51 // class Widget : public FastAllocBase { ... }; 52 // 53 // char* charPtr = fastNew<char>(); 54 // fastDelete(charPtr); 55 // 56 // char* charArrayPtr = fastNewArray<char>(37); 57 // fastDeleteArray(charArrayPtr); 58 // 59 // void** voidPtrPtr = fastNew<void*>(); 60 // fastDelete(voidPtrPtr); 61 // 62 // void** voidPtrArrayPtr = fastNewArray<void*>(37); 63 // fastDeleteArray(voidPtrArrayPtr); 64 // 65 // POD* podPtr = fastNew<POD>(); 66 // fastDelete(podPtr); 67 // 68 // POD* podArrayPtr = fastNewArray<POD>(37); 69 // fastDeleteArray(podArrayPtr); 70 // 71 // Object* objectPtr = fastNew<Object>(); 72 // fastDelete(objectPtr); 73 // 74 // Object* objectArrayPtr = fastNewArray<Object>(37); 75 // fastDeleteArray(objectArrayPtr); 76 // 77 78 #include <new> 79 #include <stdint.h> 80 #include <stdlib.h> 81 #include <string.h> 82 #include "Assertions.h" 83 #include "FastMalloc.h" 84 #include "TypeTraits.h" 85 86 namespace WTF { 87 88 class FastAllocBase { 89 public: 90 // Placement operator new. 91 void* operator new(size_t, void* p) { return p; } 92 void* operator new[](size_t, void* p) { return p; } 93 94 void* operator new(size_t size) 95 { 96 void* p = fastMalloc(size); 97 fastMallocMatchValidateMalloc(p, Internal::AllocTypeClassNew); 98 return p; 99 } 100 101 void operator delete(void* p) 102 { 103 fastMallocMatchValidateFree(p, Internal::AllocTypeClassNew); 104 fastFree(p); 105 } 106 107 void* operator new[](size_t size) 108 { 109 void* p = fastMalloc(size); 110 fastMallocMatchValidateMalloc(p, Internal::AllocTypeClassNewArray); 111 return p; 112 } 113 114 void operator delete[](void* p) 115 { 116 fastMallocMatchValidateFree(p, Internal::AllocTypeClassNewArray); 117 fastFree(p); 118 } 119 }; 120 121 // fastNew / fastDelete 122 123 template <typename T> 124 inline T* fastNew() 125 { 126 void* p = fastMalloc(sizeof(T)); 127 128 if (!p) 129 return 0; 130 131 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew); 132 return ::new(p) T; 133 } 134 135 template <typename T, typename Arg1> 136 inline T* fastNew(Arg1 arg1) 137 { 138 void* p = fastMalloc(sizeof(T)); 139 140 if (!p) 141 return 0; 142 143 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew); 144 return ::new(p) T(arg1); 145 } 146 147 template <typename T, typename Arg1, typename Arg2> 148 inline T* fastNew(Arg1 arg1, Arg2 arg2) 149 { 150 void* p = fastMalloc(sizeof(T)); 151 152 if (!p) 153 return 0; 154 155 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew); 156 return ::new(p) T(arg1, arg2); 157 } 158 159 template <typename T, typename Arg1, typename Arg2, typename Arg3> 160 inline T* fastNew(Arg1 arg1, Arg2 arg2, Arg3 arg3) 161 { 162 void* p = fastMalloc(sizeof(T)); 163 164 if (!p) 165 return 0; 166 167 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew); 168 return ::new(p) T(arg1, arg2, arg3); 169 } 170 171 template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4> 172 inline T* fastNew(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) 173 { 174 void* p = fastMalloc(sizeof(T)); 175 176 if (!p) 177 return 0; 178 179 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew); 180 return ::new(p) T(arg1, arg2, arg3, arg4); 181 } 182 183 template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> 184 inline T* fastNew(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) 185 { 186 void* p = fastMalloc(sizeof(T)); 187 188 if (!p) 189 return 0; 190 191 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew); 192 return ::new(p) T(arg1, arg2, arg3, arg4, arg5); 193 } 194 195 namespace Internal { 196 197 // We define a union of pointer to an integer and pointer to T. 198 // When non-POD arrays are allocated we add a few leading bytes to tell what 199 // the size of the array is. We return to the user the pointer to T. 200 // The way to think of it is as if we allocate a struct like so: 201 // struct Array { 202 // AllocAlignmentInteger m_size; 203 // T m_T[array count]; 204 // }; 205 206 template <typename T> 207 union ArraySize { 208 AllocAlignmentInteger* size; 209 T* t; 210 }; 211 212 // This is a support template for fastNewArray. 213 // This handles the case wherein T has a trivial ctor and a trivial dtor. 214 template <typename T, bool trivialCtor, bool trivialDtor> 215 struct NewArrayImpl { 216 static T* fastNewArray(size_t count) 217 { 218 T* p = static_cast<T*>(fastMalloc(sizeof(T) * count)); 219 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray); 220 return p; 221 } 222 }; 223 224 // This is a support template for fastNewArray. 225 // This handles the case wherein T has a non-trivial ctor and a trivial dtor. 226 template <typename T> 227 struct NewArrayImpl<T, false, true> { 228 static T* fastNewArray(size_t count) 229 { 230 T* p = static_cast<T*>(fastMalloc(sizeof(T) * count)); 231 232 if (!p) 233 return 0; 234 235 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray); 236 237 for (T* pObject = p, *pObjectEnd = pObject + count; pObject != pObjectEnd; ++pObject) 238 ::new(pObject) T; 239 240 return p; 241 } 242 }; 243 244 // This is a support template for fastNewArray. 245 // This handles the case wherein T has a trivial ctor and a non-trivial dtor. 246 template <typename T> 247 struct NewArrayImpl<T, true, false> { 248 static T* fastNewArray(size_t count) 249 { 250 void* p = fastMalloc(sizeof(AllocAlignmentInteger) + (sizeof(T) * count)); 251 ArraySize<T> a = { static_cast<AllocAlignmentInteger*>(p) }; 252 253 if (!p) 254 return 0; 255 256 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray); 257 *a.size++ = count; 258 // No need to construct the objects in this case. 259 260 return a.t; 261 } 262 }; 263 264 // This is a support template for fastNewArray. 265 // This handles the case wherein T has a non-trivial ctor and a non-trivial dtor. 266 template <typename T> 267 struct NewArrayImpl<T, false, false> { 268 static T* fastNewArray(size_t count) 269 { 270 void* p = fastMalloc(sizeof(AllocAlignmentInteger) + (sizeof(T) * count)); 271 ArraySize<T> a = { static_cast<AllocAlignmentInteger*>(p) }; 272 273 if (!p) 274 return 0; 275 276 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray); 277 *a.size++ = count; 278 279 for (T* pT = a.t, *pTEnd = pT + count; pT != pTEnd; ++pT) 280 ::new(pT) T; 281 282 return a.t; 283 } 284 }; 285 } // namespace Internal 286 287 template <typename T> 288 inline T* fastNewArray(size_t count) 289 { 290 return Internal::NewArrayImpl<T, WTF::HasTrivialConstructor<T>::value, WTF::HasTrivialDestructor<T>::value>::fastNewArray(count); 291 } 292 293 template <typename T> 294 inline void fastDelete(T* p) 295 { 296 if (!p) 297 return; 298 299 fastMallocMatchValidateFree(p, Internal::AllocTypeFastNew); 300 p->~T(); 301 fastFree(p); 302 } 303 304 template <typename T> 305 inline void fastDeleteSkippingDestructor(T* p) 306 { 307 if (!p) 308 return; 309 310 fastMallocMatchValidateFree(p, Internal::AllocTypeFastNew); 311 fastFree(p); 312 } 313 314 namespace Internal { 315 // This is a support template for fastDeleteArray. 316 // This handles the case wherein T has a trivial dtor. 317 template <typename T, bool trivialDtor> 318 struct DeleteArrayImpl { 319 static void fastDeleteArray(void* p) 320 { 321 // No need to destruct the objects in this case. 322 // We expect that fastFree checks for null. 323 fastMallocMatchValidateFree(p, Internal::AllocTypeFastNewArray); 324 fastFree(p); 325 } 326 }; 327 328 // This is a support template for fastDeleteArray. 329 // This handles the case wherein T has a non-trivial dtor. 330 template <typename T> 331 struct DeleteArrayImpl<T, false> { 332 static void fastDeleteArray(T* p) 333 { 334 if (!p) 335 return; 336 337 ArraySize<T> a; 338 a.t = p; 339 a.size--; // Decrement size pointer 340 341 T* pEnd = p + *a.size; 342 while (pEnd-- != p) 343 pEnd->~T(); 344 345 fastMallocMatchValidateFree(a.size, Internal::AllocTypeFastNewArray); 346 fastFree(a.size); 347 } 348 }; 349 350 } // namespace Internal 351 352 template <typename T> 353 void fastDeleteArray(T* p) 354 { 355 Internal::DeleteArrayImpl<T, WTF::HasTrivialDestructor<T>::value>::fastDeleteArray(p); 356 } 357 358 359 template <typename T> 360 inline void fastNonNullDelete(T* p) 361 { 362 fastMallocMatchValidateFree(p, Internal::AllocTypeFastNew); 363 p->~T(); 364 fastFree(p); 365 } 366 367 namespace Internal { 368 // This is a support template for fastDeleteArray. 369 // This handles the case wherein T has a trivial dtor. 370 template <typename T, bool trivialDtor> 371 struct NonNullDeleteArrayImpl { 372 static void fastNonNullDeleteArray(void* p) 373 { 374 fastMallocMatchValidateFree(p, Internal::AllocTypeFastNewArray); 375 // No need to destruct the objects in this case. 376 fastFree(p); 377 } 378 }; 379 380 // This is a support template for fastDeleteArray. 381 // This handles the case wherein T has a non-trivial dtor. 382 template <typename T> 383 struct NonNullDeleteArrayImpl<T, false> { 384 static void fastNonNullDeleteArray(T* p) 385 { 386 ArraySize<T> a; 387 a.t = p; 388 a.size--; 389 390 T* pEnd = p + *a.size; 391 while (pEnd-- != p) 392 pEnd->~T(); 393 394 fastMallocMatchValidateFree(a.size, Internal::AllocTypeFastNewArray); 395 fastFree(a.size); 396 } 397 }; 398 399 } // namespace Internal 400 401 template <typename T> 402 void fastNonNullDeleteArray(T* p) 403 { 404 Internal::NonNullDeleteArrayImpl<T, WTF::HasTrivialDestructor<T>::value>::fastNonNullDeleteArray(p); 405 } 406 407 408 } // namespace WTF 409 410 using WTF::FastAllocBase; 411 using WTF::fastDeleteSkippingDestructor; 412 413 #endif // FastAllocBase_h 414