Skip to content

Tweak future ABI to make sense independently of streams #524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

lukewagner
Copy link
Member

@lukewagner lukewagner commented Jun 2, 2025

This PR is a "part 2" of #520, allowing future.write to take up to MAX_FLAT_ASYNC_PARAMS (=4) flat params before resorting to an i32 pointer. For symmetry with async lowering, future.read is changed to take zero parameters if there is no element type.(Update: removed this part of the change)

Working through these changes in the spec highlighted the fact that framing future as "a stream that mostly takes 1 element" is too much of a stretch and requires too many hacks that overall add more confusion than simplification. Based on this, this PR decouples future from stream so that futures make sense on their own. Concretely, this results in the following tweaks to the CABI:

  • the {stream,future}.close-{readable,writable} built-ins are renamed to {stream,future}.drop-{readable,writable} both for symmetry with { resource.drop, subtask.drop } and because "close" is a stream-specific verb. The CLOSED result code is accordingly renamed DROPPED.
  • There is no "number of elements written" packed in the high 28 bits of the future.{read,write} results.
  • On successful copy, future.{read,write} return COMPLETED instead of CLOSED (which, as noted above, was renamed to DROPPED, making it especially "wrong" as the result code).
  • When a future is "done" (by a COMPLETED read/write or by the writable end receiving DROPPED), the only valid operation is future.drop-{readable,writable}. future.{read,write} or lifting traps.
  • Because there's no great reason for streams to be more permissive than futures in this regard, streams are also given a "done" state with the same trapping rules as futures, but the stream "done" state is only set when DROPPED is received.

dicej added a commit to dicej/wasm-tools that referenced this pull request Jun 6, 2025
This implements WebAssembly/component-model#524 insofar
as it affects validation, componentization, etc.

- `future.write` now accepts its payload value as up to 4 flat parameters before
  spilling to linear memory.

- `future.read` takes no payload pointer when it has no payload type

- `{stream,future}.close-{readable,writable}` have been renamed to
  `{stream,future}.drop-{readable,writable}`

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to dicej/wasm-tools that referenced this pull request Jun 6, 2025
This implements WebAssembly/component-model#524 insofar
as it affects validation, componentization, etc.

- `future.write` now accepts its payload value as up to 4 flat parameters before
  spilling to linear memory.

- `future.read` takes no payload pointer when it has no payload type

- `{stream,future}.close-{readable,writable}` have been renamed to
  `{stream,future}.drop-{readable,writable}`

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to dicej/wasm-tools that referenced this pull request Jun 6, 2025
This implements WebAssembly/component-model#524 insofar
as it affects validation, componentization, etc.

- `future.write` now accepts its payload value as up to 4 flat parameters before
  spilling to linear memory.

- `future.read` takes no payload pointer when it has no payload type

- `{stream,future}.close-{readable,writable}` have been renamed to
  `{stream,future}.drop-{readable,writable}`

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to dicej/wasm-tools that referenced this pull request Jun 6, 2025
This implements WebAssembly/component-model#524 insofar
as it affects validation, componentization, etc.

- `future.write` now accepts its payload value as up to 4 flat parameters before
  spilling to linear memory.

- `future.read` takes no payload pointer when it has no payload type

- `{stream,future}.close-{readable,writable}` have been renamed to
  `{stream,future}.drop-{readable,writable}`

Signed-off-by: Joel Dice <[email protected]>
github-merge-queue bot pushed a commit to bytecodealliance/wasm-tools that referenced this pull request Jun 6, 2025
* update `future.{write,read}` ABIs

This implements WebAssembly/component-model#524 insofar
as it affects validation, componentization, etc.

- `future.write` now accepts its payload value as up to 4 flat parameters before
  spilling to linear memory.

- `future.read` takes no payload pointer when it has no payload type

- `{stream,future}.close-{readable,writable}` have been renamed to
  `{stream,future}.drop-{readable,writable}`

Signed-off-by: Joel Dice <[email protected]>

* address CI issues

Signed-off-by: Joel Dice <[email protected]>

* address review feedback

Signed-off-by: Joel Dice <[email protected]>

* add WAST tests for various `future.{write,read}` payload sizes

Signed-off-by: Joel Dice <[email protected]>

* revert lint allow

Signed-off-by: Joel Dice <[email protected]>

* add test output

Signed-off-by: Joel Dice <[email protected]>

---------

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to dicej/wit-bindgen that referenced this pull request Jun 6, 2025
This updates the Rust generator to use the new ABI defined in
WebAssembly/component-model#524.  The C generator will
need a similar update as well.

- `future.write` now accepts its payload value as up to 4 flat parameters before spilling to linear memory.

- `future.read` takes no payload pointer when it has no payload type

- `{stream,future}.close-{readable,writable}` have been renamed to `{stream,future}.drop-{readable,writable}`

