We write a function that converts a string to lowercase in WebAssembly, demonstrating how to set the input string from JavaScript.
WASM Fiddle: https://wasdk.github.io/WasmFiddle/?h1s69
Demo Repo: https://github.com/guybedford/wasm-intro
[00:00] In this example application, I'm calling a console.log function within the main function of my C application. This function takes two arguments and offsets into the WebAssembly memory, which is the first character of the string that I have defined, and then the length in that memory, the length of the string.
[00:17] When run, this function is defined in JavaScript, where it creates a [indecipherable] buffer on top WebAssembly memory for that offset and length. It then uses the text decoder to decode the string and log the output JavaScript string.
[00:32] We're reading raw data from WebAssembly memory. What if we wanted to write into WebAssembly memory? As an example, I'm going to consider a function to_lower_case, where we take an input string and we then output an output string that is the lowercase version of it.
[00:48] We're going to have two strings here and I'm going to say that they're both 20 characters long. In the to_lower_case function, we can now loop over each character of the string. We read the character value from the input string, and we can then check if it's a capital letter based on the ASCII range.
[01:04] This is much faster with bitwise arithmetic, but for clarity we can just check if it's between the 65 to 90 range in ASCII. If it's in that range, we then just shift it. Once we've got the results in lowercase character, we set that into the output string.
[01:19] To make this really easy to run, I'm then just going to run the console.log function on the address of the out string, with the total length, and remove the main function. To be able to write to the input string in JavaScript, I'm going to create a get_offset function, just like we have before, that returns the address of the input string in the WebAssembly memory.
[01:40] With this built successfully, what we're then going to do in JavaScript is populate that input string by writing WebAssembly memory from JavaScript. We're then going to call the to_lower_case function and that'll then go ahead and log the lowercase output for us.
[01:56] What we'd like to have here is a function that allows us to write a string from JavaScript into that WebAssembly memory. We could then provide an offset of where to write that memory, which we can then get from our get_in_string_offset function that we wrote.
[02:11] To create this write_string function, we're going to take its string and offset inputs. The first thing you want to do is generate the raw byte buffer from the string. To do that, we can use the text encoder interface to convert the JavaScript string into a typed array Uint8 buffer just like we have above.
[02:31] To write to the WebAssembly memory, we're going to create another buffer, which represents that input string, "WebAssembly memory." We're going to generate it from the WebAssembly memory buffer at the offset of that input string that was passed.
[02:43] We're also going to set it to the length of the buffer that we've just created, that we're going to write into it. Looping through each byte index in the string buffer, we can then set into the out buffer, which represents that input string in WebAssembly memory, set each byte from that string buffer.
[03:00] By writing directly into the WebAssembly typed array, we're writing directly into WebAssembly memory. Running this, we can see that it's correctly lowercasing the input string that we've set from JavaScript, including some null bytes at the end because we've padded it up to 20 characters.
[03:15] It's worth noting here, there's quite a bit of performance overhead to this copying of memory that's going on between JavaScript and WebAssembly. For this reason, it's worth thinking about where a piece of memory belongs, as its source of truth, quite carefully, and letting it always stay there as the main source of truth to minimize the copying operations.