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