Skip to content

wasmtime-wit-bindgen: Typecheck exports at {Foo}Indices construction #10610

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

Merged
merged 4 commits into from
Apr 21, 2025

Conversation

pchickey
Copy link
Contributor

@pchickey pchickey commented Apr 17, 2025

Based on #10621

Currently, in bindgen-emitted component wrappers, the existence of export functions is checked at the construction of the {interface-name}Indices struct, but each export function is only finally typechecked on their invocation in {interface-name}::call_{func-name}.

The goal of this PR is to typecheck component exports at the construction of Indices. This is desirable because it gives a type error as early as possible - when using {interface-name}Indices by way of {interface-name}Pre, this can be performed with only an InstancePre, where the creation of an InstancePre requires only a Component and Linker, and typechecks all of the Component's imports. So, really, this is about getting exports on parity with imports.

Closes #9155 . I've worked around this with ugly hacks in embeddings for 2 different employers now and I'm not about to do it for a third.

Addition to Wasmtime

component::types::ComponentFunc has a new method typecheck<Params, Returns>(&self, instance_type: &InstanceType) -> Result<()>. The underlying typecheck performed here is the exact same one performed in Func::typed<Params, Returns>(&self, store: impl AsContextMut) -> Result<()>, except rather than the type information coming out of the store, its provided by the InstanceType.

This addition is a pub interfaces but marked #[doc(hidden)] to make them "internal", because the prior art was that InstanceType and is internal, and there are no other public interfaces for retrieving InstanceType or typechecking, with the sole exception of Func::typed. I think that we should consider making these documented public interfaces, but I'll leave that to a future PR unless requested.

Changes to wasmtime-wit-bindgen

The resources-import test case demonstates the extent of the changes: https://github.com/bytecodealliance/wasmtime/pull/10610/files#diff-0b0815115f3addd488fbf1f032466f210b9fcd29ec42f4b4a777e58f80abba16

  • Since typechecking information is available from the InstancePre (thanks to wasmtime component: get InstancePre from Instance #10621), we can unify the two variations on constructing an Indices struct: there is now a single constructor fn new<T>(_instance_pre: InstancePre<T>) -> Result<Self>. Deduplicating this eliminates both generated code and complexity in the generator.
  • The new sigular constructor uses _instance_pre.component() to lookup exports (both their index and their ComponentItem), and _instance_pre.instance_type() is used to typecheck the export.
  • Each place an export index is retrieved for a function, .get_export_index has been substituted out with .get_export, and the returned ComponentItem is checked to be a ComponentItem::ComponentFunc(func), and then func.typecheck is invoked with the type argument corresponding to the TypedFunc type parameters.

Future work

Each export func is typechecked again in its bindgen call_{funcname} function, in which the Func member owned by the typed instance {Foo} struct is cast to a TypedFunc with the specific type parameters bindgen keeps track of for each func. Since the {Foo} struct is created from a {Foo}Indices, we can guarantee that the export funcs have been typechecked against a given Linker or Store, so we could potentially elide the repeated typecheck there, and make an unchecked cast to TypedFunc instead. (TypedFuncs are not stored in the {Foo} struct at least in part because their type parameters may use &'a ... which only apply to the site of the call, and not to the storage of that member in {Foo}. The for<'a> trick only works for trait objects, not concrete types like TypedFunc.)

@github-actions github-actions bot added the wasmtime:api Related to the API of the `wasmtime` crate itself label Apr 18, 2025
pchickey added a commit that referenced this pull request Apr 18, 2025
Having refs to a pair of arcs made it less expensive to create an
InstanceType, but tied its to a borrow of the ComponentInstance
(transitively the Store) which makes some new typechecking operations
which have an AsContextMut impossible.

This has no direct benefit in this PR, but it split out of #10610
because it is more easily reviewed in isolation.
@pchickey pchickey force-pushed the pch/typecheck_componentfunc branch from 020983c to 1ccb97f Compare April 18, 2025 20:28
@pchickey pchickey changed the title Pch/typecheck componentfunc wasmtime-wit-bindgen: Move export typechecking up to {Foo}Indices creation Apr 18, 2025
@pchickey pchickey changed the title wasmtime-wit-bindgen: Move export typechecking up to {Foo}Indices creation wasmtime-wit-bindgen: Move export typechecking up to {Foo}Indices construction Apr 18, 2025
@pchickey pchickey changed the title wasmtime-wit-bindgen: Move export typechecking up to {Foo}Indices construction wasmtime-wit-bindgen: Typecheck exports at {Foo}Indices construction Apr 18, 2025
@pchickey pchickey force-pushed the pch/typecheck_componentfunc branch 2 times, most recently from 9b0d640 to 2472422 Compare April 18, 2025 23:06
@pchickey pchickey marked this pull request as ready for review April 18, 2025 23:23
@pchickey pchickey requested a review from a team as a code owner April 18, 2025 23:23
@pchickey pchickey requested review from dicej and removed request for a team April 18, 2025 23:23
@alexcrichton
Copy link
Member

alexcrichton commented Apr 21, 2025

I'm a bit concerned about #10616 and the cost implications of having more Arc-clones on lifting/lowering paths, and after reading over this more I've got a possibilty which I forget if we already talked about and/or whether you tried, so let me know if I sound like a broken record. Could the various *Indices constructors take a &InstancePre<T> instead of a &Component? That way we could refactor the internals of InstancePre<T> to hold whatever is necessary to cheaply create the InstanceType<'_> I think?

@pchickey
Copy link
Contributor Author

Thanks, I'll explore that now!

@pchickey pchickey force-pushed the pch/typecheck_componentfunc branch 2 times, most recently from b5d7be5 to a601180 Compare April 21, 2025 21:03
@pchickey pchickey changed the base branch from main to pch/instance_pre_from_instance April 21, 2025 21:07
@pchickey
Copy link
Contributor Author

I addressed the concerns above and rewrote the description accordingly.

Base automatically changed from pch/instance_pre_from_instance to main April 21, 2025 21:38
@pchickey pchickey force-pushed the pch/typecheck_componentfunc branch from a601180 to 96ccf12 Compare April 21, 2025 21:40
@pchickey pchickey enabled auto-merge April 21, 2025 21:40
@pchickey pchickey added this pull request to the merge queue Apr 21, 2025
Merged via the queue into main with commit bb77f60 Apr 21, 2025
43 checks passed
@pchickey pchickey deleted the pch/typecheck_componentfunc branch April 21, 2025 22:16
pchickey added a commit that referenced this pull request Apr 21, 2025
I know we usually do these all at the end, but I wanted to write these
up myself while I still had them fresh.
github-merge-queue bot pushed a commit that referenced this pull request Apr 22, 2025
I know we usually do these all at the end, but I wanted to write these
up myself while I still had them fresh.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wasmtime:api Related to the API of the `wasmtime` crate itself
Projects
None yet
Development

Successfully merging this pull request may close these issues.

wasmtime::component::bindgen: GuestPre should typecheck exports before instantiation
3 participants