Skip to content
This repository has been archived by the owner on Mar 28, 2024. It is now read-only.

Plans to stabilize this package? #50

Open
Arshia001 opened this issue Dec 8, 2022 · 5 comments
Open

Plans to stabilize this package? #50

Arshia001 opened this issue Dec 8, 2022 · 5 comments

Comments

@Arshia001
Copy link

This package is a very cool proof of concept, and it would be very useful for my team if it was ever stabilized. Currently, some features are missing, notably the args array is always empty and Console.ReadLine throws an exception.

Are there plans to do further work on this package? Is there some kind of documentation we can study to get an idea of how everything is working so we can help push the project forward?

@SteveSandersonMS
Copy link
Owner

We are now tentatively starting on work to bring all of this inside the main dotnet/runtime repo and make it all fully stable and work for real. However we haven't yet confirmed any specific official support level or shipping timeframe - it remains an open question pending feedback from the .NET community. If you would plan to build real software with .NET on WASI, it would certainly be interesting to hear more from you about it, as it helps to justify the investment needed for a particular level of support.

@akhanalcs
Copy link

akhanalcs commented Jan 4, 2023

IMHO, when MSFT ships this product, this will really take off.
Because not a lot of developers want to invest their time on experimental projects.

I love this project; I really hope MSFT makes adequate investment on it.

@kpreisser
Copy link

kpreisser commented Jan 13, 2023

Hi there! We would also love to see this getting stabilized.

We are currently integrating wasmtime-dotnet in our .NET application (middleware) to allow to run WASM plugins (in addition to JavaScript code with Jurassic), which can dynamically be started and stopped while the host application is running, and run in a sandboxed environment so e.g. they can't access arbitrary files on the machine, but only specific resources defined by the host.

For this, we define an API that consists of WASM functions that the host provides as imports, and of functions that the WASM module may export (e.g. to handle callbacks).

We plan to create a custom SDK that customers can use in order to create .NET WASM plugins for our application (in addition to SDKs for other languages like C/C++, AssemblyScript etc. that can compile to WebAssembly), where this custom SDK would include the nessary bindings to integrate with our WASM API (e.g. an .NET interop layer that contains a high-level .NET API, that gets translated to the low-level WASM API provided by the host).

In our tests this worked already pretty well with Wasi.Sdk 0.1.3-preview.10012. However, one thing that we noticed is that the GC seems to crash the WASM with the following assertion when being invoked (e.g. with GC.Collect(), or after instantiating a large number of objects), with an error like this printed to WASI's stderr:

[wasm_trace_logger] * Assertion at /home/runner/work/dotnet-wasi-sdk/dotnet-wasi-sdk/modules/runtime/src/mono/mono/metadata/sgen-stw.c:77, condition `info->client_info.stack_start >= info->client_info.info.stack_start_limit && info->client_info.stack_start < info->client_info.info.stack_end' not met

Is there any fix for this?

Additionally, I noticed that it doesn't seem to be possibile to use mono_add_internal_call for .NET methods that use Int64 parameters (in order to bind them to imported WASM functions taking an i64 parameter), as then the binding fails with this error:

[wasm_trace_logger] CANNOT HANDLE INTERP ICALL SIG IILII

Currently, I work-around this by defining the .NET functions as taking a long* pointer (which would be 32-bit for WASM with a 32-bit memory model), and then add a stub C function that dereferences the pointer and calls the actual WASM function, for example:

__attribute__((__import_module__("codabix_wasm_v1.error"), __import_name__("GetLastErrorMessage")))
extern void __codabix_wasm_v1_error_GetLastErrorMessage(uint64_t bufferPtr, int64_t bufferLength, int32_t stringEncoding, int32_t includeNullTerminator);

void call_codabix_wasm_v1_error_GetLastErrorMessage(uint64_t* bufferPtrPtr, int64_t* bufferLengthPtr, int32_t stringEncoding, int32_t includeNullTerminator) {
    __codabix_wasm_v1_error_GetLastErrorMessage(*bufferPtrPtr, *bufferLengthPtr, stringEncoding, includeNullTerminator);
}

void attach_internal_calls()
{
    mono_add_internal_call("Codabix.Interop::GetLastErrorMessageCore", call_codabix_wasm_v1_error_GetLastErrorMessage);
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern unsafe void GetLastErrorMessageCore(ulong* bufferPtrPtr, long* bufferLengthPtr, int stringEncoding, int includeNullTerminator);

// When calling the function:

string errorMessage = string.Create<object?>(stringLength, null, (span, _) => {
    fixed (char* spanPtr = span) {
        ulong spanPtrLong = (nuint)spanPtr;
        long bufferLengthLong = (long)span.Length * sizeof(char);

        GetLastErrorMessageCore(
                &spanPtrLong,
                &bufferLengthLong,
                (int)HostStringEncoding,
                0);
    }
});

Furthermore, it would be good to know whether the host should define additional (non-WASI) functions that may be required by the .NET runtime for certain scenarios, and how they should behave.
For example, I noticed that we may need to implement System.Threading.TimerQueue::SetTimeout and System.Threading.ThreadPool::QueueCallback (by attaching C functions to them as internal call), so that Task.Delay(...) will work (see #42), and also e.g. functions like ThreadPool.QueueUserWorkItem. This will then also require us to call queued callbacks from the host later (by calling TimerQueue.TimeoutCallback() for TimerQueue.SetTimeout, and ThreadPool.Callback() for ThreadPool.QueueCallback).

Note that the execution model of our host is that an "entrypoint" WASM function will be called, which is expected to return fast (as we don't use a event loop model with a blocking host function that will run the loop within WASM). Once the function returns, the host may call other WASM functions at a later time, for example when a timer or other event occurs.

Currently, our host application already provides such functions that allow to schedule a WASM callback to be called later (e.g. using a timeout/interval, or by adding an event handler), which seems to work, athough the WASM produced by the .NET WASI SDK seems to use the "component" WASI model with an _start function (where WASI defines that no other function must be called after that function returns), in contrast to the reactor model with an _initialize function that explicitely allows to call other functions once this returns (see https://github.com/WebAssembly/WASI/blob/main/legacy/application-abi.md#current-unstable-abi, WebAssembly/WASI#13).
Is this supported?

Thank you!

@adamreed90
Copy link

My interest for this would be to use .NET with Cloudflare Workers. Cloudflare Pages supports Blazor, however you must still write APIs in JS or something that compiles to WASM. This would be perfect to have an entirely .NET solution that can run on Cloudflare.

@bobby
Copy link

bobby commented Jul 2, 2023

We have a use-case that will require support for the WebAssembly Component Model, which would allow Wasm components written in C#/.NET to integrate with Wasm components written in other languages, and defined using a common interface definition language called WIT.

See also the wit-bindgen project.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants