 Okay, thanks everybody for coming today. My name is Joel Dice. I'm an engineer at Fermion. And I wanted to talk to you about one of the projects I'm working on at Fermion. The funny thing about this is it wasn't really intended to be a project. It was just going to be an afternoon experiment and a little time to find out if I was able to build a cloud native app using WebAssembly and Java. And the answer to that was no. And a more practical person would have stopped there and gone on to more productive matters. But I actually decided to dig deeper, find out what was missing. And so that's what I'm here to share with you today. And not only did I find out what was missing, I started to piece things together and added some new tools to the mix to actually make it work. And now I've become somewhat addicted and now you have to listen to me rave about it today. So to set a little context here, this is the vision probably very fresh in your mind after Luke's talk here that we have, which is you should be able to take any language you want. In fact, a bundle of languages, if you're a Polyglot development shop and target WebAssembly, build a WebAssembly component and then run it in whatever target environment you want it to run in. And that could include application plugins, it could include serverless functions, stored procedures and databases, and of course the web browser. And a couple things to notice about all these places I've listed here is that we want to be able to provide isolation. In pretty much all these cases, we have sort of a mixed trust model where you've got code possibly from multiple origins, certainly that's going to happen in a web browser but potentially in any of these cases. And you want to separate them from a security standpoint and a privacy standpoint. There could be sensitive data you're handling. There could be a multi-tenant situation that you need to support. So that's really important. And the other thing is in many of these cases we want fast startup time. In the browser you want a page to load very quickly and start being interactive very quickly. You want fast startup time in terms of HTTP request handlers in a serverless scenario. In a database you want to be able to run a function on a piece of data hundreds and thousands of times and you want the latency to be minimized for each of those runs. So that's going to be a big theme here is isolation, sandboxing, whatever you want to call it to ensure that separation of concerns, separation of data, separation of resources. But today we're going to focus in particular on JVM languages, Java itself, Scala, Closure, Kotlin, whatever your favorite JVM language is. We want to see that work in all those environments. So we'll start out by looking at some of the traditional tools you would use in Java development and then compare those with what you'd use today to develop web assembly components and then see how we can combine those. And then we'll look at why you would want to do that and also why you might not want to do it. We'll look at performance, what sacrifices, if any, do we have to make to achieve that level of isolation? Is there a throughput versus latency straight off? What have you? And then we'll look at some of the limitations of the current state of this tooling and how we can remedy them over time. And then I've recorded a quick demo. The law of demo says if I tried to do it live, it won't work. So let's pre-record, which I had to do like six takes. But so I want that work to pay off here. And I'm going to show you the result. All right. So in Java land, it's all centered around so-called Java byte code. And we basically want to start as an application developer, whether I want to write my program in Clojure or Scholar or Kotlin or Java itself. All of these are going to compile to Java byte code. And that Java byte code can then be run on what's called a JRE or a Java runtime environment. And that environment has two pieces. It's got a virtual machine that interprets the byte code, executes it. And then it's got a standard class library, which provides the APIs and basic tools that you would use to build an application. And the main function of those APIs is to provide access to the outside world. Operating system functionality, networking, that sort of thing. So how does that compare with the WebAssembly component model development experience? Well, it turns out it looks very similar. It shouldn't probably surprise you. If you've been around computing for a few decades now, you'll recognize that Java has already sort of covered a lot of this ground with mixed success. Certainly there were Java applets back in the day running in the browser. You could run it, you know, the whole idea was write once, run everywhere. That's what we're trying to do with WebAssembly. We're trying to do it better. But it's not surprising that we're following a similar pattern. And so here, you take your favorite programming language again. You compile to a WebAssembly module or component. And then you run that this time in an environment that very much resembles the JVM. But this is a WebAssembly runtime. It interprets just in time compiles what have you the byte code in the WebAssembly file. And then we have various APIs to interface with outside world. That's what Luke's talk was about, is modularizing those APIs. But right now we have Wazzy for interacting with POSIX style systems or something that can be made to look like a POSIX style system. We have Web APIs, if you're running this in the browser, that you can create JavaScript shims for. And then you can run that anywhere. So what would it look like to combine those things? What if your favorite programming language is, in fact, Java or Kotlin or what have you? We want to be able to do the same thing. And so in order to do that, we've introduced a couple of tools here that might not be familiar to you. The first one is TVM. And I've since created a friendly fork called TVM Wazzy. And this is a tool that takes Java byte code and will essentially transpile it to WebAssembly. And then that WebAssembly can be run as usual on a WebAssembly runtime according to the world to use Luke's terminology that has been defined for your application. And so any compatible host that can host that world will be able to run it. And you'll run it as usual. I mentioned worlds to mention the other tool, which I think Luke also mentioned, which is WitBindGen. And this takes a set of WebAssembly interfaces and generates bindings. And that's the second big contribution we've made here, which is Java bindings. They landed probably about a week or two ago in the WitBindGen repository. So now you can generate Java bindings. And if you know anything about the Java ecosystem, it's very easy to reuse those bindings in closure and from Scala and so on. So one set of bindings makes it usable from all of those languages. So next question might be, why would you want to do this? This looks a little more complicated, right? Good news is these tools are actually sort of hidden behind the scenes. You don't really have to work with them directly, as we'll see later. All you have to do is a maven build and you're off to the races. You've got a WebAssembly. But there is extra complication, extra things that could go wrong potentially. So why would you want to do it? Well, first let's look at why you might not want to. First of all, if you are well served already with the Java ecosystem and your team knows Java or Scala, what have you, and you're used to the tools that are available in that ecosystem, you probably do want to stick with that. If you're well served, if you're writing long-lived stateful applications and services, that's what Java was made for. It's got decades of optimizations and fine tuning for those sorts of things. If all your code is trusted, you're writing a monolith or microservice that all your dependencies are vetted, Java does really well there. And then as we'll see in a moment, the JVM has maximum throughput. It's the hotspot JVM from Sun and now Oracle has been optimized for decades. It's an amazing piece of technology. And so I would sum this up as by default, if you're using Java, you should probably use the JVM. Especially if it fits the workloads that you have. And so when we would consider WebAssembly here for Java, it's kind of the flip side of that. Many shops these days want to be able to use possibly a mix of languages that are JVM friendly and not so JVM friendly. And the hot thing these days is building services out of stateless functions, the whole serverless paradigm. And as we saw earlier, short lived functions have applications and databases, smart contracts, etc. Those cases are not necessarily what the JVM was designed to handle. Whereas WebAssembly, that's kind of its bread and butter. Untrusted and or multi-tenant code. This is definitely something you've seen the browser, serverless. If you're hosting a platform as a service, or you're choosing a platform as a service, you want to know that there's strong security and isolation guarantees, that your data's not going to be leaked. Through side channel attacks or otherwise. So a strong sandboxing model is super important. And then even if you're not in a multi-tenant context, these days, any modern app is going to have a long list of dependencies and transitive dependencies. And for Java developers in particular, the whole log for J fiasco is fresh in mind. And people have been talking seriously about how do we deal with this? How do we address supply chain issues? And that's a multifaceted problem. But one of those facets is sandboxing and limiting the scope, the capabilities to use Luke's term that are available to a dependency. And so if you were a Java systems administrator a few months ago, you were probably asking yourself, why did my logging framework make network calls? A, and why did it load classes off the internet to execute locally? With WebAssembly, that's a non-starter. First of all, you wouldn't give your logging framework network capability unless it specifically needed it. And even then, you would restrict the set of hosts it could access. And class loading just isn't really a thing in WebAssembly. So all your code's gonna be there up front. So, but one question often comes up, certainly came up in my mind when I was working on this, is what about performance? Is sandboxing expensive? What cost am I paying to achieve that sandboxing? And so here's a chart, performance is a complicated subject. It's hard to sum up in a single chart or set of numbers. But what I've done here is I took just a handful of little example, CPU heavy types of problems and benchmarked them in various execution models. So just the main takeaway here is what I said before, maximum throughput is what you would get from OpenJDK or any other modern JVM. And that's what we see here in the blue. That's OpenJDK with no attempt at sandboxing. We're just trying to get the best possible performance. And then over in red, we have TVM plus WASM time, a popular WebAssembly runtime. And we can see how performance stacks up there. And then in the yellow, we have OpenJDK again. But this time, we're actually trying to sandbox it. We're actually forking a process for each invocation of our function here. And so we see that has a performance impact. And just for fun, I threw in GrawLVM's ahead of time native compile option, which also with sandboxing. Just to kind of see how WebAssembly with TVM stacks up against the other options you have for sandboxing Java. If you've been around the Java ecosystem for a while, you know that there were originally, I should say, past tense ways to sandbox code within the JVM. That's been deprecated. The security manager, if you're familiar with that, that's been deprecated. There's no planned replacement. So these are really the only viable options you have for sandboxing Java. And the main takeaway I want you to have here is that TVM and WebAssembly are competitive with your other sandboxed options. You do lose a little bit in terms of single core raw throughput, going from a non-sandbox scenario to a sandbox one. But for a lot of us, sandboxing is non-negotiable anyway. So we don't even need to look at that. And the other thing I want to mention here is that even though performance, there is a performance hit, you can gain some of that back because pure sandbox functions where you're spinning them up very quickly and then tearing them down often don't need to garbage collect. And that's important in a managed language like Java because the execution was executed so quickly that you can shut it down before you even need to garbage collect, and that's pretty much instantaneous. Plus these things are embarrassingly absurdly parallelizable. Each invocation has its own memory, is not sharing state with others. You can horizontally scale these things to the nth degree and win back some of that performance that you lost in terms of pure CPU single core. All right, so all this hopefully sounds pretty good. We've got strict isolation. We've got competitive performance compared to what else is out there. We're buzzword friendly, we're modern, we're hip or cool. So what's not to like about this? Well, there are some limitations. They're all addressable, but they're worth mentioning. Right now the WebAssembly support in TVM itself is experimental. It was actually intended originally as a tool to transpile Java bytecode to JavaScript, and that's still its bread and butter to be run in the browser. So there are some bugs hidden there. It works really well for the most part, but there's bugs and we're going to need to address those. The standard library is incomplete, there was a deliberate decision, and I think it was the right one not to reuse the OpenJDK class library due to licensing concerns, the GPL, and it's maybe not so business friendly nature. Reflection, if you're a long time Java developer, you know that reflection can be like there's a drug that you tend to use to solve. It's the hammer you use to solve all the problems, and many upstream dependencies might need it one way or the other. And that takes a little bit of extra upfront development effort. And then the wazzy component model that Luke talked about earlier, it is under rapid development, that's a good thing, we're making rapid progress. It also means the tools are churning, the interfaces, with bind gen, every day the interfaces change and whatnot. So it takes some work to keep up with. And then finally debugging and profiling, if you're used to visual VM or debugging in Eclipse, the experience for WebAssembly is not nearly as slick. It is doable, it could be made better. And let's see, so in terms of next steps and ways we could improve, it's basically a reflection of the last slide. We wanna get more TVM test passing. We want to add more features to the standard library as popular third party dependencies need those extra features. We need to stay current with the component model as it evolves. We need to ideally generate some debug info. There's various formats such as Dwarf, which Wazemtime supports. And it would be really cool to be able to just open up your favorite debugger and see all the local variables, see the line numbers and whatnot. So we wanna get there. And ideally we implement the JVMTI interface, which is the standard interface for Java applications and debugging. And then finally, the current generated bindings are not necessarily, they're more a direct translation of the WebAssembly interface types. They could be made more idiomatic in terms of error handling via exceptions and so on. Right now they're very usable, but could be better. So given all that, let's see this in action. Let me see if I can find a moment please. So this is my prerecorded demo. Sure we got volume here. It's gonna snap back into place, that's silly. My goodness. Linux on the desktop, what do you know? Let me, got it. It uses wazzy and spin SDK to handle incoming HTTP requests and translate English words to Spanish words. It uses wazzy to access the file system and load the dictionary of words. Also just to show off outbound HTTP capabilities, it can optionally proxy a response from another host. I'm not gonna spend too much time looking at this code right now, but you're welcome to check out the link at the end of the presentation. Here we have the spin manifest that defines the environment that our application will run in, including the list of hosts we're allowed to make outbound HTTP requests to, as well as the set of files that will be available in our virtual file mount. In this case, that will include the dictionary from English to Spanish words. So let's go ahead and build the app that just invokes the maven command we specified in the manifest. And that looks good. So we'll spin up to run it, bring that to the background, find out what cloud is in Spanish, nube. And since I'm already logged into my free Fermion cloud account using GitHub, I can go ahead and spin deploy, which we'll send it out to the internet. And then I can share this URL with other people. Go ahead and test it real quick. Find out what goodbye is in Spanish. Adios. And there you have it. Adios, amigos. Thank you. All right, so that's about it. That was the demo. There's going to be a link here. There's all the links. So the benchmarks I showed you, the results I showed you, those are available in a repository here. There's a link to that and as well as the demo I just did, the application and a few other resources, the link to the Java binding generator in with bind gen and then TVM wazzy. I should just note I didn't make this clear earlier. TVM wazzy is a friendly fork of upstream TVM. We do have a PR open for upstream TVM. We'd like to get it upstream. It's not clear whether that really fits the mission of TVM as the lead maintainers see it. So it may not end up upstream, in which case we'll just maintain a parallel friendly fork going forward. So I think we have time for questions. If anybody has any questions, I'll self-explanatory. This is awesome. Thanks for presenting. Just wondering if you talk a little bit about the translation between Java bytecode into WebAssembly and what's compatible, what's not. How do you kind of polyfill any gaps? For sure, yeah. So the question was, wanted to hear more about the translation that TVM does from Java bytecode to WebAssembly. The first thing to know is because WebAssembly currently doesn't have garbage collector support, doesn't have exception support, doesn't have any notion of reflection and whatnot, that all gets bundled into the WebAssembly that you create, the component. And the cool thing is that amounts to about 180 kilobytes in the Hello World case. That's kind of where you're starting from. So very minimal. Otherwise, Java bytecode, if you squint, it's not that different from WebAssembly. Things like working with floats and integers and so on, that translates almost one to one. The stack model and the register model is a little bit different, but there's a straightforward transformation. Higher level instructions in Java bytecode, such as invoke virtual, invoke interface and whatnot, those all have to be kind of built out of the WebAssembly primitives to do lookups. So there's a whole static memory segment that is instantiated in the WebAssembly for virtual function tables and that sort of thing. But it compiles down to a pretty efficient code, and I'm sure if the proposals to add garbage collection and exceptions to core WebAssembly gain traction, then we'll see that become an even smoother and more straightforward transition. Does that answer the question? Cool, anything else? So in the course of your experiments, I'm curious to see one of the things we tend to see is this, the idea is really easy to see WebAssembly in fast firing functions model kind of thing. A lot of the things like Java.net, like I'm from Microsoft, so it's a similar model in approach, are based on sort of the idea of a kind of a heavy scalable middle tier sort of concept. It's long running, it can do all kinds of cool things. In the course of this experiment that you were working on in this project, how did your thoughts evolve with respect to sort of where the strengths and weaknesses were a little bit more than what you just said here? Did you have things where like, oh, actually we can do that or oh, no, that's not really the thing we should do and so on? Yeah, well, so I was coming at it from the point of view of spin. Matt and Radu talked a bit about the whole idea behind spin and it was very much this mindset of serverless functions and whatnot, so I actually have about two decades of development experience in Java and have worked on those big monolithic long-lived servers and whatnot and I think there's still a place for that, there always is going to be a place for those but I'm really excited about the component model and in the serverless context for basically, starting with stateless functions, using that as your super horizontally scalable building block and then using a distributed data store whatnot to kind of store your state, between requests and so on, to build those distributed systems and so it's really, I think it's a matter of opinion and also a matter of use case whether microservices and nano services and serverless are appropriate versus a monolithic big iron server and I think you just need to know your problem domain well enough to kind of make that decision. I don't think there's ever gonna be the right, a single right answer so that's why I was trying to be very balanced here. I think a lot of people just should stick with that Java model that kind of just long-lived stateful service model and but I do think there's room for a different model depending on your use case and again, being able to reuse this in the context of databases, in the context of blockchain, in the context of the browser, I think we're just seeing a lot of different places people wanna use Java or any other language and that's what this is all about. All right, that's all I got. Thanks for coming. All right.