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
This PR moves the Windows build to Visual Studio 2026 (Clang 22 / MSVC 14.51),
switches ARM64EC from MSVC to Clang, and makes ARM64 and ARM64EC first-class
in CI: both now build the full target set and run the complete test suite on a
native ARM64 agent pool instead of being cross-compiled without tests.
ARM64 and ARM64EC had never been fully compiled (only hermes.dll / hermes-icu.dll were) and no test had ever run against them. Everything else in
this PR is what it took to get there.
Toolchain
Visual Studio 2026 is now required. build.js locates it with vswhere -version 18; there is no VS 2022 fallback.
vs2022-msvc-* CMake presets are replaced by vs2026-msvc-{x64,x86,arm64}
(generator Visual Studio 18 2026). The Ninja presets are unchanged.
ARM64EC no longer forces MSVC. It builds with Clang like every other target; --msvc still selects MSVC explicitly.
Developer documentation is updated for the new required VS version and the
correct component IDs.
ARM64EC on Clang
The MSVC force was one line; making ARM64EC actually compile and link with Clang
was the bulk of the source change. Reviewers will find one root cause behind
almost all of it:
ARM64EC deliberately advertises the x64 predefined macros
(__x86_64__, _M_X64, __SSE2__) so that x64-targeting source keeps
compiling. But Clang generates AArch64 code there and ships no x86
intrinsics — MSVC papered over this with softintrin-backed emulated
intrinsics; Clang does not. Every guard keyed on an x64 macro must therefore
also test __arm64ec__.
Guard fixes (all mechanical, all in the shape above): Support/SIMD.h now
selects NEON; VM/Profiler.h skips <x86intrin.h> / __rdtsc; llvh's Host.cpp skips the x86 cpuid / xgetbv inline asm; dragonbox drops the two _umul128 / _addcarry_u64 fast paths; folly reports FOLLY_SSE 0 / FOLLY_NEON 1 and emits an AArch64 yield for asm_volatile_pause.
Boost's fiber_winfib.hpp gets the BOOST_NO_EXCEPTIONS guards fiber_fcontext.hpp already had. ARM64EC is the only target that uses winfib,
and Clang hard-errors on throw / try under -fno-exceptions where MSVC did
not.
softintrin.lib is now linked for ARM64EC + Clang. MSVC emits a /DEFAULTLIB:softintrin directive automatically; Clang does not, so every link
failed with undefined symbol: _mm_getcsr (EC symbol) from the UCRT
floating-point objects. It is set in CMAKE_EXE/SHARED_LINKER_FLAGS so that
CMake's configure-time try_compile checks link too, per-target for the .node test addons (MODULE libraries do not inherit those flags), and via SHERMES_CC_SYSLDFLAGS for the C that shermes generates and links.
The arm64ec-pc-windows-msvc target triple is now passed regardless of host
architecture, for both the main build and shermes: on an ARM64 host Clang's
default target is plain ARM64, and non-EC objects cannot link against
ARM64EC output. The MSVC-only -arm64EC flag injection is now MSVC-only.
Static Hermes AOT: ARM64EC raw longjmp
lib/VM/StaticH.cpp is the one non-mechanical change. Static Hermes throws via setjmp/longjmp, and the CRT's longjmp goes through RtlUnwindEx. The file
already used a raw longjmp on x64 and ARM64 to avoid unwinding across DLL
boundaries, but excluded ARM64EC — where the CRT path additionally trips RtlUnwindEx's Control Flow Guard check
(FAST_FAIL_INVALID_LONGJUMP_TARGET, 0xC0000409) whenever the AOT module is
loaded into a CFG-enforced host process, which is exactly what shermes -exec
does.
The ARM64EC _sh_raw_longjmp restores the AArch64 callee-saved state from the x64-layoutjmp_buf (ARM64EC has no _M_ARM64EC branch in setjmp.h, and _M_ARM64EC implies _M_X64), following the fixed ARM64EC x64↔AArch64 register
map. The mapping, the registers that are intentionally not restored (x23/x24/x28
are never used by ARM64EC codegen) and the MxCsr slot decision are documented in
the code. This turned 22 failing AOT lit tests into a clean run.
CI and PR pipelines
The top-level pool now demands ImageOverride -equals windows-2025-1espt,
which is what moves x64, x86 and all UWP cells onto the VS 2026 image.
win32_arm64 and win32_arm64ec run on the windows-2025-1espt-arm64 pool
(single-image, so no ImageOverride) with CanRunTest: true. On a native host
both stop being cross builds, so the tools, the unit-test binaries and the lit
drivers are built, and the C++ unit tests, JS regression tests and Test262 Intl
tests all run. The pool is selected by a per-cell UseArm64Pool flag rather
than by TargetCPU, which keeps uwp_arm64 on the x64 pool — UWP binaries are
not executed by the pipeline on any architecture.
ARM64EC is tested, not just built: the test executables are themselves ARM64EC
and load the ARM64EC hermes.dll / hermes-icu.dll, so the shipped artifacts
are what gets exercised.
New .ado/ensure-node10-shim.yml, referenced first in the ARM64 jobs. ARM64
agents ship no externals\node10, but the mandatory 1ES build-retention
post-job still runs on the Node 10 task handler and would otherwise fail.
New .ado/image/README.md documenting the pool ↔ image mapping. The image
definitions themselves are shared with microsoft/v8-jsi and are not
duplicated here.
Agent environment
The new images differ from the old ones in ways the pipeline and the build
script had silently depended on:
UseNode@1 is removed. The images ship Node.js 24 on PATH; the task tried
to provision a runtime instead, which the network-isolated PR pipeline blocks.
The diagnostic file listing used ls -R, which is not on cmd.exe's PATH
on these images. It is now a pwsh step.
Git Bash discovery in build.js is fixed. It used to take the first git.exe
on PATH and rewrite cmd to bin in that path; on the new agents the first
Git is the agent's own bundled copy, which has no bash.exe, so every lit
test failed with "Running Hermes LIT tests in CMD.exe is not supported". It
now scans all git.exe locations plus the default install directories and
picks one that actually contains bash.exe.
Package contents
Because the ARM64 cells are now native builds, they also stage hermes.exe and hermesc.exe. The NuGet package therefore carries tools for every target
platform (tools\native\release\{x64,x86,arm64,arm64ec}\) instead of only x64
and x86. The existing signing patterns and nuspec globs pick them up unchanged.
Feed compliance
A repo-level NuGet.config pins package restore to the ADO feed, and the local
BinSkim download now uses that feed instead of nuget.org.
Validation
All runs are Release, on VS 2026 18.8 / MSVC 14.51.36231 / Clang 22.1.3 /
Windows SDK 10.0.28000. ARM64 and ARM64EC were validated on a native ARM64 host.
Target
Build
C++ unit tests
JS regression tests
Test262 Intl
BinSkim
x64
0 errors
16/16
3064 pass, 0 unexpected
100% (348/348)
—
x86
0 errors
16/16
3063 pass, 0 unexpected
100% (348/348)
—
arm64
0 errors
16/16
3064 pass, 0 unexpected
100% (348/348)
all rules pass
arm64ec
0 errors
16/16
3064 pass, 0 unexpected
100% (348/348)
all rules pass
JS regression runs additionally report the pre-existing 9 expected failures and
78 unsupported tests, unchanged from main.
Machine types verified with dumpbin /headers for hermes.dll, hermes-icu.dll
and the test executables: AA64 machine (ARM64) for arm64, and 8664 machine (x64) (ARM64X) for arm64ec.
Notes for reviewers
Breaking for developers: VS 2022 no longer builds this repo, and the vs2022-msvc-* presets are gone.
ARM64 CI jobs are now real builds with three test suites, so those cells take
substantially longer than the previous library-only cross builds.
Vendored-dependency edits (llvh, folly, boost, dragonbox) are kept as small,
additive __arm64ec__ guards to minimize friction when syncing upstream.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR moves the Windows build to Visual Studio 2026 (Clang 22 / MSVC 14.51),
switches ARM64EC from MSVC to Clang, and makes ARM64 and ARM64EC first-class
in CI: both now build the full target set and run the complete test suite on a
native ARM64 agent pool instead of being cross-compiled without tests.
ARM64 and ARM64EC had never been fully compiled (only
hermes.dll/hermes-icu.dllwere) and no test had ever run against them. Everything else inthis PR is what it took to get there.
Toolchain
build.jslocates it withvswhere -version 18; there is no VS 2022 fallback.vs2022-msvc-*CMake presets are replaced byvs2026-msvc-{x64,x86,arm64}(generator
Visual Studio 18 2026). The Ninja presets are unchanged.--msvcstill selects MSVC explicitly.correct component IDs.
ARM64EC on Clang
The MSVC force was one line; making ARM64EC actually compile and link with Clang
was the bulk of the source change. Reviewers will find one root cause behind
almost all of it:
Support/SIMD.hnowselects NEON;
VM/Profiler.hskips<x86intrin.h>/__rdtsc; llvh'sHost.cppskips the x86cpuid/xgetbvinline asm; dragonbox drops the two_umul128/_addcarry_u64fast paths; folly reportsFOLLY_SSE 0/FOLLY_NEON 1and emits an AArch64yieldforasm_volatile_pause.fiber_winfib.hppgets theBOOST_NO_EXCEPTIONSguardsfiber_fcontext.hppalready had. ARM64EC is the only target that uses winfib,and Clang hard-errors on
throw/tryunder-fno-exceptionswhere MSVC didnot.
softintrin.libis now linked for ARM64EC + Clang. MSVC emits a/DEFAULTLIB:softintrindirective automatically; Clang does not, so every linkfailed with
undefined symbol: _mm_getcsr (EC symbol)from the UCRTfloating-point objects. It is set in
CMAKE_EXE/SHARED_LINKER_FLAGSso thatCMake's configure-time
try_compilechecks link too, per-target for the.nodetest addons (MODULE libraries do not inherit those flags), and viaSHERMES_CC_SYSLDFLAGSfor the C thatshermesgenerates and links.arm64ec-pc-windows-msvctarget triple is now passed regardless of hostarchitecture, for both the main build and
shermes: on an ARM64 host Clang'sdefault target is plain ARM64, and non-EC objects cannot link against
ARM64EC output. The MSVC-only
-arm64ECflag injection is now MSVC-only.Static Hermes AOT: ARM64EC raw longjmp
lib/VM/StaticH.cppis the one non-mechanical change. Static Hermes throws viasetjmp/longjmp, and the CRT'slongjmpgoes throughRtlUnwindEx. The filealready used a raw longjmp on x64 and ARM64 to avoid unwinding across DLL
boundaries, but excluded ARM64EC — where the CRT path additionally trips
RtlUnwindEx's Control Flow Guard check(
FAST_FAIL_INVALID_LONGJUMP_TARGET,0xC0000409) whenever the AOT module isloaded into a CFG-enforced host process, which is exactly what
shermes -execdoes.
The ARM64EC
_sh_raw_longjmprestores the AArch64 callee-saved state from thex64-layout
jmp_buf(ARM64EC has no_M_ARM64ECbranch insetjmp.h, and_M_ARM64ECimplies_M_X64), following the fixed ARM64EC x64↔AArch64 registermap. The mapping, the registers that are intentionally not restored (x23/x24/x28
are never used by ARM64EC codegen) and the
MxCsrslot decision are documented inthe code. This turned 22 failing AOT lit tests into a clean run.
CI and PR pipelines
ImageOverride -equals windows-2025-1espt,which is what moves x64, x86 and all UWP cells onto the VS 2026 image.
win32_arm64andwin32_arm64ecrun on thewindows-2025-1espt-arm64pool(single-image, so no
ImageOverride) withCanRunTest: true. On a native hostboth stop being cross builds, so the tools, the unit-test binaries and the lit
drivers are built, and the C++ unit tests, JS regression tests and Test262 Intl
tests all run. The pool is selected by a per-cell
UseArm64Poolflag ratherthan by
TargetCPU, which keepsuwp_arm64on the x64 pool — UWP binaries arenot executed by the pipeline on any architecture.
and load the ARM64EC
hermes.dll/hermes-icu.dll, so the shipped artifactsare what gets exercised.
.ado/ensure-node10-shim.yml, referenced first in the ARM64 jobs. ARM64agents ship no
externals\node10, but the mandatory 1ES build-retentionpost-job still runs on the Node 10 task handler and would otherwise fail.
.ado/image/README.mddocumenting the pool ↔ image mapping. The imagedefinitions themselves are shared with
microsoft/v8-jsiand are notduplicated here.
Agent environment
The new images differ from the old ones in ways the pipeline and the build
script had silently depended on:
UseNode@1is removed. The images ship Node.js 24 onPATH; the task triedto provision a runtime instead, which the network-isolated PR pipeline blocks.
ls -R, which is not oncmd.exe'sPATHon these images. It is now a
pwshstep.build.jsis fixed. It used to take the firstgit.exeon
PATHand rewritecmdtobinin that path; on the new agents the firstGit is the agent's own bundled copy, which has no
bash.exe, so every littest failed with "Running Hermes LIT tests in CMD.exe is not supported". It
now scans all
git.exelocations plus the default install directories andpicks one that actually contains
bash.exe.Package contents
Because the ARM64 cells are now native builds, they also stage
hermes.exeandhermesc.exe. The NuGet package therefore carries tools for every targetplatform (
tools\native\release\{x64,x86,arm64,arm64ec}\) instead of only x64and x86. The existing signing patterns and nuspec globs pick them up unchanged.
Feed compliance
A repo-level
NuGet.configpins package restore to the ADO feed, and the localBinSkim download now uses that feed instead of nuget.org.
Validation
All runs are Release, on VS 2026 18.8 / MSVC 14.51.36231 / Clang 22.1.3 /
Windows SDK 10.0.28000. ARM64 and ARM64EC were validated on a native ARM64 host.
JS regression runs additionally report the pre-existing 9 expected failures and
78 unsupported tests, unchanged from
main.Machine types verified with
dumpbin /headersforhermes.dll,hermes-icu.dlland the test executables:
AA64 machine (ARM64)for arm64, and8664 machine (x64) (ARM64X)for arm64ec.Notes for reviewers
vs2022-msvc-*presets are gone.substantially longer than the previous library-only cross builds.
additive
__arm64ec__guards to minimize friction when syncing upstream.