1 /*-------------------------------------------------------------------------
2 * drawElements Base Portability Library
3 * -------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Memory management.
22 *//*--------------------------------------------------------------------*/
23
24 #include "deMemory.h"
25 #include "deInt32.h"
26
27 #include <stdio.h>
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #define DE_ALIGNED_MALLOC_POSIX 0
33 #define DE_ALIGNED_MALLOC_WIN32 1
34 #define DE_ALIGNED_MALLOC_GENERIC 2
35
36 #if (DE_OS == DE_OS_UNIX) || ((DE_OS == DE_OS_ANDROID) && (DE_ANDROID_API >= 21))
37 # define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_POSIX
38 # if defined(__FreeBSD__)
39 # include <stdlib.h>
40 # else
41 # include <malloc.h>
42 # endif
43 #elif (DE_OS == DE_OS_WIN32)
44 # define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_WIN32
45 # include <malloc.h>
46 #else
47 # define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_GENERIC
48 #endif
49
50 #if defined(DE_VALGRIND_BUILD)
51 # include <valgrind/valgrind.h>
52 # if defined(HAVE_VALGRIND_MEMCHECK_H)
53 # include <valgrind/memcheck.h>
54 # endif
55 #endif
56
57 DE_BEGIN_EXTERN_C
58
59 /*--------------------------------------------------------------------*//*!
60 * \brief Allocate a chunk of memory.
61 * \param numBytes Number of bytes to allocate.
62 * \return Pointer to the allocated memory (or null on failure).
63 *//*--------------------------------------------------------------------*/
deMalloc(size_t numBytes)64 void* deMalloc (size_t numBytes)
65 {
66 void* ptr;
67
68 DE_ASSERT(numBytes > 0);
69
70 ptr = malloc((size_t)numBytes);
71
72 #if defined(DE_DEBUG)
73 /* Trash memory in debug builds (if under Valgrind, don't make it think we're initializing data here). */
74
75 if (ptr)
76 memset(ptr, 0xcd, numBytes);
77
78 #if defined(DE_VALGRIND_BUILD) && defined(HAVE_VALGRIND_MEMCHECK_H)
79 if (ptr && RUNNING_ON_VALGRIND)
80 {
81 VALGRIND_MAKE_MEM_UNDEFINED(ptr, numBytes);
82 }
83 #endif
84 #endif
85
86 return ptr;
87 }
88
89 /*--------------------------------------------------------------------*//*!
90 * \brief Allocate a chunk of memory and initialize it to zero.
91 * \param numBytes Number of bytes to allocate.
92 * \return Pointer to the allocated memory (or null on failure).
93 *//*--------------------------------------------------------------------*/
deCalloc(size_t numBytes)94 void* deCalloc (size_t numBytes)
95 {
96 void* ptr = deMalloc(numBytes);
97 if (ptr)
98 deMemset(ptr, 0, numBytes);
99 return ptr;
100 }
101
102 /*--------------------------------------------------------------------*//*!
103 * \brief Reallocate a chunk of memory.
104 * \param ptr Pointer to previously allocated memory block
105 * \param numBytes New size in bytes
106 * \return Pointer to the reallocated (and possibly moved) memory block
107 *//*--------------------------------------------------------------------*/
deRealloc(void * ptr,size_t numBytes)108 void* deRealloc (void* ptr, size_t numBytes)
109 {
110 return realloc(ptr, numBytes);
111 }
112
113 /*--------------------------------------------------------------------*//*!
114 * \brief Free a chunk of memory.
115 * \param ptr Pointer to memory to free.
116 *//*--------------------------------------------------------------------*/
deFree(void * ptr)117 void deFree (void* ptr)
118 {
119 free(ptr);
120 }
121
122 #if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
123
124 typedef struct AlignedAllocHeader_s
125 {
126 void* basePtr;
127 size_t numBytes;
128 } AlignedAllocHeader;
129
getAlignedAllocHeader(void * ptr)130 DE_INLINE AlignedAllocHeader* getAlignedAllocHeader (void* ptr)
131 {
132 const size_t hdrSize = sizeof(AlignedAllocHeader);
133 const deUintptr hdrAddr = (deUintptr)ptr - hdrSize;
134
135 return (AlignedAllocHeader*)hdrAddr;
136 }
137
138 #endif
139
deAlignedMalloc(size_t numBytes,size_t alignBytes)140 void* deAlignedMalloc (size_t numBytes, size_t alignBytes)
141 {
142 #if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
143 /* posix_memalign() requires that alignment must be 2^N * sizeof(void*) */
144 const size_t ptrAlignedAlign = deAlignSize(alignBytes, sizeof(void*));
145 void* ptr = DE_NULL;
146
147 DE_ASSERT(deIsPowerOfTwoSize(alignBytes) && deIsPowerOfTwoSize(ptrAlignedAlign / sizeof(void*)));
148
149 if (posix_memalign(&ptr, ptrAlignedAlign, numBytes) == 0)
150 {
151 DE_ASSERT(ptr);
152 return ptr;
153 }
154 else
155 {
156 DE_ASSERT(!ptr);
157 return DE_NULL;
158 }
159
160 #elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
161 DE_ASSERT(deIsPowerOfTwoSize(alignBytes));
162
163 return _aligned_malloc(numBytes, alignBytes);
164
165 #elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
166 void* const basePtr = deMalloc(numBytes + alignBytes + sizeof(AlignedAllocHeader));
167
168 DE_ASSERT(deIsPowerOfTwoSize(alignBytes));
169
170 if (basePtr)
171 {
172 void* const alignedPtr = deAlignPtr((void*)((deUintptr)basePtr + sizeof(AlignedAllocHeader)), alignBytes);
173 AlignedAllocHeader* const hdr = getAlignedAllocHeader(alignedPtr);
174
175 hdr->basePtr = basePtr;
176 hdr->numBytes = numBytes;
177
178 return alignedPtr;
179 }
180 else
181 return DE_NULL;
182 #else
183 # error "Invalid DE_ALIGNED_MALLOC"
184 #endif
185 }
186
deAlignedRealloc(void * ptr,size_t numBytes,size_t alignBytes)187 void* deAlignedRealloc (void* ptr, size_t numBytes, size_t alignBytes)
188 {
189 #if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
190 return _aligned_realloc(ptr, numBytes, alignBytes);
191
192 #elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC) || (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
193 if (ptr)
194 {
195 if (numBytes > 0)
196 {
197 # if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
198 const size_t oldSize = getAlignedAllocHeader(ptr)->numBytes;
199 # else /* DE_ALIGNED_MALLOC_GENERIC */
200 const size_t oldSize = malloc_usable_size(ptr);
201 # endif
202
203 DE_ASSERT(deIsAlignedPtr(ptr, alignBytes));
204
205 if (oldSize < numBytes || oldSize > numBytes*2)
206 {
207 /* Create a new alloc if original is smaller, or more than twice the requested size */
208 void* const newPtr = deAlignedMalloc(numBytes, alignBytes);
209
210 if (newPtr)
211 {
212 const size_t copyBytes = numBytes < oldSize ? numBytes : oldSize;
213
214 deMemcpy(newPtr, ptr, copyBytes);
215 deAlignedFree(ptr);
216
217 return newPtr;
218 }
219 else
220 return DE_NULL;
221 }
222 else
223 return ptr;
224 }
225 else
226 {
227 deAlignedFree(ptr);
228 return DE_NULL;
229 }
230 }
231 else
232 return deAlignedMalloc(numBytes, alignBytes);
233
234 #else
235 # error "Invalid DE_ALIGNED_MALLOC"
236 #endif
237 }
238
deAlignedFree(void * ptr)239 void deAlignedFree (void* ptr)
240 {
241 #if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
242 free(ptr);
243
244 #elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
245 _aligned_free(ptr);
246
247 #elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
248 if (ptr)
249 {
250 AlignedAllocHeader* const hdr = getAlignedAllocHeader(ptr);
251
252 deFree(hdr->basePtr);
253 }
254 #else
255 # error "Invalid DE_ALIGNED_MALLOC"
256 #endif
257 }
258
deStrdup(const char * str)259 char* deStrdup (const char* str)
260 {
261 #if (DE_COMPILER == DE_COMPILER_MSC)
262 return _strdup(str);
263 #elif (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS)
264 /* For some reason Steve doesn't like stdrup(). */
265 size_t len = strlen(str);
266 char* copy = malloc(len+1);
267 memcpy(copy, str, len);
268 copy[len] = 0;
269 return copy;
270 #else
271 return strdup(str);
272 #endif
273 }
274
deMemory_selfTest(void)275 void deMemory_selfTest (void)
276 {
277 static const struct
278 {
279 size_t numBytes;
280 size_t alignment;
281 } s_alignedAllocCases[] =
282 {
283 { 1, 1 },
284 { 1, 2 },
285 { 1, 256 },
286 { 1, 4096 },
287 { 547389, 1 },
288 { 547389, 2 },
289 { 547389, 256 },
290 { 547389, 4096 },
291 { 52532, 1<<4 },
292 { 52532, 1<<10 },
293 { 52532, 1<<16 },
294 };
295 static const struct
296 {
297 size_t initialSize;
298 size_t newSize;
299 size_t alignment;
300 } s_alignedReallocCases[] =
301 {
302 { 1, 1, 1 },
303 { 1, 1, 2 },
304 { 1, 1, 256 },
305 { 1, 1, 4096 },
306 { 1, 1241, 1 },
307 { 1, 1241, 2 },
308 { 1, 1241, 256 },
309 { 1, 1241, 4096 },
310 { 547389, 234, 1 },
311 { 547389, 234, 2 },
312 { 547389, 234, 256 },
313 { 547389, 234, 4096 },
314 { 52532, 421523, 1<<4 },
315 { 52532, 421523, 1<<10 },
316 { 52532, 421523, 1<<16 },
317 };
318
319 int caseNdx;
320
321 for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_alignedAllocCases); caseNdx++)
322 {
323 void* const ptr = deAlignedMalloc(s_alignedAllocCases[caseNdx].numBytes, s_alignedAllocCases[caseNdx].alignment);
324
325 DE_TEST_ASSERT(ptr);
326 DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedAllocCases[caseNdx].alignment));
327
328 deMemset(ptr, 0xaa, s_alignedAllocCases[caseNdx].numBytes);
329
330 deAlignedFree(ptr);
331 }
332
333 for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_alignedReallocCases); caseNdx++)
334 {
335 void* const ptr = deAlignedMalloc(s_alignedReallocCases[caseNdx].initialSize, s_alignedReallocCases[caseNdx].alignment);
336
337 DE_TEST_ASSERT(ptr);
338 DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedReallocCases[caseNdx].alignment));
339
340 deMemset(ptr, 0xaa, s_alignedReallocCases[caseNdx].initialSize);
341
342 {
343 void* const newPtr = deAlignedRealloc(ptr, s_alignedReallocCases[caseNdx].newSize, s_alignedReallocCases[caseNdx].alignment);
344 const size_t numPreserved = s_alignedReallocCases[caseNdx].newSize < s_alignedReallocCases[caseNdx].initialSize
345 ? s_alignedReallocCases[caseNdx].newSize
346 : s_alignedReallocCases[caseNdx].initialSize;
347 size_t off;
348
349 DE_TEST_ASSERT(newPtr);
350 DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedReallocCases[caseNdx].alignment));
351
352 for (off = 0; off < numPreserved; off++)
353 DE_TEST_ASSERT(*((const deUint8*)newPtr + off) == 0xaa);
354
355 deAlignedFree(newPtr);
356 }
357 }
358 }
359
360 DE_END_EXTERN_C
361