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

Question about strings and structs and wasmtime API #891

Closed
eminence opened this issue Feb 1, 2020 · 4 comments
Closed

Question about strings and structs and wasmtime API #891

eminence opened this issue Feb 1, 2020 · 4 comments

Comments

@eminence
Copy link
Contributor

eminence commented Feb 1, 2020

I've got the following rust code:

pub struct Person {
    name: String,
    age: u8,
}

#[no_mangle]
pub fn get_age(p: &Person) -> u8 {
    p.age
}

#[no_mangle]
pub fn greet(name: &str) -> String {
    "hello there:".to_string()
}

that I'm compiling to the wasm32-unknown-unknown target:

cargo +nightly build --target wasm32-unknown-unknown --release

To my surprise, this compiled happily. Since strings and structs are not types that webassembly knows about, I was surprised to even see a successful compilation. My understanding was that in order to deal with these types you either have to use wasm-bindgen, or interface types.

I'm not using wasm-bindgen, and I'm not using interface types (since when I look at the output, I don't see any of the interface types custom sections).

So my first question is: how is this actually working in the first place?

I'm not fluent in reading wasm, but when I looked at the generated code (attached in full at the bottom, but quoted in brief here), it all looked quite reasonable:

    (func $get_age (type 5) (param i32) (result i32) 
      local.get 0
      i32.load8_u offset=12)

This seems reasonable: The parameter looks to be an offset into wasm linear memory to some structure that expects the 'age' field to be at offset 12 from the start of the structure.

My next question: how do I call this from the wasmtime API? How to I construct an instance of my Person struct and put it into the right memory? How do I know how to layout my struct?

A similar question applies to greet:

  (func $greet (type 4) (param i32 i32 i32)

It looks like string types are transferred using 3 i32s (how do I create those from a string), but where's the return type?

Thanks!

plugin.wat.txt

@yurydelendik
Copy link
Contributor

Most of questions above can be answered by Rust's type layout and ABI discussion. Bottom line is you need to known both to call Rust functions directly without wasm-bindgen or interface types.

You can make your life easier and use repr(C) and extern "C" to use C layout and call convention.

how do I call this from the wasmtime API?

There are examples about embedding the wasmtime into custom project, see e.g. "gcd" and "memory". (You may also find the example at #39 (comment) relatively useful -- it shows how C compiled code can send a string to host function)

How to I construct an instance of my Person struct and put it into the right memory?

You have to call Rust a helper function to allocate a memory for a Person struct, then you populate it based on its repr() rules. The wasmtime provides Memory object to have the access to instance memory.

pub fn greet(name: &str) -> String {
(func $greet (type 4) (param i32 i32 i32)
It looks like string types are transferred using 3 i32s (how do I create those from a string), but where's the return type?

If I'm not mistaken, first two are pointer and length of name, and the third is a pointer to String structure, that is the return arg.

@eminence does this answer all of your questions?

@eminence
Copy link
Contributor Author

eminence commented Feb 5, 2020

This helps at lot, thanks. In retrospect I should have realized that this is how things work. I had gotten myself confused with several things.

I think you already answered my follow up question, but just to confirm: The long-term approach to calling rust code (compiled to wasm) from wasmtime is with interface types? (And not with the a C or Rust ABI)

@yurydelendik
Copy link
Contributor

The long-term approach to calling rust code (compiled to wasm) from wasmtime is with interface types?

That's correct. See more discussions on the subject at #677

Closing the issue as answered.

@eminence
Copy link
Contributor Author

eminence commented Feb 5, 2020

Thanks!

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

No branches or pull requests

2 participants