Web Assembly (Wasm)

Debugging Wasm Modules & Defining Imports

Jem Young

Jem Young

Web Assembly (Wasm)

Check out a free preview of the full Web Assembly (Wasm) course

The "Debugging Wasm Modules & Defining Imports" Lesson is part of the full, Web Assembly (Wasm) course featured in this preview video. Here's what you'd learn in this lesson:

Jem demonstrates how to debug Web Assembly. The AssemblyScript source maps help identify the location of an exception within AssemblyScript code. Importing a custom log function into AssemblyScript is also covered in this segment.


Transcript from the "Debugging Wasm Modules & Defining Imports" Lesson

>> Let's talk about debugging, because I do believe the fundamental part of any good programmer, is knowing how to fix or knowing how to debug a program. That's honestly, what one of the gauges I have measured when I talk about what is a senior engineer and like what makes senior engineer, it's not someone who can write code.

Anybody can write code, it doesn't mean it's good, anybody can write code. I think people are really good engineers, know how to debug code. And that, again, is something that is an underrated skill, that we probably don't talk about enough as engineers, like we spend most of our time reading code and not writing code.

So the ability to debug it is critical. So jumping back, I'll just refresh the page, we should be at an error, I'm using Chrome right now, where I pause on exceptions. So it's paused right here, which is pretty nice, and I'm gonna let it play out. And I say nice in that debugging is actually a fairly recent feature in web assembly.

You couldn't do it, you could do it before, but you have to use console logs and things like that. Fortunately, assembly scripts serve source maps, and we can use those source map to figure out what went wrong. So for looking at the console, it's big enough for everybody.

So we're looking at the console, and it's saying the call stack is the issue happened, at minus one in our build function. But because we're using source maps, we can map directly to the typeScript source that we're running. Now this is really cool, because before, it would just be maybe a what file or just plain.

Actually, yeah, it was just a what file or it was some gibberish or garbage that you're like what, what just happened? But now because we have source maps, we can actually dive back into our assembly script and see what's running. I wanna remind people, we're not actually running index.ts, this is just a map back to it.

And if you run into issues, or this isn't working, let's go into Chrome. We're gonna go to experiments, we're gonna scroll down and then we're gonna make sure web assembly debugging is enabled. I'll say this, this has been really hit and miss. I've had some really useful source map debugging stories, when I was writing this course.

But sometimes it just doesn't seem to work. I think, this falls under experimental so it may or may not work. But generally the source map story works and web assembly by default, or assembly script by default ships, the source maps websites. So when we throw an error, we can trace back to exactly where that error is called.

Again, this seems simple, we reload dev tools. That seems simple, but I the key to being good at something is the ability to break it and then see what you broke and then fix it later, that's just philosophy. Okay, so we managed to, so far we've exported functions, into JavaScript and now we've imported functions into web assembling.

And we did it in the standard way we use the port which is built into assembly script as a known object. We don't have to define that at all. And let's check out, actually they have a list of the imports that are available. So, if we were to say if we use memory or table or abort, which we just use.

We don't have to define those in our TypeScript or our assembly script code, because there are known functions, to assembly script. But what happens if we want to define our own custom JavaScript, that assembly doesn't know about? How does that work, how would we import that? Well, let's go and try that out.

What I really want to do now is, I want to be able to console log in any way. I just want to console log, because that's always a useful feature. Like I said, debugging is what is the more interesting story. I do believe the ability of a program in a programming language is it's hinged on its ability to debug it properly.

So, right now I want to create a log function that just logs the number, or logs the input that I put into that function. So let's jump back to the code, in our index.ts. Let's take out the abort, because that is not necessarily more of just an example, and I wanted to say.

I Want to have a log function that is just going to log the inputs that we have. And right now the linter is finding where the type scripts literally is finding an issue because log is not defined. So what we have to do, because we're working with types, we need to declare, the function and the function signature.

So I'm going to declare function log. It's gonna take one parameter and or wherever you wanna call it. And that's going to be a 32 bit integer. And it's gonna be void, it's not gonna return anything, all right? So now having that let us recompile, so NPM run-s build.

Looking good so far, and again, a useful way of seeing just what exactly is going on is to check the what file. We see now that we have an import declared under index. It's under index because the default namespace is the namespace of the file itself. So index.ts, and the function is called log.

And down here if we're calling our imported functions, that's just a call. The opcode is call within web assembly. But if we ran it now it still wouldn't work. Actually, let's just write it out and see what happens. That's my philosophy of life, module index. The module is not an object or function, you're probably gonna run into this error at some point in your assembly script journey.

And this is because we never defined it in our import objects. So let's jump back to the loader. And I'm gonna say, it's under the namespace index. And under index is a function called log, which we've defined already, it's gonna take n, And we're just gonna console log and you can make fancier if you want.

So now, if we've done everything correctly, we should see a console log and not an error. Refresh the page and there we go. In logged out 44, everybody follow what happened there. So I, first thing I did was I created a log function or any function I want to call, I declared a type its type so that the assembly script compiler knows what to do.

What the parameters are what the return type is. And because I, sometimes we can get unclear about what's happening, I always check the optimize or I check the what file to see what exactly is happening. I see that the index, the namespace is index and the function is log.

And then in my loader, I just define that under index and log. And the reason why we built this in end, because it's like I said, as I said before it's part of the assembly script loader and we're going to use that next, and that's just under end of word aboard.

And so that's why in the import object its name states under n. So not too bad, now we have the ability to pretty much also do anything we want. [LAUGH] I've gotten into trouble in the past where like we can do whatever we want. We can't really, but we can now define functions in JavaScript that can be called in web assembly.

And then now we can define a function in the web assembly that can be called JavaScript. So we understand how these, two bridges work. Which is pretty pretty dang cool if you ask me.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now