///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// #ifndef EASTLTEST_ALLOCATOR_H #define EASTLTEST_ALLOCATOR_H #include #include #include #include #if !EASTL_OPENSOURCE #include #include #include #if defined(EA_COMPILER_MSVC) #include // VS2008 has an acknowledged bug that requires math.h (and possibly also string.h) to be #included before intrin.h. #include #pragma intrinsic(_ReturnAddress) #endif /////////////////////////////////////////////////////////////////////////////// // EASTLTest_GetGeneralAllocator() // namespace EA { namespace Allocator { #ifdef EA_DEBUG extern PPM_API GeneralAllocatorDebug* gpEAGeneralAllocatorDebug; #else extern PPM_API GeneralAllocator* gpEAGeneralAllocator; #endif static inline auto& EASTLTest_GetGeneralAllocator() { #ifdef EA_DEBUG using GeneralAllocatorType = GeneralAllocatorDebug; #else using GeneralAllocatorType = GeneralAllocator; #endif static GeneralAllocatorType sGeneralAllocator; return sGeneralAllocator; } } } /////////////////////////////////////////////////////////////////////////////// // allocator counts for debugging purposes // int gEASTLTest_AllocationCount = 0; int gEASTLTest_TotalAllocationCount = 0; /////////////////////////////////////////////////////////////////////////////// // EASTLTest_ValidateHeap // bool EASTLTest_ValidateHeap() { #ifdef EA_DEBUG return EA::Allocator::EASTLTest_GetGeneralAllocator().ValidateHeap(EA::Allocator::GeneralAllocator::kHeapValidationLevelBasic); #else return true; #endif } /////////////////////////////////////////////////////////////////////////////// // Microsoft function parameter annotations // https://msdn.microsoft.com/en-CA/library/hh916382.aspx // #ifndef _Ret_maybenull_ #define _Ret_maybenull_ #endif #ifndef _Post_writable_byte_size_ #define _Post_writable_byte_size_(x) #endif #ifndef _Ret_notnull_ #define _Ret_notnull_ #endif /////////////////////////////////////////////////////////////////////////////// // operator new extensions // namespace { #ifdef EA_DEBUG const char gUnattributedNewTag[] = "Anonymous new"; #endif #if defined(EA_COMPILER_MSVC) #define UNATTRIBUTED_NEW_FILE "raw_return_address" #define UNATTRIBUTED_NEW_LINE ((int)(uintptr_t)_ReturnAddress()) #else #define UNATTRIBUTED_NEW_FILE NULL #define UNATTRIBUTED_NEW_LINE 0 #endif } /////////////////////////////////////////////////////////////////////////////// // system memory allocation helpers // namespace { void* PlatformMalloc(size_t size, size_t alignment = 16) { #ifdef EA_PLATFORM_MICROSOFT return _aligned_malloc(size, alignment); #else void *p = nullptr; alignment = alignment < sizeof( void *) ? sizeof( void *) : alignment; posix_memalign(&p, alignment, size); return p; #endif } void PlatformFree(void* p) { #ifdef EA_PLATFORM_MICROSOFT _aligned_free(p); #else free(p); #endif } void* InternalMalloc(size_t size) { void* mem = nullptr; auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator(); #ifdef EA_DEBUG mem = allocator.MallocDebug(size, 0, 0, gUnattributedNewTag, UNATTRIBUTED_NEW_FILE, UNATTRIBUTED_NEW_LINE); #else mem = allocator.Malloc(size); #endif if(mem == nullptr) mem = PlatformMalloc(size); return mem; } void* InternalMalloc(size_t size, const char* name, int flags, unsigned debugFlags, const char* file, int line) { void* mem = nullptr; auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator(); #ifdef EA_DEBUG mem = allocator.MallocDebug(size, flags, debugFlags, name, file, line); #else mem = allocator.Malloc(size, flags); EA_UNUSED(debugFlags); EA_UNUSED(file); EA_UNUSED(line); EA_UNUSED(name); #endif if(mem == nullptr) mem = PlatformMalloc(size); return mem; } void* InternalMalloc(size_t size, size_t alignment, const char* name, int flags, unsigned debugFlags, const char* file, int line) { void* mem = nullptr; auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator(); #ifdef EA_DEBUG mem = allocator.MallocAlignedDebug(size, alignment, 0, flags, debugFlags, name, file, line); #else mem = allocator.MallocAligned(size, alignment, flags); EA_UNUSED(debugFlags); EA_UNUSED(file); EA_UNUSED(line); EA_UNUSED(name); #endif if(mem == nullptr) mem = PlatformMalloc(size, alignment); return mem; } void* InternalMalloc(size_t size, size_t alignment) { void* mem = nullptr; auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator(); #ifdef EA_DEBUG mem = allocator.MallocAlignedDebug(size, alignment, 0, 0, 0, gUnattributedNewTag, UNATTRIBUTED_NEW_FILE, UNATTRIBUTED_NEW_LINE); #else mem = allocator.MallocAligned(size, alignment); #endif if(mem == nullptr) mem = PlatformMalloc(size, alignment); return mem; } void InternalFree(void* p) { auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator(); if(allocator.ValidateAddress(p, EA::Allocator::GeneralAllocator::kAddressTypeOwned) == p) { allocator.Free(p); } else { PlatformFree(p); } } } class EASTLTestICA : public EA::Allocator::ICoreAllocator { public: EASTLTestICA() { } virtual ~EASTLTestICA() { } virtual void* Alloc(size_t size, const char* name, unsigned int flags) { return ::InternalMalloc(size, name, (int)flags, 0, NULL, 0); } virtual void* Alloc(size_t size, const char* name, unsigned int flags, unsigned int align, unsigned int) { return ::InternalMalloc(size, (size_t)align, name, (int)flags, 0, NULL, 0); } virtual void Free(void* pData, size_t /*size*/) { return ::InternalFree(pData); } }; EA::Allocator::ICoreAllocator* EA::Allocator::ICoreAllocator::GetDefaultAllocator() { static EASTLTestICA sEASTLTestICA; return &sEASTLTestICA; } /////////////////////////////////////////////////////////////////////////// // operator new/delete implementations // _Ret_maybenull_ _Post_writable_byte_size_(size) void* operator new(size_t size, const std::nothrow_t&) EA_THROW_SPEC_NEW_NONE() { return InternalMalloc(size); } void operator delete(void* p, const std::nothrow_t&) EA_THROW_SPEC_DELETE_NONE() { if(p) // The standard specifies that 'delete NULL' is a valid operation. { gEASTLTest_AllocationCount--; InternalFree(p); } } _Ret_maybenull_ _Post_writable_byte_size_(size) void* operator new[](size_t size, const std::nothrow_t&) EA_THROW_SPEC_NEW_NONE() { gEASTLTest_AllocationCount++; gEASTLTest_TotalAllocationCount++; void* p = InternalMalloc(size); return p; } void operator delete[](void* p, const std::nothrow_t&) EA_THROW_SPEC_DELETE_NONE() { if(p) { gEASTLTest_AllocationCount--; InternalFree(p); } } _Ret_notnull_ _Post_writable_byte_size_(size) void* operator new(size_t size) { gEASTLTest_AllocationCount++; gEASTLTest_TotalAllocationCount++; void* mem = InternalMalloc(size); #if !defined(EA_COMPILER_NO_EXCEPTIONS) if (mem == NULL) { throw std::bad_alloc(); } #endif return mem; } _Ret_notnull_ _Post_writable_byte_size_(size) void* operator new[](size_t size) { gEASTLTest_AllocationCount++; gEASTLTest_TotalAllocationCount++; void* mem = InternalMalloc(size); #if !defined(EA_COMPILER_NO_EXCEPTIONS) if (mem == NULL) { throw std::bad_alloc(); } #endif return mem; } void* operator new[](size_t size, const char* name, int flags, unsigned debugFlags, const char* file, int line) { gEASTLTest_AllocationCount++; gEASTLTest_TotalAllocationCount++; return InternalMalloc(size, name, flags, debugFlags, file, line); } void* operator new[](size_t size, size_t alignment, size_t alignmentOffset, const char* name, int flags, unsigned debugFlags, const char* file, int line) { gEASTLTest_AllocationCount++; gEASTLTest_TotalAllocationCount++; return InternalMalloc(size, alignment, name, flags, debugFlags, file, line); } // Used by GCC when you make new objects of classes with >= N bit alignment (with N depending on the compiler). void* operator new(size_t size, size_t alignment) { gEASTLTest_AllocationCount++; gEASTLTest_TotalAllocationCount++; return InternalMalloc(size, alignment); } // Used by GCC when you make new objects of classes with >= N bit alignment (with N depending on the compiler). void* operator new(size_t size, size_t alignment, const std::nothrow_t&) EA_THROW_SPEC_NEW_NONE() { gEASTLTest_AllocationCount++; gEASTLTest_TotalAllocationCount++; return InternalMalloc(size, alignment); } // Used by GCC when you make new objects of classes with >= N bit alignment (with N depending on the compiler). void* operator new[](size_t size, size_t alignment) { gEASTLTest_AllocationCount++; gEASTLTest_TotalAllocationCount++; return InternalMalloc(size, alignment); } // Used by GCC when you make new objects of classes with >= N bit alignment (with N depending on the compiler). void* operator new[](size_t size, size_t alignment, const std::nothrow_t&) EA_THROW_SPEC_NEW_NONE() { gEASTLTest_AllocationCount++; gEASTLTest_TotalAllocationCount++; return InternalMalloc(size, alignment); } void operator delete(void* p) EA_THROW_SPEC_DELETE_NONE() { if(p) // The standard specifies that 'delete NULL' is a valid operation. { gEASTLTest_AllocationCount--; InternalFree(p); } } void operator delete[](void* p) EA_THROW_SPEC_DELETE_NONE() { if(p) { gEASTLTest_AllocationCount--; InternalFree(p); } } void EASTLTest_SetGeneralAllocator() { EA::Allocator::SetGeneralAllocator(&EA::Allocator::EASTLTest_GetGeneralAllocator()); #ifdef EA_DEBUG EA::Allocator::gpEAGeneralAllocatorDebug->SetDefaultDebugDataFlag(EA::Allocator::GeneralAllocatorDebug::kDebugDataIdGuard); #endif } #else #if !defined(EA_PLATFORM_MICROSOFT) || defined(EA_PLATFORM_MINGW) #include #endif namespace Internal { void* EASTLAlignedAlloc(size_t size, size_t alignment) { #ifdef EA_PLATFORM_MICROSOFT return _aligned_malloc(size, alignment); #else void *p = nullptr; alignment = alignment < sizeof( void *) ? sizeof( void *) : alignment; posix_memalign(&p, alignment, size); return p; #endif } void EASTLAlignedFree(void* p) { #ifdef EA_PLATFORM_MICROSOFT _aligned_free(p); #else free(p); #endif } } void* operator new(size_t size) { return Internal::EASTLAlignedAlloc(size, 16); } void* operator new[](size_t size) { return Internal::EASTLAlignedAlloc(size, 16); } void* operator new[](size_t size, const char* /*name*/, int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/) { return Internal::EASTLAlignedAlloc(size, 16); } void* operator new[](size_t size, size_t alignment, size_t /*alignmentOffset*/, const char* /*name*/, int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/) { return Internal::EASTLAlignedAlloc(size, alignment); } void* operator new(size_t size, size_t alignment) { return Internal::EASTLAlignedAlloc(size, alignment); } void* operator new(size_t size, size_t alignment, const std::nothrow_t&) EA_THROW_SPEC_NEW_NONE() { return Internal::EASTLAlignedAlloc(size, alignment); } void* operator new[](size_t size, size_t alignment) { return Internal::EASTLAlignedAlloc(size, alignment); } void* operator new[](size_t size, size_t alignment, const std::nothrow_t&)EA_THROW_SPEC_NEW_NONE() { return Internal::EASTLAlignedAlloc(size, alignment); } // C++14 deleter void operator delete(void* p, std::size_t sz ) EA_THROW_SPEC_DELETE_NONE() { Internal::EASTLAlignedFree(p); EA_UNUSED(sz); } void operator delete[](void* p, std::size_t sz ) EA_THROW_SPEC_DELETE_NONE() { Internal::EASTLAlignedFree(p); EA_UNUSED(sz); } void operator delete(void* p) EA_THROW_SPEC_DELETE_NONE() { Internal::EASTLAlignedFree(p); } void operator delete[](void* p) EA_THROW_SPEC_DELETE_NONE() { Internal::EASTLAlignedFree(p); } void EASTLTest_SetGeneralAllocator() { /* intentionally blank */ } bool EASTLTest_ValidateHeap() { return true; } #endif // !EASTL_OPENSOURCE #endif // Header include guard