WIP: fix(runtime): preserve guest pages when discarding on macOS #478

Draft
mooki wants to merge 3 commits from mooki/Longshot:mac/guest-memory into main
Member

Why

On macOS the game's memory cannot be set up or given back correctly with the Linux code. The 512 GiB guest window is
reserved with Linux-only calls (MAP_FIXED_NOREPLACE, memfd_create, MADV_REMOVE, MADV_NOHUGEPAGE), so it does not
compile. And memory the game frees must read as zero afterwards, but Darwin's MADV_DONTNEED leaves the old bytes in
place: freed guest pages would come back holding stale data. Native Apple silicon also has 16 KiB host pages under the
game's 4 KiB ones, so a free must not take the neighbouring live 4 KiB pages with it.

What changed

  • runtime: host/posix/darwin_mem.c and darwin_mem.h (new).

    • darwin_mem_map reserves with mach_vm_map and never replaces what is already mapped there (EEXIST).
    • darwin_mem_discard zeroes exactly the bytes asked for: whole host pages inside the range get a fresh private
      mapping over the same address (mmap(MAP_FIXED), one call, so no gap another thread could take), which also returns
      their memory to the system; partial host pages at either end are zeroed in place, so the guest pages beside them keep
      their bytes.
    • darwin_mem_protect changes protection on the real host page size (16 KiB native, 4 KiB under Rosetta).
  • runtime: host/hos_main.c reserve_guest on macOS: the window at its fixed address, read-write and paged on demand,
    with a clear message when something already occupies it. hos_posix_guest_discard uses darwin_mem_discard there.

  • runtime: host/posix/win32_posix.c on macOS: VirtualAlloc, VirtualFree and VirtualProtect use the three
    functions above. They keep their 4 KiB guest-page rules: MEM_DECOMMIT rounds out to 4 KiB, MEM_RESET discards only
    the whole 4 KiB pages inside the range. Overflowing ranges and failed calls return an error instead of success.

  • runtime: host/hos_mem.c and host/hos_svc.c on macOS: a failed discard is reported (FreeMemoryPages and
    UnmapPhysicalMemory, svc 0x2D, return 0xCA01; a region discard is fatal) instead of being ignored. Ranges under a
    GPU import are still zeroed in place, as on Linux.

  • Windows and Linux: unchanged. Every change is under __APPLE__, with main's lines in #else.

  • tests: tests/test_darwin_guest_memory.py with tests/darwin_guest_memory_test.c (new; macOS only). It compiles
    darwin_mem.c with the real functions cut by text from hos_main.c, hos_mem.c, hos_svc.c, mkw_glue.c and
    win32_posix.c, and runs them on real memory:

    • the full 512 GiB reservation at its fixed address, a second one refused, its first and last pages untouched;
    • 24 helper and wrapper ranges on 16 KiB and 4 KiB hosts: zero after recommit, neighbours kept;
    • commit and free rounds at high and low addresses, the error paths, and a region that cannot be discarded;
    • 128 MiB freed: resident memory drops by it before anything reads the pages back.

    --arch arm64 --arch x86_64 runs both routes (x86_64 under Rosetta); without it, the native one. --source tests
    another tree.

  • docs: docs/development.md, "macOS guest-memory groundwork".

Flags and settings

None in the game. The test takes --arch, --source, --out and --cc.

Measurements

