 Hello, everyone. We're really glad to be here. So our talk today is about how small can you go. And this is in the context of customizing interpreted languages for WebAssembly. And so if we talk about the REST report that we have in the state of Wasm as of 2022, we see that we have a lot of users that are interested or are already using serverless or containerized environments. And for example, they are also using WebAssembly as a plug-in environment. But also more than that, if we look at the evolution from 2021 to 2022, we see that serverless and containerization, everything is a plug-in environment, especially everything is growing a lot. And so we ask or we wonder, is there anything we can do to help this community? Is there anything we can do to help WebAssembly and also the people who actually want to try WebAssembly and see the benefits of WebAssembly? And the answer with interpreted languages is that they have a huge existing user base. And so we want to take advantage of that. We want them to see that WebAssembly has multiple benefits. We have seen today multiple times in terms of security, in terms of portability, of composability. And so we want them to come to WebAssembly. And at the same time, we want WebAssembly to have more users. And so we want them to come with their ecosystem and reach WebAssembly completely. And the question there is, how do we bring them to WebAssembly? Do we just lift and ship their applications? Will just that work? Like when we add virtual machines, we move to containers kind of a lift and ship kind of move. Is this something that we can actually pull? Does it really make sense? And so the target for interpreted language, this is a little bit different. And so in this case, because we are focusing on size, we are trying to make our interpretation smaller. And the reason that we are trying to do this is because when you move to the edge or closer to the edge, I don't have a really good definition of fits. But what I can understand, or my guts tell me, is that it's a monetary business environment. It's usually smaller in terms of what it can compute. And so we want things to be smaller. We want things to speed up faster. And so the first thing that we want to do in terms of size is to reduce external dependencies on the interpreters. And so for that, the Wasm Labs team, we created the Wasm Language Runtems Project that other companies are using today or are contributing to it. And so we have created or we have published Ruby, Python, and PHP. So you can just use those interpreters, run your programs in those languages, and just use them. But as part of this work, and because we want these people that are using interpreted languages to come to WebAssembly without having to do a lot of other work, we want things to just work out of the box. So we had to support a lot of different libraries. This is a work in progress, and the job is not done. Of course, it's not finished. But we needed, for example, to board libraries as the ones that you see here, and more will come, of course. By the way, if you want to contribute, you have the door open, so come and contribute to this project. And so these libraries is not only to support these languages. In this project, we also want other people to use these libraries as third-party libraries. So if you need SettleDeep, you know where to go. You get SettleDeep, and then you use SettleDeep from there. So that's in terms of the interpreter. We just made the interpreter smaller, and so this is what we can do with the interpreter itself. But there is another moving piece that is the standard library. And so, yeah, one second. So there is a standard library that we can also reduce. And so for example, with Python, you are able to reduce the standard library in two ways mainly. One is, I can seep the standard library, and then the interpreter is going to unzip it on the fly, and then it's going to read that interpreter. It's going to read that standard library. Or you can extract and use features from it. And so what we saw from the standard library of Python, this is just from the standard library itself. You see that the unit test, for example, takes a lot of space. This is something we didn't really experiment with on the WebAsync language runtimes yet. But for example, if you remove this, you are stripping almost two megs out of it. Let's try the way. And so this is something that we wanted to check as well. So if we go to the interpreter again, we were talking about having this slim version that you can just run closer to the user. So it's something less powerful that can run it. And so for this, we have this limb, and the battery is included in versions. This limb is around 5 megs for PHP CGI. Batteries included versions are around 13 megs. But what happens if I need something in the middle? Because I want things to just run out of the box. I don't need a lot of things. I just need what I need. So for example, in this case, I just built with this parade, with WebAsync language runtimes, a version that just built XML and SQLite that is around 10 megs. And so you are able to make your own. So we have all this pipe work, let's say, that you can just use. And you can configure and build your own interpreter. And you can even optimize it as you want. So basically, you have the door open to do whatever you need in terms of optimizing your interpreter on the standard library. And so the last part of this is, OK, I need to embed everything into a single piece of software. And then you need to bundle three things. Mainly, that's the interpreter. That's the standard library. If it applies, for example, in PHP, there is no standard library that goes next to the interpreter. Everything is bundled into the interpreter. And then your application, that is what is actually going to serve the user. And so for this, you have different options. Oscar is going to look more into that, and he's going to give you more hints on how to do that. But you have manual pre-opens, where you have the source code next to your module. You just open that, and then it runs. You would also use Docker plus Wasm, where you just build the container, and then you run that right away. Or you could use Wasi VFS. This is a period that hasn't been mentioned before. You need to have Wasi builds for it. But in this case, on Web as in language runtimes, we are using Wasi for all our builds. And it's a virtual file system where you can just put that together with your statically linked with your program. And so you can refer to files on this virtual file system and load them. So one thing that we did for this talk was, OK, let's try to compress with Wasi VFS. So this is a feature that is not supported on Wasi VFS as of today. And so it's like, what if we are able to compress? So when you do Wasi VFS, there is two things. One is the guest part, which is the static library that you link together with the program. And then the Wasi VFS pack CLI that you call from your host, actually CC64, if you want, for example. And then it will just go and read all the things that you want to mount inside the Web as in the module. And it gets bundled together into the Web as in the binary itself. So let's look for a quick demo on this one. This is not yet open. There is no request open for this. But we are going to open that soon. And so, for example, we have a very simple main C program that is just going to FOPEN TMP test file. And then it's going to read a recharacter and it's going to print a recharacter that it finds. The cool thing about this is that with the compress option, as you can see, there is nothing that this program knows about XSET. This implementation that we created uses XSET. So we have 12 support lib LZMA. In order for this to work, this is going to be transparent to you. You just open and you just read. And the thing is that when you do WASP VFS minus C with compress, it will do on the CLI side compress everything and pre-open everything compressed with XSET. And then the guest part of it will automatically decompress when it reads or when you read from the module. It can be optimized a lot because right now it doesn't even implement a cursor. So every time you kind of read, it decompresses the whole thing. So it's very slow right now. But the idea is that it will optimize it. So this is a test file that I just created for this example. And now I have another file that is bigger. It's ASCII test. So it has a very high compressed ratio. And so we have the test file here and a big ASCII text file. And then what I'm going to do here is to package a regular WASP VFS version of our module without compress. So the first command that you can see here is just going to build our program, the main C file. As you can see here, it's also going to link the WASP VFS, the guest site, along with it. And then it's going to output that to main WASP TMP. And then we have the target, WASP 32 WASP. So this was suspected. And now I can do the very same thing but with compress option. And in this case, you can see I can skip the part where I built the main C file. And now I can just do the minus C and then it just finished. And now we can compare both files, one without compress and one with compress. And you can see it's left and half the size because it had a really high compressed ratio. So it's pretty easy for that to work that way. And now we can just brand the compressed version out of it. OK, so this is just an example of a very simple text file. But for example, if you create a WASP program that contains everything embedded with WASP VFS, and for example, you embed WordPress in it, you will see that there are really, really high compressed ratios. Like we are talking about 29 megs instead of 71, for example, right? So it's like very big compressed ratios that we can just pull without having to worry about lots of things. OK, and with that, Oscar has been talking more about the details of other options. All right, so that's one side of the coin, right? Where it's like, OK, how small can we get the interpreter itself, like the actual web assembly module that we need to run? But the other side of that is, what if we can actually take the source code that the user wants to run and provide that at runtime? If we can do that, essentially, especially in this component model kind of world, we can essentially link in that code at runtime and only move that bit over, and then that's going to be quite a bit smaller. So that's the huge thing is just having the interpreter ready to go. That also is going to help out a lot with speed and performance, because a lot of the computation time is actually, hey, we have to compile that huge interpreter and get it up and running. Now, the easiest way to do this is just via WASI. And there's sort of two main approaches you can do that. One is via pre-opens. So essentially, you have your interpreter running, and when you run that interpreter, you just say, hey, I'm going to pre-open this directory that has the user's code in it that I want to run. And so it's actually pretty simple to do this. And in a language like Python that just loves that disk, this solution actually works really, really well. Because essentially, hey, yeah, just method directory, it works kind of just the same way you run Python on your computer. There can be some downsides with this approach, where it can be a little bit brittle. Because in this approach, it's not the situation of, hey, I just compiled a Rust module, for example, where the only thing I need to care about when I run that thing is that Rust module. I don't need to care about additional files. But when going to a system like this, all of a sudden, now when I want to run that user's program, I've got to make sure I have that WASM file ready to go, and I've got to make sure that I've got their source code somewhere that I can actually pre-load it or pre-open it so that way the system can read it. So depending on how you architect your system, that could be a little bit brittle. Now, ways around this, and this is, for example, at Suborbital, how we do this today is we just bundle all the code in with the interpreter itself, have one WASM module, and it's not a problem. But there are other ways around this as well. The other major way is via standard in. So it's like, hey, I don't want to deal with the files at all. I actually just have some source code that I want to run. And this sort of thing works really well with a language like JavaScript. Because essentially, all JavaScript bundlers do anyway is take a bunch of JavaScript code and just concatenate it all together. So that actually works really well here because, hey, I can just stream that in over standard in. The interpreter can read it and run it, and hey, I didn't have to deal with any files, and I'm a happy camper. So one downside of this approach is what if you want your user's code to be able to use standard in and standard out, that could potentially be a problem because you're taking it away to be able to do this exact thing. But depending on how you architect your system, you can restore it. There's solutions here like, hey, actually, let's just use a different file descriptor. There are some easy ways around that. Now, where things get really interesting is doing it via module linking. So this goes back to, hey, actually, I just want to deal with web assembly modules. I don't want to deal with source code files. I don't want to stream source code over standard in. I really just want a web assembly module. So our system at Suborbital really likes web assembly modules. It doesn't really like other types of files, and I don't want to have to get the team to re-architect everything to make it work by bringing source files along. So by packaging up user source into its own web assembly module and linking that in at runtime solves a million issues here. And in some cases, we can even pre-compile byte code. So instead of saying, hey, actually, this is just a web assembly module that wraps some text. Potentially for whatever interpreter you're using, it has some sort of byte code format that it uses. You can pre-compile that to whatever byte code format. And then when you link it in at runtime, it's even faster because it's already completely ready to go. The interpreter doesn't have to do that extra work to get it working. So the cool thing about that is you get exceptionally small binaries. Especially if you're not even dealing with generating byte code, the size of your wasm module is only just a hair bigger than the size of whatever your source code was. And so then we go from having to deal with this 26 megabyte Python web assembly module to this little baby 300 bytes web assembly module. And that's a lot easier to move around in the system. So I want to show you guys some code on how if you are using an interpreter, this is how you sort of make it work. A lot of this code is being pulled directly from the web assembly language runtimes repo. And so in here, the major way you make this work is you have a couple of exports for your interpreter that the web assembly module itself is going to expose. So the main thing you need is, how can I allocate memory so I can feed in that source code? And we do that via this allocate string function. Then the next is, how do I execute that user source code? We do that via exec string. And then, of course, every interpreter needs to do some initialization. So we provide a way to do that as well. So these functions are dead simple to implement. And it's really easy for anyone to do. Don't feel that, hey, this is too complicated for me to get this working. You have to write this code one time. In the sense, each of these are just a single line of code. So for initialize, it's OK. Just tell the interpreter, hey, I'll just do whatever you got to do to get ready. That's pretty easy. Allocating a string, it's just a matter of, in this case, we want to have a no-terminated string. I was lazy. I just used Calyx for this and added one to it, which, in production, you can write code that's slightly better, but this totally works for here. And then in terms of actually doing the execution, that's it. You just say, hey, whatever method. And I'll show you that as well. Whatever method by which your interpreter does that, just tell it, hey, I just execute the string. In this case, it's literally a matter for Python anyway, of saying, hey, Python, compile this string. And it's just like, all right, I did it. Here you go. And then the next is, hey, now I want you to execute that code. And that's it. And this is all of the code that is necessary, really, to get this working. You don't need anything more complicated than that. So how do you actually get the code that the user wrote into a WebAssembly module? I promise you that it's so dang easy, you could write that WebAssembly module by hand. And so what I did was I wrote that WebAssembly module by hand, because it's really that easy. So it's a matter of on line six. And this is the program that we want to run. It's just print hello world. That's pretty easy. Line seven is just, what's the size of the data? It's 21 bytes. Line eight does the actual loading into memory. But that's just a couple of WebAssembly instructions. And then the big piece here is just the start function. So what the start function does is it'll say, hey, let me allocate a string for this data, sets it into a local. Then after that, we load that data in. And that's calling the function that we define on line eight, which just literally writes that data into memory. And then on line 19, we just say, all right, interpreter, execute that. That's how dead simple it is to put something like this together. So in fact, in terms of the quote unquote tool that you need to actually take source code and put it in a WebAssembly module, actually just wrote a bash script, because you don't need anything more complicated than that. You can, of course, do it properly, break out some rust as we all like to do. But sometimes it's literally a matter of write a bash script that writes this file out and then just use something like what to wasm to just switch it into WebAssembly and then you can get this stuff running. So with that, I swear I know how to run my own demo, I swear. So with that, I'm going to show you how easy it is to actually get this up and running. Sweet. So the Python code that we're going to want to bundle into a module is right here. It's super simple. It's literally a hello world file. Nothing special there. But we need to actually build that module. Like I said, I literally made a bash script. All it does is it takes the code from the file, puts it into that file, writes it to disk, and then runs what to wasm on it. It's super simple. And so that's it. And then the next question is, of course, how do you actually run that? This is possible literally with wasm time. You don't need to do anything special. So the way this works here is wasm time has this flag called dash dash preload. And you just tell it, hey, here is the interpreter. It is here. It is ready. And you give it a name in this case. They call it Python Provider. And here's that web assembly module. So just preload this and then execute my web assembly module that I gave you. And if we do that, it runs. And it's actually pretty quick. It says we get our hello wasm day running in Python. And it was linked from two separate web assembly modules. Now, the sweet part about that is in my system, I can have that Python Provider web assembly module already running. I can already have it cached to hell just waiting ready at the edge. And then I have this 300 megabyte web assembly file that I'm shipping. And boy, can I get that over the network quick. And that makes me pretty happy than shipping this 26 megabyte web assembly file. So overall, it's an actual real way to make this happen. And in fact, if you use Java and you use the linking flag for that, it does the exact same thing. And so this is an easy general approach you can use for your interpret language is running in web assembly. So with that, how can we make the experience with interpreters better overall? Well, we have a lot of WASI proposals coming up for things like, oh, databases and HTTP. One of the things that exists as a Python standard library is a full-fledged HTTP client. And imagine there was a way that we didn't have to ship that because I'm sure that takes up probably like one, two, maybe even three megabytes in our interpreter, right? Well, the beauty of that is we can maybe get that working via WASI and via the component model. Because with the new proposals coming up on WASI, we can start replacing a lot of the functionality in our interpreters with native support that exists in WASI. And that's going to be able to get us our interpreter binary sizes way, way down, because we're essentially just removing so much handwritten functionality that just doesn't need to be there when we can re-provide it. And that's going to be the big piece that gets it all working and gets those interpreters even smaller. And that's about it, folks. Thank you so much. Thank you for a great presentation, Oscar and Rafael. We have time for a few questions? Yes. I don't think you need the introduction, but. Hey, Alan Bailey. So I'm curious how much of this do you think can land in the upstream languages like for Python and PHP? Yep. Thank you for the question. That's a great one. So for example, in the case of what we're doing, we are maintaining the PHP patch, because it's kind of a big patch. And what we are doing is contributing to the upstream. And so we are seeing when the community is going to give that like a green light, and it's going to get into there. But we don't know much about when is that going to happen. But we're trying to upstream everything we do in that case. One of the things I'll add to that is the work that Rafael did on Wasi BFS with Compress. He told me he was going to get a PR up for that pretty soon. And so that would be available. Because that's obviously a tool that a lot of us use in just having the ability to just hit a compile flag and say, hey, man, just compress this for me. And it just works with no effort required. It's amazing. So I believe that's going to be up pretty soon, and with tests too, maybe. And that should be upstream pretty soon. Any other questions? OK, thank you very much. Please give a round of applause to Rafael Oscar. Thank you very much. Thank you.