Add wasmtime-hostmodule DSL crate #175
Add wasmtime-hostmodule DSL crate #175eira-fransham wants to merge 7 commits intobytecodealliance:mainfrom
wasmtime-hostmodule DSL crate #175Conversation
|
This looks pretty cool! I like how the macro primarily relies on traits and I also like how the macro itself is pretty small. I'm not super familiar with wasmtime so it seems a little odd there's no parts of the macro where you actually provide a module, but I'm gonna assume that's working as intended. I also think it's a really cool idea to get all this hooked up with safe code and less implicit casting. That way it's easier to get things right and avoid things like off-by-one errors. I found it pretty hard to wrap my head around the type system here unfortunately. I was thinking it might be good to try to simplify the various hierarchies of traits and how it all interacts. For example it's somewhat unfortunate to call I was thinking types like Stylistically BTW there's no need to put leading underscores in front of type variables, no need to have accidentally C++-isms leak in! |
|
@alexcrichton Thanks for the feedback! So some of the unsafe is unavoidable - You don't need to call Value isn't required just to specify the bits of a float, it's also so you can choose different types for the global at runtime. I don't know why you'd want to do that, but there's not reason to disallow it. The leading underscores within the macro bodies is to avoid them clashing with parameter names passed in from the outside - it's deliberately a violation of style guidelines, exploiting the fact that the calling code will follow the styleguide in order to avoid name clashes. Unfortunately Rust has no hygiene on type parameters, you can try removing the underscores to see what I mean. The Finally, can I ask what you mean about implicit casting? I tried to make it as unmagical as possible as far as that goes, I'm not sure I know what you mean. I'd definitely be happy to fix that though. |
|
Oh sorry I meant to say it's great to be removing unsafe code from callers by having some sort of abstraction to call through, I'd naturally assume some
This to me seems like a bit of an odd distinction? Couldn't it just be for for all types that implement
I was thinking about this recently as well, and I think that we could take this even further and remove both let mut builder = ...;
builder.add_global_i32("foo", "bar", 3);
builder.add_func("foo", "baz", |x: i32| x + 2);
let imports = builder.finish();(or something like that) That way you'd pick at runtime which method to call and you'd also have more flexibility over the structure of the imports/exports since it doesn't have to be statically determined in the code.
Does that apply to Rust? Do you have an example in Rust where bits change in meaningful ways that matter?
I understand what you mean here but you're being "hygienic" with one precise internal callsite. That doesn't seem wortwhile to sprinkle unnecessary
I guess I wouldn't disagree with that, but I would at least personally have no way to make heads or tails of this implementation. It seems like it should be more straightforward than it probably currently is and shouldn't need
Sorry I may have mistated, but I was basically saying the macro is a good thing. |
| winapi = "0.3" | ||
|
|
||
| [workspace] | ||
| members = ["./wasmtime-*"] |
There was a problem hiding this comment.
What is this line for? Is it intentional to exclude lightbeam?
There was a problem hiding this comment.
wasmtime doesn't import wasmtime-hostmodule, so we have to do this. I would be in favour of making the wasmtime root crate reexport hostmodule but I wanted to get some feedback first. I actually mention this in the first comment, although I wasn't clear enough about it:
I haven't added any code that reexports this from the wasmtime root crate but I could imagine that that would be helpful (plus, it would mean we can remove the workspace glob that I added in 1a59141).
Yes, you can use
This is fair but would make closures a lot slower and reduces the amount done at compile-time, as well as being much less convenient to use. I basically want to make this as zero-overhead as possible. My wager is that the structure of the host module (for example, the names of the exports) is very unlikely to need to change at runtime, but the values are more likely to change. I support allowing different types for globals basically only because it's trivial to do so, but I would expect it to be unlikely to be necessary in practice.
Yes, I do: http://troubles.md/posts/i-triple-equals/. I linked it in the original comment but it was definitely too easy to miss, sorry about that. That post only applies to x86 32-bit but there's nothing stopping other architectures from doing the same so you have to at least allow people to specify floats bitwise without going through the float type.
You're right, I could just use
Yeah you don't need |
|
@alexcrichton @sunfishcode Could we get some movement on this? |
|
Note that I can't actually merge here, I was just trying to help out with review. This is basically too far over my head that I can't really review it. It looks like this isn't too tied to wasmtime itself so it may be best as an external crate you maintain? |
|
@Vurich What would you think about landing this without the wasmtime-wast parts for now? Then folks can go ahead and build on it, and we can see how it works out in practice. |
|
Sure, but I feel like the likelihood of it being used is slim if it's not part of wasmtime proper. Not because it's not useful, but because people will say "oh, how do I add a host module" and they'll just look into wasmtime's source code for the answer and find the |
|
I'm looking for a way forward here. I'm not comfortable having a system which, in its current form, and with my current experience with Rust, is beyond my understanding, as the main connection point between modules. At the same time, it's clear this provides valuable functionality. I'd like to do something. I myself will need more time to learn more about parts of Rust that I haven't previously encountered, and also to play with the code and break stuff to see how it breaks when I change it, and so on. Another option is, in addition to removing the wasmtime-wasi changes, we could re-add the "spectest" module binding to a different place in the tree, and leave the current "spectest" module binding in the tree, to serve as a usage example, and also to allow us to easily compare various aspects of the manual approach with the wasmtime-hostmodule approach. I'm open to suggestions for other ways to proceed too. |
|
So I've been giving an implementation that doesn't use any type-level trickery a go, and here are the problems I'm finding:
We can avoid the second by making the function pointers that |
|
Also, if you need a good walkthrough of how type-level computation works in Rust (especially W.R.T. HLists) here's an article about it: https://beachape.com/blog/2017/03/12/gentle-intro-to-type-level-recursion-in-Rust-from-zero-to-frunk-hlist-sculpting/ |
* fix Linux `isatty` implementation * defer `WasiCtxBuilder` errors to `build()`; don't change API yet This changes the fields on the builder to types that let the various `.arg()`, `.env()`, etc methods infallible, so we don't have to worry about handling any errors till we actually build. This reduces line noise when using a builder in a downstream application. Deferring the processing of the builder fields also has the advantage of eliminating the opening and closing of `/dev/null` for the default stdio file descriptors unless they're actually used by the resulting `WasiCtx`. Unicode errors when inheriting arguments and environment variables no longer cause a panic, but instead go through `OsString`. We return `ENOTCAPABLE` at the end if there are NULs, or if UTF-8 conversion fails on Windows. This also changes the bounds on some of the methods from `AsRef<str>` to `AsRef<[u8]>`. This shouldn't break any existing code, but allows more flexibility when providing arguments. Depending on the outcome of https://github.com/WebAssembly/WASI/issues/8 we may eventually want to require these bytes be UTF-8, so we might want to revisit this later. Finally, this fixes a tiny bug that could arise if we had exactly the maximum number of file descriptors when populating the preopens. * make `WasiCtxBuilder` method types less restrictive This is a separate commit, since it changes the interface that downstream clients have to use, and therefore requires a different commit of `wasmtime` for testing. That `wasmtime` commit is currently on my private fork, so this will need to be amended before merging. Now that failures are deferred until `WasiCtxBuilder::build()`, we don't need to have `Result` types on the other methods any longer. Additionally, using `IntoIterator` rather than `Iterator` as the trait bound for these methods is slightly more general, and saves the client some typing. * enforce that arguments and environment variables are valid UTF-8 * remove now-unnecessary platform-specific OsString handling * `ENOTCAPABLE` -> `EILSEQ` for failed arg/env string conversions * fix up comment style * Apply @acfoltzer's fix to isatty on Linux to BSD
|
Does this PR still make sense now that we have wasmtime-witx? |
|
Indeed, Wasmtime's API and bindings support has changed a lot. |
Implement conditional branch joining logic for if/else branches that assign to distinct targets. Until now all conditionals in ASLp programs have assigned to the same targets on both branches. The merging logic or "phi nodes" only implemented the logic for this simpler case. The `VecMisc` instructions required for `popcnt` verification include `if` statements without `else`, and therefore fail in this step. This PR refactors the code to handle the distinct case. The change is a no-op on current specs. Updates #35 #34
Implement conditional branch joining logic for if/else branches that assign to distinct targets. Until now all conditionals in ASLp programs have assigned to the same targets on both branches. The merging logic or "phi nodes" only implemented the logic for this simpler case. The `VecMisc` instructions required for `popcnt` verification include `if` statements without `else`, and therefore fail in this step. This PR refactors the code to handle the distinct case. The change is a no-op on current specs. Updates #35 #34
…http Migrate http tests to `wasmtime-wasi-http`
This adds a crate defining a DSL for creating host modules. I debated whether to include this in
wasmtimeproper or whether to define an external crate, but I could definitely imagine that most people usingwasmtimewill want something like this in order to define host functions etc. I haven't added any code that reexports this from thewasmtimeroot crate but I could imagine that that would be helpful (plus, it would mean we can remove the workspace glob that I added in 1a59141).The DSL looks like so:
Run
cargo docfrom the crate root for more info. This isn't a proc macro, the macro does almost nothing at all. All the magic is done in the type system, as God intended.