-
Notifications
You must be signed in to change notification settings - Fork 281
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
How to access linear memory from rust code that is compiled to wasm #203
Comments
This is actually a very common pattern to do! A compiled wasm module would use linear memory as it's working memory, like RAM. That means, that in order to access linear memory from within a wasm module you just need to do regular loads from memory. For example, let's say that in #[no_mangle]
extern "C" fn process_data(data_ptr: *const u8, count: usize) {
use core::slice;
// This is safe only if `data_ptr` is not null.
let data: Vec<u8> = unsafe { slice::from_raw_parts(data_ptr, count).to_vec() };
// .. you can use `data` to deserialize in what ever format you want.
} |
Thanks, that looks interesting. I understand that the I'm currently struggling to figure out how to get a mut pointer to index 0 of that linear memory to pass as the param. (this won't work...)
a pointer to any working code doing this stuff already would be great! |
Nope. A linear memory in wasm is just that: an array of bytes indexable by u32. Thus a pointer is just a u32 number that points on the value (or the first item in case of an array). So the idea is that you somehow allocate (as in, find the address of the first byte of) the vector you wish to pass in getting your Actually getting As to an example, the best I can recommend is the project that I am working on, here. It uses the host allocator approach. As a nice little trick, you can call |
Ah, found this, might be simpler than substrate |
Thanks!
Lots of stuff happening I'm not familiar with, but if this is the recommended approach I'll git it a try. |
Yep,
I am not sure if I can call this as generally recommended approach. For instance, If your wasm instances are not retained, i.e. used only for one call and then discarded, then you don't have to do explicit deallocation on the wasm side. Null termination is another concern that depends on what usecases you want to support. So I will repeat myself once more: everything really depends on the design of your wasm environment. This example I sent you is just that - an example, substrate execution environment is another one. There is another that I know - polkadot validation function. All of them do things a bit differently from each other. |
FYI I've cleaned-up that code, refactored a bit and made the wasm module be actually built from the source code in the repo (original had a sha1.wasm that who knows where it came from...) here: |
Thanks for all your help. I'll evolve my copy of wasmi-string to be more generic as a worked example, then try using the technique in my own app. |
Be careful with each unsafe though! For example, But otherwise, looks good! |
Agreed. It’s full of unwraps(), assumptions and some unsafe code - but works so far, which is a major step forward. I still don’t really understand how the WASM module rust code is “allocating” that vector, and will have to read up on it. It’s using the linear memory as heap I guess, and rust is generating code to handle that. In my real app, there will only be one function per module, it will be “pure” and I will ensure answer is smaller than input, so I should be able to make it work with this approach... |
If you have any further questions feel free to ask them here! |
One thing I am not clear on (continued from original code) is:
Seems to me that could be wrong, and we should calculate it's offset from first byte of linear memory? WDYT? |
The pointer to allocated data is actually an offset from the first byte of the linear memory. I.e. they are the same |
As you might have seen, by avoiding having to use null-terminated strings and working with the String lengths, I was able to remove the byte-by-byte copy on the getting of the response, using MemoryRef.get() https://github.com/andrewdavidmackenzie/wasmi-string/blob/master/main/src/main.rs#L61 Any idea how to achieve the same with the sending? It's unclear to me from the docs whether MemoryRef.set() https://docs.rs/wasmi/0.0.0/wasmi/struct.MemoryRef.html uses the size of the source Slice you are setting from... (I guess I'll try it and see!) |
I am not sure what you mean: The link to wasmi that you sent actually refers the first wasmi ever: 0.0.0. I'd recommend using the latest docs : ) |
I've changed this now and it works. The previous code had a loop with memory.set_value(), and so my code was doing it byte by byte (as it was originally looking for null termination of string). Now it's using memory.set() call once for the whole slice. |
really inside it will be |
Hi, I'm not sure the best place to ask this type of question, so apologies if this is not it. Just let me know where and I'll ask there.
(this relates to a previous question of mine: #166)
I am writing an app that used a series of "library" functions that are written in rust and compiled to wasm modules (I'll call this the 'rust-wasm' side).
The app (written in rust and compiled native so I'll call it the 'rust-native' side) loads and executes these modules from files using wasmi. This is working just fine.
However, I am attempting to pass some complex structs back and fore over the rust-native/rust-wasm boundary:
does that make sense?
I would like to know if I can use wasmi library functions to read the linear memory on the "wasm side"?
The code would be something like this, but instead of allocating the memory, it would just be getting a reference to the linear memory passed to it.
But remember, this would be compiled to wasm, and be interpreted by wasmi.
Thanks for any help!
The text was updated successfully, but these errors were encountered: