Re: [whatwg/streams] Brainstorming a buffer-reusing version of writable streams (#495)

MattiasBuelens left a comment (whatwg/streams#495)

While immutable ArrayBuffers sound interesting, what we'd really need for streams is a way to *partially* detach an ArrayBuffer.

Today, when you use a BYOB reader, every `read(view)` detaches the *whole* `ArrayBuffer`. This means that any bytes in other parts of the `ArrayBuffer` are not available while the `read(view)` is pending. This is *usually* not that big of a deal, since most of the time those other bytes contain bytes from previous reads which the application is already "done" processing. However, for e.g. WebAssembly memories, those other bytes could represent the state of other parts of the program, which you definitely *do not want modified* by the readable byte streams.
* Right now, we "fix" this by making WebAssembly memories non-detachable (i.e. their `ArrayBuffer`s have a custom `[[ArrayBufferDetachKey]]`). This means you simply *cannot* use a memory's buffer for a BYOB read at all. Instead, WebAssembly programs have to [create a separate "regular" ArrayBuffer to receive the read bytes](https://github.com/MattiasBuelens/wasm-streams/blob/v0.4.2/src/readable/into_async_read.rs#L84), and then [copy those bytes back over to the WebAssembly memory afterwards](https://github.com/MattiasBuelens/wasm-streams/blob/v0.4.2/src/readable/into_async_read.rs#L118-L121). This defeats the purpose of BYOB a bit... 😅 
* With immutable `ArrayBuffer`s, we could invent a way for a WebAssembly program to "pause" itself, in such a way that its memory cannot be mutated by the program. While paused, the memory *would* be transferable, and we could pass it to `read(view)`. When the read is done, we can "unpause" the program and allow it to mutate its memory again.
* With partially-detachable `ArrayBuffer`s, we could transfer *only* the part of the WebAssembly memory that represents the read buffer, leaving the other parts usable by the program. This would allow the WebAssembly program to continue running other execution stacks (as in the [stack switching](https://github.com/WebAssembly/stack-switching) proposal) while the `read(view)` is in progress.

For "Please Use This Buffer" writers, there is an even bigger need for partially-detachable `ArrayBuffer`s. [The canonical writer loop](https://streams.spec.whatwg.org/#example-manual-write-with-backpressure) looks like this:
```javascript
const writer = writableStream.getWriter();

while (true) {
  await writer.ready;

  const bytes = new Uint8Array(writer.desiredSize);
  crypto.getRandomValues(bytes);

  // Purposefully don't await; awaiting writer.ready is enough.
  writer.write(bytes).catch(() => {});
}
```
We want to be able to start *multiple writes* at the same time, so we can fill the writable stream's queue up to its high water mark.
* Today, if those chunks are backed by the same `ArrayBuffer`, we could really only do one write at a time, since that would immediately detach the whole buffer.
* Immutable `ArrayBuffer`s wouldn't help much in this case.
* With partially-detachable `ArrayBuffer`s, we could have each write detach *only* its part of the buffer, so the remaining buffer can still be used for other writes.

There's still a lot of questions though:
* How do we "restore" the original `ArrayBuffer` after partially detaching it? Right now, `read(view)` returns a view upon the *new* `ArrayBuffer`, so users know they have to use that one from now on. However, if you had two writes in progress and they both complete separately, how do you get your "full" ArrayBuffer back without fragmenting its memory?
  * Perhaps partially detaching needs to give you some sort of "lock" object, and you have to manually release the lock when you're done with the partial `ArrayBuffer`? Maybe the partial buffer can be a special kind of `ArrayBuffer` that also represents that lock?

-- 
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/streams/issues/495#issuecomment-2662375750
You are receiving this because you are subscribed to this thread.

Message ID: <whatwg/streams/issues/495/2662375750@github.com>

Received on Monday, 17 February 2025 08:26:39 UTC