Skip to content

Remove type information from wasmtime::component::Val#8062

Merged
fitzgen merged 1 commit into
bytecodealliance:mainfrom
alexcrichton:untyped-val
Mar 8, 2024
Merged

Remove type information from wasmtime::component::Val#8062
fitzgen merged 1 commit into
bytecodealliance:mainfrom
alexcrichton:untyped-val

Conversation

@alexcrichton
Copy link
Copy Markdown
Member

This commit is a large refactor of the Val type as used with components to remove inherent type information present currently. The Val type is now only an AST of what a component model value looks like and cannot fully describe the type that it is without further context. For example enums only store the case that's being used, not the full set of cases.

The motivation for this commit is to make it simpler to use and construct Val, especially in the face of resources. Some problems solved here are:

  • With resources in play managing type information is not trivial and can often be surprising. For example if you learn the type of a function from a component and the instantiate the component twice the type information is not suitable to use with either function due to exported resources acquiring unique types on all instantiations.

  • Functionally it's much easier to construct values when type information is not required as it no longer requires probing various pieces for type information here and there.

  • API-wise there's far less for us to maintain as there's no need for a type-per-variant of component model types. Pieces now fit much more naturally into a Val shape without extra types.

  • Functionally when working with Val there's now only one typecheck instead of two. Previously a typecheck was performed first when a Val was created and then again later when it was passed to wasm. Now the typecheck only happens when passed to wasm.

It's worth pointing out that Val as-is is a pretty inefficient representation of component model values, for example flags are stored as a list of strings. While semantically correct this is quite inefficient for most purposes other than "get something working". To that extent my goal is to, in the future, add traits that enable building a custom user-defined Val (of sorts), but still dynamically. This should enable embedders to opt-in to a more efficient representation that relies on contextual knowledge.

This commit is a large refactor of the `Val` type as used with
components to remove inherent type information present currently. The
`Val` type is now only an AST of what a component model value looks like
and cannot fully describe the type that it is without further context.
For example enums only store the case that's being used, not the full
set of cases.

The motivation for this commit is to make it simpler to use and
construct `Val`, especially in the face of resources. Some problems
solved here are:

* With resources in play managing type information is not trivial and
  can often be surprising. For example if you learn the type of a
  function from a component and the instantiate the component twice the
  type information is not suitable to use with either function due to
  exported resources acquiring unique types on all instantiations.

* Functionally it's much easier to construct values when type
  information is not required as it no longer requires probing various
  pieces for type information here and there.

* API-wise there's far less for us to maintain as there's no need for a
  type-per-variant of component model types. Pieces now fit much more
  naturally into a `Val` shape without extra types.

* Functionally when working with `Val` there's now only one typecheck
  instead of two. Previously a typecheck was performed first when a
  `Val` was created and then again later when it was passed to wasm. Now
  the typecheck only happens when passed to wasm.

It's worth pointing out that `Val` as-is is a pretty inefficient
representation of component model values, for example flags are stored
as a list of strings. While semantically correct this is quite
inefficient for most purposes other than "get something working". To
that extent my goal is to, in the future, add traits that enable
building a custom user-defined `Val` (of sorts), but still dynamically.
This should enable embedders to opt-in to a more efficient
representation that relies on contextual knowledge.
@alexcrichton alexcrichton requested a review from dicej March 7, 2024 23:11
@alexcrichton alexcrichton requested a review from a team as a code owner March 7, 2024 23:11
@alexcrichton alexcrichton requested review from fitzgen and removed request for a team March 7, 2024 23:11
@github-actions github-actions Bot added fuzzing Issues related to our fuzzing infrastructure wasmtime:api Related to the API of the `wasmtime` crate itself labels Mar 8, 2024
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 8, 2024

Subscribe to Label Action

cc @fitzgen, @peterhuene

Details This issue or pull request has been labeled: "fuzzing", "wasmtime:api"

Thus the following users have been cc'd because of the following labels:

  • fitzgen: fuzzing
  • peterhuene: wasmtime:api