main: 5e072fc8c2adadba5ea610148be1c47800ba0cca (2026-11-14)
this PR: mac/guest-memory @ 9c6791454f8a29c22adcbb1591202a94ec01c1c6
Hardware: Apple M4 Max (16 CPUs, 64 GiB), macOS 26.7.1 (25G241), Apple clang 21.0.0, C11, -O2 -Wall -Wextra -Werror,
-mmacosx-version-min=14.4. No GPU, no game
Scene: none (a portability fix; its proof is the test, as CONTRIBUTING's fix row allows)
Method: tests/test_darwin_guest_memory.py --cc clang --arch arm64 --arch x86_64 on this PR and against main's source
(git archive 5e072fc8, --source), in two interleaved rounds (PR, main, PR, main). Then the full game-free suite on
this PR, compared by test name with main's on the same Mac.
How to reproduce: python -I -B tests/test_darwin_guest_memory.py --cc clang --arch arm64 --arch x86_64, then the same
with --source <a tree of main>.

main @ 5e072fc8 this PR @ 9c679145
A freed host page, arm64 (16 KiB) returns 0, the bytes stay returns 0, the bytes read zero, both neighbours kept
A freed host page, Rosetta (4 KiB) returns 0, the bytes stay returns 0, the bytes read zero, both neighbours kept
The guest window and its callers (both routes) do not compile: MAP_FIXED_NOREPLACE, MADV_REMOVE, MADV_NOHUGEPAGE, SYS_memfd_create 512 GiB reserved at 0x100000000000, a second reservation refused
Helper and wrapper ranges (do not compile) 24 of 24 on each route
128 MiB freed: resident drop before readback, arm64 / Rosetta (do not compile) 134,217,728 / 134,189,056 bytes; all zero after, neighbours kept
test exit, both rounds 1, 1 0, 0
main @ 5e072fc8:
DISCARD page=16384 rc=0 zero=0 neighbors=1
DISCARD page=4096 rc=0 zero=0 neighbors=1
host/hos_main.c:212:44: error: use of undeclared identifier 'MAP_FIXED_NOREPLACE'
host/hos_main.c:233:49: error: use of undeclared identifier 'MADV_REMOVE'
FAIL: Darwin guest memory: arm64/direct/run, arm64/integrated/compile, x86_64/direct/run, x86_64/integrated/compile

this PR @ 9c679145:
DISCARD page=16384 rc=0 zero=1 neighbors=1
RESERVATION base=0x100000000000 bytes=549755813888 page=16384 duplicate_refused=1 first_last_preserved=1
BYTE_RANGES cases=24 host_page=16384 helper_byte_exact=1 wrappers_guest_rounded=1 zero_on_recommit=1
FAILURE_PATHS overflow_unaligned_hole_readonly=refused free_svc_result=0xca01 region_fatal_exit=23
RECLAIM bytes=134217728 rss_before=136347648 rss_after=2129920 drop=134217728 cost_us=584.250
DISCARD page=4096 rc=0 zero=1 neighbors=1
RESERVATION base=0x100000000000 bytes=549755813888 page=4096 duplicate_refused=1 first_last_preserved=1
BYTE_RANGES cases=24 host_page=4096 helper_byte_exact=1 wrappers_guest_rounded=1 zero_on_recommit=1
RECLAIM bytes=134217728 rss_before=137568256 rss_after=3379200 drop=134189056 cost_us=3269.417
PASS: Darwin guest memory: arm64, x86_64

Why a fresh mapping for whole pages: on this Mac, of the ways to drop a page, only a new private mapping both read back
as zero and returned the memory at once. MADV_DONTNEED, MADV_FREE, MADV_FREE_REUSABLE, MS_KILLPAGES and
msync(MS_INVALIDATE) left the bytes; memset and MADV_ZERO zeroed them but kept them resident (and MADV_ZERO is
ENOTSUP under Rosetta). That comparison ran on the topic branch before this rebase (macos/guest-memory, 3 runs per
candidate and route); the call it chose is unchanged here.

Testing

Tested:

  • On an Apple M4 Max with macOS 26.7.1, game-free only, natively and under Rosetta, as above.

  • The test without --arch, as the suite runs it: native arm64 only, exit 0.

  • The full suite, tests/run_all.py, 6 at once, on this PR, compared by test name with main on the same Mac (the
    runner labels macOS linux):

    main @ 5e072fc8:     525 passed, 19 failed, 17 skipped in 177 s (linux, 6 at once)
    this PR @ 9c679145:  526 passed, 19 failed, 17 skipped in 174 s (linux, 6 at once)
    
    • By test name, the only difference is the new tests/test_darwin_guest_memory.py (pass): no other check changed
      status, and the same 17 are skipped.
    • The 19 failures are the same on both. They are main's own on a Mac, which the macOS port's other pull requests
      address: test_appimage_package_retry, test_collect_wide, test_control, test_framegen_resources,
      test_game_layout, test_low_memory_notice, test_mem_gate, test_mem_gate_children, test_mirror_trim,
      test_module_ids, test_oot_state_tap, test_pad_layout, test_pcache_header_read, test_pipeline_cache_file,
      test_pipeline_cache_save, test_pipeline_play_cache, test_prof_symbols, test_program_cache_cleanup,
      test_program_cache_one_variant.
    • No new crash report during this PR's run.

Not tested:

  • Windows and Linux. Nothing was built or run there. Their lines are main's, in the #else branches.
  • The game on macOS. main does not build for macOS yet; the other macOS pull requests (#420) do the rest. The
    macOS build links host/posix/darwin_mem.c into the executable and the renderer through the build-scripts pull request
    of the same wave (build(macos): discover dual-architecture toolchains and form Mach-O commands), not through this one.
  • Memory under a GPU import. Such ranges are zeroed in place, as on Linux, never remapped; no renderer ran here.
  • Two threads freeing and reusing the same range at once, memory pressure, long runs. The caller must own the
    memory and serialize its lifetime, as on Linux.
  • macOS 14.4 and an Intel Mac. Built for 14.4, run on 26.7.1 on Apple silicon only.

Needs other testers:

  • Windows (llvm-mingw) and Linux: build the host and run tests/run_all.py, expecting the same results as on main
    (request to open).
  • macOS 14.4 on Apple silicon: python -I -B tests/test_darwin_guest_memory.py --cc clang --arch arm64 --arch x86_64,
    expecting PASS (request to open).

Screenshots

Nothing on screen.

Risk and rollback

  • Only macOS takes the new code. There, a freed range now really reads zero and its memory goes back to the system; a
    failed discard is an error instead of a silent success.
  • A fresh mapping under a live GPU import would leave the GPU on the old pages. The existing import checks
    (rx_guest_imported) keep zeroing those in place, unchanged.
  • Protection on macOS works on whole host pages (16 KiB native), not on single 4 KiB guest pages.
  • No file hashed into LONGSHOT_SHADER_STAMP (nx2/build.py:1176-1182) changes.
  • Reverting the three commits is enough. There is no switch.

Reviewer notes

  • Start with darwin_mem_discard, then the 4 KiB rounding kept in VirtualAlloc(MEM_RESET) and
    VirtualFree(MEM_DECOMMIT).
  • Commits: fe35e00a and a350a531 are macos/guest-memory's 969eab22 and fb4a2c21, cherry-picked onto main
    without a conflict (the same patch ids), with the Assisted-by and Co-Authored-By trailers of this rebase added.
    9c679145 is new: main's #324 made hos_commit return int, and the test cut it by its old void head, so on
    main it stopped with a ValueError before compiling anything. It now cuts int hos_commit(.
  • With #324, FreeMemoryPages un-counts the pages (mapped_bytes) before the discard. On macOS, if that discard fails
    (the fresh mapping refused), the game gets 0xCA01 with the pages already un-counted, so the count errs low, as #324's
    own comment allows for a failed count. It is left as is: changing the order would change #324's code on every
    platform.
  • Whichever of this PR and fix(runtime): compile host jumps and pause hints on macOS arm64 merges second meets a
    one-hunk conflict in docs/development.md (both add a section after "Log levels"): keep both.
  • Written from Apple's SDK headers and manuals (mach_vm.h, sys/mman.h, madvise(2), msync(2)); nothing copied.

Issues

See #420 (the macOS port).

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main. Branched from 5e072fc8; main has moved since, and it is rebased in one sweep before ready.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above). On macOS:
    526 passed, 17 skipped, and the same 19 failures as main on this Mac, named under Testing.
  • Tested in the game, or what wasn't is named under Testing. No game run; named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). The test
    requests are still to open.
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each,
    the median reported. For a fix: the test fails on main and passes here, 2 interleaved rounds, both routes.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • A game-free test added for the fix, failing on main and passing here.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. Not built there; requested under
    Needs other testers.
  • Docs updated.
## Why On macOS the game's memory cannot be set up or given back correctly with the Linux code. The 512 GiB guest window is reserved with Linux-only calls (`MAP_FIXED_NOREPLACE`, `memfd_create`, `MADV_REMOVE`, `MADV_NOHUGEPAGE`), so it does not compile. And memory the game frees must read as zero afterwards, but Darwin's `MADV_DONTNEED` leaves the old bytes in place: freed guest pages would come back holding stale data. Native Apple silicon also has 16 KiB host pages under the game's 4 KiB ones, so a free must not take the neighbouring live 4 KiB pages with it. ## What changed - runtime: `host/posix/darwin_mem.c` and `darwin_mem.h` (new). - `darwin_mem_map` reserves with `mach_vm_map` and never replaces what is already mapped there (`EEXIST`). - `darwin_mem_discard` zeroes exactly the bytes asked for: whole host pages inside the range get a fresh private mapping over the same address (`mmap(MAP_FIXED)`, one call, so no gap another thread could take), which also returns their memory to the system; partial host pages at either end are zeroed in place, so the guest pages beside them keep their bytes. - `darwin_mem_protect` changes protection on the real host page size (16 KiB native, 4 KiB under Rosetta). - runtime: `host/hos_main.c` `reserve_guest` on macOS: the window at its fixed address, read-write and paged on demand, with a clear message when something already occupies it. `hos_posix_guest_discard` uses `darwin_mem_discard` there. - runtime: `host/posix/win32_posix.c` on macOS: `VirtualAlloc`, `VirtualFree` and `VirtualProtect` use the three functions above. They keep their 4 KiB guest-page rules: `MEM_DECOMMIT` rounds out to 4 KiB, `MEM_RESET` discards only the whole 4 KiB pages inside the range. Overflowing ranges and failed calls return an error instead of success. - runtime: `host/hos_mem.c` and `host/hos_svc.c` on macOS: a failed discard is reported (`FreeMemoryPages` and `UnmapPhysicalMemory`, svc 0x2D, return 0xCA01; a region discard is fatal) instead of being ignored. Ranges under a GPU import are still zeroed in place, as on Linux. - Windows and Linux: unchanged. Every change is under `__APPLE__`, with `main`'s lines in `#else`. - tests: `tests/test_darwin_guest_memory.py` with `tests/darwin_guest_memory_test.c` (new; macOS only). It compiles `darwin_mem.c` with the real functions cut by text from `hos_main.c`, `hos_mem.c`, `hos_svc.c`, `mkw_glue.c` and `win32_posix.c`, and runs them on real memory: - the full 512 GiB reservation at its fixed address, a second one refused, its first and last pages untouched; - 24 helper and wrapper ranges on 16 KiB and 4 KiB hosts: zero after recommit, neighbours kept; - commit and free rounds at high and low addresses, the error paths, and a region that cannot be discarded; - 128 MiB freed: resident memory drops by it before anything reads the pages back. `--arch arm64 --arch x86_64` runs both routes (x86_64 under Rosetta); without it, the native one. `--source` tests another tree. - docs: `docs/development.md`, "macOS guest-memory groundwork". ## Flags and settings None in the game. The test takes `--arch`, `--source`, `--out` and `--cc`. ## Measurements main: `5e072fc8c2adadba5ea610148be1c47800ba0cca` (2026-11-14) this PR: `mac/guest-memory` @ `9c6791454f8a29c22adcbb1591202a94ec01c1c6` Hardware: Apple M4 Max (16 CPUs, 64 GiB), macOS 26.7.1 (25G241), Apple clang 21.0.0, C11, `-O2 -Wall -Wextra -Werror`, `-mmacosx-version-min=14.4`. No GPU, no game Scene: none (a portability fix; its proof is the test, as CONTRIBUTING's `fix` row allows) Method: `tests/test_darwin_guest_memory.py --cc clang --arch arm64 --arch x86_64` on this PR and against `main`'s source (`git archive 5e072fc8`, `--source`), in two interleaved rounds (PR, main, PR, main). Then the full game-free suite on this PR, compared by test name with `main`'s on the same Mac. How to reproduce: `python -I -B tests/test_darwin_guest_memory.py --cc clang --arch arm64 --arch x86_64`, then the same with `--source <a tree of main>`. | | main @ 5e072fc8 | this PR @ 9c679145 | |---|---|---| | A freed host page, arm64 (16 KiB) | returns 0, the bytes stay | returns 0, the bytes read zero, both neighbours kept | | A freed host page, Rosetta (4 KiB) | returns 0, the bytes stay | returns 0, the bytes read zero, both neighbours kept | | The guest window and its callers (both routes) | do not compile: `MAP_FIXED_NOREPLACE`, `MADV_REMOVE`, `MADV_NOHUGEPAGE`, `SYS_memfd_create` | 512 GiB reserved at 0x100000000000, a second reservation refused | | Helper and wrapper ranges | (do not compile) | 24 of 24 on each route | | 128 MiB freed: resident drop before readback, arm64 / Rosetta | (do not compile) | 134,217,728 / 134,189,056 bytes; all zero after, neighbours kept | | test exit, both rounds | 1, 1 | 0, 0 | ``` main @ 5e072fc8: DISCARD page=16384 rc=0 zero=0 neighbors=1 DISCARD page=4096 rc=0 zero=0 neighbors=1 host/hos_main.c:212:44: error: use of undeclared identifier 'MAP_FIXED_NOREPLACE' host/hos_main.c:233:49: error: use of undeclared identifier 'MADV_REMOVE' FAIL: Darwin guest memory: arm64/direct/run, arm64/integrated/compile, x86_64/direct/run, x86_64/integrated/compile this PR @ 9c679145: DISCARD page=16384 rc=0 zero=1 neighbors=1 RESERVATION base=0x100000000000 bytes=549755813888 page=16384 duplicate_refused=1 first_last_preserved=1 BYTE_RANGES cases=24 host_page=16384 helper_byte_exact=1 wrappers_guest_rounded=1 zero_on_recommit=1 FAILURE_PATHS overflow_unaligned_hole_readonly=refused free_svc_result=0xca01 region_fatal_exit=23 RECLAIM bytes=134217728 rss_before=136347648 rss_after=2129920 drop=134217728 cost_us=584.250 DISCARD page=4096 rc=0 zero=1 neighbors=1 RESERVATION base=0x100000000000 bytes=549755813888 page=4096 duplicate_refused=1 first_last_preserved=1 BYTE_RANGES cases=24 host_page=4096 helper_byte_exact=1 wrappers_guest_rounded=1 zero_on_recommit=1 RECLAIM bytes=134217728 rss_before=137568256 rss_after=3379200 drop=134189056 cost_us=3269.417 PASS: Darwin guest memory: arm64, x86_64 ``` Why a fresh mapping for whole pages: on this Mac, of the ways to drop a page, only a new private mapping both read back as zero and returned the memory at once. `MADV_DONTNEED`, `MADV_FREE`, `MADV_FREE_REUSABLE`, `MS_KILLPAGES` and `msync(MS_INVALIDATE)` left the bytes; `memset` and `MADV_ZERO` zeroed them but kept them resident (and `MADV_ZERO` is `ENOTSUP` under Rosetta). That comparison ran on the topic branch before this rebase (`macos/guest-memory`, 3 runs per candidate and route); the call it chose is unchanged here. ## Testing **Tested:** - On an Apple M4 Max with macOS 26.7.1, game-free only, natively and under Rosetta, as above. - The test without `--arch`, as the suite runs it: native arm64 only, exit 0. - The full suite, `tests/run_all.py`, 6 at once, on this PR, compared by test name with `main` on the same Mac (the runner labels macOS `linux`): ``` main @ 5e072fc8: 525 passed, 19 failed, 17 skipped in 177 s (linux, 6 at once) this PR @ 9c679145: 526 passed, 19 failed, 17 skipped in 174 s (linux, 6 at once) ``` - **By test name**, the only difference is the new `tests/test_darwin_guest_memory.py` (pass): no other check changed status, and the same 17 are skipped. - **The 19 failures are the same on both.** They are `main`'s own on a Mac, which the macOS port's other pull requests address: `test_appimage_package_retry`, `test_collect_wide`, `test_control`, `test_framegen_resources`, `test_game_layout`, `test_low_memory_notice`, `test_mem_gate`, `test_mem_gate_children`, `test_mirror_trim`, `test_module_ids`, `test_oot_state_tap`, `test_pad_layout`, `test_pcache_header_read`, `test_pipeline_cache_file`, `test_pipeline_cache_save`, `test_pipeline_play_cache`, `test_prof_symbols`, `test_program_cache_cleanup`, `test_program_cache_one_variant`. - No new crash report during this PR's run. **Not tested:** - **Windows and Linux.** Nothing was built or run there. Their lines are `main`'s, in the `#else` branches. - **The game on macOS.** `main` does not build for macOS yet; the other macOS pull requests (#420) do the rest. The macOS build links `host/posix/darwin_mem.c` into the executable and the renderer through the build-scripts pull request of the same wave (`build(macos): discover dual-architecture toolchains and form Mach-O commands`), not through this one. - **Memory under a GPU import.** Such ranges are zeroed in place, as on Linux, never remapped; no renderer ran here. - **Two threads freeing and reusing the same range at once, memory pressure, long runs.** The caller must own the memory and serialize its lifetime, as on Linux. - **macOS 14.4** and an Intel Mac. Built for 14.4, run on 26.7.1 on Apple silicon only. **Needs other testers:** - Windows (llvm-mingw) and Linux: build the host and run `tests/run_all.py`, expecting the same results as on `main` (request to open). - macOS 14.4 on Apple silicon: `python -I -B tests/test_darwin_guest_memory.py --cc clang --arch arm64 --arch x86_64`, expecting `PASS` (request to open). ## Screenshots Nothing on screen. ## Risk and rollback - Only macOS takes the new code. There, a freed range now really reads zero and its memory goes back to the system; a failed discard is an error instead of a silent success. - A fresh mapping under a live GPU import would leave the GPU on the old pages. The existing import checks (`rx_guest_imported`) keep zeroing those in place, unchanged. - Protection on macOS works on whole host pages (16 KiB native), not on single 4 KiB guest pages. - No file hashed into `LONGSHOT_SHADER_STAMP` (`nx2/build.py:1176-1182`) changes. - Reverting the three commits is enough. There is no switch. ## Reviewer notes - Start with `darwin_mem_discard`, then the 4 KiB rounding kept in `VirtualAlloc(MEM_RESET)` and `VirtualFree(MEM_DECOMMIT)`. - Commits: `fe35e00a` and `a350a531` are `macos/guest-memory`'s `969eab22` and `fb4a2c21`, cherry-picked onto `main` without a conflict (the same patch ids), with the `Assisted-by` and `Co-Authored-By` trailers of this rebase added. `9c679145` is new: `main`'s #324 made `hos_commit` return `int`, and the test cut it by its old `void` head, so on `main` it stopped with a `ValueError` before compiling anything. It now cuts `int hos_commit(`. - With #324, `FreeMemoryPages` un-counts the pages (`mapped_bytes`) before the discard. On macOS, if that discard fails (the fresh mapping refused), the game gets 0xCA01 with the pages already un-counted, so the count errs low, as #324's own comment allows for a failed count. It is left as is: changing the order would change #324's code on every platform. - Whichever of this PR and `fix(runtime): compile host jumps and pause hints on macOS arm64` merges second meets a one-hunk conflict in `docs/development.md` (both add a section after "Log levels"): keep both. - Written from Apple's SDK headers and manuals (`mach_vm.h`, `sys/mman.h`, madvise(2), msync(2)); nothing copied. ## Issues See #420 (the macOS port). ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [ ] Rebased on current `main`. Branched from 5e072fc8; main has moved since, and it is rebased in one sweep before ready. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). On macOS: 526 passed, 17 skipped, and the same 19 failures as `main` on this Mac, named under Testing. - [x] Tested in the game, or what wasn't is named under Testing. No game run; named under Testing. - [ ] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). The test requests are still to open. - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. For a `fix`: the test fails on `main` and passes here, 2 interleaved rounds, both routes. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] A game-free test added for the fix, failing on `main` and passing here. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. Not built there; requested under Needs other testers. - [x] Docs updated.
Reserve the fixed guest window with a non-overwriting Mach mapping. Reclaim
complete owned host pages with fresh anonymous mappings and zero only the
partial-page edges, preserving adjacent 4 KiB guest pages on 16 KiB hosts.
Use the actual host granule for non-guest allocation/protection and report
macOS discard failures instead of returning success.

Add game-free source-linked arm64/Rosetta tests covering collisions, repeated
free/recommit, unaligned ranges, failure paths and resident-memory reduction.
Keep Linux and Windows paths unchanged. Build-list integration is separate.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Keep the POSIX layer's outward 4 KiB MEM_DECOMMIT and inward 4 KiB MEM_RESET
contracts above the byte-exact Darwin helper. Check arithmetic before rounding,
and keep separate real-memory assertions for helper and wrapper ranges.

Default the Darwin regression test to the native architecture. Both CPU routes
remain explicitly selectable for acceptance without requiring Rosetta or arm64
execution from every ordinary macOS suite run.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
test(runtime): cut main's int hos_commit in the Darwin guest-memory test
All checks were successful
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 5s
CI / Conventional Commit title (pull_request) Successful in 5s
CI / Workflow lint (actionlint) (pull_request) Successful in 9s
Third-party parts / As their notes say (pull_request) Successful in 15s
Website / Website on Cloudflare (pull_request_target) Has been skipped
9c6791454f
Main's #324 (a4c77174) made hos_commit in host/mkw_glue.c return whether
the range was committed, so its definition now starts "int hos_commit(".
The Darwin guest-memory test cut the function by its old "void" head and
stopped with a ValueError on main's source, on this branch and on main alike,
before compiling anything. Cut it by the new head.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
All checks were successful
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 5s
CI / Conventional Commit title (pull_request) Successful in 5s
CI / Workflow lint (actionlint) (pull_request) Successful in 9s
Third-party parts / As their notes say (pull_request) Successful in 15s
Website / Website on Cloudflare (pull_request_target) Has been skipped
This pull request is marked as a work in progress.
This branch is out-of-date with the base branch
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'mac/guest-memory:mooki-mac/guest-memory'
git switch 'mooki-mac/guest-memory'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!478
No description provided.