Skip to content
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

Move Wasmtime for .NET to the Wasmtime repo. #624

Merged
merged 3 commits into from
Nov 26, 2019

Conversation

peterhuene
Copy link
Member

This moves the Wasmtime for .NET implementation to the Wasmtime repo.

Wasmtime for .NET is a binding of the Wasmtime API for use in .NET.

The previous location for the implementation was here.

This moves the Wasmtime for .NET implementation to the Wasmtime repo.

Wasmtime for .NET is a binding of the Wasmtime API for use in .NET.
@peterhuene peterhuene force-pushed the wasmtime-for-dotnet branch 2 times, most recently from 5a59617 to 623ac87 Compare November 23, 2019 03:03
@peterhuene
Copy link
Member Author

When we merge this, I'll retire the "wasmtime.net" repo and update the docs so that everything points to bytecodealliance/wasmtime (we'll keep the GitHub pages on my personal repo address for now).

Copy link
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

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

Nice! I won't really pretend to know anything about .NET though or claim any ability to review C# code. Some notes I'd have though are:

  • This differs from the Python extension quite a lot, in that this one is extremely fleshed out and well tested. The Python extension also currently only supports "integration through the module system" whereas this extension is more about exposing the API of the wasmtime crate itself to C#. (not sure if it makes sense to have a "module system integration" hook for C#). We should make sure to file an issue to getting the Python extension on par with this C# one (exposing API surface area and all that). I think this is my main note about this PR, which of course is not a blocker, just something for us to get to :)

  • Does the .NET extension work by using the cdylib output of the wasmtime api crate? Or does it build its own custom cdylib?

  • It'd be awesome if we could avoid checking in lots of *.wasm files, would it be possible to tweak the wasmtime API to either take text or binary? (I'm not sure if this was part of the C# extension or baked into the API itself)

  • Out of curiosity, and this is equally applicable to the Python extension, do you think that this'll cause much review churn/burden? I suspect most of us are pretty unfamiliar with C#, but I also suspect that the APIs used here are pretty stable, so I doubt it'll be a problem. Curious what you think though!

crates/misc/dotnet/docs/articles/intro.md Show resolved Hide resolved
crates/misc/dotnet/docs/articles/intro.md Show resolved Hide resolved
@peterhuene
Copy link
Member Author

peterhuene commented Nov 25, 2019

This differs from the Python extension quite a lot, in that this one is extremely fleshed out and well tested. The Python extension also currently only supports "integration through the module system" whereas this extension is more about exposing the API of the wasmtime crate itself to C#. (not sure if it makes sense to have a "module system integration" hook for C#). We should make sure to file an issue to getting the Python extension on par with this C# one (exposing API surface area and all that). I think this is my main note about this PR, which of course is not a blocker, just something for us to get to :)

Unfortunately C# is a statically-typed compiled language that has no analogous concept for hooking up the underlying machinery as an "imported module" the way the Python extension works.

The closest C# has is the dynamic type, which is just compiler magic for runtime dispatch based on reflection. The C# implementation is actually leveraging this when you call Module.CreateInstance as it returns a dynamic so users can call into Wasm exports in a more natural way.

I'd love to make this easier for .NET users, so I'm totally open to changing the API in any way that would help.

Does the .NET extension work by using the cdylib output of the wasmtime api crate? Or does it build its own custom cdylib?