I've tested this end-to-end with `wasip3-prototyping` and will soon post a
corresponding PR there.

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to dicej/wit-bindgen that referenced this pull request Jun 6, 2025
This updates the Rust generator to use the new ABI defined in
WebAssembly/component-model#524.  The C generator will
need a similar update as well.

- `future.write` now accepts its payload value as up to 4 flat parameters before spilling to linear memory.

- `future.read` takes no payload pointer when it has no payload type

- `{stream,future}.close-{readable,writable}` have been renamed to `{stream,future}.drop-{readable,writable}`

I've tested this end-to-end with `wasip3-prototyping` and will soon post a
corresponding PR there.

Finally, `rustfmt` was complaining about using `gen` as a field name, so I took
this opportunity to address that.

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to dicej/wit-bindgen that referenced this pull request Jun 6, 2025
This updates the Rust generator to use the new ABI defined in
WebAssembly/component-model#524.  The C generator will
need a similar update as well.

- `future.write` now accepts its payload value as up to 4 flat parameters before spilling to linear memory.

- `future.read` takes no payload pointer when it has no payload type

- `{stream,future}.close-{readable,writable}` have been renamed to `{stream,future}.drop-{readable,writable}`

I've tested this end-to-end with `wasip3-prototyping` and will soon post a
corresponding PR there.

Finally, `rustfmt` was complaining about using `gen` as a field name, so I took
this opportunity to address that.

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to bytecodealliance/wasip3-prototyping that referenced this pull request Jun 6, 2025
This updates the plumbing, FACT, compilation, and runtime code to use the new
ABI defined in WebAssembly/component-model#524.

- `future.write` now accepts its payload value as up to 4 flat parameters before spilling to linear memory.

- `future.read` takes no payload pointer when it has no payload type

- `{stream,future}.close-{readable,writable}` have been renamed to `{stream,future}.drop-{readable,writable}`

This commit does _not_ address the following items:

> * There is no "number of elements written" packed in the high 28 bits of the `future.{read,write}` results.
> * On successful copy, `future.{read,write}` return `COMPLETED` instead of `CLOSED` (which, as noted above, was renamed to `DROPPED`, making it especially "wrong" as the result code).
> * When a `future` is "done" (by a `COMPLETED` read/write or by the writable end receiving `DROPPED`), the only valid operation is `future.drop-{readable,writable}`.  `future.{read,write}` or lifting traps.
> * Because there's no great reason for streams to be more permissive than futures in this regard, streams are also given a "done" state with the same trapping rules as futures, but the stream "done" state is only set when `DROPPED` is received.

I'll address those in one or more follow-up commits.

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to bytecodealliance/wasip3-prototyping that referenced this pull request Jun 6, 2025
This updates the plumbing, FACT, compilation, and runtime code to use the new
ABI defined in WebAssembly/component-model#524.

- `future.write` now accepts its payload value as up to 4 flat parameters before spilling to linear memory.

- `future.read` takes no payload pointer when it has no payload type

- `{stream,future}.close-{readable,writable}` have been renamed to `{stream,future}.drop-{readable,writable}`

This commit does _not_ address the following items:

> * There is no "number of elements written" packed in the high 28 bits of the `future.{read,write}` results.
> * On successful copy, `future.{read,write}` return `COMPLETED` instead of `CLOSED` (which, as noted above, was renamed to `DROPPED`, making it especially "wrong" as the result code).
> * When a `future` is "done" (by a `COMPLETED` read/write or by the writable end receiving `DROPPED`), the only valid operation is `future.drop-{readable,writable}`.  `future.{read,write}` or lifting traps.
> * Because there's no great reason for streams to be more permissive than futures in this regard, streams are also given a "done" state with the same trapping rules as futures, but the stream "done" state is only set when `DROPPED` is received.

I'll address those in one or more follow-up commits.

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to bytecodealliance/wasip3-prototyping that referenced this pull request Jun 6, 2025
This updates the plumbing, FACT, compilation, and runtime code to use the new
ABI defined in WebAssembly/component-model#524.

- `future.write` now accepts its payload value as up to 4 flat parameters before spilling to linear memory.

- `future.read` takes no payload pointer when it has no payload type

- `{stream,future}.close-{readable,writable}` have been renamed to `{stream,future}.drop-{readable,writable}`

This commit does _not_ address the following items:

> * There is no "number of elements written" packed in the high 28 bits of the `future.{read,write}` results.
> * On successful copy, `future.{read,write}` return `COMPLETED` instead of `CLOSED` (which, as noted above, was renamed to `DROPPED`, making it especially "wrong" as the result code).
> * When a `future` is "done" (by a `COMPLETED` read/write or by the writable end receiving `DROPPED`), the only valid operation is `future.drop-{readable,writable}`.  `future.{read,write}` or lifting traps.
> * Because there's no great reason for streams to be more permissive than futures in this regard, streams are also given a "done" state with the same trapping rules as futures, but the stream "done" state is only set when `DROPPED` is received.

