 All right, so welcome welcome to from was zero to was hero an introduction to was here for gopher's and other species Just in case that you didn't know You would be getting a lot of was zero even if you were we're in this session because for one reason or another these people are using was zero and We're pretty close to reaching 4k stars. So You have the power and I trust you to do the right thing Eternal happiness is just a star away Anyway Who the hell am I my name is Eduardo Vakia did a bunch of things before this but now I work at Tetris service mesh company And it's also an open-source company. There's a few projects that they support and one of them is was zero So I'm gonna talk about that obviously today Also, I'm a goal and noob. So if I say something wrong, please bear with me or correct me. I'm fine I'm gonna give you an introduction to the go ecosystem for people that may not be completely Familiar with it and the challenges that are peculiar to that ecosystem, but this is not necessarily a talk about go you can probably take a lot of You know ideas and Especially if you're a maintainer of a runtime Then I give an introduction to was zero and then explain how zero is being used and now zero is implemented in some of its part and finally Some lessons that we learn along the way. So if I had to say three features that are peculiar and Correctorizing of go are static linking cross compilation and go routines All these things are a kind of defining for the go ecosystem reasons of the success So you can build your static executable deploy it pretty much everywhere. You can cross compile so you can compile I don't know on my M one arm 64. I can compile for Windows x86. That's pretty cool and go routines for easy Easy concurrency so that's pretty cool But however these come with some drawbacks if you're doing static linking It's more complicated to do dynamic code logging. Well, it's actually kind of impossible Well, you can actually do it somehow And cross compilation depends on the go tool chain. That's not an issue per se Good routines and abstraction over OS threads. The reason why I'm marking these are Drawbacks gonna explain a little bit That's the the issue pretty much so every language run time every language has a form of foreign function interface to interface with general native code or C code Here I'm putting I put C in C++ rust and zig as in a you know example languages that compile to see compatible Interface and what you have doing to interface with these languages you have to abide to the rules of these languages So for instance in Python you have C types in Java. You have J and I You have Lib FFI that works with a bunch of other languages and go you have C go So what's the problem with C go? Well, there's not a lot of problems, especially if you're just supporting one platform Like if you're supporting just Linux and boom to that's gonna be that's gonna be a big deal But he was supporting other platforms that was already One of the issues that you might encounter like you no longer can trust I mean that you no longer can just trust the compiler to compile for any Platform that it's out there because it now relies on the presence of a C compiler on your platform And as you might know cross compilation using the C toolchain is kind of painful or it used to be There are also tooling issues. So the tools that you're familiar with Profilers debuggers now do not really work well with the native bit of code that you're linking against because it's a it's an opaque Kind of binary you cannot really introspect Runtime issues as I mentioned go routines are pretty cool But they work because the runtime is aware of them as soon as you run foreign code that it's Native code that is not aware of the presence of the routines basically the the runtime has to give up And it has to give up an entire thread and devoted basically to to that routine that you're that you're running so they do not play well together there are also performance issues and Security issues. Let me explain those more detail. So there's this old issue on the go get up repo That it's it's from 2017 and it and it speaks about performance problems with sego Things have changed over the years, but this is a very recent recent blog post last week and it still discuss discusses performance of sego The too long didn't read version is it's not as low as you would think so things have improved over the years But it's not for free. So it's still It's still a boundary that you have to cross now. Let's see other issues It's isolation isolation security and safety issues So suppose that you have your routine compile using rust and your routine compile using another routine compile using zig And you want to call them Now this is in a way the way your memory will kind of look like and this is can be the Mental model that you can use so everything is mixed up There's no real boundary between the memory that is being allocated with zig the memory that go is using the memory that Rust is using So what you really would like to have especially if you're running foreign code and especially if this is user written code for Extensions is something more neat like this you want your the memory of your of your host or your guest code of your extensions to be neatly isolated this way, so that's how kind of works with with with zero and in particular with web assembly in particular with was zero This is an old talk from the Takeshi wrote and presented cover code for con 2022 the APIs have changed a little bit But that's a that's the same concept anyway You have a bite slice that is a bite array and your memory is all confined in that space for Rust and for zig There's also the other property that your must be familiar with web assembly where only host functions that you explicitly expose are available to the guest so The zig function cannot just call any function only the function I made explicitly available to it will be invocable and it is In this example, we're invoking OS primitives Only those OS primitives that are making exclusively available will be available to the guest So that's a way to isolate make it more secure And in turn this is a way to break the monolith that is break the statically linked executables This is not a talk from another colleague of mine Adrian call This is an example where dapper which is you know a way to do a Sidecars and and and middleware and in the cloud Now provides through was zero a way to write your own HTTP filters using web assembly So instead of having other microservices connecting to the sidecar You can run the web assembly HTTP filter directly in the core with a lot of benefits and it's using this HTTP wasm ABI which is similar conceptually to was HTTP, but it predates that so Before was zero all of the wasm runtimes that were available required sego So all of those downsides that I explained were there so was zero was implemented to support Go developers In a way that's more convenient for them and it's if the name is zero was zero That's zero stands for zero dependency. This means Both that we do not depend on sego extensions and that in general we do not use any on the other third-party dependency So it was funded it was originally developed in 2020 as a site project that's cash you developed and in 2021 Tetris decided to sponsor it with as a top-level project There's three from time developers and there's also two external committee the committers Contributing and of course we also welcome any external contribution With zero voids sego entirely and in the rest of the talk I'm gonna show you a few of the techniques that we're using to do that so by so that these are the premises and this is the you know The the things that we do and this way you can still have static linking But you are able to do dynamic code loading by loading wasm You can still use cross compilation because you're still using the regular Traditional go-to chain. We are not using sego So you can still cross compile and go routines works the way you expect what I mean when I say go go routines work the way You expect well for instance When you're using go you would expect Your go routines to integrate with the context pattern the way which is part of the standard library is using It's used throughout all the standard library enterprise party libraries So you can cancel a context The context is being threaded through all the call chain and this is a way to terminate an Execution abort an execution and this is the crates neatly in was zero so that you can abort the execution of a long-running Web assembly routine. This is simply not no, I don't know if it's possible But in general it's very complicated to do with an 80 native code And so this is another way we cater for our go users oracle things that we support Again, we support cross compilation and we leverage the go compiler for that and we try we strive to make sure that we We are able to cross compile and as many As many platform as possible most of the pattern already supported by a good compiler. So even fancy Fancy platform such as previous D which is not particularly exotic but even plan 9 because why not and Unless you're not familiar with the logo the gopher logo originates from the plan 9 logo When that Rob Pike who's one of the creator of language is also one of the creator of plan 9 So that's not by mistake and you can also do fancy your stuff like you can compile with zero in Web assembly and then you can run the web assembly version of was zero in interpreter mode and then run doom compiled in was zero and then so you can run your was zero in your was zero so you can wasn't while you wasn't and So this is an example of running a doom web assembly doom Version that renders in ASCII art and it'll works. So that's pretty impressive It didn't require any other change besides Actually making sure that cross compilation worked. So I didn't do anything for particularly actually most of the work Adrian did There are a few Projects in the cloud native ecosystem. They're already using what's here in some form or another dappers I already mentioned mozen is an HTTP proxy just like and boy, but it's all written in go Tri-V is a security scanners using was zero to load dynamically web assembly definition for for scanning Cuber net is this is still a work in progress. It's incubating a way to provide custom settlers Using web assembly and it's using with your under the hood Oh, and if you are one user and you have a use case or you know people you can have more use cases at that page at the bottom Just open up here So the main use case for web assembly and was zero is to do plugins and extensions From another point of view want what kind of Compilers and flavors of the compiler are available to compile to web assembly when just tiny go probably you're familiar with it It was probably the first to support wazzy preview one Nowadays even What the proper go tool chain supports wazzy and that's the way I compile with zero in web assembly And this is starting from go 121 which is that just released last month So let's see how was your actually works was zero is that go run time for web assembly, of course And it implements an interpreter. So there's both an interpreter mode and a compiler mode I mentioned the interpreter mode in in the When I was mentioning cross compilation to web assembly because that's the default mode When the compiler is not available. So And that it's supposed to work on most platforms that are supported by go because that doesn't generate any fancy native code It's just to go code But was it also implements an ahead of time low time single pass known optimizing compiler for web assembly Supports MD64 and IRM 64. So if you're on or any on any of those platforms and We're also testing on a major open operating system, which means make who has linux windows if you are in those platforms With which automatically to this this compiler So this is a bunch of words because I wanted to be pedantic though the reason I'm saying it's a low time I had a time compiler is that this is the way it works you load your web assembly module The module is immediately compiled at that time and then at runtime you can instantiate it several times as many times You want it won't be recompiled. So some people would say this is still adjusting time compiler I just want to be pedantic it does the compilation in a separate phase from runtime while for adjusting time compiler I would expect to be there some tracing or at least on specialization at runtime. We're not doing that So if you're familiar with V8 V8 architecture, there's lift-off, which is the fastest single pass compiler This is similar to what we do and then there's and then there's Turbo find which is an optimizing compiler. So our current compiler is more similar to a lift-off than it is to Turbo find but the cool thing is that the cool news is that we're working on an optimizing compiler multi personal optimizing compiler and The showing promising results results the V1 spec is already sort of passing. So the desk cases are released of passing So that's pretty cool So If you're familiar with web assembly, you will be familiar with those functions when you want to provide features and Functions to call in your host language You will write your functions using your host language if you're in the browser You will use JavaScript if you're using Rust it would be rust if you're using web Go. Well, it will be guess what so This is the way you do it. The code is pretty much the same length at the bottom It looks a little bit longer because we're also instantiated a runtime, but it's pretty much the same stuff So in this case where I am providing a dot function not fire very fancy that just summing to number and This is the diagram of how it sort of work inside inside Inside was zero so you have your runtime you provide to the runtime this host module and the host module is just The was zero way to define a collection of go functions that you wanted to be able to invoke from web assembly And then at runtime if the signatures and the names match You will be able to invoke them. So here I'm expecting some function called my host Dota to be available and this is being provided by my host module, which is reading in go and everything would work But how does this work under the hood? Okay, so I already mentioned there's Compiled time and there's one time. So let's see how the runtime works So each wasn't function is compiled to basically as lights of bytes an array of bytes And then this is this is m mopped into memory and then what pretty much happens is that we jump into there? The the execution of that byte array and those are just CPU instruction that will be executed by the CPU Now that's okay, and that will be executed until until we have to leave that that function and return Now what happens if there is an host function call or or a trap? There is an error or some erratic situation So traps an host function are invoked by a trampoline. So what does mean does that mean? Well, that means that basically we have to Play a little bit with this stack to make sure that everything aligns and you can invoke The stuff and then make sure that everything is aligned the right way So when you instantiate a model for instance In an exact native function is being invoked under the hood on the go space and we set up the Registers and the stack in such a way that then we can jump into the execution of the start function in this case That's the fine in the web assembly space that's being compiled Then we execute the function and suppose that some point there is an error. There's a trap So we just leave execution by doing a clean exit from that that function But we return an exit code and an exit code in the go space is being analyzed being matched against the list and Basically what we do in that case is panicking that is throwing an error run Reception whatever so and that's how execution terminates Now suppose you are actually not panicking, but you want to execute of one particular function The cool thing is it's pretty much the same So we still we still want to we still want to exit execution at some point So instead of a just leaving execution with an error code We still leave with some exit code, but the exit code this time contains an identifier for a function that we want to that We want to invoke so on the stack will be the arguments of the function that we want to invoke There will also be the exit code and the exit code is actually pointing to some function we find a function in the go space so we're back jumping back here and We invoke the function with the right arguments that we massage from the stack We we get the results we push them back the result to the to the stack and then we jump back this time To the execution of the native code So we resume execution and so that's pretty much the difference between panicking and execution Of a nose function. That's pretty cool. And that's how it works So what's the lesson that we learned by developing was zero I mean, this is these are my opinion my personal opinion. So I think these are the lessons with that we learned So the web assembly space is a moving target. We know it. There's a lot of cool stuff happening here We're learning a lot of bunch of interesting proposals But our team is not huge. So we have to deal with you know being being conservative versus bleeding edge We have to choose. So what how do we do it? Well, first of all, we have a dual test base We have a lot of we fast the compiler obviously We have our own test suite for the standard library and for Obviously the compiler We test against the course back and these are tests that we do every single time up here up here is being open So every time We also test again the standard libraries of some languages the ghost and a library the zig standard library They're compiling for web assembly and we run all of the tests against our web assembly run time to make sure that we're not Breaking anything and then we also test against tiny go and go in its js flavor Which is still compiling a special flavor of web assembly will suggest. I think we also have test against The m script and flavor of web assembly. So we're pretty covering and of course does was it test suite? We also run that Other things that we do we try to be conservative So we do not implement specs. There are not fairly advanced in their stage of adoption. So Rule of time phase four it has happened. I think we it has happened that we adopted phase three But that's the rule of thumb We're for instance eagerly awaiting for the trading threading to stabilize because that's also really important for go developers in the In the go guest side for the go compiler to compile web assembly And and we want to be user driven when you come to implementing stuff We don't we're not implementing stuff just for the sake of it. We want to have use cases. That's just Our approach we tend to have that approach And also when there are apis that we do not support or we cannot support or we don't want to support Be sure to chat the rationale.md document because we all we always Document the reasons so there are usually well defined reasons why something is not implemented or it is implemented the way it is so We try to be Very very structured that way other compatibility concerns Well, we try to keep the coupling with the code very low So for instance, we try to find the right abstraction like right balance. Well, typical, you know engineering engineering strategies and good good practices We take backwards compatibility very seriously We release a was your 1.0 this March and that's a promise that we did to our end user not to break their user space And we strive to be as cross-platform as possible as already mentioned We test against all major plus and especially we try to test also against Windows and Windows is a primary target So even if it's sometimes a pain because some APIs for instance in YZ pull one off It's kind of a pain because Windows IO Does not really work the way it's not really compatible to pose X like no blocking IO And that's because it's an asynchronous kind of IO But it's not in working in the same exactly the same way as No blocking pose X APIs an interesting Don't you don't have to read all of this But this is an interesting blog post from Matthew Garrett and many Gary is a Linux kernel engineer and In this blog post very recent blog post last week, I think He mentioned that is for living is doing also support of pose X APIs on Windows And it's mentioned how painful it is to do that and an interesting blog post fairly fairly short So you can check it out the taking ways Be mindful of other platforms and other languages. There are many languages on there and we want to have a web assembly to succeed to support all of these languages both as a guest and as a host and Be mindful of operating systems and think about your end users And this has been tried before in a way And I'm not just mentioning Java. I don't want to just talk about only Java There's a history, but as a Java developer myself, that's the history. I'm most familiar with so my Java my fellow Java developers are always like going like oh, yeah web assembly. We know that we've been doing that for quite a while You know, and they didn't really work on the on the on the client. We what's new with that? But I don't want to talk about the JVM only the JVM I want to talk about this project called grow VM. I don't know if you feel you're familiar with it It's kind of top of the hotspot VM. It's it implemented jit compiler different jit compiler from the hotspot VM there's also these layers because there it's an umbrella of projects and Under the same umbrella. There is also polyglot programming. It supports of one varieties of languages Ruby R. J. S. Python and and even C++ and C and even rust through this basically an LLVM fast interpreter for for LLVM IR And and it's being used in the while they're also using it inside I think Oracle database, but that's not its most famous use case In fact, that's in fact Java developers are like, oh, this is grow VM then In fact one of the most famous paper is one VM to rule them all Because the holy grail was also polyglot programming. So what I'm trying to what's the point? I'm trying to make to here. Well, the point I'm trying to make here is the Most mainstream part of grow VM was not something that what they were designing for which is native image That is a compiler Compiler that compiles to native code your bytecode And that's because people did not really embrace for a polyglot programming on that platform you can think of native image as an hybrid between wiser and And and an actual native compiler because it's also doing pre initialization of the bytecode and There's a lot of things that we can also learn from their experience For instance, you cannot really pre initialize everything because if you pre initialize for instance a random seed Well, this is the other you're gonna get so and You cannot really be sure about random, you know So The point I'm trying to make as a maintainer things are moving fast, but you don't have to get burned out things are moving fast, but Adoption will still take a while So you can still make choices and as a community think of your use cases Think of the use case you want to enable enable think of your end users And of course be nice to your friendly maintainers Thank you Of course if you want you can give us a star and these are all the reference that we have If you want to chat with us, we are on the gopher's luck We hang out all of us most of us hang here and That's it. That's all I have. I don't know if I have some time for questions We do okay good so Yeah, we have you a few minutes There's a question there from a maintainer Okay, so the question is if you're curious about was here what would be the best way to start You know playing with it or contribute. No, well, there are many ways as usual with open source software Well, first of all using it The best way to start contributing If you find a bug You can open an issue or and or you can join this luck and just ask us Yeah, and you can contribute. I don't know documentation. Maybe we're pretty good with that So you can try it. That's that's the best way to do it If you want to scratch an itch and there's some features that you would like to see you can propose it and potentially You can implement it like we have a contributor that's working on supporting and scripting and they are doing it and they're contributing that code and They suggest features to introduce inside the engine itself and sometimes these are is these are merged inside a core So yeah, oh another way if you are a user you can contribute to the users are a list of users So that's another good way any other questions Oh, by the way, the question from was from a shield from stealth rocket You should check out the stuff that they're doing time craft and wc prof actually have a slide Since we have time I can show you this light for that as well It's a very cool profiler that sits on top of was zero. I Think I should have a slide for that But anyway Check that out. It's a it's a profiler for your code and integrates nicely with we tiny go with We'd go when it's compiles web assembly. You can also inspect the stack cool stuff and you can also profile pattern. This is recent, right? Super cool. Oh, there it is Any other questions? What blog post? Oh, okay, so the question was when is the blog post coming up? So there's a blog post that is gonna be published about web assembly support In in go proper and the answer is Wednesday. They tell me okay Wednesday Any other questions, okay cool, I'll be around so just just Let's talk in the hallway if you'd like and again, thank you