Replace GetHost with a function pointer#158
Conversation
Turns out we don't actually need to generate this `GetHost` trait, we can instead have it live in one location with extra documentation. There are already extra bounds on the `Host` associated type at all call-sites so there's no need to additionally have trait bounds in the trait definition, meaning the trait definition is always the same and it can move within Wasmtime. This shouldn't have any impact on any embedders today, it's just moving things around.
f8dff07 to
06c49de
Compare
GetHost with a function pointer
30b47e2 to
f16744a
Compare
|
Ok @dicej I think this is ready to go. Should be passing all tests and I've updated a few things:
I'd like to get your eyes on these changes as well, especially the ones related to |
dicej
left a comment
There was a problem hiding this comment.
Looks great; safer and way less boilerplate. Thanks for putting so much thought and effort into this!
| // TODO: once access to the store is possible in a non-async context (similar to Accessor pattern) | ||
| // we should convert this to a sync function that works w/ &mut self. | ||
| async fn finish<U>( | ||
| accessor: &mut Accessor<U, Self>, | ||
| async fn finish<T>( |
There was a problem hiding this comment.
Could we convert this to a sync function that takes a Access now, or would that require further wit-bindgen changes?
There was a problem hiding this comment.
Not yet, would require more wit-bindgen changes yeah. Would be pretty easy to do after plumbing the macro configuration, and the only real gotcha I see is that HostConcurrent is no longer a great name for the trait necessarily. That's not a huge thing though and is something we can massage over time too.
prtest:full
f16744a to
cecb7fd
Compare
|
Ok I'm going to flag this for merge with follow-up work being:
That should hopefully prove end-to-end that this is all working and should proceed upstream as well. |
Since the beginning the `T` type parameter on `Store<T>` has had no bounds on it. This was intended for maximal flexibility in terms of what embedders place within a `Store<T>` and I've personally advocated that we need to keep it this way. In the development of the WASIp3 work, however, I've at least personally reached the conclusion that this is no longer tenable and proceeding will require adding a `'static` bound to data within a store. Wasmtime today [already] carries unsafe `transmute`s to work around this lack of `'static` bound, and while the number of `unsafe` parts is relatively small right now we're still fundamentally lying to the compiler about lifetime bounds internally. With the WASIp3 async work this degree of "lying" has become even worse. Joel has written up some examples [on Zulip] about how the Rust compiler is requiring `'static` bounds in surprising ways. These patterns are cropping up quite frequently in the WASIp3 work and it's becoming particularly onerous maintaining all of the `unsafe` and ensuring that everything is in sync. In the WASIp3 repository I've additionally [prototyped a change] which would additionally practically require `T: 'static` in more locations. This change is one I plan on landing in Wasmtime in the near future and while its main motivations are for enabling WASIp3 work it is also a much nicer system than what we have today, in my opinion. Overall the cost of not having `T: 'static` on `Store<T>` is effectively becoming quite costly, in particular with respect to WASIp3 work. This is coupled with all known embedders already using `T: 'static` data within a `Store<T>` so the expectation of the impact of this change is not large. The main downside of this change as a result is that when and where to place `'static` bounds is sort of a game of whack-a-mole with the compiler. For example I changed `Store<T>` to require `'static` here, but the rest of the change is basically "hit compile until rustc says it's ok". There's not necessarily a huge amount of rhyme-or-reason to where `'static` bounds crop up, which can be surprising or difficult to work with for users. In the end I feel that this change is necessary and one we can't shy away from. If problems crop up we'll need to figure out how to thread that needle at that time, but I'm coming around to thinking that `T: 'static` is just a fundamental constraint we'll have to take on at this time. Maybe a future version of Rust that fixes some of Joel's examples (if they can be fixed, we're not sure of that) we could consider relaxing this but that's left for future work. [already]: https://github.com/bytecodealliance/wasmtime/blob/35053d6d8d1a5d4692cf636cba0c920b4a79a44b/crates/wasmtime/src/runtime/store.rs#L602-L611 [on Zulip]: https://rust-lang.zulipchat.com/#narrow/channel/122651-general/topic/.22type.20may.20not.20live.20long.20enough.22.20for.20generic.20closure/near/473862072 [prototyped a change]: bytecodealliance/wasip3-prototyping#158
* Add `T: 'static` to `Store<T> Since the beginning the `T` type parameter on `Store<T>` has had no bounds on it. This was intended for maximal flexibility in terms of what embedders place within a `Store<T>` and I've personally advocated that we need to keep it this way. In the development of the WASIp3 work, however, I've at least personally reached the conclusion that this is no longer tenable and proceeding will require adding a `'static` bound to data within a store. Wasmtime today [already] carries unsafe `transmute`s to work around this lack of `'static` bound, and while the number of `unsafe` parts is relatively small right now we're still fundamentally lying to the compiler about lifetime bounds internally. With the WASIp3 async work this degree of "lying" has become even worse. Joel has written up some examples [on Zulip] about how the Rust compiler is requiring `'static` bounds in surprising ways. These patterns are cropping up quite frequently in the WASIp3 work and it's becoming particularly onerous maintaining all of the `unsafe` and ensuring that everything is in sync. In the WASIp3 repository I've additionally [prototyped a change] which would additionally practically require `T: 'static` in more locations. This change is one I plan on landing in Wasmtime in the near future and while its main motivations are for enabling WASIp3 work it is also a much nicer system than what we have today, in my opinion. Overall the cost of not having `T: 'static` on `Store<T>` is effectively becoming quite costly, in particular with respect to WASIp3 work. This is coupled with all known embedders already using `T: 'static` data within a `Store<T>` so the expectation of the impact of this change is not large. The main downside of this change as a result is that when and where to place `'static` bounds is sort of a game of whack-a-mole with the compiler. For example I changed `Store<T>` to require `'static` here, but the rest of the change is basically "hit compile until rustc says it's ok". There's not necessarily a huge amount of rhyme-or-reason to where `'static` bounds crop up, which can be surprising or difficult to work with for users. In the end I feel that this change is necessary and one we can't shy away from. If problems crop up we'll need to figure out how to thread that needle at that time, but I'm coming around to thinking that `T: 'static` is just a fundamental constraint we'll have to take on at this time. Maybe a future version of Rust that fixes some of Joel's examples (if they can be fixed, we're not sure of that) we could consider relaxing this but that's left for future work. [already]: https://github.com/bytecodealliance/wasmtime/blob/35053d6d8d1a5d4692cf636cba0c920b4a79a44b/crates/wasmtime/src/runtime/store.rs#L602-L611 [on Zulip]: https://rust-lang.zulipchat.com/#narrow/channel/122651-general/topic/.22type.20may.20not.20live.20long.20enough.22.20for.20generic.20closure/near/473862072 [prototyped a change]: bytecodealliance/wasip3-prototyping#158 * Remove a no-longer-necessary `unsafe` block * Update test expectations * Fix gc-disabled builds
Major refactor:
GetHostentirely.HasDatatrait to replace it (see its own docs for more words)wasmtime-wit-bindgenHostand, optionally,HostConcurrentGetHostis effectively replaced with a normal function pointer, andD: HasDatais used in its stead to handle the return value.Accessorstoresfn(...), no longer has aGAccessornow has aD, but doesn't actually store it, just usesD::Data<'_>to assign a type to the function pointerAccessno longer derefs toD::Data, instead it requires aget()method. Lifetimes are subtly different which required refactoring host codeadd_to_linker_get_hostis all removed, onlyadd_to_linkerremainsbindgen!now has to worry aboutHasData, what I consider a small cost to pay for supporting all thiswit-bindgento make the concurrent/not trait split reasonable to manage