• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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