You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
361 lines
9.2 KiB
361 lines
9.2 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Base Portability Library
|
|
* -------------------------------------
|
|
*
|
|
* Copyright 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*//*!
|
|
* \file
|
|
* \brief Memory management.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "deMemory.h"
|
|
#include "deInt32.h"
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define DE_ALIGNED_MALLOC_POSIX 0
|
|
#define DE_ALIGNED_MALLOC_WIN32 1
|
|
#define DE_ALIGNED_MALLOC_GENERIC 2
|
|
|
|
#if (DE_OS == DE_OS_UNIX) || ((DE_OS == DE_OS_ANDROID) && (DE_ANDROID_API >= 21))
|
|
# define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_POSIX
|
|
# if defined(__FreeBSD__)
|
|
# include <stdlib.h>
|
|
# else
|
|
# include <malloc.h>
|
|
# endif
|
|
#elif (DE_OS == DE_OS_WIN32)
|
|
# define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_WIN32
|
|
# include <malloc.h>
|
|
#else
|
|
# define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_GENERIC
|
|
#endif
|
|
|
|
#if defined(DE_VALGRIND_BUILD)
|
|
# include <valgrind/valgrind.h>
|
|
# if defined(HAVE_VALGRIND_MEMCHECK_H)
|
|
# include <valgrind/memcheck.h>
|
|
# endif
|
|
#endif
|
|
|
|
DE_BEGIN_EXTERN_C
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Allocate a chunk of memory.
|
|
* \param numBytes Number of bytes to allocate.
|
|
* \return Pointer to the allocated memory (or null on failure).
|
|
*//*--------------------------------------------------------------------*/
|
|
void* deMalloc (size_t numBytes)
|
|
{
|
|
void* ptr;
|
|
|
|
DE_ASSERT(numBytes > 0);
|
|
|
|
ptr = malloc((size_t)numBytes);
|
|
|
|
#if defined(DE_DEBUG)
|
|
/* Trash memory in debug builds (if under Valgrind, don't make it think we're initializing data here). */
|
|
|
|
if (ptr)
|
|
memset(ptr, 0xcd, numBytes);
|
|
|
|
#if defined(DE_VALGRIND_BUILD) && defined(HAVE_VALGRIND_MEMCHECK_H)
|
|
if (ptr && RUNNING_ON_VALGRIND)
|
|
{
|
|
VALGRIND_MAKE_MEM_UNDEFINED(ptr, numBytes);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return ptr;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Allocate a chunk of memory and initialize it to zero.
|
|
* \param numBytes Number of bytes to allocate.
|
|
* \return Pointer to the allocated memory (or null on failure).
|
|
*//*--------------------------------------------------------------------*/
|
|
void* deCalloc (size_t numBytes)
|
|
{
|
|
void* ptr = deMalloc(numBytes);
|
|
if (ptr)
|
|
deMemset(ptr, 0, numBytes);
|
|
return ptr;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Reallocate a chunk of memory.
|
|
* \param ptr Pointer to previously allocated memory block
|
|
* \param numBytes New size in bytes
|
|
* \return Pointer to the reallocated (and possibly moved) memory block
|
|
*//*--------------------------------------------------------------------*/
|
|
void* deRealloc (void* ptr, size_t numBytes)
|
|
{
|
|
return realloc(ptr, numBytes);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Free a chunk of memory.
|
|
* \param ptr Pointer to memory to free.
|
|
*//*--------------------------------------------------------------------*/
|
|
void deFree (void* ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
|
|
|
|
typedef struct AlignedAllocHeader_s
|
|
{
|
|
void* basePtr;
|
|
size_t numBytes;
|
|
} AlignedAllocHeader;
|
|
|
|
DE_INLINE AlignedAllocHeader* getAlignedAllocHeader (void* ptr)
|
|
{
|
|
const size_t hdrSize = sizeof(AlignedAllocHeader);
|
|
const deUintptr hdrAddr = (deUintptr)ptr - hdrSize;
|
|
|
|
return (AlignedAllocHeader*)hdrAddr;
|
|
}
|
|
|
|
#endif
|
|
|
|
void* deAlignedMalloc (size_t numBytes, size_t alignBytes)
|
|
{
|
|
#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
|
|
/* posix_memalign() requires that alignment must be 2^N * sizeof(void*) */
|
|
const size_t ptrAlignedAlign = deAlignSize(alignBytes, sizeof(void*));
|
|
void* ptr = DE_NULL;
|
|
|
|
DE_ASSERT(deIsPowerOfTwoSize(alignBytes) && deIsPowerOfTwoSize(ptrAlignedAlign / sizeof(void*)));
|
|
|
|
if (posix_memalign(&ptr, ptrAlignedAlign, numBytes) == 0)
|
|
{
|
|
DE_ASSERT(ptr);
|
|
return ptr;
|
|
}
|
|
else
|
|
{
|
|
DE_ASSERT(!ptr);
|
|
return DE_NULL;
|
|
}
|
|
|
|
#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
|
|
DE_ASSERT(deIsPowerOfTwoSize(alignBytes));
|
|
|
|
return _aligned_malloc(numBytes, alignBytes);
|
|
|
|
#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
|
|
void* const basePtr = deMalloc(numBytes + alignBytes + sizeof(AlignedAllocHeader));
|
|
|
|
DE_ASSERT(deIsPowerOfTwoSize(alignBytes));
|
|
|
|
if (basePtr)
|
|
{
|
|
void* const alignedPtr = deAlignPtr((void*)((deUintptr)basePtr + sizeof(AlignedAllocHeader)), alignBytes);
|
|
AlignedAllocHeader* const hdr = getAlignedAllocHeader(alignedPtr);
|
|
|
|
hdr->basePtr = basePtr;
|
|
hdr->numBytes = numBytes;
|
|
|
|
return alignedPtr;
|
|
}
|
|
else
|
|
return DE_NULL;
|
|
#else
|
|
# error "Invalid DE_ALIGNED_MALLOC"
|
|
#endif
|
|
}
|
|
|
|
void* deAlignedRealloc (void* ptr, size_t numBytes, size_t alignBytes)
|
|
{
|
|
#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
|
|
return _aligned_realloc(ptr, numBytes, alignBytes);
|
|
|
|
#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC) || (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
|
|
if (ptr)
|
|
{
|
|
if (numBytes > 0)
|
|
{
|
|
# if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
|
|
const size_t oldSize = getAlignedAllocHeader(ptr)->numBytes;
|
|
# else /* DE_ALIGNED_MALLOC_GENERIC */
|
|
const size_t oldSize = malloc_usable_size(ptr);
|
|
# endif
|
|
|
|
DE_ASSERT(deIsAlignedPtr(ptr, alignBytes));
|
|
|
|
if (oldSize < numBytes || oldSize > numBytes*2)
|
|
{
|
|
/* Create a new alloc if original is smaller, or more than twice the requested size */
|
|
void* const newPtr = deAlignedMalloc(numBytes, alignBytes);
|
|
|
|
if (newPtr)
|
|
{
|
|
const size_t copyBytes = numBytes < oldSize ? numBytes : oldSize;
|
|
|
|
deMemcpy(newPtr, ptr, copyBytes);
|
|
deAlignedFree(ptr);
|
|
|
|
return newPtr;
|
|
}
|
|
else
|
|
return DE_NULL;
|
|
}
|
|
else
|
|
return ptr;
|
|
}
|
|
else
|
|
{
|
|
deAlignedFree(ptr);
|
|
return DE_NULL;
|
|
}
|
|
}
|
|
else
|
|
return deAlignedMalloc(numBytes, alignBytes);
|
|
|
|
#else
|
|
# error "Invalid DE_ALIGNED_MALLOC"
|
|
#endif
|
|
}
|
|
|
|
void deAlignedFree (void* ptr)
|
|
{
|
|
#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
|
|
free(ptr);
|
|
|
|
#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
|
|
_aligned_free(ptr);
|
|
|
|
#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
|
|
if (ptr)
|
|
{
|
|
AlignedAllocHeader* const hdr = getAlignedAllocHeader(ptr);
|
|
|
|
deFree(hdr->basePtr);
|
|
}
|
|
#else
|
|
# error "Invalid DE_ALIGNED_MALLOC"
|
|
#endif
|
|
}
|
|
|
|
char* deStrdup (const char* str)
|
|
{
|
|
#if (DE_COMPILER == DE_COMPILER_MSC)
|
|
return _strdup(str);
|
|
#elif (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS)
|
|
/* For some reason Steve doesn't like stdrup(). */
|
|
size_t len = strlen(str);
|
|
char* copy = malloc(len+1);
|
|
memcpy(copy, str, len);
|
|
copy[len] = 0;
|
|
return copy;
|
|
#else
|
|
return strdup(str);
|
|
#endif
|
|
}
|
|
|
|
void deMemory_selfTest (void)
|
|
{
|
|
static const struct
|
|
{
|
|
size_t numBytes;
|
|
size_t alignment;
|
|
} s_alignedAllocCases[] =
|
|
{
|
|
{ 1, 1 },
|
|
{ 1, 2 },
|
|
{ 1, 256 },
|
|
{ 1, 4096 },
|
|
{ 547389, 1 },
|
|
{ 547389, 2 },
|
|
{ 547389, 256 },
|
|
{ 547389, 4096 },
|
|
{ 52532, 1<<4 },
|
|
{ 52532, 1<<10 },
|
|
{ 52532, 1<<16 },
|
|
};
|
|
static const struct
|
|
{
|
|
size_t initialSize;
|
|
size_t newSize;
|
|
size_t alignment;
|
|
} s_alignedReallocCases[] =
|
|
{
|
|
{ 1, 1, 1 },
|
|
{ 1, 1, 2 },
|
|
{ 1, 1, 256 },
|
|
{ 1, 1, 4096 },
|
|
{ 1, 1241, 1 },
|
|
{ 1, 1241, 2 },
|
|
{ 1, 1241, 256 },
|
|
{ 1, 1241, 4096 },
|
|
{ 547389, 234, 1 },
|
|
{ 547389, 234, 2 },
|
|
{ 547389, 234, 256 },
|
|
{ 547389, 234, 4096 },
|
|
{ 52532, 421523, 1<<4 },
|
|
{ 52532, 421523, 1<<10 },
|
|
{ 52532, 421523, 1<<16 },
|
|
};
|
|
|
|
int caseNdx;
|
|
|
|
for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_alignedAllocCases); caseNdx++)
|
|
{
|
|
void* const ptr = deAlignedMalloc(s_alignedAllocCases[caseNdx].numBytes, s_alignedAllocCases[caseNdx].alignment);
|
|
|
|
DE_TEST_ASSERT(ptr);
|
|
DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedAllocCases[caseNdx].alignment));
|
|
|
|
deMemset(ptr, 0xaa, s_alignedAllocCases[caseNdx].numBytes);
|
|
|
|
deAlignedFree(ptr);
|
|
}
|
|
|
|
for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_alignedReallocCases); caseNdx++)
|
|
{
|
|
void* const ptr = deAlignedMalloc(s_alignedReallocCases[caseNdx].initialSize, s_alignedReallocCases[caseNdx].alignment);
|
|
|
|
DE_TEST_ASSERT(ptr);
|
|
DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedReallocCases[caseNdx].alignment));
|
|
|
|
deMemset(ptr, 0xaa, s_alignedReallocCases[caseNdx].initialSize);
|
|
|
|
{
|
|
void* const newPtr = deAlignedRealloc(ptr, s_alignedReallocCases[caseNdx].newSize, s_alignedReallocCases[caseNdx].alignment);
|
|
const size_t numPreserved = s_alignedReallocCases[caseNdx].newSize < s_alignedReallocCases[caseNdx].initialSize
|
|
? s_alignedReallocCases[caseNdx].newSize
|
|
: s_alignedReallocCases[caseNdx].initialSize;
|
|
size_t off;
|
|
|
|
DE_TEST_ASSERT(newPtr);
|
|
DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedReallocCases[caseNdx].alignment));
|
|
|
|
for (off = 0; off < numPreserved; off++)
|
|
DE_TEST_ASSERT(*((const deUint8*)newPtr + off) == 0xaa);
|
|
|
|
deAlignedFree(newPtr);
|
|
}
|
|
}
|
|
}
|
|
|
|
DE_END_EXTERN_C
|