diff options
Diffstat (limited to 'src/zencore/memory/memory.cpp')
| -rw-r--r-- | src/zencore/memory/memory.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/src/zencore/memory/memory.cpp b/src/zencore/memory/memory.cpp new file mode 100644 index 000000000..f236796ad --- /dev/null +++ b/src/zencore/memory/memory.cpp @@ -0,0 +1,281 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include <zencore/commandline.h> +#include <zencore/memory/fmalloc.h> +#include <zencore/memory/mallocansi.h> +#include <zencore/memory/mallocmimalloc.h> +#include <zencore/memory/mallocrpmalloc.h> +#include <zencore/memory/mallocstomp.h> +#include <zencore/memory/memory.h> +#include <zencore/memory/memorytrace.h> +#include <zencore/string.h> + +#if ZEN_PLATFORM_WINDOWS +# include <zencore/windows.h> +ZEN_THIRD_PARTY_INCLUDES_START +# include <shellapi.h> // For command line parsing +ZEN_THIRD_PARTY_INCLUDES_END +#endif + +#if ZEN_PLATFORM_LINUX +# include <stdio.h> +#endif + +namespace zen { + +enum class MallocImpl +{ + None = 0, + Ansi, + Stomp, + Mimalloc, + Rpmalloc +}; + +static int +InitGMalloc() +{ + MallocImpl Malloc = MallocImpl::None; + FMalloc* InitMalloc = GMalloc; + + // Pick a default base allocator based on availability/platform + +#if ZEN_MIMALLOC_ENABLED + if (Malloc == MallocImpl::None) + { + Malloc = MallocImpl::Mimalloc; + } +#endif + +#if ZEN_RPMALLOC_ENABLED + if (Malloc == MallocImpl::None) + { + Malloc = MallocImpl::Rpmalloc; + } +#endif + + // Process any command line overrides + // + // Note that calls can come into this function before we enter the regular main function + // and we can therefore not rely on the regular command line parsing for the application + + using namespace std::literals; + + auto ProcessMallocArg = [&](const std::string_view& Arg) { +#if ZEN_RPMALLOC_ENABLED + if (Arg == "rpmalloc"sv) + { + Malloc = MallocImpl::Rpmalloc; + } +#endif + +#if ZEN_MIMALLOC_ENABLED + if (Arg == "mimalloc"sv) + { + Malloc = MallocImpl::Mimalloc; + } +#endif + + if (Arg == "ansi"sv) + { + Malloc = MallocImpl::Ansi; + } + + if (Arg == "stomp"sv) + { + Malloc = MallocImpl::Stomp; + } + }; + + constexpr std::string_view MallocOption = "--malloc="sv; + + std::function<void(const std::string_view&)> ProcessArg = [&](const std::string_view& Arg) { + if (Arg.starts_with(MallocOption)) + { + const std::string_view OptionArgs = Arg.substr(MallocOption.size()); + + IterateCommaSeparatedValue(OptionArgs, ProcessMallocArg); + } + }; + + IterateCommandlineArgs(ProcessArg); + + switch (Malloc) + { +#if ZEN_WITH_MALLOC_STOMP + case MallocImpl::Stomp: + GMalloc = new FMallocStomp(); + break; +#endif + +#if ZEN_RPMALLOC_ENABLED + case MallocImpl::Rpmalloc: + GMalloc = new FMallocRpmalloc(); + break; +#endif + +#if ZEN_MIMALLOC_ENABLED + case MallocImpl::Mimalloc: + GMalloc = new FMallocMimalloc(); + break; +#endif + default: + break; + } + + if (GMalloc == InitMalloc) + { + GMalloc = new FMallocAnsi(); + } + + return 1; +} + +void +Memory::GCreateMalloc() +{ + static int InitFlag = InitGMalloc(); +} + +void +Memory::Initialize() +{ + GCreateMalloc(); +} + +////////////////////////////////////////////////////////////////////////// + +void* +Memory::SystemMalloc(size_t Size) +{ + void* Ptr = ::malloc(Size); + MemoryTrace_Alloc(uint64_t(Ptr), Size, 0, EMemoryTraceRootHeap::SystemMemory); + return Ptr; +} + +void +Memory::SystemFree(void* Ptr) +{ + MemoryTrace_Free(uint64_t(Ptr), EMemoryTraceRootHeap::SystemMemory); + ::free(Ptr); +} + +} // namespace zen + +////////////////////////////////////////////////////////////////////////// + +static ZEN_NOINLINE bool +InvokeNewHandler(bool NoThrow) +{ + std::new_handler h = std::get_new_handler(); + + if (!h) + { +#if defined(_CPPUNWIND) || defined(__cpp_exceptions) + if (NoThrow == false) + throw std::bad_alloc(); +#else + ZEN_UNUSED(NoThrow); +#endif + return false; + } + else + { + h(); + return true; + } +} + +////////////////////////////////////////////////////////////////////////// + +ZEN_NOINLINE void* +RetryNew(size_t Size, bool NoThrow) +{ + void* Ptr = nullptr; + while (!Ptr && InvokeNewHandler(NoThrow)) + { + Ptr = zen::Memory::Malloc(Size, zen::DEFAULT_ALIGNMENT); + } + return Ptr; +} + +void* +zen_new(size_t Size) +{ + void* Ptr = zen::Memory::Malloc(Size, zen::DEFAULT_ALIGNMENT); + + if (!Ptr) [[unlikely]] + { + const bool NoThrow = false; + return RetryNew(Size, NoThrow); + } + + return Ptr; +} + +void* +zen_new_nothrow(size_t Size) noexcept +{ + void* Ptr = zen::Memory::Malloc(Size, zen::DEFAULT_ALIGNMENT); + + if (!Ptr) [[unlikely]] + { + const bool NoThrow = true; + return RetryNew(Size, NoThrow); + } + + return Ptr; +} + +void* +zen_new_aligned(size_t Size, size_t Alignment) +{ + void* Ptr; + + do + { + Ptr = zen::Memory::Malloc(Size, uint32_t(Alignment)); + } while (!Ptr && InvokeNewHandler(/* NoThrow */ false)); + + return Ptr; +} + +void* +zen_new_aligned_nothrow(size_t Size, size_t Alignment) noexcept +{ + void* Ptr; + + do + { + Ptr = zen::Memory::Malloc(Size, uint32_t(Alignment)); + } while (!Ptr && InvokeNewHandler(/* NoThrow */ true)); + + return Ptr; +} + +void +zen_free(void* Ptr) noexcept +{ + zen::Memory::Free(Ptr); +} + +void +zen_free_size(void* Ptr, size_t Size) noexcept +{ + ZEN_UNUSED(Size); + zen::Memory::Free(Ptr); +} + +void +zen_free_size_aligned(void* Ptr, size_t Size, size_t Alignment) noexcept +{ + ZEN_UNUSED(Size, Alignment); + zen::Memory::Free(Ptr); +} + +void +zen_free_aligned(void* Ptr, size_t Alignment) noexcept +{ + ZEN_UNUSED(Alignment); + zen::Memory::Free(Ptr); +} |