feat: add wasm-gc support for Promise bridging, ReadableStream, and HTTP client#315
Open
duobei wants to merge 8 commits intomoonbitlang:mainfrom
Open
feat: add wasm-gc support for Promise bridging, ReadableStream, and HTTP client#315duobei wants to merge 8 commits intomoonbitlang:mainfrom
duobei wants to merge 8 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.
- Mention time module alongside timer and event loop - Show correct import usage with named exports
There was a problem hiding this comment.
Pull request overview
Adds wasm-gc target support across async JS interop and HTTP by introducing Promise/AbortController bridging, ReadableStream wrappers for byte transfer, and a fetch-based HTTP client wired via WASM imports (building on the wasm-gc timer/event-loop foundation).
Changes:
- Add wasm-gc implementations for
@js_asyncPromise bridging and ReadableStream interop, plus reference JS import objects. - Add a wasm-gc fetch-based
@http.Clientimplementation and its reference JS import object. - Extend wasm-gc runtime plumbing (event loop + timer + wall-clock time) and update package target mappings.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/js_async/wasm-gc-imports.js | Reference host import object for wasm-gc Promise + stream bridging. |
| src/js_async/readable_stream.wasm-gc.mbt | wasm-gc ReadableStream wrapper + pipe-to-stream interop via callback byte copying. |
| src/js_async/moon.pkg | Enables wasm-gc targets for new js_async implementations; narrows unimplemented targets. |
| src/js_async/js_async.wasm-gc.mbt | wasm-gc Promise/AbortController/JsError bridging via Deferred pattern and WASM imports. |
| src/internal/time/time.mbt | Implements ms_since_epoch() for wasm-gc via Date.now() WASM import. |
| src/internal/event_loop/wasm-gc-imports.js | Reference host import object for wasm-gc timer + time imports. |
| src/internal/event_loop/timer.wasm-gc.mbt | wasm-gc timer implementation using setTimeout/clearTimeout WASM imports. |
| src/internal/event_loop/moon.pkg | Registers wasm-gc event loop + timer targets; adjusts unimplemented targets. |
| src/internal/event_loop/event_loop.wasm-gc.mbt | wasm-gc cooperative rescheduling implementation. |
| src/http/wasm-gc-imports.js | Reference host import object for wasm-gc fetch client and Headers/Response helpers. |
| src/http/moon.pkg | Enables wasm-gc target for new HTTP client and for request model package file. |
| src/http/client.wasm-gc.mbt | wasm-gc fetch-based HTTP client using RawExternRef + %identity to bridge externref signatures. |
💡 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.
…TTP client Port js_async and http packages to wasm-gc target using WASM imports instead of extern "js". Key design decisions: - Deferred pattern replaces new Promise(executor) since wasm-gc cannot directly call JS functions received as parameters - Callback-based byte copying for Bytes/Uint8Array boundary crossing (one FFI call per chunk, JS loops internally) - RawExternRef + %identity for cross-package #external types in WASM import signatures (compiler restriction workaround) - JsHeaders::for_each replaces to_array (wasm-gc Array != JS Array)
9fff7bc to
da6b6b8
Compare
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.
Summary
Add wasm-gc implementations for
js_asyncandhttppackages, building on the timer/event-loop foundation from #314.js_async):Promise::wait(),run_promise(),Promise::from_async()via Deferred pattern (wasm-gc cannot directly call JS functions received as parameters)js_async): callback-based byte copying for Bytes/Uint8Array boundary crossing (one FFI call per chunk)http): fetch-based client withRawExternRef+%identityfor cross-package#externaltype limitation in WASM import signaturesNew files
src/js_async/js_async.wasm-gc.mbtsrc/js_async/readable_stream.wasm-gc.mbtsrc/http/client.wasm-gc.mbtsrc/js_async/wasm-gc-imports.jsmoonbitlang_async_js(11) +moonbitlang_async_stream(11)src/http/wasm-gc-imports.jsmoonbitlang_async_http(8)Key design decisions
new Promise(executor)— wasm-gc closures (funcref) can be called from JS, but JS functions received as parameters cannot be called from MoonBitByteson wasm-gc is a GC type (notUint8Array), so JS iterates theUint8Arrayand calls a MoonBitset_bytecallback; reverse direction uses aget_bytecallbackRawExternRef+%identity— wasm-gc compiler requires WASM import parameter/return types to be defined in the same compilation unit; cross-package#externaltypes are wrapped via local externref aliasesJsHeaders::for_eachreplacesto_array— wasm-gcArrayis not a JSArrayVerification
moon check --target wasm-gc --deny-warn✅moon check --target native --deny-warn✅moon check --target js --deny-warn✅moon test --target native— 407/415 passed (8 pre-existing IPv6/WebSocket env failures)Depends on