The example for wasmlink with the renderer and the markdown. In the markdown module the export is
(export "render" (func $render.command_export))
with a type of
(func $render.command_export (type 7) (param i32 i32) (result i32)
In the renderer the import is
(import "markdown" "render" (func $renderer::markdown::render::witx_import::h556dc1094c69443f (type 8)))
with a type of
(type (;8;) (func (param i32 i32 i32)))
Why does the import take the result from a param and not a result?. Is the result a pointer to a block of 2 i64s?
I mean the last parameter is that a pointer to 2 i64s that are populated by the markdown module, or is it a pointer to a pointer to 2 i64s and the pointer is supplied by the markdown/linker?
Forgot the online tool which is super useful, thanks for that. I see its the first option
#[link(wasm_import_module = "input")]
extern "C" {
#[cfg_attr(target_arch = "wasm32", link_name = "hello")]
#[cfg_attr(not(target_arch = "wasm32"), link_name = "input_hello")]
fn witx_import(_: i32, _: i32, _: i32, );
}
witx_import(ptr0, len0, ptr1);
let len2 = *((ptr1 + 8) as *const i32) as usize;
String::from_utf8(Vec::from_raw_parts(*((ptr1 + 0) as *const i32) as *mut _, len2, len2)).unwrap()
}
}
static mut RET_AREA: [i64; 2] = [0; 2];
Hi @Scott Waye. wasmlink is expecting the canonical ABI that witx-bindgen uses for its imports and exports. For functions that return "multiple values" (i.e. anything that can't fit in a single wasm value type, which a list is considered to be because it returns a pointer-length pair), the importer (caller) passes in an additional argument that is a pointer to an array of 64-bit values and the exporter (callee) returns a pointer to an array of 64-bit values of the same length. This facilitates the adapter code that sits between the caller and callee as it does not need to explicitly allocate any space in either linear memory; the code generated by witx-bindgen handles allocating the return value space and the code generated by wasmlink ensures that what's returned by the callee is marshaled correctly to the caller.
and the utf8 array, is that memcpy'ed between the 2?
no wait, scrap that.
yes, the adapter code that wasmlink generates calls into each module to allocate space from their linear memories and uses memory.copy
instructions to memcpy the memory between the two linear memories
ah, ok, that's why it needs canonical_abi_realloc (which I'll need to create on the c# side)
that's right
thanks
Scott Waye has marked this topic as resolved.
one thing to note is that there'll be a bit more churn on the ABI before this is all fully stabilized. For example, we already know that the way short reads/writes are facilitated will change a bit, from the push/pull buffers right now to a streams based interface. We're aiming to wrap this phase of churn up as quickly as we can, though
thanks, no problem, I'm just playing. wasmlink is completing without errors so made some progress.
Thanks for the help. I've successfully started with a dotnet string, sent it to rust, reversed it, and passed it back. Ship it!
image.png
super cool work! :)
is this using mono to target wasm?
No, this is NativeAOT-LLVM
ah, nice
Its an experimental backend to https://github.com/dotnet/runtimelab/tree/feature/NativeAOT
as a fan of C# myself, it's really exciting to see work in this space
Last updated: Dec 23 2024 at 12:05 UTC