1/*
2 *  Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 *
4 *  This library is free software; you can redistribute it and/or
5 *  modify it under the terms of the GNU Library General Public
6 *  License as published by the Free Software Foundation; either
7 *  version 2 of the License, or (at your option) any later version.
8 *
9 *  This library is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 *  Library General Public License for more details.
13 *
14 *  You should have received a copy of the GNU Library General Public License
15 *  along with this library; see the file COPYING.LIB.  If not, write to
16 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 *  Boston, MA 02110-1301, USA.
18 *
19 */
20
21#ifndef WTF_FastMalloc_h
22#define WTF_FastMalloc_h
23
24#include <new>
25#include <stdlib.h>
26#include <wtf/PossiblyNull.h>
27#include <wtf/StdLibExtras.h>
28
29namespace WTF {
30
31    // These functions call CRASH() if an allocation fails.
32    WTF_EXPORT_PRIVATE void* fastMalloc(size_t);
33    WTF_EXPORT_PRIVATE void* fastZeroedMalloc(size_t);
34    WTF_EXPORT_PRIVATE void* fastCalloc(size_t numElements, size_t elementSize);
35    WTF_EXPORT_PRIVATE void* fastRealloc(void*, size_t);
36    WTF_EXPORT_PRIVATE char* fastStrDup(const char*);
37    WTF_EXPORT_PRIVATE size_t fastMallocSize(const void*);
38    WTF_EXPORT_PRIVATE size_t fastMallocGoodSize(size_t);
39
40    struct TryMallocReturnValue {
41        TryMallocReturnValue(void* data)
42            : m_data(data)
43        {
44        }
45        TryMallocReturnValue(const TryMallocReturnValue& source)
46            : m_data(source.m_data)
47        {
48            source.m_data = 0;
49        }
50        ~TryMallocReturnValue() { ASSERT(!m_data); }
51        template <typename T> bool getValue(T& data) WARN_UNUSED_RETURN;
52        template <typename T> operator PossiblyNull<T>()
53        {
54            T value;
55            getValue(value);
56            return PossiblyNull<T>(value);
57        }
58    private:
59        mutable void* m_data;
60    };
61
62    template <typename T> bool TryMallocReturnValue::getValue(T& data)
63    {
64        union u { void* data; T target; } res;
65        res.data = m_data;
66        data = res.target;
67        bool returnValue = !!m_data;
68        m_data = 0;
69        return returnValue;
70    }
71
72    WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastMalloc(size_t n);
73    TryMallocReturnValue tryFastZeroedMalloc(size_t n);
74    WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastCalloc(size_t n_elements, size_t element_size);
75    WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastRealloc(void* p, size_t n);
76
77    WTF_EXPORT_PRIVATE void fastFree(void*);
78
79#ifndef NDEBUG
80    WTF_EXPORT_PRIVATE void fastMallocForbid();
81    WTF_EXPORT_PRIVATE void fastMallocAllow();
82#endif
83
84    WTF_EXPORT_PRIVATE void releaseFastMallocFreeMemory();
85
86    struct FastMallocStatistics {
87        size_t reservedVMBytes;
88        size_t committedVMBytes;
89        size_t freeListBytes;
90    };
91    WTF_EXPORT_PRIVATE FastMallocStatistics fastMallocStatistics();
92
93    // This defines a type which holds an unsigned integer and is the same
94    // size as the minimally aligned memory allocation.
95    typedef unsigned long long AllocAlignmentInteger;
96
97    namespace Internal {
98        enum AllocType {                    // Start with an unusual number instead of zero, because zero is common.
99            AllocTypeMalloc = 0x375d6750,   // Encompasses fastMalloc, fastZeroedMalloc, fastCalloc, fastRealloc.
100            AllocTypeClassNew,              // Encompasses class operator new from FastAllocBase.
101            AllocTypeClassNewArray,         // Encompasses class operator new[] from FastAllocBase.
102            AllocTypeNew,                   // Encompasses global operator new.
103            AllocTypeNewArray               // Encompasses global operator new[].
104        };
105
106        enum {
107            ValidationPrefix = 0xf00df00d,
108            ValidationSuffix = 0x0badf00d
109        };
110
111        typedef unsigned ValidationTag;
112
113        struct ValidationHeader {
114            AllocType m_type;
115            unsigned m_size;
116            ValidationTag m_prefix;
117            unsigned m_alignment;
118        };
119
120        static const int ValidationBufferSize = sizeof(ValidationHeader) + sizeof(ValidationTag);
121    }
122
123#if ENABLE(WTF_MALLOC_VALIDATION)
124
125    // Malloc validation is a scheme whereby a tag is attached to an
126    // allocation which identifies how it was originally allocated.
127    // This allows us to verify that the freeing operation matches the
128    // allocation operation. If memory is allocated with operator new[]
129    // but freed with free or delete, this system would detect that.
130    // In the implementation here, the tag is an integer prepended to
131    // the allocation memory which is assigned one of the AllocType
132    // enumeration values. An alternative implementation of this
133    // scheme could store the tag somewhere else or ignore it.
134    // Users of FastMalloc don't need to know or care how this tagging
135    // is implemented.
136
137    namespace Internal {
138
139        // Handle a detected alloc/free mismatch. By default this calls CRASH().
140        void fastMallocMatchFailed(void* p);
141
142        inline ValidationHeader* fastMallocValidationHeader(void* p)
143        {
144            return reinterpret_cast<ValidationHeader*>(static_cast<char*>(p) - sizeof(ValidationHeader));
145        }
146
147        inline ValidationTag* fastMallocValidationSuffix(void* p)
148        {
149            ValidationHeader* header = fastMallocValidationHeader(p);
150            if (header->m_prefix != static_cast<unsigned>(ValidationPrefix))
151                fastMallocMatchFailed(p);
152
153            return reinterpret_cast<ValidationTag*>(static_cast<char*>(p) + header->m_size);
154        }
155
156        // Return the AllocType tag associated with the allocated block p.
157        inline AllocType fastMallocMatchValidationType(void* p)
158        {
159            return fastMallocValidationHeader(p)->m_type;
160        }
161
162        // Set the AllocType tag to be associaged with the allocated block p.
163        inline void setFastMallocMatchValidationType(void* p, AllocType allocType)
164        {
165            fastMallocValidationHeader(p)->m_type = allocType;
166        }
167
168    } // namespace Internal
169
170    // This is a higher level function which is used by FastMalloc-using code.
171    inline void fastMallocMatchValidateMalloc(void* p, Internal::AllocType allocType)
172    {
173        if (!p)
174            return;
175
176        Internal::setFastMallocMatchValidationType(p, allocType);
177    }
178
179    // This is a higher level function which is used by FastMalloc-using code.
180    inline void fastMallocMatchValidateFree(void* p, Internal::AllocType)
181    {
182        if (!p)
183            return;
184
185        Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(p);
186        if (header->m_prefix != static_cast<unsigned>(Internal::ValidationPrefix))
187            Internal::fastMallocMatchFailed(p);
188
189        if (*Internal::fastMallocValidationSuffix(p) != Internal::ValidationSuffix)
190            Internal::fastMallocMatchFailed(p);
191
192        Internal::setFastMallocMatchValidationType(p, Internal::AllocTypeMalloc);  // Set it to this so that fastFree thinks it's OK.
193    }
194
195    inline void fastMallocValidate(void* p)
196    {
197        if (!p)
198            return;
199
200        Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(p);
201        if (header->m_prefix != static_cast<unsigned>(Internal::ValidationPrefix))
202            Internal::fastMallocMatchFailed(p);
203
204        if (*Internal::fastMallocValidationSuffix(p) != Internal::ValidationSuffix)
205            Internal::fastMallocMatchFailed(p);
206    }
207
208#else
209
210    inline void fastMallocMatchValidateMalloc(void*, Internal::AllocType)
211    {
212    }
213
214    inline void fastMallocMatchValidateFree(void*, Internal::AllocType)
215    {
216    }
217
218#endif
219
220} // namespace WTF
221
222using WTF::fastCalloc;
223using WTF::fastFree;
224using WTF::fastMalloc;
225using WTF::fastMallocGoodSize;
226using WTF::fastMallocSize;
227using WTF::fastRealloc;
228using WTF::fastStrDup;
229using WTF::fastZeroedMalloc;
230using WTF::tryFastCalloc;
231using WTF::tryFastMalloc;
232using WTF::tryFastRealloc;
233using WTF::tryFastZeroedMalloc;
234
235#ifndef NDEBUG
236using WTF::fastMallocForbid;
237using WTF::fastMallocAllow;
238#endif
239
240#if COMPILER(GCC) && OS(DARWIN)
241#define WTF_PRIVATE_INLINE __private_extern__ inline __attribute__((always_inline))
242#elif COMPILER(GCC)
243#define WTF_PRIVATE_INLINE inline __attribute__((always_inline))
244#elif COMPILER(MSVC)
245#define WTF_PRIVATE_INLINE __forceinline
246#else
247#define WTF_PRIVATE_INLINE inline
248#endif
249
250#define WTF_MAKE_FAST_ALLOCATED \
251public: \
252    void* operator new(size_t, void* p) { return p; } \
253    void* operator new[](size_t, void* p) { return p; } \
254    \
255    void* operator new(size_t size) \
256    { \
257        void* p = ::WTF::fastMalloc(size); \
258        ::WTF::fastMallocMatchValidateMalloc(p, ::WTF::Internal::AllocTypeClassNew); \
259        return p; \
260    } \
261    \
262    void operator delete(void* p) \
263    { \
264        ::WTF::fastMallocMatchValidateFree(p, ::WTF::Internal::AllocTypeClassNew); \
265        ::WTF::fastFree(p); \
266    } \
267    \
268    void* operator new[](size_t size) \
269    { \
270        void* p = ::WTF::fastMalloc(size); \
271        ::WTF::fastMallocMatchValidateMalloc(p, ::WTF::Internal::AllocTypeClassNewArray); \
272        return p; \
273    } \
274    \
275    void operator delete[](void* p) \
276    { \
277        ::WTF::fastMallocMatchValidateFree(p, ::WTF::Internal::AllocTypeClassNewArray); \
278        ::WTF::fastFree(p); \
279    } \
280    void* operator new(size_t, NotNullTag, void* location) \
281    { \
282        ASSERT(location); \
283        return location; \
284    } \
285private: \
286typedef int __thisIsHereToForceASemicolonAfterThisMacro
287
288#endif /* WTF_FastMalloc_h */
289