mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
### What does this PR do? <!-- **Please explain what your changes do** --> This PR should fix #14219 and implement `WebAssembly.instantiateStreaming()` and `WebAssembly.compileStreaming()`. This is a mixture of WebKit's implementation (using a helper, `handleResponseOnStreamingAction`, also containing a fast-path for blobs) and some of Node.js's validation (error messages) and its builtin-based strategy to consume chunks from streams. `src/bun.js/bindings/GlobalObject.zig` has a helper function (`getBodyStreamOrBytesForWasmStreaming`), called by C++, to validate the response (like [Node.js](214e4db60e/lib/internal/wasm_web_api.js) does) and to extract the data from the response, either as a slice/span (if we can get the data synchronously), or as a `ReadableStream` body (if the data is still pending or if it is a file/S3 `Blob`). In C++, `handleResponseOnStreamingAction` is called by `compileStreaming` and `instantiateStreaming` on the `JSC::GlobalObjectMethodTable`, just like in [WebKit](97ee3c598a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp (L517)). It calls the aforementioned Zig helper for validation and getting the response data. The data is then fed into `JSC::Wasm::StreamingCompiler`. If the data is received as a `ReadableStream`, then we call a JS builtin in `WasmStreaming.ts` to iterate over each chunk of the stream, like [Node.js](214e4db60e/lib/internal/wasm_web_api.js (L50-L52)) does. The `JSC::Wasm::StreamingCompiler` is passed into JS through a new wrapper object, `WebCore::WasmStreamingCompiler`, like [Node.js](214e4db60e/src/node_wasm_web_api.h) does. It has `addBytes`, `finalize`, `error`, and (unused) `cancel` methods to mirror the underlying JSC class. (If there's a simpler way to do this, please let me know...that would be very much appreciated) - [x] Code changes ### How did you verify your code works? <!-- **For code changes, please include automated tests**. Feel free to uncomment the line below --> I wrote automated tests (`test/js/web/fetch/wasm-streaming.test`). <!-- If JavaScript/TypeScript modules or builtins changed: --> - [x] I included a test for the new code, or existing tests cover it - [x] I ran my tests locally and they pass (`bun-debug test test/js/web/fetch/wasm-streaming.test`) <!-- If Zig files changed: --> - [x] I checked the lifetime of memory allocated to verify it's (1) freed and (2) only freed when it should be (NOTE: consumed `AnyBlob` bodies are freed, and all other allocations are in C++ and either GCed or ref-counted) - [x] I included a test for the new code, or an existing test covers it (NOTE: via JS/TS unit test) - [x] JSValue used outside of the stack is either wrapped in a JSC.Strong or is JSValueProtect'ed (NOTE: N/A, JSValue never used outside the stack) - [x] I wrote TypeScript/JavaScript tests and they pass locally (`bun-debug test test/js/web/fetch/wasm-streaming.test`) --------- Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
8.4 KiB
8.4 KiB