Home | History | Annotate | Download | only in debase
      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  *//*--------------------------------------------------------------------*/
     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  *//*--------------------------------------------------------------------*/
     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  *//*--------------------------------------------------------------------*/
    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  *//*--------------------------------------------------------------------*/
    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 
    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 
    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 
    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 
    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 
    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 
    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