I'll address those in one or more follow-up commits.

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to dicej/wit-bindgen that referenced this pull request Jun 9, 2025
This updates `wit-bindgen-rt` etc. to use (some of) the new ABI defined in
WebAssembly/component-model#524.  It covers everything
in that PR _except_ the lifting and lowering changes to `future.{read,write}`,
which we decided are more trouble than they're worth.

I've tested this end-to-end with `wasip3-prototyping` and will soon post a
corresponding PR there.

Finally, `rustfmt` was complaining about using `gen` as a field name, so I took
this opportunity to address that.

Signed-off-by: Joel Dice <[email protected]>

fix rust codegen build errors

Signed-off-by: Joel Dice <[email protected]>

snapshot

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to dicej/wit-bindgen that referenced this pull request Jun 9, 2025
This updates `wit-bindgen-rt` etc. to use (some of) the new ABI defined in
WebAssembly/component-model#524.  It covers everything
in that PR _except_ the lifting and lowering changes to `future.{read,write}`,
which we decided are more trouble than they're worth.

I've tested this end-to-end with `wasip3-prototyping` and will soon post a
corresponding PR there.

Finally, `rustfmt` was complaining about using `gen` as a field name, so I took
this opportunity to address that.

Signed-off-by: Joel Dice <[email protected]>

fix rust codegen build errors

Signed-off-by: Joel Dice <[email protected]>

snapshot

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to dicej/wasmtime that referenced this pull request Jun 9, 2025
This updates `wasmtime-environ`, `wasmtime-cranelift`, and `wasmtime` to to use
(some of) the new ABI defined in
WebAssembly/component-model#524.  It covers everything
in that PR _except_ the lifting and lowering changes to `future.{read,write}`,
which we decided are more trouble than they're worth.

Still to do: add tests for the following items (Luke has volunteered to do this):

> * When a `future` is "done" (by a `COMPLETED` read/write or by the writable end receiving `DROPPED`), the only valid operation is `future.drop-{readable,writable}`.  `future.{read,write}` or lifting traps.
> * Because there's no great reason for streams to be more permissive than futures in this regard, streams are also given a "done" state with the same trapping rules as futures, but the stream "done" state is only set when `DROPPED` is received.

Signed-off-by: Joel Dice <[email protected]>
dicej added a commit to bytecodealliance/wasip3-prototyping that referenced this pull request Jun 9, 2025
This updates `wasmtime-environ`, `wasmtime-cranelift`, and `wasmtime` to to use
(some of) the new ABI defined in
WebAssembly/component-model#524.  It covers everything
in that PR _except_ the lifting and lowering changes to `future.{read,write}`,
which we decided are more trouble than they're worth.

Still to do: add tests for the following items (Luke has volunteered to do this):

> * When a `future` is "done" (by a `COMPLETED` read/write or by the writable end receiving `DROPPED`), the only valid operation is `future.drop-{readable,writable}`.  `future.{read,write}` or lifting traps.
> * Because there's no great reason for streams to be more permissive than futures in this regard, streams are also given a "done" state with the same trapping rules as futures, but the stream "done" state is only set when `DROPPED` is received.

Signed-off-by: Joel Dice <[email protected]>
@lukewagner
Copy link
Member Author

I updated the PR to remove special case where future.write takes MAX_FLAT_ASYNC_PARAMS and future.read has zero params when there is no T, keeping future.{read,write} like stream.{read,write} in always taking a single i32 pointer. The other 5 tweaks in the bulleted list above are kept (along with the spec refactoring which splits out futures), which still seem to like an improvement, but, after some experimentation, the implementation complexity of handling flat-args for futures doesn't seem worth it.

@lukewagner lukewagner changed the title Give future.write flat params (like async imports) Tweak future ABI to make sense independently of streams Jun 9, 2025
github-merge-queue bot pushed a commit to bytecodealliance/wit-bindgen that referenced this pull request Jun 9, 2025
* update `future`/`stream` ABIs and names

This updates `wit-bindgen-rt` etc. to use (some of) the new ABI defined in
WebAssembly/component-model#524.  It covers everything
in that PR _except_ the lifting and lowering changes to `future.{read,write}`,
which we decided are more trouble than they're worth.

I've tested this end-to-end with `wasip3-prototyping` and will soon post a
corresponding PR there.

Finally, `rustfmt` was complaining about using `gen` as a field name, so I took
this opportunity to address that.

Signed-off-by: Joel Dice <[email protected]>

fix rust codegen build errors

Signed-off-by: Joel Dice <[email protected]>

snapshot

Signed-off-by: Joel Dice <[email protected]>

* skip unnecessary `ReturnCode::decode` call

Signed-off-by: Joel Dice <[email protected]>

* update C runtime tests for new ABI return codes

Signed-off-by: Joel Dice <[email protected]>

---------

Signed-off-by: Joel Dice <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants