aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/memory/mallocansi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zencore/memory/mallocansi.cpp')
-rw-r--r--src/zencore/memory/mallocansi.cpp251
1 files changed, 251 insertions, 0 deletions
diff --git a/src/zencore/memory/mallocansi.cpp b/src/zencore/memory/mallocansi.cpp
new file mode 100644
index 000000000..9c3936172
--- /dev/null
+++ b/src/zencore/memory/mallocansi.cpp
@@ -0,0 +1,251 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include <zencore/memory/mallocansi.h>
+
+#include <zencore/intmath.h>
+#include <zencore/memory/align.h>
+#include <zencore/windows.h>
+
+#if ZEN_PLATFORM_LINUX
+# define PLATFORM_USE_ANSI_POSIX_MALLOC 1
+#endif
+
+#if ZEN_PLATFORM_MAC
+# define PLATFORM_USE_CUSTOM_MEMALIGN 1
+#endif
+
+#ifndef PLATFORM_USE_ANSI_MEMALIGN
+# define PLATFORM_USE_ANSI_MEMALIGN 0
+#endif
+
+#ifndef PLATFORM_USE_ANSI_POSIX_MALLOC
+# define PLATFORM_USE_ANSI_POSIX_MALLOC 0
+#endif
+
+#ifndef PLATFORM_USE_CUSTOM_MEMALIGN
+# define PLATFORM_USE_CUSTOM_MEMALIGN 0
+#endif
+
+#if PLATFORM_USE_ANSI_POSIX_MALLOC
+# include <malloc.h>
+# include <string.h>
+#endif
+
+#define MALLOC_ANSI_USES__ALIGNED_MALLOC ZEN_PLATFORM_WINDOWS
+
+namespace zen {
+
+//////////////////////////////////////////////////////////////////////////
+
+void*
+AnsiMalloc(size_t Size, uint32_t Alignment)
+{
+#if MALLOC_ANSI_USES__ALIGNED_MALLOC
+ void* Result = _aligned_malloc(Size, Alignment);
+#elif PLATFORM_USE_ANSI_POSIX_MALLOC
+ void* Result;
+ if (posix_memalign(&Result, Alignment, Size) != 0)
+ {
+ Result = nullptr;
+ }
+#elif PLATFORM_USE_ANSI_MEMALIGN
+ Result = reallocalign(Ptr, NewSize, Alignment);
+#elif PLATFORM_USE_CUSTOM_MEMALIGN
+ void* Ptr = malloc(Size + Alignment + sizeof(void*) + sizeof(size_t));
+ void* Result = nullptr;
+ if (Ptr)
+ {
+ Result = Align((uint8_t*)Ptr + sizeof(void*) + sizeof(size_t), Alignment);
+ *((void**)((uint8_t*)Result - sizeof(void*))) = Ptr;
+ *((size_t*)((uint8_t*)Result - sizeof(void*) - sizeof(size_t))) = Size;
+ }
+#else
+# error Unknown allocation path
+#endif
+
+ return Result;
+}
+
+size_t
+AnsiGetAllocationSize(void* Original)
+{
+#if MALLOC_ANSI_USES__ALIGNED_MALLOC
+ return _aligned_msize(Original, 16, 0); // TODO: incorrectly assumes alignment of 16
+#elif PLATFORM_USE_ANSI_POSIX_MALLOC || PLATFORM_USE_ANSI_MEMALIGN
+ return malloc_usable_size(Original);
+#elif PLATFORM_USE_CUSTOM_MEMALIGN
+ return *((size_t*)((uint8_t*)Original - sizeof(void*) - sizeof(size_t)));
+#else
+# error Unknown allocation path
+#endif
+}
+
+void*
+AnsiRealloc(void* Ptr, size_t NewSize, uint32_t Alignment)
+{
+ void* Result = nullptr;
+
+#if MALLOC_ANSI_USES__ALIGNED_MALLOC
+ if (Ptr && NewSize)
+ {
+ Result = _aligned_realloc(Ptr, NewSize, Alignment);
+ }
+ else if (Ptr == nullptr)
+ {
+ Result = _aligned_malloc(NewSize, Alignment);
+ }
+ else
+ {
+ _aligned_free(Ptr);
+ Result = nullptr;
+ }
+#elif PLATFORM_USE_ANSI_POSIX_MALLOC
+ if (Ptr && NewSize)
+ {
+ size_t UsableSize = malloc_usable_size(Ptr);
+ if (posix_memalign(&Result, Alignment, NewSize) != 0)
+ {
+ Result = nullptr;
+ }
+ else if (UsableSize)
+ {
+ memcpy(Result, Ptr, Min(NewSize, UsableSize));
+ }
+ free(Ptr);
+ }
+ else if (Ptr == nullptr)
+ {
+ if (posix_memalign(&Result, Alignment, NewSize) != 0)
+ {
+ Result = nullptr;
+ }
+ }
+ else
+ {
+ free(Ptr);
+ Result = nullptr;
+ }
+#elif PLATFORM_USE_CUSTOM_MEMALIGN
+ if (Ptr && NewSize)
+ {
+ // Can't use realloc as it might screw with alignment.
+ Result = AnsiMalloc(NewSize, Alignment);
+ size_t PtrSize = AnsiGetAllocationSize(Ptr);
+ memcpy(Result, Ptr, Min(NewSize, PtrSize));
+ AnsiFree(Ptr);
+ }
+ else if (Ptr == nullptr)
+ {
+ Result = AnsiMalloc(NewSize, Alignment);
+ }
+ else
+ {
+ free(*((void**)((uint8_t*)Ptr - sizeof(void*))));
+ Result = nullptr;
+ }
+#else
+# error Unknown allocation path
+#endif
+
+ return Result;
+}
+
+void
+AnsiFree(void* Ptr)
+{
+#if MALLOC_ANSI_USES__ALIGNED_MALLOC
+ _aligned_free(Ptr);
+#elif PLATFORM_USE_ANSI_POSIX_MALLOC || PLATFORM_USE_ANSI_MEMALIGN
+ free(Ptr);
+#elif PLATFORM_USE_CUSTOM_MEMALIGN
+ if (Ptr)
+ {
+ free(*((void**)((uint8_t*)Ptr - sizeof(void*))));
+ }
+#else
+# error Unknown allocation path
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+FMallocAnsi::FMallocAnsi()
+{
+#if ZEN_PLATFORM_WINDOWS
+ // Enable low fragmentation heap - http://msdn2.microsoft.com/en-US/library/aa366750.aspx
+ intptr_t CrtHeapHandle = _get_heap_handle();
+ ULONG EnableLFH = 2;
+ HeapSetInformation((void*)CrtHeapHandle, HeapCompatibilityInformation, &EnableLFH, sizeof(EnableLFH));
+#endif
+}
+
+void*
+FMallocAnsi::TryMalloc(size_t Size, uint32_t Alignment)
+{
+ Alignment = Max(Size >= 16 ? (uint32_t)16 : (uint32_t)8, Alignment);
+
+ void* Result = AnsiMalloc(Size, Alignment);
+
+ return Result;
+}
+
+void*
+FMallocAnsi::Malloc(size_t Size, uint32_t Alignment)
+{
+ void* Result = TryMalloc(Size, Alignment);
+
+ if (Result == nullptr && Size)
+ {
+ OutOfMemory(Size, Alignment);
+ }
+
+ return Result;
+}
+
+void*
+FMallocAnsi::TryRealloc(void* Ptr, size_t NewSize, uint32_t Alignment)
+{
+ Alignment = Max(NewSize >= 16 ? (uint32_t)16 : (uint32_t)8, Alignment);
+
+ void* Result = AnsiRealloc(Ptr, NewSize, Alignment);
+
+ return Result;
+}
+
+void*
+FMallocAnsi::Realloc(void* Ptr, size_t NewSize, uint32_t Alignment)
+{
+ void* Result = TryRealloc(Ptr, NewSize, Alignment);
+
+ if (Result == nullptr && NewSize != 0)
+ {
+ OutOfMemory(NewSize, Alignment);
+ }
+
+ return Result;
+}
+
+void
+FMallocAnsi::Free(void* Ptr)
+{
+ AnsiFree(Ptr);
+}
+
+bool
+FMallocAnsi::GetAllocationSize(void* Original, size_t& SizeOut)
+{
+ if (!Original)
+ {
+ return false;
+ }
+
+#if MALLOC_ANSI_USES__ALIGNED_MALLOC
+ ZEN_UNUSED(SizeOut);
+ return false;
+#else
+ SizeOut = AnsiGetAllocationSize(Original);
+ return true;
+#endif
+}
+
+} // namespace zen