wasm: fix pointer builtins, missing -sASYNCIFY, and add main_loop() - #632
Open
nbeerbower wants to merge 1 commit into
Open
wasm: fix pointer builtins, missing -sASYNCIFY, and add main_loop()#632nbeerbower wants to merge 1 commit into
nbeerbower wants to merge 1 commit into
Conversation
Three independent fixes to the browser story, all verified against
Emscripten 4.0.7 + Node.
1. Raw pointer builtins no longer panic (or fail to link) under WASM.
builtins_ffi.c was wrapped entirely in #ifndef __EMSCRIPTEN__, which
swept up the ptr_offset / ptr_read_* / ptr_write_* / ptr_deref_*
family living at the bottom of the file. Those need neither dlopen
nor libffi -- they are address arithmetic and loads/stores over
linear memory -- so the guard now closes before them.
Four of them (ptr_offset, ptr_read_i32, ptr_write_i32,
ptr_deref_i32) had panicking stubs in wasm_shim.c; those are gone.
The other ten (ptr_read_i8/i16/u8/u16/u32/i64/u64/ptr/f32/f64) had
no stub at all, so a program touching them failed at wasm-ld with
"undefined symbol". Both cases now work.
2. --target wasm links with -sASYNCIFY.
hml_sleep() compiles to emscripten_sleep(), which only exists when
Asyncify is on. Without the flag Emscripten links a throwing stub,
so the program dies the first time it sleeps:
Please compile your program with async support in order to use
asynchronous operations like emscripten_sleep
The threaded branch already documented the flag in a comment but
never passed it. Both branches pass it now.
3. New main_loop(callback, fps) / main_loop_stop() in @stdlib/time.
Asyncify is not free: it instruments the module so it can unwind and
rewind the WASM stack at any suspend point. Measured here at ~1.3-1.4x
on CPU-bound code and +31% .wasm size.
main_loop() hands the frame callback to the host's own scheduler
(emscripten_set_main_loop_arg) instead, so a frame loop needs no
sleep() and the program can be linked with the new --no-asyncify.
It also gets the timing right: fps 0 means requestAnimationFrame,
i.e. vsync-locked and throttled in background tabs, where a sleep()
loop is not frame-locked at all.
Natively it is a paced loop that returns once stopped. Under
--target wasm it does not return, since the host owns the event loop
from that point on -- documented in stdlib/docs/time.md.
Tests: tests/wasm/wasm_pointers.hml and tests/wasm/wasm_main_loop.hml
(both run through emcc + node in the WASM suite), plus a
tests/parity/builtins/main_loop.hml parity test covering frames,
restart, fps pacing, closures and the error paths.
make test 715 passed / 2 failed (both pre-existing on main: no
libwebsockets and no IPv6 in this container), parity 321/321,
test-compiler 54/54, test-contracts 23/23, wasm-test 19 passed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsuZNWvEWeYRDTk3jzNNPL
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.
Three independent fixes to the browser story, all verified against
Emscripten 4.0.7 + Node.
Raw pointer builtins no longer panic (or fail to link) under WASM.
builtins_ffi.c was wrapped entirely in #ifndef EMSCRIPTEN, which
swept up the ptr_offset / ptr_read_* / ptr_write_* / ptr_deref_*
family living at the bottom of the file. Those need neither dlopen
nor libffi -- they are address arithmetic and loads/stores over
linear memory -- so the guard now closes before them.
Four of them (ptr_offset, ptr_read_i32, ptr_write_i32,
ptr_deref_i32) had panicking stubs in wasm_shim.c; those are gone.
The other ten (ptr_read_i8/i16/u8/u16/u32/i64/u64/ptr/f32/f64) had
no stub at all, so a program touching them failed at wasm-ld with
"undefined symbol". Both cases now work.
--target wasm links with -sASYNCIFY.
hml_sleep() compiles to emscripten_sleep(), which only exists when
Asyncify is on. Without the flag Emscripten links a throwing stub,
so the program dies the first time it sleeps:
Please compile your program with async support in order to use
asynchronous operations like emscripten_sleep
The threaded branch already documented the flag in a comment but
never passed it. Both branches pass it now.
New main_loop(callback, fps) / main_loop_stop() in @stdlib/time.
Asyncify is not free: it instruments the module so it can unwind and
rewind the WASM stack at any suspend point. Measured here at ~1.3-1.4x
on CPU-bound code and +31% .wasm size.
main_loop() hands the frame callback to the host's own scheduler
(emscripten_set_main_loop_arg) instead, so a frame loop needs no
sleep() and the program can be linked with the new --no-asyncify.
It also gets the timing right: fps 0 means requestAnimationFrame,
i.e. vsync-locked and throttled in background tabs, where a sleep()
loop is not frame-locked at all.
Natively it is a paced loop that returns once stopped. Under
--target wasm it does not return, since the host owns the event loop
from that point on -- documented in stdlib/docs/time.md.
Tests: tests/wasm/wasm_pointers.hml and tests/wasm/wasm_main_loop.hml
(both run through emcc + node in the WASM suite), plus a
tests/parity/builtins/main_loop.hml parity test covering frames,
restart, fps pacing, closures and the error paths.
make test 715 passed / 2 failed (both pre-existing on main: no
libwebsockets and no IPv6 in this container), parity 321/321,
test-compiler 54/54, test-contracts 23/23, wasm-test 19 passed.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01FsuZNWvEWeYRDTk3jzNNPL