To subscribe or unsubscribe from this label, edit the .github/subscribe-to-label.json configuration file.

Learn more.

Copy link
Copy Markdown
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@fitzgen fitzgen added this pull request to the merge queue Mar 8, 2024
Merged via the queue into bytecodealliance:main with commit 9de6828 Mar 8, 2024
alexcrichton added a commit to alexcrichton/wasmtime that referenced this pull request Mar 8, 2024
This commit removes the `&Component` argument from the
`component::Linker::func_new` API. This is inspired by bytecodealliance#8062 where `Val`
holds less type information as well in addition to the realization that
type-checking happens at runtime rather than instantiation time.

This argument was originally added to mirror
`wasmtime::Linker::func_new` which takes a type argument of the core
wasm function that's being defined. Unlike core wasm, though, component
functions already have to carry along their type information as part of
function calls to handle resources correctly. This means that when a
host function is invoked the type is already known of all the parameters
and results. Additionally values are already required to be type-checked
going back into wasm, so there's less of a need to perform an additional
type-check up front.

The main consequence of this commit is that it's a bit more difficult
for embeddings to know what the expected types of results are. No type
information is provided when a host function is defined, not even
function arity. This means that when the host function is invoked it may
not know how many results are expected to be produced and of what type.
Typically though a bindings generator is used somewhere along the way so
that's expected to alleviate this issue.

Finally my hope is to enhance this "dynamic" API in the future with a
bit more information so the type information is more readily accessible
at runtime. For now though hosts will have to "simply know what to do".
github-merge-queue Bot pushed a commit that referenced this pull request Mar 8, 2024
* Remove type information from dynamic component funcs

This commit removes the `&Component` argument from the
`component::Linker::func_new` API. This is inspired by #8062 where `Val`
holds less type information as well in addition to the realization that
type-checking happens at runtime rather than instantiation time.

This argument was originally added to mirror
`wasmtime::Linker::func_new` which takes a type argument of the core
wasm function that's being defined. Unlike core wasm, though, component
functions already have to carry along their type information as part of
function calls to handle resources correctly. This means that when a
host function is invoked the type is already known of all the parameters
and results. Additionally values are already required to be type-checked
going back into wasm, so there's less of a need to perform an additional
type-check up front.

The main consequence of this commit is that it's a bit more difficult
for embeddings to know what the expected types of results are. No type
information is provided when a host function is defined, not even
function arity. This means that when the host function is invoked it may
not know how many results are expected to be produced and of what type.
Typically though a bindings generator is used somewhere along the way so
that's expected to alleviate this issue.

Finally my hope is to enhance this "dynamic" API in the future with a
bit more information so the type information is more readily accessible
at runtime. For now though hosts will have to "simply know what to do".

* Update crates/wasmtime/src/runtime/component/linker.rs

Co-authored-by: Joel Dice <joel.dice@fermyon.com>

* Fix doc links

* Fix component call benchmarks

---------

Co-authored-by: Joel Dice <joel.dice@fermyon.com>
@alexcrichton alexcrichton deleted the untyped-val branch March 11, 2024 18:22
zifeo pushed a commit to metatypedev/metatype that referenced this pull request Apr 27, 2024
)

Motivations:
* Major API changes in wasmtime that affected the type conversion
bytecodealliance/wasmtime#8062

* Major API changes in wit-bindgen (required semicolon in wit,
introduction of macro `export!(...)`)

https://github.com/bytecodealliance/wit-bindgen/releases/tag/wit-bindgen-cli-0.14.0
https://github.com/bytecodealliance/wit-bindgen/releases/tag/v0.24.0

#### Migration notes

None

<!-- 5. Readiness checklist
- [ ] The change come with new or modified tests
- [ ] Hard-to-understand functions have explanatory comments
- [ ] End-user documentation is updated to reflect the change
-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fuzzing Issues related to our fuzzing infrastructure wasmtime:api Related to the API of the `wasmtime` crate itself

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants