You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Pierre, we are preparing to support the Delphi 13.1+ Arm64EC target in our Delphi codebase (200 MB+). I asked GPT-5.6-SOL to review FastMM5's readiness for this architecture. Could you please look over the issue below and assess which parts would make sense to implement?
Summary
FastMM5's core is already source-compatible with Delphi 13.1 WinARM64EC, but it is not yet safe to claim production support. This review was made against master commit ade11ff with Delphi compiler 37.0 (dccarm64ec).
Verified working:
FastMM5.pas compiles and links for WinARM64EC with no defines and with each reviewed define set: FastMM_FullDebugModeWhenDLLAvailable;FastMM_DebugLibraryDynamicLoading, FastMM_FullDebugMode, and FastMM_ShareMM;FastMM_AttemptToUseSharedMM.
Non-x86/x64 targets correctly select PurePascal and exclude the core x86/x64 assembly (FastMM5.pas:199-218).
The core uses pointer-sized types and non-executable VirtualAlloc allocations (PAGE_NOACCESS/PAGE_READWRITE).
BorlndMM Release and Debug configurations produce an Arm64EC DLL, but Debug currently loses its intended FullDebug import (section 4). The existing usage/debug/sharing demo sources also compile for the target.
These are compile/link results only; runtime validation on Windows ARM remains part of the work below.
1. Complete ARM memory ordering
WeakMemoryOrdering is defined but unused (FastMM5.pas:205-218). There are 31 assignments that clear core lock fields with an ordinary store, plus the FullDebug cache lock. The smallest example already documents the problem:
procedureTSimpleLock.Unlock;
begin{Need a memory fence for ARM here.}
FLock := 0;
end;
The sequential-feed state is also published as separately ordered fields. For example:
Inc(Manager.LastMediumBlockSequentialFeedOffset.ABACounter);
Manager.SequentialFeedMediumBlockSpan := NewSpan;
{May need a memory fence here for ARM.}
Manager.LastMediumBlockSequentialFeedOffset.IntegerValue := Offset;
FastMM_WalkBlocks may see that flag and immediately dereference the not-yet-published manager (FastMM5.pas:6905-6912, 6958-6975, 8746-8753). Conversely, the sequential-feed offset must not be activated before the flag: once nonzero, lock-free consumers can allocate from a span that a concurrent walker may still identify as a medium block.
Tasks:
Define and use a consistent acquire/release protocol for TSimpleLock, all small/medium/large arena locks, and the FullDebug cache lock. Delphi's own monitor lock uses AtomicExchange for release; System.MemoryBarrier is also available.
Replace or audit every plain *ManagerLocked := 0/FLock := 0 release, including every early-exit and exception path.
Publish the complete aligned offset/ABA value with release semantics only after its span pointer and all metadata required by lock-free consumers are published; use matching acquire semantics before consumers read companion fields.
In both small-span implementations, initialize SmallBlockManager and the counts, release-publish IsSmallBlockSpan, and only then release-publish the sequential-feed offset/ABA value that activates lock-free allocation. Make the concurrent walker acquire and recheck the flag safely.
Resolve the existing ARM fence comments at lines 2787, 5368, 5454, 6827, 6977, 7265, and 8768. Observed compiler 37 output for the reviewed AtomicCmpExchange calls uses acquire/release instructions, so redundant barriers should not be added without defining the intended contract.
if (Span.BlocksInUse <> 0) or MayFreeSmallBlockSpans then
It must retain an empty span when not MayFreeSmallBlockSpans. The current code retains empty spans in normal mode and frees them when the default dmoNeverFreeSmallBlockSpans debug option is active. The x86 implementation at 6698-6702 has the intended behavior.
The reused-block corruption path can also unlock another thread's lock (FastMM5.pas:7265-7276):
Another thread may acquire the arena between those stores. The second store must be removed. These bugs also affect Win64 because this routine uses its Pascal implementation there.
Tasks:
Change the span-retention test to use not MayFreeSmallBlockSpans.
Remove the second unlock in the corruption path and use the release helper for the first one.
3. Provide a safe FullDebug stack-trace path
The FullDebug DLL does not compile natively for Arm64EC because it contains unconditional x86/x64 assembly for GetStackRange, x87, and MXCSR handling (262-273, 404-430):
Its raw tracer is also x86-specific and limited to the low 4 GB:
if (ReturnAddress > $ffff) and (ReturnAddress <= $ffffffff) thenif PByteArray(CallAddress)[3] = $E8 then{x86 CALL rel32}
See the fixed map at 342-343, address limit at 443, and x86 decoder at 461-533. Delphi 13.1 linked the review executables at 0x140000000, so their frames are rejected even before instruction decoding. FastMM currently selects the raw export by default in both the dynamic and static paths (FastMM5.pas:10836-10845, 10858-10860).
The existing 64-bit frame tracer avoids the x86 instruction decoder and is the candidate fallback, but it ignores the number returned by RtlCaptureStackBackTrace and does not clear unused entries (FastMM_FullDebugMode.dpr:277-288).
Tasks:
On CPUARM64, select GetFrameBasedStackTrace instead of the x86 raw tracer. Validate mixed Arm64EC/x64 capture with the existing x64 helper; require a native Arm64EC helper if it cannot capture native Arm frames completely.
Make the exported GetRawStackTrace delegate to the frame tracer on Arm64EC, or explicitly document that callers must not select it on Arm.
Guard x86/x64 assembly and FPU state code by CPU, or exclude it entirely from the Arm frame-based path, so a native Arm64EC FullDebug build is possible if desired.
Honor the captured-frame count and zero the unused return-address entries.
Validate capture and source/line symbolization on Windows ARM with the chosen JCL/native or existing x64 helper deployment.
4. Add correct WinARM64EC project configurations
None of the seven checked-in .dproj files defines WinARM64EC: six explicitly enumerate only Win32/Win64, while MemoryCorruptionDetectionDemo uses older TargetedPlatforms and Win32/Win64 property groups. Examples: BorlndMM.dproj:135-138 and FastMM_FullDebugMode.dproj:133-136.
The BorlndMM DEBUG source tries to retain a static FullDebug dependency through an address-only reference:
if @LogStackTrace <> nilthen
FastMM_EnterDebugMode;
LLVM/LLD --gc-sections removes this reference in an Arm64EC build, leaving no FastMM_FullDebugMode64.dll import despite the promise at BorlndMM.dpr:91-96. Defining FastMM_DebugLibraryStaticDependency retains the three intended imports and prevents premature unload.
Tasks:
Add WinARM64EC Base/Debug/Release configurations to BorlndMM, FullDebug when built natively, Usage Tracker, both debug demos, and both ShareMem projects.
Make the WinARM64EC BorlndMM DEBUG configuration define FastMM_DebugLibraryStaticDependency (or otherwise create a real static import).
Set UsePackages=false in the WinARM64EC ShareMem demo configurations; Delphi 13.1 does not support dynamic BPLs for this target. Keep System.ShareMem and deploy the Arm64EC BorlndMM DLL.
Following the repository's existing binary policy, add BorlndMM DLL/Precompiled/Arm64EC/{Debug,Release}/BorlndMM.dll. If the existing x64 FullDebug helper passes Windows ARM validation, no new FullDebug binary is required; otherwise keep a native helper in a separate Arm64EC subdirectory so it does not replace the tracked x64 DLL of the same name.
Update README/support comments: WinARM64EC requires Delphi 13.1+ and the 64-bit IDE; its output runs on Windows 11 Arm (or supported Windows Server), not x64 Windows. Document that the core uses Pascal routines on Arm, the supported FullDebug deployment/path, and the package limitation above.
Completion checks
Build the core configurations, BorlndMM Debug/Release, the supported FullDebug deployment, and applicable demos with Delphi 13.1 dccarm64ec/WinARM64EC projects.
On Windows 11 ARM, exercise allocation/free/reallocation and alignments across small, medium, and large boundaries, debug-mode transitions, pending-free lists, sequential feeds, concurrent FastMM_WalkBlocks, and memory-leak logging.
Run high-contention multithreaded allocation/free tests long enough to exercise every arena release/publication path.
Exercise memory-manager sharing with Arm64EC EXE/DLL pairs, static and delay-loaded DLL demos, and System.ShareMem/BorlndMM. Either validate mixed Arm64EC/x64 sharing or document it as unsupported.
Confirm no Win32/Win64 behavior regression, especially the two Pascal-path fixes and the small-span publication order in both implementations.
Scope notes
No CI work is requested; the repository does not currently use CI.
Matching the x86/x64 assembly paths is not required for production support. Delphi 13.1 compiles the Pascal paths to native Arm64EC code and does not support inline assembly; consider external Arm64EC assembly/static-library optimizations only later, for measured hot paths where Windows ARM benchmarks show a material improvement.
No VirtualAlloc2 change is required: FastMM allocates data, not executable/JIT pages.
No relocation-stripping problem was found.
Dynamic BPL support is a Delphi limitation, not a FastMM implementation task.
FastMM_GetMemoryMap and the Usage Tracker's existing low-4-GB view remain documented legacy limitations; they are not proposed for expansion here.
Pierre, we are preparing to support the Delphi 13.1+ Arm64EC target in our Delphi codebase (200 MB+). I asked GPT-5.6-SOL to review FastMM5's readiness for this architecture. Could you please look over the issue below and assess which parts would make sense to implement?
Summary
FastMM5's core is already source-compatible with Delphi 13.1 WinARM64EC, but it is not yet safe to claim production support. This review was made against
mastercommitade11ffwith Delphi compiler 37.0 (dccarm64ec).Verified working:
FastMM5.pascompiles and links for WinARM64EC with no defines and with each reviewed define set:FastMM_FullDebugModeWhenDLLAvailable;FastMM_DebugLibraryDynamicLoading,FastMM_FullDebugMode, andFastMM_ShareMM;FastMM_AttemptToUseSharedMM.PurePascaland exclude the core x86/x64 assembly (FastMM5.pas:199-218).VirtualAllocallocations (PAGE_NOACCESS/PAGE_READWRITE).These are compile/link results only; runtime validation on Windows ARM remains part of the work below.
1. Complete ARM memory ordering
WeakMemoryOrderingis defined but unused (FastMM5.pas:205-218). There are 31 assignments that clear core lock fields with an ordinary store, plus the FullDebug cache lock. The smallest example already documents the problem:See FastMM5.pas:2778-2789, representative arena releases at 4750, 6271, and 7265-7267, and the FullDebug release at FastMM_FullDebugMode.dpr:901.
The sequential-feed state is also published as separately ordered fields. For example:
Inc(Manager.LastMediumBlockSequentialFeedOffset.ABACounter); Manager.SequentialFeedMediumBlockSpan := NewSpan; {May need a memory fence here for ARM.} Manager.LastMediumBlockSequentialFeedOffset.IntegerValue := Offset;See FastMM5.pas:5449-5456, the corresponding small-span publication at 6963-6983, and consumers at 5546-5563 and 7091-7104.
A new small span is additionally advertised before its identifying metadata is initialized in both the x86 and Pascal paths:
FastMM_WalkBlocksmay see that flag and immediately dereference the not-yet-published manager (FastMM5.pas:6905-6912, 6958-6975, 8746-8753). Conversely, the sequential-feed offset must not be activated before the flag: once nonzero, lock-free consumers can allocate from a span that a concurrent walker may still identify as a medium block.Tasks:
TSimpleLock, all small/medium/large arena locks, and the FullDebug cache lock. Delphi's own monitor lock usesAtomicExchangefor release;System.MemoryBarrieris also available.*ManagerLocked := 0/FLock := 0release, including every early-exit and exception path.SmallBlockManagerand the counts, release-publishIsSmallBlockSpan, and only then release-publish the sequential-feed offset/ABA value that activates lock-free allocation. Make the concurrent walker acquire and recheck the flag safely.AtomicCmpExchangecalls uses acquire/release instructions, so redundant barriers should not be added without defining the intended contract.2. Fix two Pascal-path correctness bugs
The empty-small-span condition is inverted (FastMM5.pas:6728-6734):
It must retain an empty span when
not MayFreeSmallBlockSpans. The current code retains empty spans in normal mode and frees them when the defaultdmoNeverFreeSmallBlockSpansdebug option is active. The x86 implementation at 6698-6702 has the intended behavior.The reused-block corruption path can also unlock another thread's lock (FastMM5.pas:7265-7276):
Another thread may acquire the arena between those stores. The second store must be removed. These bugs also affect Win64 because this routine uses its Pascal implementation there.
Tasks:
not MayFreeSmallBlockSpans.3. Provide a safe FullDebug stack-trace path
The FullDebug DLL does not compile natively for Arm64EC because it contains unconditional x86/x64 assembly for
GetStackRange, x87, and MXCSR handling (262-273, 404-430):Its raw tracer is also x86-specific and limited to the low 4 GB:
See the fixed map at 342-343, address limit at 443, and x86 decoder at 461-533. Delphi 13.1 linked the review executables at
0x140000000, so their frames are rejected even before instruction decoding. FastMM currently selects the raw export by default in both the dynamic and static paths (FastMM5.pas:10836-10845, 10858-10860).The existing 64-bit frame tracer avoids the x86 instruction decoder and is the candidate fallback, but it ignores the number returned by
RtlCaptureStackBackTraceand does not clear unused entries (FastMM_FullDebugMode.dpr:277-288).Tasks:
CPUARM64, selectGetFrameBasedStackTraceinstead of the x86 raw tracer. Validate mixed Arm64EC/x64 capture with the existing x64 helper; require a native Arm64EC helper if it cannot capture native Arm frames completely.GetRawStackTracedelegate to the frame tracer on Arm64EC, or explicitly document that callers must not select it on Arm.4. Add correct WinARM64EC project configurations
None of the seven checked-in
.dprojfiles definesWinARM64EC: six explicitly enumerate only Win32/Win64, while MemoryCorruptionDetectionDemo uses olderTargetedPlatformsand Win32/Win64 property groups. Examples: BorlndMM.dproj:135-138 and FastMM_FullDebugMode.dproj:133-136.The BorlndMM DEBUG source tries to retain a static FullDebug dependency through an address-only reference:
LLVM/LLD
--gc-sectionsremoves this reference in an Arm64EC build, leaving noFastMM_FullDebugMode64.dllimport despite the promise at BorlndMM.dpr:91-96. DefiningFastMM_DebugLibraryStaticDependencyretains the three intended imports and prevents premature unload.Tasks:
WinARM64ECBase/Debug/Release configurations to BorlndMM, FullDebug when built natively, Usage Tracker, both debug demos, and both ShareMem projects.FastMM_DebugLibraryStaticDependency(or otherwise create a real static import).UsePackages=falsein the WinARM64EC ShareMem demo configurations; Delphi 13.1 does not support dynamic BPLs for this target. KeepSystem.ShareMemand deploy the Arm64EC BorlndMM DLL.BorlndMM DLL/Precompiled/Arm64EC/{Debug,Release}/BorlndMM.dll. If the existing x64 FullDebug helper passes Windows ARM validation, no new FullDebug binary is required; otherwise keep a native helper in a separate Arm64EC subdirectory so it does not replace the tracked x64 DLL of the same name.Completion checks
dccarm64ec/WinARM64ECprojects.FastMM_WalkBlocks, and memory-leak logging.System.ShareMem/BorlndMM. Either validate mixed Arm64EC/x64 sharing or document it as unsupported.Scope notes
VirtualAlloc2change is required: FastMM allocates data, not executable/JIT pages.FastMM_GetMemoryMapand the Usage Tracker's existing low-4-GB view remain documented legacy limitations; they are not proposed for expansion here.References
System.MemoryBarrierSystem.AtomicCmpExchange