feat: add wasm-gc support for timer, event loop, and time#314
feat: add wasm-gc support for timer, event loop, and time#314duobei wants to merge 5 commits intomoonbitlang:mainfrom
Conversation
Add wasm-gc implementations that delegate to the JS host via WASM imports: - timer.wasm-gc.mbt: Timer using host-provided setTimeout/clearTimeout - event_loop.wasm-gc.mbt: cooperative scheduling via setTimeout(0) - time.mbt: ms_since_epoch via host-provided Date.now() - wasm-gc-imports.js: JS import object for the host to provide This enables @async.sleep(), @async.Timer, and @async.now() on the wasm-gc target when running in a JavaScript host (browser or Node.js). The WASM import convention uses "moonbitlang_async_timer" and "moonbitlang_async_time" as module names. Partial fix for moonbitlang#233 — timer/event-loop/time only; fs/process/socket remain unimplemented on wasm-gc.
There was a problem hiding this comment.
Pull request overview
Adds wasm-gc target support for the async runtime’s wall-clock time and cooperative event-loop/timer scheduling when running under a JavaScript host (browser/Node), enabling @async.sleep(), @async.Timer, and @async.now() on wasm-gc.
Changes:
- Add wasm-gc timer implementation backed by WASM imports to
setTimeout/clearTimeout. - Add wasm-gc event-loop
reschedule()implementation usingsetTimeout(0, ...)to cooperatively yield. - Implement
ms_since_epoch()for wasm-gc via a WASM import toDate.now(), keeping plainwasmas unimplemented.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/internal/time/time.mbt | Adds wasm-gc ms_since_epoch() via imported Date.now() equivalent. |
| src/internal/event_loop/wasm-gc-imports.js | Provides reference JS import modules for wasm-gc timer and time. |
| src/internal/event_loop/timer.wasm-gc.mbt | Implements Timer::new/Timer::cancel for wasm-gc using WASM imports. |
| src/internal/event_loop/event_loop.wasm-gc.mbt | Implements wasm-gc reschedule() mirroring the JS backend behavior. |
| src/internal/event_loop/moon.pkg | Wires new wasm-gc files into target selection; narrows unimplemented.mbt to wasm only. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
- Mention time module alongside timer and event loop - Show correct import usage with named exports
|
The This test passes on the main branch's latest CI run, so it appears to be a flaky test on the Windows sanitizer runner. Our changes only touch |
|
All CI checks are now passing ✅ (17/17 green). The previous failures were transient GitHub Actions infrastructure issues (auth/checkout failures) and a flaky Windows timing test — all unrelated to this PR's changes. Ready for review when you have a chance! |
|
Just some random notes here: maybe we should provide a small document telling people how to manually import stuff or where can they find the Testing seems difficult because there is currently no way for |
- Use #cfg(target) to share Timer FFI in timer.js.mbt for both js and wasm-gc backends, replacing the duplicate timer.wasm-gc.mbt - Extend event_loop.js.mbt target to [js, wasm-gc] in moon.pkg, replacing the duplicate event_loop.wasm-gc.mbt - Rename wasm-gc FFI imports to camelCase (setTimeout/clearTimeout) to match JS native names and js backend convention - Fix comment typo: untin -> until
Thanks for the review! Both suggestions adopted in the latest commit (8d0e632):
|
|
This PR itself looks good to me. But It would also be very helpful if you could share your current scenario and workflow with wasm-gc + JS stub. That would give us a good reference of what users expect from the wasm-gc + JS combination. If your intention is to share code between browser and native, you could use JS backend for the browser. Currently native support for |
|
Thanks for the review and the suggestion about JS backend — that's a fair point for browser use cases. The main scenarios where wasm-gc would differ from JS backend:
That said, these are forward-looking rather than urgent. Happy to wait for |
|
Thanks for sharing. My thought on this:
That said, wasm-gc + JS stub is still useful for scenario such as high performance computation for the Web, so we will definitely look into support for it. But for many non computation-heavy program, the JS backend of MoonBit and |
Summary
Add wasm-gc implementations for timer, event loop scheduling, and wall-clock time, enabling
@async.sleep(),@async.Timer, and@async.now()on the wasm-gc target when running in a JavaScript host (browser or Node.js).Changes
timer.wasm-gc.mbt—Timer::new/Timer::cancelvia WASM imports (setTimeout/clearTimeout)event_loop.wasm-gc.mbt— cooperativereschedule()viasetTimeout(0, ...), mirrorsevent_loop.js.mbttime.mbt—ms_since_epoch()for wasm-gc via WASM import (Date.now()), wasm target remainsabortmoon.pkg— target config for new files,unimplemented.mbtnarrowed towasmonlywasm-gc-imports.js— reference JS import object for the hostDesign
Uses WASM import syntax (
fn f() = "module" "func") instead ofextern "js"(unsupported on wasm-gc). The host must provide import modulesmoonbitlang_async_timerandmoonbitlang_async_time— seewasm-gc-imports.jsfor the reference implementation.The implementation mirrors the existing JS backend (
timer.js.mbt/event_loop.js.mbt) as closely as possible.Verification
moon checkpasses on all 4 targets: native, js, wasm, wasm-gcmoon build --target wasm-gcpassesmoon test --target native— no regressions (8 pre-existing socket test failures unrelated to this change)Limitations
moon test --target wasm-gcrequires the host to provide the import object, which the default test runner does not support