Home | History | Annotate | Download | only in wtf
      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