dotnet-webassembly icon indicating copy to clipboard operation
dotnet-webassembly copied to clipboard

How to read and write strings to memory with a compiled WASM?

Open 0xOmarA opened this issue 3 years ago • 3 comments

Hi. I have a compiled WASM and I'm loading it through the following code.

using System;
using System.Runtime.InteropServices;
using WebAssembly.Runtime;

ImportDictionary imports = new ImportDictionary { };
WebAssembly.Instance<InternalService> instance = Compile.FromBinary<InternalService>("../../target/wasm32-unknown-unknown/release/service.wasm")(imports);

String str = "Hello World!";
int pointer = instance.Exports.alloc(Encoding.ASCII.GetByteCount(str) + 1);
// How to write the the string to the memory?

I would like to write the string str to the linear memory of the WASM instance. However, I have not been able to find any resources on how I can do that. Any help would be highly appreciated.

0xOmarA avatar Sep 03 '22 11:09 0xOmarA

I was wanting to do this too, and I have some test code for it that I could put in a gist for you. Briefly, you simply need to choose an encoding and then write it into memory with Marshal.Copy.

However, the very next thing you're going to need to think about is what you intend to do with the string once it is in the linear memory. Do you want to compare it or perform some other operation in wasm? Or do you want to get it out at a later point?

What you want to do with it will determine what other primitive operations, such as a string comparison algorithm, which needs to take into account the string encoding, that you will need.

munik avatar Sep 03 '22 11:09 munik

One thing that makes this easier on recent versions of .NET is the Span<T>) type (and the related ReadOnlySpan). One of the constructors takes a Void* parameter, which can be obtained via the Start property of exported memory. From there, Slice it to the appropriate range for the string's bytes (either predefined statically or exported some other way) and use it with Encoding.ASCII/UTF8/etc to read or write from it without having to dabble in pointers or other forms of raw memory access.

RyanLamansky avatar Sep 18 '22 23:09 RyanLamansky

One thing that makes this easier on recent versions of .NET is the Span<T>) type (and the related ReadOnlySpan). One of the constructors takes a Void* parameter, which can be obtained via the Start property of exported memory. From there, Slice it to the appropriate range for the string's bytes (either predefined statically or exported some other way) and use it with Encoding.ASCII/UTF8/etc to read or write from it without having to dabble in pointers or other forms of raw memory access.

Oh, that's awesome!! A very useful technique

munik avatar Sep 19 '22 00:09 munik

Yeah, it's extremely useful and didn't exist when I first started development (this project's first commit is April 2017, Span came with .NET Core/Standard 2.1 in May 2018).

I've considered replacing most of the internal raw memory usage with Span-based mechanisms, but I'd have to give up .NET Standard 2.0 compatibility or use a lot of conditional compilation. Doesn't seem worth the trouble right now.

In the nearer term, I could potentially add an example on how handle strings with the help of Span.

RyanLamansky avatar Sep 25 '22 15:09 RyanLamansky

You might be able to use Span and still keep .net standard 2.0. It sounds like the full benefit isn't there but that it could help.

https://github.com/dotnet/corefxlab/issues/2581

Terricide avatar Jan 16 '23 14:01 Terricide