The former. The .NET API works via "P/Invoke" (which is .NET's term for FFI) and it loads the wasmtime library to invoke the C API directly.

It'd be awesome if we could avoid checking in lots of *.wasm files, would it be possible to tweak the wasmtime API to either take text or binary? (I'm not sure if this was part of the C# extension or baked into the API itself)

Right now we're using the standard C API which operates just on Wasm blobs, so if we want to continue to stick to the API, we'd have to get that approved (I wager there might be some push back as not all runtime implementations may want to have to also compile wats).

Out of curiosity, and this is equally applicable to the Python extension, do you think that this'll cause much review churn/burden? I suspect most of us are pretty unfamiliar with C#, but I also suspect that the APIs used here are pretty stable, so I doubt it'll be a problem. Curious what you think though!

I don't think there will be a lot of churn here yet. There's still some feature work to do (namely supporting tables, reference types [when they place nice with a host GC], and interface types), though. Some of that work will likely require changes to the C API to implement. @yurydelendik mentioned that he has at least some familiarity with C#, so when there are smaller PRs to review that aren't shuffling around lots of files he might be able to assist.

The benefit of having this code live near the Wasmtime library is that it's much easier to test with local Wasmtime changes and gives additional test coverage of the C API in CI.

@alexcrichton
Copy link
Member

Ok thanks for all the info! To be clear I'd personally be fine with this landing at any time.

This does mean though that the Python extension as-is is significantly different from the .NET extension (and not in great ways, .NET seems much better I think). We'll want to resolve these differences, like:

  • The Python extension probably shouldn't use the pyo3 project, but rather it should use libwasmtime.so and otherwise be written in more Python.
  • The Python extension should provide a programmatic API for working with wasm modules in the same way that this .NET module does. I think Python, since it works, still wants to support the import foo where foo.wasm exists, but that may want to be an opt-in like import wasmtime.magic or something like that where import wasmtime gives you the general package of functionality.
  • We'll want to figure out WASI, either with something wasmtime-specific or by pushing on the standards work to get WASI into the C API somewhere.

For *.wat vs *.wasm I'm not sure if we want to follow the C "spec" too closely or rather try out our own extensions to it, but this seems like something that's going to be awfully common and would be pretty nice if we exposed the *.wat capabilities of wasmtime.

@tschneidereit
Copy link
Member

* The Python extension should provide a programmatic API for working with wasm modules in the same way that this .NET module does. I think Python, since it works, still wants to support the `import foo` where `foo.wasm` exists, but that may want to be an opt-in like `import wasmtime.magic` or something like that where `import wasmtime` gives you the general package of functionality.

I don't think I agree with this: I think the support for "just using" a Wasm module as if it were a Python module is a strong feature, and should be the default.

Would something similar to the proc-macro based Rust API work in C#, by any chance?

Having a more explicit API, available through something like import wasmtime_api, for the more manual API does seem to make sense, though!

@peterhuene
Copy link
Member Author

peterhuene commented Nov 25, 2019

Would something similar to the proc-macro based Rust API work in C#, by any chance?

Unfortunately C# does not have macros or any similar compile-time code generation feature (although I do know the compiler devs have considered such a proposal). Roslyn, which is the C# compiler infrastructure, can be used to build up C# ASTs to generate source code that could be included in a build, but there would need to be build tooling around making that work.

However, .NET does have runtime binding (and code generation) via reflection. I could envision a similar interface like:

interface WasmMarkdown
{
    string Render(string input);
}

void RenderHello()
{
    using (var markdown = Wasmtime.LoadFile<WasmMarkdown>("markdown.wasm"))
    {
        Console.WriteLine($"{markdown.Render("# Hello, C#!")}");
    }
}

Of course, this would require interface types to be implemented, but I could see potentially hiding the C API machinery behind the scenes with an interface like this.

@tschneidereit
Copy link
Member

However, .NET does have runtime binding via reflection. I could envision a similar interface like:

Ah, that does seem quite promising!

Of course, this would require interface types to be implemented, but I could see potentially hiding the C API machinery behind the scenes with an interface like this.

Right, I certainly didn't mean this to be a short-term thing. We should probably have this discussion in another forum :)

@alexcrichton
Copy link
Member

@tschneidereit oh I'd be down for that as well!

I do think it's worthwhile to provide the nitty-gritty Rust-like internals API for all extensions, but I also agree that having a "super nice and easy to import" way of instantiating as the default ergonomic way (macros in Rust, import in Python, reflection in .NET) seems good as well.

I do think though we should probably rewrite the Python extension to be basically a blob of Python instead a blob of Rust. That blob of python would call into another blob of python we write which wraps libwasmtime.so, and that's where all the C++ is. So basically I think it would be good to rewrite the Python extension with libwasmtime.so, expose a programmatic API for working with wasm through this, and then rewrite the current module system integration in terms of that.

Copy link
Contributor

@yurydelendik yurydelendik left a comment

Choose a reason for hiding this comment

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

The c# code is read. Easy to follow. Thanks.

Right, I certainly didn't mean this to be a short-term thing. We should probably have this discussion in another forum :)

Agree

Copy link
Member

@sunfishcode sunfishcode left a comment

Choose a reason for hiding this comment

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

Very cool! I'm also not the best person to review most of the code here, but the PR here looks reasonable to merge and continue development in tree.

@kubkon
Copy link
Member

kubkon commented Nov 26, 2019

This is by no means criticism in any shape or form, but wondering out loud, do we need to keep the hello.wasm binary in this repo, or could we provide the source or a link to some other example(s) that we've got in wasmtime already?

@peterhuene
Copy link
Member Author

peterhuene commented Nov 26, 2019

hello.wasm was being directly referenced from the tutorial, so I wanted to keep it separate as part of the documentation tree, thus guaranteeing it doesn't accidentally change without realizing it is being referenced from documentation.

I'm fine with removing any unnecessary wasm files we feel don't need to be there, but these are stripped files that total maybe a few kilobytes so far.

@peterhuene peterhuene merged commit 3e7bc74 into bytecodealliance:master Nov 26, 2019
@peterhuene peterhuene deleted the wasmtime-for-dotnet branch November 26, 2019 20:47
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.

6 participants