Welcome to WebAssembly Unleashed, your monthly dive into the dynamic world of WebAssembly (Wasm). Join F5’s Joel Moses, Oscar Spencer, and Wasm enthusiast Matthew Yacobucci as they unpack the potential, challenges, and innovations within the Wasm ecosystem.
Designed for architects, practitioners, technologists, and Wasm enthusiasts, episodes offer:
Insightful discussions on Wasm advancements.
Practical tips for seamless integration into projects.
Interviews with influential figures shaping the Wasm landscape.
Strategies for maximizing the potential of WebAssembly.
Subscribe now and stay abreast of the latest in Wasm development. Whether you’re a seasoned pro or new to the field, WebAssembly Unleashed is your ticket to unlocking the full power of this revolutionary technology. Tune in for a deep dive into the limitless possibilities of WebAssembly.
Okay. Hello, everybody. Welcome to WebAssembly Unleashed, your source for news and views about the world of WebAssembly. As a podcast, we are raw and unvarnished all the time, sort of like an IKEA flat pack of YouTube content. I'm your host, Joel Moses, and aside me today, standing in for Oscar Spencer is my colleague, Chris Fallon.
Joel Moses:Welcome, Chris. Good. As well as our good friend and regular, Matt Yakabuchi. We spend our time inside this growing WebAssembly community because we're passionate about what hard work can be done with it. And the fact you're tuning in means that you care too.
Joel Moses:And thank you for that. If this is a return visit with us, thanks for your loyalty and your subscription. But if it's your first time here, welcome to the party and make sure to subscribe. We've got a great Wasm community guest lined up for you today that's also well known in the JavaScript ECMAScript community. And we're gonna talk about the intersection of those technologies with WebAssembly in detail.
Joel Moses:But first, we've got to do the normal pleasantries. If you've been with us here on the podcast, you know Matt and that Chris Fallon has been an occasional guest, but he's on co host duties today. So welcome, Chris. Always start these things with a quick rundown what you've seen inside the community recently that you think is important or compelling. So do you have anything for us?
Joel Moses:Chris, what's going on in the community that you think is interesting?
Chris Fallin:Yeah. I think sort of the interesting thing with WASM these days is that it's maturing. Right? And so things are actually kind of slowing down in some sense, we're reaching the interesting implementation phase of a lot of technologies. So we have garbage collection now as a feature that's out there, for example.
Chris Fallin:So yeah, it's cool to see how people are starting to use that and use Wasm for real.
Matthew Yacobucci:Yeah. One thing that I wanted to point out in regards to that is Zig is looking at refreshing their async model or redoing their async IO layer. And it's interesting, Zig has always been able to compile to Wasm. They started with that philosophy, but coming into it redeveloping and coming out with like a very, like a re engineered feature that is thinking about Wasm. So they have a couple implementations that aren't going to be immediately Wasm supportive, but they are thinking about it if you read Loris's blog about the design principles there.
Matthew Yacobucci:Yeah. It's it's just it's just really wild to see that WASM is a is a first class citizen here in in these things.
Joel Moses:That's fantastic. Alright. Now it's time to introduce our special guest. Wanna bring on Oliver Medhurst. Oliver is a Nexmozilla engineer who's been working in the JavaScript community for a while now.
Joel Moses:And I had the pleasure of hosting the recent TC thirty nine event where you were an, an invited expert based on the project we're gonna talk about today called Porffor, which is a compiler kit for JavaScript that has some unique features, and among them, the ability to ahead of time compile JavaScript to WebAssembly. We're gonna dig into that ahead of time business in just a moment. But first, welcome, Oliver. Thanks for joining us today. Before we get started, why don't you introduce yourself to our audience?
Oliver Medhurst:Yeah, thanks for the invite. I'm Oliver. I used to do Firefox things a few years ago. And since August, I've been doing compiling JavaScript to WebAssembly full time.
Joel Moses:That's great. Now for those listeners who are not familiar with the term, can you explain to us what ahead of time compilation is and maybe dig into why it's a bit of a tricky business with a scripted language like JavaScript?
Oliver Medhurst:Yeah, so ahead of time is usually as opposed to just in time, which basically every JS engine today, say like VA, SpiderMonkey, JavaScript call does to try and get the best performance, which is when instead of compiling, say, like C plus plus on the developer's machine, and then you ship a binary to your users, you just ship the source code and then compile on the user's machine because that's great for performance, but also tricky for various other reasons as compilers are. But ahead of time is like C plus plus or REST or any of the more traditional language, which is you compile your source code on the developer's machine, you ship a blob to our users, and they just run it either natively or with WebAssembly or elsewhere else.
Joel Moses:Now JavaScript, of course, brings along with it an interpreter. And the interpreter well, has to lack of a better term, you kind of have to ship interpreter logic as part of this. So why is that specifically tricky? Why is that tricky to do?
Oliver Medhurst:Yeah, so JavaScript is a very dynamic language. Anyone who's used it can tell you that it's very hard because the main things compilers do is statically analyze to be like, oh, these pipelines could just be five instructions. But with JavaScript, it's very hard to do that because it's just so dynamic that you could have string concatenation and integer addition at the exact same instruction and look the exact same. It just depends on what data you have at runtime. So yeah, it's very tricky, but I think it's promising.
Chris Fallin:So I'd love to get more into the type aspect of the dynamic types. I had ton of questions there. But first, maybe it'd be useful for our viewers to understand why would you want to do ahead of time compilation, right? So just in time compilation has been the standard in browsers for, what, fifteen or twenty years now. And it seems to work fine.
Chris Fallin:It does take CPU time on the client side. But why would you want to do ahead of time compilation?
Oliver Medhurst:Yeah, so there are, I guess, a multitude of reasons, one of which is there are many environments where you just can't do just in time. Like, say, you're shipping to an embedded device or a game console, but for security reasons, they just don't allow just in time, you still want good performance. Because in some micro benchmarks, interpreters can be worse than 10 times slower because it's just interpreting. And then there's other reasons, like say you just want a native binary for your JavaScript. Like say you're making a CLI app, then your only option today is to ship, say like all of Node.
Oliver Medhurst:Js or like one of those alternatives, which is like 100 megabytes, which is not really ideal. But with ahead of time, you can just ship a like less than one megabyte binary. Just And looks hopefully.
Joel Moses:And I imagine the systems that also launched and process a number of different streams simultaneously, where instantiation cost is at a premium, is also one of those.
Oliver Medhurst:Yeah, Cloud offerings like say AWS Lambda, they really struggle with cold start times, which is you have to start the entire JS runtime if ASM has started recently, which can easily take like hundreds of milliseconds, which for web request is not ideal. But if you're compiling to WebAssembly or native binary, it's basically zero three times. It's very nice.
Chris Fallin:So so let's dig into the the dynamic aspect of JavaScript a little bit more. You you kind of alluded to just in time compilation being the standard and that having to do with the dynamism of the language. Maybe could you explain to our viewers why it's typically good for an engine to observe the program executing before it tries to optimize?
Oliver Medhurst:Yeah, so because JavaScript types are so wide ranging, if you say have a loop which adds 100 variables just statically, usually you do not know all those strings, all those numbers, all those floats, they integers. So just in time compilers being able to analyze on the fly, where this function has been run five times, it's always been run with integers. I can just rewrite this code to always use an integer. Worst case, you just de opt, fall back to the interpreter, which is still relatively fast anyway. So it specializes on the fly for those typical situations, which is great usually.
Oliver Medhurst:But then there's also the problem of the kind of monomorphism of, like, say you have a function and you call it 100 times of an integer, then you call it again with a float. You can easily see that one call taking like 100 times longer, which some big projects, like I think there was the TypeScript compiler, because that's all written in TypeScript and JavaScript. They have had some just like changing a few lines to make things monomorphic and it's like a 10 times speed up for some functions.
Chris Fallin:Wow. That sounds difficult to deal with as a developer having these performance clips.
Oliver Medhurst:Yeah. So like ahead of time, for example, you can't do that dynamic observation. You just have to statically analyze as best as you can. Because if you guess, oh, this is always called a vintages, but then it isn't, you can't optimize on the flight, you just crash.
Matthew Yacobucci:So are there like ultimately will just in time compiling give you best performance, but ahead of time compiling will maybe degrade performance a little bit. That's probably not the right word, but it gives you more consistent performance. You don't necessarily have these spikes and troughs.
Oliver Medhurst:Yeah. At least for now, my goal isn't to be as fast as just in time. It's something to be faster than say interpreters. But I think there's a happy in between of it's like reliably say five times faster interpreter and 50% slower than just in time. Like no matter what types you give it, it has that consistency.
Oliver Medhurst:But then also I have experimented with, say, profile guided optimization, which kind of does the same thing as Just In Time, but that's like its own field and also has its own wormhole of tricks and troubles.
Chris Fallin:So walk us through you're not able to observe the program and see the types. Is Perfor doing any type specialization still with some sort of ahead of time analysis? Like are you inferring types? That sort
Oliver Medhurst:So probably there's at least a thousand lines of code just for type inference and like analyzing types. It's still, you still have to like only do things if you really know it. So like my inferring is very hesitant to just completely delete code. But if you know this is just a string and then you say like do a plus sign, you know that's concatenation because that's a string, which is really nice. But then say like functional arguments, typically you can infer those types because that could be called of any arguments anywhere.
Oliver Medhurst:So unless you have really good analyzation, then it's very tricky, which I'm starting to get, but it's still very, only does it if it's completely sure.
Chris Fallin:So for the compiler nerds on the call, I guess it sounds like you're saying you have intra procedural, but not inter procedural analysis?
Oliver Medhurst:Yep. Yeah. Basically. And I'm starting to do that, at least for my optimization approach, I am trying to be very low level essentially where it's like Wasm instruction by Wasm instruction probably them being really high level because it's like much more annoying to do, but the kind of payoffs you get is much wider reaching. Like say I have dead code elimination, but I haven't specially written that.
Oliver Medhurst:It just knows, oh, this if instruction is always called with, like, true. So just never take the else path.
Chris Fallin:I think I saw something about this in your repository. You have some partial evaluation. The approach you're using?
Matthew Yacobucci:Yep. Sorry. Mhmm.
Chris Fallin:That's super cool.
Oliver Medhurst:Thanks.
Joel Moses:So let's talk about the performance aspects of this. And I know that there's a deficit. You support in Porffor JS to Wasm compilation, but also JS to native. And I think native is significantly faster, but Wasm is of course portable across run times, for for WebAssembly. But compare that to compare that to the being able to run a JavaScript routine in in Wasm itself.
Joel Moses:What is the benefit of Port four to JavaScript in Wasm?
Oliver Medhurst:Yeah. So one of the main benefits is say like your website has plugins and you want to be able to run those with good security. There are some like JS sandboxes today, but they are all have CVEs yearly at least because sandboxing JS is very hard. But if you just run-in WebAssembly, you have control of every single import and export, like no matter what. So you get that kind of free sandboxing.
Oliver Medhurst:And also a lot of times it's just say my hosting provider only takes WebAssembly for some reason, like the specially optimized WebAssembly, then you just have to have a WebAssembly binary. There's no And other
Joel Moses:most of the JavaScript tooling for WebAssembly bundles an interpreter inside. And your approach, of course, does not do that. Now, what does that do to both the size and the performance?
Oliver Medhurst:Yeah, so for the size and performance, I will gather up the data so I'm not just talking.
Joel Moses:You actually have graphs on this one,
Oliver Medhurst:Yes. So, yeah, so for JS to WebAssembly versus an interpreter, I get like 10 to 30 times smaller binaries. So instead of like one megabyte, get like 100 kilobytes, which is very nice.
Chris Fallin:And
Oliver Medhurst:it's similar for performance as well because you're just compiling instead of interpreting.
Joel Moses:Now, presume since this is not a full interpreter that you are essentially, you're doing some of the JavaScript interpretation and build yourself. So there's a conformance gap, I imagine. Some things that are supported and not supported. Where is Porffor right now in that?
Oliver Medhurst:Yeah, so that's the main trouble of doing this, not even just the ahead of time part, but running an entire JS engine from scratch. Because JS is a big language because it supports the entire web that has to be. So I currently support about 60 of the entire language because there are tests written by the spec authors of JavaScript. And they cover everything from basic variables to for loops to date to newer proposals like temporal, which is the new fancier way of doing the end time things, which most browsers don't deploy yet, but they do this.
Matthew Yacobucci:Does this mean there's an optimum use case for Port four right now?
Oliver Medhurst:Yeah, I think the main ultimate thing right now is just say like, I think that the short term dream is say you have a CLI app, you can just run out of this and get like a one megabyte binary file, which you just run instead of needing the user to install Node. Js or something or shipping like 100 megabyte binary of some runtime bundles. Because even with something like Quick. Js, which is like the kind of go to JavaScript interpreter, which is much smaller than say node or do you know, or etcetera. But even that is like a few megabytes.
Oliver Medhurst:Look, if
Matthew Yacobucci:you could save people from using NPM, I think you're gonna have a lot of friends. Yeah.
Joel Moses:We have plenty of experience with JavaScript interpreters here, both in JS for NGINX directly and also QuickJS is also supported within the NGINX console complex as well. And yeah, the functionality gap is real you're implementing.
Oliver Medhurst:Yeah, QuickJS is very nice. I think my proudest moment making this so far was I did a benchmark, which is I think, like a twenty fifteen VA benchmark. And me me compiling and running in WebAssembly was two times faster than QuickJS running natively. Wow. That's very nice.
Joel Moses:That's very nice.
Chris Fallin:So I'm curious how one even gets started building something as large as a JavaScript engine from scratch. You mentioned the 60% number. Do is the way you think of this just to kind of start with, like, the oldest version of JavaScript and then keep adding like, okay, now we support ES3 and now ES5?
Joel Moses:That's a question.
Chris Fallin:Are you building based on, I have this one holy grail thing that I want to run. I'll build everything it needs. How do you go about this?
Oliver Medhurst:Yes. So starting out is more like what is easiest? Like what can I do this week? But now lately it's more of like a target. Like I think like one of my big targets coming up is being able to self host, which is being able to compile itself fully with its own compiler, which is both very nice to have, also very hard because writing it, I'm like, oh, I'll use all the new fancy modern JS things, which I now have to support to compile.
Oliver Medhurst:But say, like every built in API, like say, array. Push, dates, all of those are all written in TypeScript, and then compiled with Portal to WebAssembly to have those built in APIs. I So already kind of have that to a degree, which is really nice for that kind of dog feeding. Because I've had it a few times where like Yes, I was implementing Regex, a Regex interpreter, which is written in TypeScript compiled by itself. There's a few things I wrote another compiler failed, and I was like, Oh, guess I'll fix this compiler bug I accidentally found.
Oliver Medhurst:So yeah, I think for the most part, it's just have a nice subset, which is like most things need, which I'm kind of getting to, like say Temporal, which is a newer proposal. I probably won't talk about for a while because not even most browsers support it yet. Most people don't use it yet. But the main things I'm lacking is more just I haven't gotten to it rather than for any technical reason.
Joel Moses:Yeah. Cool. Cool. Well, the JavaScript community does tend to be a little bit some how do I say this? A little bit religious in some of its affiliations.
Joel Moses:Yes. What would I know that you were invited to to present at TC39. And what's the reaction in the JavaScript community been to Port 4?
Oliver Medhurst:I'd say it's been surprisingly positive. I was expecting some pushback of, we like, didn't want to learn a new JavaScript engine or have to deal with new limitations. But I think probably everyone I talked to has been really looking forward to it. It's just mostly the unfortunate state of people really want to use it when it's ready, Which like there's still not a huge gap, but like a large gap of just getting things to work, which is like an unfortunate necessity.
Joel Moses:Yeah, I think on your website, describe it as pre alpha with usability beginning in 2025. Are you there? Are you there yet?
Oliver Medhurst:I'm definitely starting together. Like even though the start of this year is passing less than 40% of the entire spec. It's been a nice bump. The main thing now is not even just what parts of the JS spec I support, but just like not crashing. Like I fixed most, like say like I can run a lot of things, but if you run them for thirty minutes, I'll have some memory leak and crash.
Oliver Medhurst:But it's lot of things like this is just like getting it stable. So
Matthew Yacobucci:does that mean I do have some garbage collection issues
Oliver Medhurst:or like with the Yeah. It's Okay. PC is like its own art and all my allocation, etcetera, is very simple, which is just like, how can I get this working well enough? So, yeah, for like long running programs, isn't that. But my main target probably for this year is say like an AWS Lambda thing, is just you have five hundred milliseconds to respond to a web request.
Oliver Medhurst:Stuff like that, I can probably just not have a GC because it will just die in five hundred milliseconds. So I just don't have to worry about running out of memory, etcetera.
Chris Fallin:So there's the WebAssembly GC proposal, right, an extension to the core bytecode that allows using a host side GC instead of the thing built in. Have you thought about using that or a mode that would use that in Perfor? I imagine there are some shortcomings still with like finalizers and stuff that but, yeah, what what do you think about it?
Oliver Medhurst:Yeah. I think my kind of dream is to have like a setting somewhere, which is just I want no GC, I want full force on GC, or I want Wasm GC. Just being able to configure that because say you're running in a web browser, that's like the dream for Wasm GC. It will run really well. If you'll say, compiling to C or to like, a server side Wasm runtime, which doesn't support Wasm GC, then you all want to not use that.
Oliver Medhurst:I think the dream is just having letting the user decide and having some, like, nice subscription.
Chris Fallin:So so one other thing I wanted to ask about was the the community aspect of this. So so we've mentioned, you know, this has gotten and you mentioned this has gotten positive interest in the JavaScript community. Really impressive progress. Have you found that it's been productive in terms of people come in, see it's not ready and say, let me help and contribute? And has that built kind of a community that's working well?
Chris Fallin:Or how have you found that process?
Oliver Medhurst:Yes. I think the main thing which has helped me recently is just people filing books rather than PRs because it's just like someone tries to run this code, it doesn't work. Because there's so much JavaScript, it's hard to just know what to try, like what people are actually using today. I've had a lot of issues, which is just like, here's a JS file, please fix, which is typically not that helpful. But it's nice to just have the code to sample.
Oliver Medhurst:And there's been a few people making PRs, which is really nice. Like, one nice thing is, like, the actual compiler itself isn't that nice to work on because I don't think any compiler is. But say, like, all the built in APIs, that's basically just normal TypeScript, which like hundreds of thousands of people probably know because it's basically web dev, but cursed. So it's nice to see people like working on that. Like, it's typically pretty easy to work on.
Oliver Medhurst:You you
Matthew Yacobucci:mentioned people giving you bug reports. How how do you how do you wanna be contacted? What's your what's your favorite way? Do you have, like, a Discord or Zulip or or is it mainly just through GitHub?
Oliver Medhurst:Yeah, so I have GitHub and Discord, which both they use. GitHub is nicer for that kind of organization. But if someone's just like, how do I do, like, how do I run a file? For example, like if they can't understand the docs, then this code is great for just being like, sick man, please try it. Excellent.
Oliver Medhurst:Yeah. So for everyone listening,
Matthew Yacobucci:we'll have that we'll have those linked below.
Joel Moses:Definitely. Now you all you ship a essentially a WASM to c engine two c, JS as as I understand it, for compilation. Is there is there something in WebAssembly that would make it easier for you to to maintain or or construct a cross compilation utility? Is there something it's missing?
Oliver Medhurst:Yeah, so it wasn't, I forgot which project, but there's like a official wasn't to see compiler, which is great, but it's very like, it will give you C to, like, use in a C project. It would just give you a C file to use, like, say, any imports or exports. It will just give up and make you define them in C, which is fine to a degree, but it's nice because I have my own. I can say, like, if you have locals, I can name them properly and see for, like, easier debugging, or I can do a few performance tricks. Like, I can recognize an if as an if, not just like, oh, there's like two blocks on an if.
Oliver Medhurst:I can usually work around that to have a bit faster C performance. But I'd say typically it's fine. There's some stuff like, say, Wasm GC, will probably never support that and just move it up the chain as an abstraction. Or some other WASM proposals are kind of tricky, like say, I haven't done this yet, but say like atomics would probably be tricky in C. But I think for the most part, it's pretty nice because a lot of it is just like, one or two lines of c per Wasm instruction.
Joel Moses:Now the people that you see that are interested in Port four R, do they tend to be JavaScript people who are looking for ways to gate to WebAssembly, or are they WebAssembly people looking to support JavaScript?
Oliver Medhurst:I'd say it's kind of probably not fiftyfifty, but a lot of interest from both sides I've experienced. Just wasn't people say that making a product which is a cloud thing for only users wasn't files as input. So many of them want to support JS without having to ship an entire interpreter for various reasons on their side. So a lot of interest there and a lot of interest from just, I want to ship my JS as a blob. Even regardless of say performance and size reasons, say you're working on a capture, which you don't want anyone to reverse engineer for security reasons, having that as a WASM blob is probably 10 times harder than reverse engineering some JS instead.
Joel Moses:Now I know that on your GitHub repo, at the very bottom, state that you intend to only use WASM proposals that are common. The ones that are uncommon or draft, you stay away from. Are there some draft ones that you have been tempted by?
Oliver Medhurst:Yeah, a few. I think the first one that comes to mind was, I think there was a SIMD proposal after the initial one, which I think is, it might be merged now. It's might be really merged merged now.
Chris Fallin:Relaxed SIMD, is that the one you're
Oliver Medhurst:thinking Yes, I think that is. I think that's in most engines. But when I was first doing it, it was I was either not in V eight or behind the flag or something. There's a few ones like that which are really nice, but like, especially if, say, V eight doesn't support it, even if it's behind a flag, most people will just not know how to do that.
Chris Fallin:Are there proposals that you or changes to the bytecode that you would like to see that would make it easier to target?
Oliver Medhurst:I mean, honestly, the first one that comes to mind is having some way of duplicating a value on the stack without having to use a local, which I feel like is a tiny ask. But I feel like there's probably a way it doesn't exist. Like, there's probably a reason why. But there's just so many times where I have to have some temporary local to do some stack manipulation. Where it's like, I want to swap two values on the stack or I want to duplicate a value And just there are no nice ways of doing that.
Oliver Medhurst:It's understandable to a degree, but
Joel Moses:So is there anything the community can do for the Porphyro project that you would like to see?
Oliver Medhurst:I guess the main thing is just harassing you with bug reports. It's
Joel Moses:harassing you.
Oliver Medhurst:One of the most useful things, which is just people trying things and being like, this is broken.
Joel Moses:Gotcha.
Oliver Medhurst:Like, can just add that to my list of, like, things to try. Got it.
Matthew Yacobucci:I'm wondering if there's I'm curious in this. This is a little bit of a digression, but are there any lessons that other ahead of time compiler people could learn? Like, let's say, I think it's safe to say Python is a popular language and it also has a similar paradigm to JavaScript being dynamic. Are there generalities that us as a community can learn from what you're doing?
Oliver Medhurst:Yeah, think it's a good question. I think generally my advice is it might be a hot take, like sometimes I'll spend days theorizing on like a good way to do something, but just going for it is often nice to just see like what works. Like, there's been some things about, say, I'm doing a performance change and I can spend easily days in a Google Doc writing code by hand, theorizing, I think this will be 50% faster than just doing it And just seeing kind of real world results is nice. Like when I was first starting the project, I thought it would fail immediately. Like I thought I would hit some hurdle and be like, I give up.
Oliver Medhurst:Because I just thought of it as a side project. So I was like, this will occupy my free time and make me learn more lesson stuff and compiler stuff. But like, I haven't hit a brick wall. So it's basically just iterate, try things.
Joel Moses:Yeah. Well, it's certainly impressive progress. We're ticking down to the end here, unfortunately, but I've got one final question. And I just because I've read the GitHub, but I just for our listeners, why Porffor? What's the name?
Oliver Medhurst:Yes. I was learning Welsh when I started this project, and Porffor is purple because no other JS engine is purple colored. Nice. Almost everything is yellow or blue or some shade, but I was like, need the SEO.
Joel Moses:That's great. That's great. Well, Oliver, thank you very much. Look, you've made a tremendous amount of progress. And it was wonderful to host you here for TC39.
Joel Moses:And I know that the community really enjoyed the discussion. And as always, thanks for Chris for pitching in as cohosts. Before I go, a quick reminder, friends don't let friends jit in production, so compile ahead of time and responsibly. It's a big application world out there, and it's time to unleash the power and promise of WebAssembly. For Oliver, for Matt, for Chris, myself, thank you for listening in.
Joel Moses:Be sure to subscribe for future WebAssembly news and views. And until next time, take care.