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 //    Macro: WTF_MAKE_FAST_ALLOCATED
     36 //    namespace WTF {
     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 {
     52 //        WTF_MAKE_FAST_ALLOCATED
     53 //    ...
     54 //    };
     55 //
     56 //    struct Data {
     57 //        WTF_MAKE_FAST_ALLOCATED
     58 //    public:
     59 //    ...
     60 //    };
     61 //
     62 //    char* charPtr = fastNew<char>();
     63 //    fastDelete(charPtr);
     64 //
     65 //    char* charArrayPtr = fastNewArray<char>(37);
     66 //    fastDeleteArray(charArrayPtr);
     67 //
     68 //    void** voidPtrPtr = fastNew<void*>();
     69 //    fastDelete(voidPtrPtr);
     70 //
     71 //    void** voidPtrArrayPtr = fastNewArray<void*>(37);
     72 //    fastDeleteArray(voidPtrArrayPtr);
     73 //
     74 //    POD* podPtr = fastNew<POD>();
     75 //    fastDelete(podPtr);
     76 //
     77 //    POD* podArrayPtr = fastNewArray<POD>(37);
     78 //    fastDeleteArray(podArrayPtr);
     79 //
     80 //    Object* objectPtr = fastNew<Object>();
     81 //    fastDelete(objectPtr);
     82 //
     83 //    Object* objectArrayPtr = fastNewArray<Object>(37);
     84 //    fastDeleteArray(objectArrayPtr);
     85 //
     86 
     87 #include <new>
     88 #include <stdint.h>
     89 #include <stdlib.h>
     90 #include <string.h>
     91 #include "Assertions.h"
     92 #include "FastMalloc.h"
     93 #include "TypeTraits.h"
     94 
     95 #define WTF_MAKE_FAST_ALLOCATED \
     96 public: \
     97     void* operator new(size_t, void* p) { return p; } \
     98     void* operator new[](size_t, void* p) { return p; } \
     99     \
    100     void* operator new(size_t size) \
    101     { \
    102         void* p = ::WTF::fastMalloc(size); \
    103          ::WTF::fastMallocMatchValidateMalloc(p, ::WTF::Internal::AllocTypeClassNew); \
    104         return p; \
    105     } \
    106     \
    107     void operator delete(void* p) \
    108     { \
    109         ::WTF::fastMallocMatchValidateFree(p, ::WTF::Internal::AllocTypeClassNew); \
    110         ::WTF::fastFree(p); \
    111     } \
    112     \
    113     void* operator new[](size_t size) \
    114     { \
    115         void* p = ::WTF::fastMalloc(size); \
    116         ::WTF::fastMallocMatchValidateMalloc(p, ::WTF::Internal::AllocTypeClassNewArray); \
    117         return p; \
    118     } \
    119     \
    120     void operator delete[](void* p) \
    121     { \
    122          ::WTF::fastMallocMatchValidateFree(p, ::WTF::Internal::AllocTypeClassNewArray); \
    123          ::WTF::fastFree(p); \
    124     } \
    125 private: \
    126 typedef int ThisIsHereToForceASemicolonAfterThisMacro
    127 
    128 namespace WTF {
    129 
    130     // fastNew / fastDelete
    131 
    132     template <typename T>
    133     inline T* fastNew()
    134     {
    135         void* p = fastMalloc(sizeof(T));
    136 
    137         if (!p)
    138             return 0;
    139 
    140         fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
    141         return ::new(p) T;
    142     }
    143 
    144     template <typename T, typename Arg1>
    145     inline T* fastNew(Arg1 arg1)
    146     {
    147         void* p = fastMalloc(sizeof(T));
    148 
    149         if (!p)
    150             return 0;
    151 
    152         fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
    153         return ::new(p) T(arg1);
    154     }
    155 
    156     template <typename T, typename Arg1, typename Arg2>
    157     inline T* fastNew(Arg1 arg1, Arg2 arg2)
    158     {
    159         void* p = fastMalloc(sizeof(T));
    160 
    161         if (!p)
    162             return 0;
    163 
    164         fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
    165         return ::new(p) T(arg1, arg2);
    166     }
    167 
    168     template <typename T, typename Arg1, typename Arg2, typename Arg3>
    169     inline T* fastNew(Arg1 arg1, Arg2 arg2, Arg3 arg3)
    170     {
    171         void* p = fastMalloc(sizeof(T));
    172 
    173         if (!p)
    174             return 0;
    175 
    176         fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
    177         return ::new(p) T(arg1, arg2, arg3);
    178     }
    179 
    180     template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
    181     inline T* fastNew(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
    182     {
    183         void* p = fastMalloc(sizeof(T));
    184 
    185         if (!p)
    186             return 0;
    187 
    188         fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
    189         return ::new(p) T(arg1, arg2, arg3, arg4);
    190     }
    191 
    192     template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
    193     inline T* fastNew(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
    194     {
    195         void* p = fastMalloc(sizeof(T));
    196 
    197         if (!p)
    198             return 0;
    199 
    200         fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNew);
    201         return ::new(p) T(arg1, arg2, arg3, arg4, arg5);
    202     }
    203 
    204     namespace Internal {
    205 
    206         // We define a union of pointer to an integer and pointer to T.
    207         // When non-POD arrays are allocated we add a few leading bytes to tell what
    208         // the size of the array is. We return to the user the pointer to T.
    209         // The way to think of it is as if we allocate a struct like so:
    210         //    struct Array {
    211         //        AllocAlignmentInteger m_size;
    212         //        T m_T[array count];
    213         //    };
    214 
    215         template <typename T>
    216         union ArraySize {
    217             AllocAlignmentInteger* size;
    218             T* t;
    219         };
    220 
    221         // This is a support template for fastNewArray.
    222         // This handles the case wherein T has a trivial ctor and a trivial dtor.
    223         template <typename T, bool trivialCtor, bool trivialDtor>
    224         struct NewArrayImpl {
    225             static T* fastNewArray(size_t count)
    226             {
    227                 T* p = static_cast<T*>(fastMalloc(sizeof(T) * count));
    228                 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray);
    229                 return p;
    230             }
    231         };
    232 
    233         // This is a support template for fastNewArray.
    234         // This handles the case wherein T has a non-trivial ctor and a trivial dtor.
    235         template <typename T>
    236         struct NewArrayImpl<T, false, true> {
    237             static T* fastNewArray(size_t count)
    238             {
    239                 T* p = static_cast<T*>(fastMalloc(sizeof(T) * count));
    240 
    241                 if (!p)
    242                     return 0;
    243 
    244                 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray);
    245 
    246                 for (T* pObject = p, *pObjectEnd = pObject + count; pObject != pObjectEnd; ++pObject)
    247                     ::new(pObject) T;
    248 
    249                 return p;
    250             }
    251         };
    252 
    253         // This is a support template for fastNewArray.
    254         // This handles the case wherein T has a trivial ctor and a non-trivial dtor.
    255         template <typename T>
    256         struct NewArrayImpl<T, true, false> {
    257             static T* fastNewArray(size_t count)
    258             {
    259                 void* p = fastMalloc(sizeof(AllocAlignmentInteger) + (sizeof(T) * count));
    260                 ArraySize<T> a = { static_cast<AllocAlignmentInteger*>(p) };
    261 
    262                 if (!p)
    263                     return 0;
    264 
    265                 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray);
    266                 *a.size++ = count;
    267                 // No need to construct the objects in this case.
    268 
    269                 return a.t;
    270             }
    271         };
    272 
    273         // This is a support template for fastNewArray.
    274         // This handles the case wherein T has a non-trivial ctor and a non-trivial dtor.
    275         template <typename T>
    276         struct NewArrayImpl<T, false, false> {
    277             static T* fastNewArray(size_t count)
    278             {
    279                 void* p = fastMalloc(sizeof(AllocAlignmentInteger) + (sizeof(T) * count));
    280                 ArraySize<T> a = { static_cast<AllocAlignmentInteger*>(p) };
    281 
    282                 if (!p)
    283                     return 0;
    284 
    285                 fastMallocMatchValidateMalloc(p, Internal::AllocTypeFastNewArray);
    286                 *a.size++ = count;
    287 
    288                 for (T* pT = a.t, *pTEnd = pT + count; pT != pTEnd; ++pT)
    289                     ::new(pT) T;
    290 
    291                 return a.t;
    292             }
    293         };
    294     } // namespace Internal
    295 
    296     template <typename T>
    297     inline T* fastNewArray(size_t count)
    298     {
    299         return Internal::NewArrayImpl<T, WTF::HasTrivialConstructor<T>::value, WTF::HasTrivialDestructor<T>::value>::fastNewArray(count);
    300     }
    301 
    302     template <typename T>
    303     inline void fastDelete(T* p)
    304     {
    305         if (!p)
    306             return;
    307 
    308         fastMallocMatchValidateFree(p, Internal::AllocTypeFastNew);
    309         p->~T();
    310         fastFree(p);
    311     }
    312 
    313     template <typename T>
    314     inline void fastDeleteSkippingDestructor(T* p)
    315     {
    316         if (!p)
    317             return;
    318 
    319         fastMallocMatchValidateFree(p, Internal::AllocTypeFastNew);
    320         fastFree(p);
    321     }
    322 
    323     namespace Internal {
    324         // This is a support template for fastDeleteArray.
    325         // This handles the case wherein T has a trivial dtor.
    326         template <typename T, bool trivialDtor>
    327         struct DeleteArrayImpl {
    328             static void fastDeleteArray(void* p)
    329             {
    330                 // No need to destruct the objects in this case.
    331                 // We expect that fastFree checks for null.
    332                 fastMallocMatchValidateFree(p, Internal::AllocTypeFastNewArray);
    333                 fastFree(p);
    334             }
    335         };
    336 
    337         // This is a support template for fastDeleteArray.
    338         // This handles the case wherein T has a non-trivial dtor.
    339         template <typename T>
    340         struct DeleteArrayImpl<T, false> {
    341             static void fastDeleteArray(T* p)
    342             {
    343                 if (!p)
    344                     return;
    345 
    346                 ArraySize<T> a;
    347                 a.t = p;
    348                 a.size--; // Decrement size pointer
    349 
    350                 T* pEnd = p + *a.size;
    351                 while (pEnd-- != p)
    352                     pEnd->~T();
    353 
    354                 fastMallocMatchValidateFree(a.size, Internal::AllocTypeFastNewArray);
    355                 fastFree(a.size);
    356             }
    357         };
    358 
    359     } // namespace Internal
    360 
    361     template <typename T>
    362     void fastDeleteArray(T* p)
    363     {
    364         Internal::DeleteArrayImpl<T, WTF::HasTrivialDestructor<T>::value>::fastDeleteArray(p);
    365     }
    366 
    367 
    368     template <typename T>
    369     inline void fastNonNullDelete(T* p)
    370     {
    371         fastMallocMatchValidateFree(p, Internal::AllocTypeFastNew);
    372         p->~T();
    373         fastFree(p);
    374     }
    375 
    376     namespace Internal {
    377         // This is a support template for fastDeleteArray.
    378         // This handles the case wherein T has a trivial dtor.
    379         template <typename T, bool trivialDtor>
    380         struct NonNullDeleteArrayImpl {
    381             static void fastNonNullDeleteArray(void* p)
    382             {
    383                 fastMallocMatchValidateFree(p, Internal::AllocTypeFastNewArray);
    384                 // No need to destruct the objects in this case.
    385                 fastFree(p);
    386             }
    387         };
    388 
    389         // This is a support template for fastDeleteArray.
    390         // This handles the case wherein T has a non-trivial dtor.
    391         template <typename T>
    392         struct NonNullDeleteArrayImpl<T, false> {
    393             static void fastNonNullDeleteArray(T* p)
    394             {
    395                 ArraySize<T> a;
    396                 a.t = p;
    397                 a.size--;
    398 
    399                 T* pEnd = p + *a.size;
    400                 while (pEnd-- != p)
    401                     pEnd->~T();
    402 
    403                 fastMallocMatchValidateFree(a.size, Internal::AllocTypeFastNewArray);
    404                 fastFree(a.size);
    405             }
    406         };
    407 
    408     } // namespace Internal
    409 
    410     template <typename T>
    411     void fastNonNullDeleteArray(T* p)
    412     {
    413         Internal::NonNullDeleteArrayImpl<T, WTF::HasTrivialDestructor<T>::value>::fastNonNullDeleteArray(p);
    414     }
    415 
    416 
    417 } // namespace WTF
    418 
    419 using WTF::fastDeleteSkippingDestructor;
    420 
    421 #endif // FastAllocBase_h
    422