From d69d111bb625ef8c0d6b3014c87ade47f732bb0f Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Mon, 13 Apr 2026 19:01:16 +0200 Subject: [PATCH] CodeCache: Align code section within cache files This allows mapping the code directly into memory for execution. --- FEXCore/Source/Interface/Core/CodeCache.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/FEXCore/Source/Interface/Core/CodeCache.cpp b/FEXCore/Source/Interface/Core/CodeCache.cpp index fcbd83fb3..b80d0d5a0 100644 --- a/FEXCore/Source/Interface/Core/CodeCache.cpp +++ b/FEXCore/Source/Interface/Core/CodeCache.cpp @@ -233,7 +233,10 @@ uint64_t CodeCache::ComputeCodeMapId(std::string_view Filename, int FD) { struct CodeCacheHeader { std::array Magic = ExpectedMagic; - uint32_t FormatVersion = 1; + // Version history: + // 1: Initial version + // 2: Padding code buffer data to enable direct mapping + uint32_t FormatVersion = 2; uint8_t FEXVersion[20] = {}; uint32_t NumBlocks; uint32_t NumCodePages; @@ -260,7 +263,7 @@ bool CodeCache::SaveData(Core::InternalThreadState& Thread, int fd, const Execut std::ranges::copy(GIT_HASH, header.FEXVersion); header.NumBlocks = LookupCache.BlockList.size(); header.NumCodePages = LookupCache.CodePages.size(); - header.CodeBufferSize = CTX.LatestOffset; + header.CodeBufferSize = FEXCore::AlignUp(CTX.LatestOffset, Utils::FEX_PAGE_SIZE); header.NumRelocations = Relocations.size(); header.SerializedBaseAddress = SerializedBaseAddress; ::write(fd, &header, sizeof(header)); @@ -313,6 +316,12 @@ bool CodeCache::SaveData(Core::InternalThreadState& Thread, int fd, const Execut return false; } ::write(fd, CodeBufferData.data(), CodeBufferData.size()); + // Pad to next page in file for mmap + { + auto PaddedSize = AlignUp(lseek(fd, 0, SEEK_CUR), Utils::FEX_PAGE_SIZE); + ::ftruncate(fd, PaddedSize); + lseek(fd, PaddedSize, SEEK_SET); + } // Dump code pages static_assert(OrderedContainer, "Non-deterministic data source");