-
Notifications
You must be signed in to change notification settings - Fork 97
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
feat: compiler flag for registering external Wasm functions #4413
base: master
Are you sure you want to change the base?
Conversation
Nice start! Something like this could work, but the mapping between Rust and Motoko values isn't that simple. Even an i32 doesn't map to Nat32, and, what's worse, the mapping will depend on the compiled code and choice of GC. What we could do is provide some Rust functions for constructing/destructing Motoko values to Rust equivalents, and have the Rust code use those functions and perhaps assert the intended Motoko type (maybe using a macro) for the compiler to pick by inspecting the custom RTS (perhaps via custom section declaring the types). The RTS code already use the type
etc.
Usually you'd have to worry about the GC running at the same time and avoid introducing GC holes (allocated data that isn't visitible to the GC and could get collected under your feet). But we might be able to avoid all that hassle because we know the GC won't run until the end of the message anyway, after all the FFI code has done its stuff and returned. |
Right; I see what you're saying about this. The assumption is that the external tooling is targeting a specific combination of GC and debug/release, so in this case the tooling would be able to specify the correct Wasm value types. Edit: I removed the DSL in favor of simply reading the types from the RTS Wasm file itself, which solves this problem.
Saw this after writing everything else (and almost suggesting this as a possibility but thinking there was some performance reason not to do this). This would certainly solve the problem of needing to pass different flags depending on GC, etc. Beginning to look into this now.
It seems reasonable to build the Motoko attribute (from the example above) directly into the RTS codebase, although it could also be valuable to expose this as an external library so that code generation tools similar to Canpack could build the RTS Wasm file from many individual crates without losing editor type checking, if that makes sense. Here are some examples for what I'm imagining (presumably handled by external preprocessing tools, but we could build the Motoko attribute directly into the RTS codebase):
# ...
[dependencies]
moc-bindgen = "1.2.3"
use moc_bindgen::{motoko, Value};
#[motoko]
pub fn hello(name: String) -> String {
format!("Hello, {name}!").into()
}
#[motoko]
pub fn custom(custom_value: Value) -> Value {
// ...
}
#[motoko]
pub fn get_record_field<A>(arg: RecordStruct<A>) -> A {
arg.value
}
#[motoko]
struct RecordStruct<A> {
pub value: A
}
moc_bindgen::export!();
// etc. Alternatively: moc_bindgen::export! {
pub fn hello(name: String) -> String {
format!("Hello, {name}!")
}
pub fn get_record_field<A>(arg: RecordStruct<A>) -> A {
arg.value
}
struct RecordStruct<A> {
pub value: A
}
// ...
};
# ...
[rust-dependencies]
my-rust-crate = "0.1.2" Another approach could be to pass Motoko type strings in the I suppose yet another approach could be to remove the |
This is very interesting. Thank you for investigation and work! |
Thanks for taking a look! Adding a warning if a custom RTS function uses |
This PR introduces the
--rts-function
flag to register customextern C
-style language bindings in the RTS. The goal is for third-party tools such as Mops and Vessel to be able to include language bindings viasources
command for custommo-rts.wasm
files.Example workflow to manually try this out:
ffi.mo
):MOC_*_RTS
variables automatically configured in Nix environment):MOC_UNLOCK_PRIM=1 moc --rts-function echo -c ffi.mo -wasi-system-api wasmtime result-ffi.wasm
Feel free to suggest other ways of passing this definition. Hoping to make this relatively simple for third-party tooling to register these interfaces while keeping everything readable at a quick glance.
Progress:
--rts-function
flagrts:
primitives to access arbitrary FFI bindings in the RTSrts:
primitives to registered functions--rts-function
flag andrts:
primitivesNext steps:
mo-rts.wasm
files