Web Assembly (Wasm) Using the __getString Function
Transcript from the "Using the __getString Function" Lesson
>> We're still not there yet, we need to pull out the functions we need to convert the string. So, I'm gonna go back to the notes. And we should be here, we should have modified our package JSON scripts to export the runtime for both our builds. We ran the builds, the runtime included now.
[00:00:15] So now, let's talk about using the assembly script loader. Again, I talk really fast, I go on good rants. And just in case I didn't explain something handsomely enough, there's always the fallback run exercise five now, if you need to catch up or something went terribly wrong. This is where we're at, this library works, I've tested the ball, so but we're here.
[00:00:43] So now let's modify, we need to modify our loader file. Because we no longer just care about the export functions, we care about all of the functions that assembly script is providing for us. So jumping back, jumping back into loader.js, what I want to do is I wanna change this.
[00:01:05] It's a relatively simple changed. So instead of pulling destructuring it and pulling out the instance, I'm just gonna call this instance now. So now we're getting the entire web as or we're getting the entire web assembly module instance that assembly script is passing. And we're gonna do the same thing here Again, I just took out the D structuring.
[00:01:32] So now let's check this out. Let's set a breakpoint in here, so I like to see what's going on. Sources, and skill into our elements. Go to Sources, where is my breakpoint? JS loader, there we go. We'll set a break point there. And I generally like to do this.
[00:02:13] I like to see what is available to me now because it makes it easier to reason about versus if you have to go into the docs and read them. They're not as intuitive versus, when you're actually coding, and you can play around with it, you can break stuff, you get a better grasp of it.
[00:02:28] So now, let's look at this instance object. So before when we were destructuring, we were just getting this instance which had exports. Which are just the exports of Fizz Buzz minusOne, the memory which we'll cover and then some helper methods for doing specific things with memory. But now instead of that, we're getting the entire exports, which has all these helper functions built-in now.
[00:02:56] And the helper function we care about is getString or actually new string technically, actually it getString, and getString is right here. Yeah, getString. So now let's jump back to our index.html, and we're now exporting Fizz Buzz as well, but we're also gonna get use getString. And I'm going to say const str = getString, and we're gonna say getString on this function fizzbuzz(3), and then we're gonna document.write that.
[00:03:45] And if I did things correctly, take off the breakpoint, hey, is not bad, not bad at all. Is everybody here so far? Because dealing with strings is a little tricky. Thumbs up, all right? So, what's actually happening though, because assembly scripts, it does a lot of work for us, what's really happening?
[00:05:11] So we're looking at the functions or the source code for the getString method that we called. As we saw before, it takes a pointer, which is what was turned by fizzbuzz or the fizz, it takes a pointer to a string. It checks if there's a pointer, if not, it returns none, we grabbed the memory buffer.
[00:05:29] Remember how we said earlier that memory is linear in web assembly, it is a fixed set of space that is allocated just for our program. And we access that by memory buffer. And again, the buffer is just a buffer, it's a fixed string of raw binary data. So it really means nothing.
[00:05:51] It's just gibberish to the computer until we give it purpose, until we give it a view. We'll give it a view by creating a 32-bit array around that memory. I think I've made a small typo there, but we're grabbing from the buffer. Now, remember how I said why don't these numbers correspond with the data function in the wot file?
[00:06:11] It's because there's an offset that every string that's saved into the memory is set to. We don't just save it directly to memory, you have to give it some sort of offset, so that we're keep moving down the line when we're saving things. Because its memory is actually just one long continuous space, it's only the length and the offset that we know where each thing is located.
[00:06:32] I know it's super technical, but it's cool to see how this stuff works under the hood. So what the getString does is it pulls the memory out, the actual ones and zeros, it sets it to a 32-bit array, and it has this custom ID_OFFSET, it has an offset that it knows about, along with a pointer.
[00:06:50] It zero fills right to the 2, that's just to give it a common ground. I promised, I swore to myself I would not get into bitwise operations because I think that's a bit outside the scope of this course. Well, it doesn't really add too much right now, but know that this is a zero [LAUGH] fill right shift, the 2.
[00:07:13] It's actually taking the ones and zeros, and shifting off to the points, and it add zeros to it. I won't get into it, but you can look at if you want, it's called a zero fill right shift if you wanna look up on MDN. And then from there, it calls getString in mutation which reaches into the buffer, which again use the pointer, and then it pulls it directly out of memory.
[00:07:35] Was that a lot? Yeah, it's a bit, but I just wannna point out how much work the loader is doing for us. Otherwise, without the loader, we'd have to do this manually ourselves. We'd have to reach into the memory, we'd have to know exactly what the offset is, we'd have to know where to look, the length of the string, the number of bits that are in it.