1 /*
2  * Copyright (C) 2008, 2009 Paul Pedriana <ppedriana@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.
new(size_t,void * p)91         void* operator new(size_t, void* p) { return p; }
92         void* operator new[](size_t, void* p) { return p; }
93 
new(size_t size)94         void* operator new(size_t size)
95         {
96             void* p = fastMalloc(size);
97             fastMallocMatchValidateMalloc(p, Internal::AllocTypeClassNew);
98             return p;
99         }
100 
delete(void * p)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>
fastNew()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>
fastNew(Arg1 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>
fastNew(Arg1 arg1,Arg2 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>
fastNew(Arg1 arg1,Arg2 arg2,Arg3 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>
fastNew(Arg1 arg1,Arg2 arg2,Arg3 arg3,Arg4 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>
fastNew(Arg1 arg1,Arg2 arg2,Arg3 arg3,Arg4 arg4,Arg5 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 {
fastNewArrayNewArrayImpl216             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