feat(watchos): arm64_32 device support (Apple Watch Series 4-8 / SE)#5060
Merged
Conversation
added 2 commits
June 13, 2026 07:49
Real pre-S9 Apple Watches use the arm64_32 architecture (64-bit ISA, 32-bit pointers). Perry never produced a working binary for them, and an old note claimed it was architecturally impossible (NaN-boxing needs 64-bit usize). That's overstated: a 32-bit pointer fits trivially in the 48-bit NaN payload — only a few heap-range guard heuristics and literal constants assumed a 64-bit address space. Runtime (32-bit literal fixes; also benefit wasm32): - array/from_concat: (1usize << 53) saturates via try_from on 32-bit - box.rs / formatting.rs / value/dynamic_object.rs: 2^47/2^48 pointer- guard upper bounds compared in u64 so the literal isn't out-of-range for 32-bit usize (no-op on 32-bit — no addresses reach that high) The heap-min *value* guards already pick the low (0x1000) floor on target_os=watchos, so no value changes were needed there. Compile driver (opt-in via PERRY_WATCHOS_ARM64_32, so the default watchos=arm64/S9+ path is untouched): - codegen emits the C entry via PERRY_ENTRY_SYMBOL (e.g. _perry_user_main) instead of renaming _main with rust-objcopy afterwards — objcopy's MachOWriter segfaults on arm64_32 Mach-O. The link-time objcopy rename is skipped on arm64_32 accordingly. - helpers.rs / app_metadata.rs / link/mod.rs / platform_cmd.rs / bundle_apple.rs resolve the arm64_32-apple-watchos triple (codegen, auto-optimize runtime rebuild, native-lib build, swiftc, link) and a low MinimumOSVersion (PERRY_WATCHOS_MIN, default 11.0). Validated end to end: built a real game (Bloom Jump) — perry-runtime + perry-ui-watchos + engine native lib all compile for arm64_32-apple- watchos; the game links to a Mach-O 'architecture: arm64_32, platform WATCHOS, minos 11.0' with __perry_user_main and _main both defined and no undefined refs. (Testable only on real pre-S9 hardware — the simulator is arm64.) Co-authored from a parked WIP exploring this target.
proggeramlug
added a commit
that referenced
this pull request
Jun 13, 2026
…#5063) The watchOS platform page predated arm64 device support (#5060) and claimed `--target watchos` produces arm64_32. Correct and expand it: - Architecture matrix: watchos = arm64 (S9+/watchOS 26) by default, arm64_32 (Series 4-8/SE) via PERRY_WATCHOS_ARM64_32; sim is arm64-only. - Device builds are tier-3: build perry-runtime/-ui-watchos from source with nightly -Z build-std + PERRY_RUNTIME_DIR (rustup target add only covers the simulator). - Build env vars (PERRY_WATCHOS_ARM64_32 / _MIN / PERRY_ENTRY_SYMBOL) and the rust-objcopy-crashes-on-arm64_32 workaround. - App rendering modes (default UI tree vs watchos-swift-app / -game-loop). - Contributor note: 32-bit usize portability in perry-runtime. New page platforms/watchos-app-store.md: the fat arm64+arm64_32 binary, the required iOS-stub wrapper for watch-only apps, the WKWatchOnly / ITSWatchOnlyContainer / arch+minOS validation rules, the arm64-only/ minOS-27 processing stall, signing, Transporter upload, and devicectl development install (Developer Mode + DDI). Co-authored-by: Ralph Küpper <ralph@skelpo.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Why
Real Apple Watches before the Series 9 use the arm64_32 architecture (64-bit ISA, 32-bit pointers). Perry has only ever produced arm64 watch binaries (S9+/watchOS 26), and an internal note claimed arm64_32 was architecturally impossible because NaN-boxing needs a 64-bit
usize.That's overstated. A 32-bit pointer fits trivially in the 48-bit NaN payload; only a few heap-range guard heuristics and literal constants assumed a 64-bit address space. With those handled, the whole stack builds and links for arm64_32.
What
Runtime (32-bit literal fixes — also fix wasm32):
array/from_concat:(1usize << 53)saturates viatry_from(...).unwrap_or(usize::MAX)on 32-bit.box.rs,builtins/formatting.rs,value/dynamic_object.rs: the 2^47 / 2^48 pointer-guard upper bounds are compared inu64so the literal isn't out-of-range for 32-bitusize(a no-op on 32-bit — no address reaches that high).0x1000ontarget_os = "watchos", so no value changes were needed there.Compile driver (opt-in via
PERRY_WATCHOS_ARM64_32, leaving the defaultwatchos=arm64/S9+ path untouched):PERRY_ENTRY_SYMBOL(e.g._perry_user_main) instead of renaming_mainwithrust-objcopyafter the fact — objcopy'sMachOWritersegfaults on arm64_32 Mach-O (both rustup- and Homebrew-shipped llvm-objcopy). The link-time objcopy rename is skipped on arm64_32.helpers.rs/app_metadata.rs/link/mod.rs/platform_cmd.rs/bundle_apple.rsresolve thearm64_32-apple-watchostriple consistently (codegen object arch, auto-optimize runtime rebuild, native-lib build, swiftc, final link) and a lowMinimumOSVersion(PERRY_WATCHOS_MIN, default 11.0).Validation
Built a real game (Bloom Jump) end to end:
perry-runtime+perry-ui-watchos+ the engine native lib all compile forarm64_32-apple-watchos(nightly-Z build-std).architecture: arm64_32, platform WATCHOS, minos 11.0with__perry_user_mainand_mainboth defined and no undefined refs.perry-runtimestill builds clean — the runtime changes are no-ops on 64-bit.Note: arm64_32 binaries cannot run on the watchOS simulator (the sim is arm64), so on-device validation requires real pre-S9 hardware; that test is pending.
Notes / follow-ups
watchos-arm64_32target name (or a fat arm64+arm64_32 build, which would let a single App Store upload cover Series 4 through 11 and drop the watchOS-27 minimum) is a natural follow-up — happy to take direction.arm64_32-apple-watchosis tier-3: runtime libs needcargo +nightly build -Z build-std. Wiring it into release-packages.yml would letPERRY_RUNTIME_DIRusers skip the local build.