Currently the integration tests on Windows AARCH64 are disabled for Scala Native unit tests, and FFI IT tests.
We were unable to make them work, and probably it might be a an issue with what Scala Native allows us to do.
The following is the result of Claude's investigation, memory reading, and past attempts. It might be wrong, incorrect, etc, but that would require a separate dedicated investigation and input from Scala Native mainteiners - cc @WojciechMazur
Scala Native: Windows ARM64 (aarch64) Support Gap
Summary
Scala Native cannot produce native ARM64 binaries on Windows ARM64. The build-time assembly code for delimited continuations (setjmp.S, delimcc.c) is missing a Windows ARM64 code path. Everything else in the toolchain (target triple detection, runtime platform detection, LLVM IR codegen, GC) already handles aarch64 correctly.
As a workaround, Chocolatey's LLVM package installs x86_64 LLVM on Windows ARM, so Scala Native silently falls back to producing x86_64 binaries. These run under Windows' Prism x64 emulation layer, masking the underlying gap.
Affected Files
1. nativelib/src/main/resources/scala-native/delimcc/setjmp.S
This assembly file implements scalanative_setjmp / scalanative_longjmp for delimited continuations. It has architecture-specific code paths:
| Architecture |
OS |
Status |
__x86_64__ |
Unix (__linux__, __APPLE__, __FreeBSD__) |
Implemented |
__i386__ |
Unix |
Implemented |
__aarch64__ |
Unix |
Implemented |
__x86_64__ |
Windows (_WIN64) |
Implemented |
__aarch64__ |
Windows (_WIN64) |
Missing |
The existing __aarch64__ block uses Unix calling conventions (preserves x19-x30, d8-d15 with FPCR/FPSR). The Windows ARM64 ABI differs in register preservation requirements. A dedicated __aarch64__ && _WIN64 section is needed, analogous to how __x86_64__ has separate Unix and _WIN64 sections with different register save/restore logic (Unix saves callee-saved GPRs; Windows x64 additionally saves xmm6-xmm15).
What's needed: A new assembly block handling __aarch64__ && _WIN64 that follows the Windows ARM64 ABI:
- Callee-saved GPRs: x19-x28, x29 (frame pointer), x30 (link register)
- Callee-saved FP/SIMD: d8-d15
- Stack pointer alignment: 16 bytes
- No FPCR/FPSR save (unlike Unix ARM64)
2. nativelib/src/main/resources/scala-native/delimcc.c
The __aarch64__ section defines jump buffer constants:
#define ASM_JMPBUF_SIZE 192
#define JMPBUF_STACK_POINTER_OFFSET (104 / 8)
These values match the Unix ARM64 jmp_buf layout. The Windows ARM64 CONTEXT structure has a different layout and size. A _WIN64 && __aarch64__ section with correct offsets is needed (similar to the existing _WIN64 && __x86_64__ section that has its own distinct constants).
What Already Works
These components are architecture-agnostic or already handle aarch64 on Windows:
Target triple detection (Discover.scala)
Parses clang --version output to extract the target triple. Accepts any architecture clang reports, including aarch64. No Windows-specific architecture restrictions.
Target triple parsing (TargetTriple.scala)
Supports 60+ architectures including aarch64. Platform checks (targetsWindows, targetsMsys, etc.) distinguish only by OS, not architecture.
Runtime platform detection (platform.c)
Already handles Windows ARM64:
#if defined(_M_AMD64)
arch = "amd64";
#elif defined(_X86_)
arch = "x86";
#elif defined(_M_ARM64)
arch = "aarch64";
LLVM IR code generation, GC, exception handling
Architecture-agnostic — these operate on LLVM IR and delegate architecture-specific code generation to LLVM/clang.
LLVM Toolchain Complication
The Chocolatey LLVM package (choco install llvm) on Windows ARM installs x86_64 LLVM running under x64 emulation, not native ARM64 LLVM:
This means Scala Native auto-detects x86_64-pc-windows-msvc as the target on Windows ARM, silently producing x86_64 binaries. The binaries work (under Prism emulation) but are not native ARM64.
To test native ARM64 builds, one must install the official LLVM-<version>-woa64.exe ARM64 installer directly (available since LLVM 12, see Arm Learning Paths).
Scala Native CI Coverage
Scala Native's own CI (.github/workflows/run-tests-windows.yml) only tests on windows-2022 (x86_64). No ARM64 Windows CI exists. No open issues requesting Windows ARM64 support as of April 2026.
Reproduction
On a windows-11-arm GitHub Actions runner (or any Windows ARM64 machine):
# Install ARM64-native LLVM (not via choco, which gives x64)
# Download LLVM-19.1.0-woa64.exe from https://github.com/llvm/llvm-project/releases
# Verify target is aarch64
clang --version
# Expected: Target: aarch64-pc-windows-msvc
# Attempt to compile any Scala Native project
sbt nativeLink
# Expected failure: compilation error in setjmp.S due to missing
# __aarch64__ + _WIN64 assembly path, or incorrect jmpbuf layout
# from using Unix-ABI constants on Windows
Without installing ARM64-native LLVM, choco install llvm gives x86_64 clang and Scala Native silently falls back to x86_64 code generation, masking the issue.
Proposed Fix
- Add
__aarch64__ && _WIN64 assembly section to setjmp.S following the Windows ARM64 ABI calling convention
- Add
_WIN64 && __aarch64__ jmpbuf constants to delimcc.c matching the Windows ARM64 CONTEXT layout
- Add a
windows-11-arm CI matrix entry to run-tests-windows.yml with ARM64-native LLVM
- (Optional) Update
LLVM.scala msysExtras to not hardcode x86_64 defines if targeting aarch64 under MSYS
References
Currently the integration tests on Windows AARCH64 are disabled for Scala Native unit tests, and FFI IT tests.
We were unable to make them work, and probably it might be a an issue with what Scala Native allows us to do.
The following is the result of Claude's investigation, memory reading, and past attempts. It might be wrong, incorrect, etc, but that would require a separate dedicated investigation and input from Scala Native mainteiners - cc @WojciechMazur
Scala Native: Windows ARM64 (aarch64) Support Gap
Summary
Scala Native cannot produce native ARM64 binaries on Windows ARM64. The build-time assembly code for delimited continuations (
setjmp.S,delimcc.c) is missing a Windows ARM64 code path. Everything else in the toolchain (target triple detection, runtime platform detection, LLVM IR codegen, GC) already handlesaarch64correctly.As a workaround, Chocolatey's LLVM package installs x86_64 LLVM on Windows ARM, so Scala Native silently falls back to producing x86_64 binaries. These run under Windows' Prism x64 emulation layer, masking the underlying gap.
Affected Files
1.
nativelib/src/main/resources/scala-native/delimcc/setjmp.SThis assembly file implements
scalanative_setjmp/scalanative_longjmpfor delimited continuations. It has architecture-specific code paths:__x86_64____linux__,__APPLE__,__FreeBSD__)__i386____aarch64____x86_64___WIN64)__aarch64___WIN64)The existing
__aarch64__block uses Unix calling conventions (preserves x19-x30, d8-d15 with FPCR/FPSR). The Windows ARM64 ABI differs in register preservation requirements. A dedicated__aarch64__ && _WIN64section is needed, analogous to how__x86_64__has separate Unix and_WIN64sections with different register save/restore logic (Unix saves callee-saved GPRs; Windows x64 additionally saves xmm6-xmm15).What's needed: A new assembly block handling
__aarch64__ && _WIN64that follows the Windows ARM64 ABI:2.
nativelib/src/main/resources/scala-native/delimcc.cThe
__aarch64__section defines jump buffer constants:These values match the Unix ARM64
jmp_buflayout. The Windows ARM64CONTEXTstructure has a different layout and size. A_WIN64 && __aarch64__section with correct offsets is needed (similar to the existing_WIN64 && __x86_64__section that has its own distinct constants).What Already Works
These components are architecture-agnostic or already handle
aarch64on Windows:Target triple detection (
Discover.scala)Parses
clang --versionoutput to extract the target triple. Accepts any architecture clang reports, includingaarch64. No Windows-specific architecture restrictions.Target triple parsing (
TargetTriple.scala)Supports 60+ architectures including
aarch64. Platform checks (targetsWindows,targetsMsys, etc.) distinguish only by OS, not architecture.Runtime platform detection (
platform.c)Already handles Windows ARM64:
LLVM IR code generation, GC, exception handling
Architecture-agnostic — these operate on LLVM IR and delegate architecture-specific code generation to LLVM/clang.
LLVM Toolchain Complication
The Chocolatey LLVM package (
choco install llvm) on Windows ARM installs x86_64 LLVM running under x64 emulation, not native ARM64 LLVM:choco install llvmon Windows ARM reportsTarget: x86_64-pc-windows-msvcThis means Scala Native auto-detects
x86_64-pc-windows-msvcas the target on Windows ARM, silently producing x86_64 binaries. The binaries work (under Prism emulation) but are not native ARM64.To test native ARM64 builds, one must install the official
LLVM-<version>-woa64.exeARM64 installer directly (available since LLVM 12, see Arm Learning Paths).Scala Native CI Coverage
Scala Native's own CI (
.github/workflows/run-tests-windows.yml) only tests onwindows-2022(x86_64). No ARM64 Windows CI exists. No open issues requesting Windows ARM64 support as of April 2026.Reproduction
On a
windows-11-armGitHub Actions runner (or any Windows ARM64 machine):Without installing ARM64-native LLVM,
choco install llvmgives x86_64 clang and Scala Native silently falls back to x86_64 code generation, masking the issue.Proposed Fix
__aarch64__ && _WIN64assembly section tosetjmp.Sfollowing the Windows ARM64 ABI calling convention_WIN64 && __aarch64__jmpbuf constants todelimcc.cmatching the Windows ARM64 CONTEXT layoutwindows-11-armCI matrix entry torun-tests-windows.ymlwith ARM64-native LLVMLLVM.scalamsysExtrasto not hardcode x86_64 defines if targeting aarch64 under MSYSReferences
setjmp.Sdelimcc.cplatform.cDiscover.scalaTargetTriple.scala