CppCast - Cheerp

Episode Date: January 21, 2021

Rob and Jason are joined by Alessandro Pignotti. They first talk about a linker project, a better assert for constexpr code. Then they talk about Cheerp, LeaningTech's C++ WebAssembly compiler, how it... differs from emscripten, Cheerp optimizations and some of LeaningTech's other Cheerp products. News mold: A Modern Linker C++ Jobs Q1 A slightly better assert using C++20's is_constant_evaluated How can I write a C++ class that iterates over its base classes Links Cheerp Extreme WebAssembly 2: the sad state of WebAssembly tail calls CheerpX: a WebAssembly-based x86 virtual machine in the browser, Yuri Iozzelli CheerpX repl Sponsors Visual Assist

Transcript
Discussion (0)
Starting point is 00:00:00 Episode 283 of CppCast with guest Alessandro Pignotti recorded January 20th, 2021. This episode of CppCast is sponsored by Visual Assist, the well-known productivity extensions for Visual Studio. Visual Assist speeds up development with features like smart navigation, code inspection and suggestions, powerful refactoring commands, and a whole lot more, even spell checking and comments. Start your free trial at wholetomato.com. In this episode, we discuss a faster linker and a better assert. Then we talk to Alessandro Pignotti, CTO of Leaning Tech.
Starting point is 00:01:25 Alessandro talks to us about Chirp, their WebAssembly compiler. Welcome to episode 283 of CppCast, the first podcast for C++ developers by C++ developers. I'm your host, Rob Irving, joined by my co-host, Jason Turner. Jason, how are you doing today? All right, Rob, how are you doing? Doing okay. You mentioned you were doing some more streaming this afternoon? Yeah, I'm going to be starting a stream in almost exactly two hours from now, but it'll be far too late by the time our listeners actually get this episode. I just haven't done any streaming in like over six months or something. So I thought,
Starting point is 00:01:48 yeah, what the heck? I'll play with it again. What are you planning on doing? I've got, well, I can't aim my camera at it or anything at the moment, but I have a Raspberry Pi here set up with four I squared C devices connected to it.
Starting point is 00:02:01 And it's just been so long since I've done any kind of embedded development. I thought that I would try to see if I can get these things talking to me with C++. Very cool. Very cool. Okay. Well, at the top of every episode,
Starting point is 00:02:14 I'd like to read a piece of feedback. This week, we got some comments on Reddit. This one is from Reddit user Kalmok on last week's episode. And he writes, with respect to networking, can, can we get at least some basic concepts and vocabulary types into the standard? Like buffers, maybe callback signatures, types for IPv4, v6 addresses, domain names, URLs, and maybe synchronous sockets.
Starting point is 00:02:39 And yeah, I think that all sounds great. And I'll just say, you know, Corinton made it clear last week that that was just his opinion uh but you know it seems like the rest of the standards committee is still trying to get uh the full networking library in so we're not really sure how that will play out but um we definitely don't think that networking is like dead on arrival or anything right now no and i think that's kind of i mean even i just wanted to say that the the linear algebra proposals that have come out of the graphics proposal look like they'll hopefully at least also just get some vocabulary types into the standard, at the very least. Right. And I do think that that was a good way to continue getting something out of the graphics proposal, getting those types. Yeah. So if networking does go down and, you know, I'm not really sure where, what my opinion is on that now after talking to quarantine last week, but yeah, if it does go down, hopefully we would get something out of it.
Starting point is 00:03:33 Like vocabulary types. I do agree with this comment, but we might still get the whole thing. We'll see. Yeah. We'll see. Okay. Well, we'd love to hear your thoughts about the show. You can always reach out to us on Facebook, Twitter, or email us at feedback at cbcast.com.
Starting point is 00:03:46 And don't forget to leave us a review on iTunes or subscribe on YouTube. Joining us today is Alessandro Pignotti. Alessandro is CTO and founder of Leaning Technologies, born in Rome, moved to Pisa for his computer engineering studies, spent several months in the U.S., and lives now in Amsterdam. He started the LightSpark project, a C++ open source implementation of the Flash Player. Back when we had lots of free time, Alessandro is fond of movies and sci-fi literature. Alessandro, welcome to the show. Thanks a lot, Rob, and thanks a lot, Jason, for having me here.
Starting point is 00:04:17 I am so curious about your free implementation of the Flash Player, although I think we might get into that a little bit later in the interview with some questions that I want to ask you later. But I am curious what sci-fi literature you're reading currently. So pretty much a couple of years ago, I joined a book club with some friends here in Amsterdam. And the book club is about futuristic literature, and we read both fiction and non-fiction stuff. But I sort of redeveloped my taste for sci-fi. But to this day, I think that the most fascinating one I read was The Forever War. Have you read this one?
Starting point is 00:04:56 I don't remember the author, but it describes the dynamic of war between humans and an alien civilization in a world where there is no faster than light travel. So it takes a lot of time to actually move between space and you will never know when you meet the opposite faction what technology they will have, because lots of time has passed.
Starting point is 00:05:19 It's really fascinating. Yeah, that sounds like, I mean, well, obviously I haven't read the novel, but like, why would you bother if it takes generations to get to the other planet or whatever? That's a good question, I guess. Well, war rarely has logical roots, right? So I'm just going to pull that up to look at that later. Yeah. Cool.
Starting point is 00:05:41 Okay. Well, Alessandro, we got a couple news articles to discuss to discuss and then we'll start talking to you more about chirp okay that's fine sure okay so this first one we have is mold which is a modern linker uh and this is a github repository with a very nice looking readme um and i thought i was interested when I first started reading through this that the main goal of this project was just to be faster than cat. Like the command used
Starting point is 00:06:12 to concatenate objects. As a linker, faster than cat. Right. I didn't think that would be the main way to improve on performance, but yeah. Yeah, but I sort of see the idea there because in the end, most of the time in a linker is actually spent, you know, copying the sections in and out from the input to the output files, which is sort of what Cat does, that you also need to do relocation,
Starting point is 00:06:33 this sort of logic, but I could see what could be the reasoning behind, let's compare to Cat. And also, I mean, yeah, if it can get to the point where it is like actually faster to link than it is to just concatenate files, that would be really impressive. You know that, Jason, it sounds a little bit... I guess it depends. It's a matter of semantics there, because that is achieved, if I understood correctly, by keeping around pre-linking steps,
Starting point is 00:06:59 sort of a demo that we just keep an up-to-date idea of the files in internal data structures so that you can link them faster. So I would argue that that shouldn't count. It's not like it really matters. In the end, the tools are intended to do... If they do their job fast, it's great. But I'm skeptical that that comparison is fair. Okay.
Starting point is 00:07:21 Okay. Okay, and then the next thing we have is a post on C c++ subreddit and this is for c++ jobs that are being posted uh in 2021 q1 uh were there any specific jobs you wanted to highlight jason or just kind of let listeners know that this is still you know being posted every quarter and it's definitely a good resource for uh if you're looking for work yeah i was just thinking i don know if we've ever mentioned it on the show. Maybe we have, but, you know, once a quarter on the C++ Reddit,
Starting point is 00:07:51 if you're actively looking for a job or looking to hire people, they have a sticky thread there. Yeah, and they all have, like, you know, very well-written job descriptions. They're all definitely for C++ jobs. And I think one of the requirements to make a posting here is that you need to have like a direct link to your company and not just like to a recruiter. Otherwise, this probably would get flooded with recruiters posting things. I've been getting some particular recruiter lately that has been contacting me. The local main
Starting point is 00:08:27 bakery in town needs a logistics person. And I'm like, why? Why are you sending me this? Well, they're doing their jobs, I guess. They're doing some job. Some job.
Starting point is 00:08:47 Okay. Something I can add here is that Lean Tech itself is looking for an intern right now. So we just started looking for it. We have not yet added to the listing. We have done it. We actually used the Reddit thread for our previous hire.
Starting point is 00:09:03 We didn't find it through the thread, but we did post it there. And I think we will also post the intern position as soon as we get the time. We are super busy, so sometimes we don't work as efficiently as we would like on the HR side. Is the company based in Amsterdam?
Starting point is 00:09:18 Yes, yes. So actually we are partially in Amsterdam and partially in Leeds, UK, but the technical team is fully here in Amsterdam. Oh, okay. And so, are you hiring people who are remote, or do you want someone ultimately who can move to Amsterdam? I think we will be
Starting point is 00:09:33 strongly preferring a person that could move eventually here. Even better, possibly, a person already here on site. We're looking for a junior position, an intern, so probably somebody from the university, from the various universities of the country will be the best student. But we don't, we will not exclude anybody from this. Okay. And I am reluctant to ask, but I'm still going to anyhow. Does the fact that half of your company in the UK, is that going to be a problem
Starting point is 00:10:02 anytime soon? So, you know, the fair answer to this is that we have no clue yet. This is how the situation is. This is just incredibly confusing. Honestly, I think we are on the safe side since we have companies on both sides of the channel. So if everything goes very bad, we have a European company that we can use to keep the business going. It's going to be okay. I just recently saw an article about a bunch of UK residents with.eu domain names that had all of their EU domains suspended, pending the ability for them to transfer the ownership to someone who is actually a resident of the EU. Yeah, to me, what is crazy is that there is such an incredible amount of small details connected to Brexit
Starting point is 00:10:49 in various ways. It's very difficult to see all the ramifications down the line, every single thing that needs to be changed. Yeah. Okay. The next thing we have here is a post on the CPB subreddit again, and this one is a slightly better assert using C++20's
Starting point is 00:11:06 std is constant evaluated, and this has a nice godbolt link. You want to tell us more about this one, Jason? Well, yeah. I mean, if you try to use assert from a constexpr function, then you'll see very quickly that you can't because assert is not a constexpr function. I mean, it's a macro, but what it does is not constexpr. So I mean, it's a macro, but what it does is not constexpr. So I've actually done tricks like this myself already recently to do.
Starting point is 00:11:29 If is constant evaluated, then do something else, otherwise call assert, or do a debug statement or something like that. So I just thought this was an interesting read. And then a bunch of people were posting it on the subreddit for possibilities for how this could be enhanced with other language features that we don't have but options for the future. This was interesting to read for me since I tend to write very defensive code.
Starting point is 00:11:59 I tend to litter my code with assertions all the time and I never figured out that this could have been that using assert in a constant text context could have been a problem. So I learned something there. Thanks for sharing this. Cool. Okay. And then the last thing we have is a post on the old new thing blog, Raymond Shen. And this is how can I write a C++ class that iterates over its base classes? And obviously this is something that we hope will be solved someday with C++ reflection. It's, you know, but it is possible.
Starting point is 00:12:33 And Raymond Chen showed an example of how you could do this with C++ today. But did you feel, guys, that there is some actual use case for this? So I appreciated the trick. I'm not sure I see the use case. Yeah, I kind of felt the same way. I don't know. What do you think, Jason? I have needed to use something kind of
Starting point is 00:12:54 like this. Oh, well, maybe not exactly like this, but in a couple of cases where, like, well, you use similar techniques when you're doing the merging multiple lambdas into a visitor for calling on variant and i've used related techniques when implementing a version of tuple that did not require recursive template instantiations so it is possible to
Starting point is 00:13:24 implement tuple without recursive templates. It makes it much faster to compile. And you kind of use something-ish like this because you have to use multiple inheritance and then you have to do things to be able to visit all of the members of your base classes. Cool. Very cool.
Starting point is 00:13:39 Okay, so Alessandro, I think we've talked about Chirp once or twice on the show in the past as a news update. But let's hear more about what Chirp is from you, right? Yeah, sure. So what Chirp is, it's a compiler which is designed to make C++ a first-class language in the web. So to solve this problem, of course, you need an efficient and high quality WebAssembly code generation backend, but that's just one part of the problem. The thing is that WebAssembly by itself cannot truly do that much because it is designed as a very self-contained
Starting point is 00:14:19 sandbox. And to give you an example, it is not even possible to truly write an LL word in pure WebAssembly. Pure WebAssembly by itself cannot even write something to the console. Any input-output is actually achieved using what are called WebAssembly imports. So imports are a set of JavaScript functions, or more in general functions coming from the environment, that you give to the WebAssembly module, and then the WebAssembly module will be able to use them. So pretty much what we did to solve the old problem of making C++ a first class language for the web is to implement a brand new fully working code generation that also works directly in JS. So the great thing about SHIP is that you can write a single C++ code base,
Starting point is 00:15:06 and then you can compile it to a combination of JavaScript and WebAssembly. And there are a bunch of rules that you need to follow. There are some complexity there, but the idea is that with SHIP, we have pretty much fused this complexity into the type system. So the compiler is able to guide you
Starting point is 00:15:24 in this somewhat convoluted process. And the end result of this is that you can pretty much use, directly use browser APIs or JavaScript APIs or anything, any object coming from the DOM directly in C++. And if for any reason you make a mistake and you're trying to do this from WebAssembly,
Starting point is 00:15:44 which is not allowed, the compiler will tell you, you will know at compile time and you're trying to do this from WebAssembly, which is not allowed, the compiler will tell you, you will not compile time, and you will be able to rework your code to avoid this problem in the first place. So what does this actually look like when we're calling? It sounds like you said we can call JavaScript functions directly from our C++. Do I understand that correctly? It's one of the things you can do. Yeah, sure. Okay.
Starting point is 00:16:02 And what does that look like? Do we have strongly typed actual function wrappers or something that's available at compile time? So the way we express this is that we have pretty much decided that there is a special namespace, which we call the namespace client. And inside of this namespace, all the classes and functions that the browser defines are available with strongly typed interfaces from C++. So you can literally call, to make the simplest example, would be client namespace console.log. And you're going to call the console.log that the browser provides. The cool thing about this is that these are all declarations. There is no implementation from us.
Starting point is 00:16:44 So this does not require reimplementing of the browser. You're just exposing to C++ what already exists in the browser. And it's also cool that this mechanism is extensible. So there's really nothing special about the browser's function. This is just a bunch of declarations which are available from JavaScript. So you can also use any JavaScript library pretty much. Or you can, if the browser is extended with new APIs, you can write the headers yourself. You don't even need to wait for us to update the interfaces. Yeah, very cool.
Starting point is 00:17:18 Whenever we talk about WebAssembly, we usually wind up talking about Inscripten, which is kind of what WebAssembly came from. How do you compare Chirp to in Scriptum? How are they different? So I think that a good perspective here is to see that the scope of the Chirp project is just much larger. So pretty much in Scriptum at this point, works together with the upstream implementation of WebAssembly in LLVM. Historically, the generation of WebAssembly was part of Emscripten. Now it's merged into upstream LLVM.
Starting point is 00:17:55 And at this point, Emscripten works both as a front-end because it offers a bunch of script that makes it easier to port existing code. And also some libraries are really important so that it's easier to port existing code. And also some libraries are ready to port, so that it's easier to use existing code. And then it also works as post-processing steps, since at least the last time we checked, the code generation of the upstream LLVM is actually not very efficient. And it is assumed that we'll run a tool
Starting point is 00:18:20 which is called WaspOpt on top of the output of LLV lvm itself and this is all abstracted away by mscript and it will do all these various steps which are required to get an optimized output in the end so in terms of uh pure web assembly output at this point uh chip and mscript are quite close there are some things that i think will better some things that they do better we always try to always catch up. But something nice is that everything we do, we do it without external tools. So, Chirp is completely self-contained, and the output is already high quality to begin with. But, you know, all this is only for the WebAssembly part.
Starting point is 00:18:59 Then there is all the other things we were discussing before. So, the JavaScript code generation and the interoperability with JS, the GS export feature that we implement, which lets you write a C++ class and then use it from JavaScript. So, you know, the other way around in terms of interoperability. All of these are features that have pretty much no comparison from script. So you just mentioned writing a C++ class, being able to use it from JavaScript, this kind of cross language interoperability with scripting language is something I've spent a lot of time with, but mostly from the Swig perspective, using Swig to generate the interface bindings and such. So how does that work? Can you give us some insight into how your tool actually takes the C++
Starting point is 00:19:43 and makes it visible in JavaScript? Yeah, sure. So the idea is that we tend to use lots of custom attributes to do what we do. So it's a very general tool that can be used for a lot of purposes. And so we have this special attribute that you can apply to a class, but also to freestanding functions in this Chirp JS export. And when you do that, the compiler will actually enable a bunch of additional checks. And these checks will make sure that what you write can be successfully supported to JavaScript. So the idea is that, of course, there are limitations to what we can do, but one of our policies is that if something is not supported or impossible, the compiler will tell you a compile
Starting point is 00:20:31 time. So stuff will not explode at runtime without any warning. We try to make sure that if something compiles it's also going to work. And the idea would be that if a class is tagged as JS export, it will export pretty much a JavaScript class. So it will have a constructor which is defined with all the various methods added to the prototype. So it will be very natural to use it. And it's very elegant to me that this works. This is tightly integrated with the JavaScript cogeneration of Chirp. Because one problem that you have is that it's about the lifetime. So in C++ you have a very well-defined lifetime of objects, but when you
Starting point is 00:21:09 allocate them from JavaScript this is not clear anymore. And it's unclear when will the destructor be called. Well, the answer is never, because you have no visibility on the garbage collector. So the compiler also imposes some rules that, for example, the destructors have to be trivial and so on and so forth, so that it's going to be safe and valid to use that code directly from JavaScript. Okay, so no sharing shared pointers between JavaScript and C++ with Jira. Well, actually, you could do that. It's important that you need to control the lifetime yourself. So if you need to have pretty much an explicit
Starting point is 00:21:47 deallocate or free function that will free the shared pointer, but you do not expect the destructor to run, and the compiler will let you know that this is the case. Okay. Now, all of these attributes that you just mentioned, do they get in the way? Like, if I wanted
Starting point is 00:22:03 to share the same code base between pure pure C++ library and a Chirp JavaScript land, is my compiler going to complain at me because I have all these attributes that Chirp wants? So in one direction, there's going to be no problem, right? So if you take existing code and try to compile it with Chirp, there will be no attributes there. So stuff will work. Of course, you will not have it exported. That's the default behavior. But in the other way around,
Starting point is 00:22:28 if I recall correctly, unsupported attributes are ignored by the compiler. So you will get a warning, but the thing will not fail at compile time. I guess that to this date, the right way of dealing with this sort of sharing would be to define
Starting point is 00:22:43 a bunch of if-death macro. Okay. In the end, multi-platform support works like that. It is not great, but this is how it in practice works. Sometimes it happens, yes. Okay. I'm kind of curious. Have you had any success stories of taking existing C++ desktop or mobile applications and bringing them onto the web with Chirp?
Starting point is 00:23:12 So, yeah, actually a bunch. Yeah. So, for a while, our company offered the service of porting mobile games to the web, which is actually a pretty great use case because the games tend to, so you know everything that runs in the main thread of the browser needs to be asynchronous, needs to be event driven, because if you have an infinite loop, the browser will stop responding, which is not great. So, but games follow this sort of piloting, right? They have a frame function which is called over and over again to update the state and show new things. And also, mobile games are based on GLES2, which maps perfectly to WebGL.
Starting point is 00:23:52 So we also offer a compatibility library there, so it was very easy to implement. And we did a bunch of this. It works very well. And all of this was before WebAssembly time. So we made all this part with pure JavaScript. And it works fine because something that is nice is that Chirp is actually
Starting point is 00:24:13 a true compiler, right? It's not just a transpiler that tries to convert Citrus Plus expressions to JavaScript expressions. Stuff is actually compiled, which means that the output is also efficient. Not only that, but there are a bunch of tricks that you can do to make it so that when the JavaScript code is actually executed by the browsers, it is fast.
Starting point is 00:24:36 So if you follow a bunch of very subtle rules, which you can figure out by taking a look at the internals of the JavaScript engines, you can achieve a much higher performance of what you could do when you write code manually. It's also a nice side effect of having something that can generate JavaScript for you. Very cool. So you said games, you know, they have this infinite loop main thing going on. And if you just directly translated that to JavaScript, it would cause the browser to hang.
Starting point is 00:25:05 But you can do that. You can just recompile your game that has a main loop in it, and Chirp takes care of that problem somehow. No, no, you will do it. So with Chirp, we try not to make magic solutions, but we try to offer the programmers the tools they need to solve the problems. So we try to reason, well, you know, at the programming language and compiler level, not truly at the framework level. We don't believe that's our job. Okay. So what does that actually look like then?
Starting point is 00:25:31 What does my game loop become if I need to, if I want to compile it with Chirp? So the idea, to make you a practical example, is that we have ported lots of Android games, okay? And these Android games are most usually written in C++, but then they are driven by a Java front-end, right? Because Android actually uses Java apps. So what you will do will be to sort of remove the Java part
Starting point is 00:25:54 and take whatever is the C++ function that they call on update and call it from RequestAnimationFrame, which is an entry point from the browser, which is called at the refresh rate of the monitor to provide fluid animation and end games pretty much. So I guess that you take all the core, you disconnect it from the Java part in the case of Android, and you reconnect it to the interfaces that the browser provides. But the good thing with Chirp is that also this glue code, this connection part, is sold in C++, because that's the idea of this project. What does performance end up looking like
Starting point is 00:26:27 when your Java slash C++ game has been recompiled to JavaScript with JIRP? So when you compile to JavaScript, you usually get a performance seat, maybe 4x, 6x, 6x, something like that. But you also need to take into account that this was in the old world. This was before WebAssembly. So now at least you will actually compile to WebAssembly and get something between either native speed or 2x
Starting point is 00:26:56 and only use Jask for the parts which are either neat to interface with the browser or in the end are not so performance sensitive. The thing is that it's not so bad as one could think. It sounds like if you're going this route, you would want to limit the amount of calls that you make back into the browser.
Starting point is 00:27:16 I just feel like that would have to be one of the bigger bottlenecks. I'm not sure. So it is historically true that the DOM is not very fast. But in my experience, there was never truly that much of a concern. Also, the amount of calls that go, you know, when you write code with this, with Chirp, you tend to have a certain amount of code that goes from JavaScript to WebAssembly, back to JavaScript and so on and so forth. But it doesn't seem to be a problem in practice. That's fine. So the cost is pretty much a
Starting point is 00:27:48 call. So if the call is expensive, then it means that your inlining threshold is where you need to tweak. So you need to add the inline keyword to the function pretty much. But it's not so different compared to native, right? It's the same sort of reasoning. I want to interrupt the discussion for just a moment to bring a word from our sponsor, Visual Assist. Visual Assist is used by serious C++ developers across the world. It's got great code generation. Do you need to implement methods from an interface?
Starting point is 00:28:15 What about changing a pointer to a smart pointer, even an Unreal Engine smart pointer? Adding a symbol you've typed but haven't declared? Visual Assist will do these and much more. Plus refactorings, more powerful than the ones included in Visual C++, or detecting errors in code and suggesting useful corrections, or navigation, helping you move anywhere in your code and open or locate what you need, or even the debug extensions. Visual Assist is written by C++ developers for
Starting point is 00:28:39 C++ developers. It includes everything you need and nothing you don't. It has a low UI philosophy. It won't take over your IDE, but will show up when useful. It's there to help, not to advertise itself. Visual Assist is relied on by the developers building software you've used. Whether that's office suites, operating systems, or games, software you use was built with Visual Assist. Get the same tooling for your own development. Visual Assist supports Unreal Engine 4 and many versions of Visual Studio, including VS 2019 and Community. Get it at wholetomato.com.
Starting point is 00:29:11 I think we saw some things on the Chirp website about Chirp-specific optimizations compared to Inscriptum or normal WebAssembly. Do you want to tell us a little bit about those? The thing is that to achieve high-quality code gen, there is truly no silver bullet, okay?
Starting point is 00:29:28 There is no single optimization that solves the problem where you can go home and rest for the night. It's just a large collection of very small things that overall give you high-quality code. And whenever we do something, we always take into account, as I was saying before, one level deeper.
Starting point is 00:29:49 So we always look at how the actual engines in Chrome and Firefox in particular, how the engines generate native code from WebAssembly or JavaScript to decide how we generate the code in the first place. So we try to bridge this gap between this additional level of virtualization that is in the middle.
Starting point is 00:30:05 But okay, taking this aside, there is also a few optimizations that are somewhat larger and we gave names to them. Also, giving names to something is nice when you have to write a blog post and mention something that people can read and talk about.
Starting point is 00:30:20 So, yeah, one of the things which are more in general, we always work, so the optimization we do always happens at the level of the LLVM internal representation, which means that we have a lot more information compared to if we were trying to optimize just WebAssembly code after it has been lowered. So working at a higher level gives you more information, which is better for optimization purposes. So one other optimization which is possible for optimization purposes. So and one other optimization which is possible by using this approach is what we call the globalizations of globals,
Starting point is 00:30:51 which sounds a little bit weird, but the general idea is that WebAssembly has an independent address space for global variables which is outside of the main memory you will normally use, and it is possible by analyzing the use of globals to figure out if they never have their pointer taken. And in that case, you can actually put them into the global space of WebAssembly, which makes for a slightly smaller code and also slightly faster in some cases. The same technique can actually also be used for constants. For example, large double constants, they fit much better into the space of WebAsimil Globals
Starting point is 00:31:27 compared to the actual regular memory space. Also, using the high-level LLVM IR, we can also do some advanced devirtualization, which is an interesting problem because you can actually do... Devirtualization works in two ways. Because on one side, if you can prove that a certain indirect call always has the same target you can change it to a direct call and that's fine that's great but then you can also maybe prove that there is no possible target for an indirect call which means that that code can never be taken which means you can that
Starting point is 00:32:03 code eliminate all of it so there are a bunch of nice optimizations you can implement by reasoning over the possible call sites. And then there is also Pre-Executor, which is probably the most brand name optimization that we have. And Pre-Executor is pretty cool, and it is designed pretty much to reduce code size at startup time by consuming and removing the global constructors that are used to initialize global data. Oh, okay. Interesting.
Starting point is 00:32:36 So you said, well, I have several things I want to discuss. Apologies. I think I said too many information all at once. Apologies. Perhaps. Let's see. The de-virtualization that you're talking about doing, that is a step more than what LLVM can do on its own. Yeah. So the idea is that pretty much after we have done our regular dead code elimination and we have reduced using normal techniques the amount of code as much as possible, we then take an additional look and we use both rules of the rules of WebAssembly and the rules of C++ to limit the set of possible code leaves. So the idea is that in WebAssembly it is illegal to indirectly call a function
Starting point is 00:33:24 with the wrong number of arguments or with different types in the arguments. So this means that you can rule out any call to something which is not signature compatible because otherwise it will anyway explode at runtime. So it's safe to remove it directly
Starting point is 00:33:40 at compile time at that point. So the platform gives you some guarantees about what is legal and you can propagate this information to remove some additional code. Is that something that could theoretically be done in a whole program optimization setting with LLVM? I would say certainly yes. There is no magic. If something can be done by us, it can also be done by LLVM upstream. It's just a matter of figuring out what is the best way in the,
Starting point is 00:34:07 what is the best place in the tool chain to do this. Of course, we always update, we rebase our work on top of upstream LVM. So if eventually upstream LVM catches up or C-Lang, that's great. We just can take advantage of whatever technique they've implemented as well. Right. How hard is that, by the way, keeping your patch set so that it can be rebased on top of... Or are you modifying LLVM, or are you working at a level higher than that, just taking the IR and modifying it and then re-injecting it into the WebAssembly generator? No, we are deeply integrated, so keeping up to date is sort of a challenge.
Starting point is 00:34:47 Over time, we have developed a process that seemed to work pretty well and it's not so time-consuming. Still, LLVM tend to change quite often, tend to break APIs quite often, so that's not great. So some of our long-term plans is to try to decouple us when possible. So for example,
Starting point is 00:35:08 we would really like that all the front-end checks that I was describing before, so all this fact that the compiler can tell you at compile time what is valid and what not, we will try to move it outside as a C-Lanq plugin so that at least we will not have that part which is fully integrated in the code base, but we have not yet started working on this project. And eventually, we really hope to contribute some of our ideas back, but currently we never have the time to do that so far. Rob, I'm just reminded of our interview with Patricia from a couple of weeks ago.
Starting point is 00:35:41 We're discussing her pain with trying to work with Chrome, which is a constantly moving target as well. Yeah, also Chrome takes 10 minutes to compile to link, 10 minutes to link just to link to my computer and takes over nights to compile.
Starting point is 00:35:59 Yeah, that's what we're talking about. Building Chromium, yeah. Apparently, following her most recent tweets about that building Chromium. Apparently, following her most recent tweets about that building Chromium, you do have to use Google's version of Clang to be able to make a pilot now. I think they ship it together. Yes, that's part of the annoyance there. But anyhow, that's just an aside.
Starting point is 00:36:21 Now, I'm curious about your pre-executor as well. You said it's mainly used to eliminate startup code did i hear that right yeah that's so let me make an example there so let's say that in c++ you allocate a global string okay an std string in a global space and you need to analyze it with a constantly string literal So let's say that a sufficiently smart compiler, especially now maybe with constexpr, it will be able to figure out that this is just constant initialize and just create the right layout in memory for this class. The thing is that this actually happens in practice.
Starting point is 00:36:59 It's not so sure. And of course, you might have something, a more complicated data structure where it gets not, where it's not viable. So the idea is that when the compiler cannot truly convert this initialization to pure memory layout, it will create what's called a global constructor. So it will create a small function that inside contains a call to the constructor for that specific global object. And if you start doing this a bunch of times, you will end up with maybe possibly hundreds of these constructors,
Starting point is 00:37:29 which are all executed before main is even started. So normally in native, you maybe don't even notice. So it's not so important, I guess. But when targeting the web platform, both the code size and startup time is a very sensitive metric. So the idea of Pre-Executor is that we actually run all this code inside the LLVM interpreter while compiling the code. So we take the code that we have just generated from LLVM, and we execute it in the interpreter.
Starting point is 00:37:58 And then we observe what the interpreter does. In particular, we observe the memory allocation and the memory writes, which are done. And at the end of this project, we are able to well, if everything goes according to plan, of course, this might fail and the compiler will bail out and keep the constructor as it is. But if everything goes according to plan, we are able to extract
Starting point is 00:38:18 an actual, just the memory layout of what you want in the end. So you don't have the constructor anymore. You just have a global and its corresponding constant that describes the initialization of it at the LVM level. The next step is that at this point, the compiler can further optimize because if this string is not used anywhere,
Starting point is 00:38:38 this is just going to be dropped and right in this case. But maybe it's only used read-only, so maybe it can be constant propagated into the user code. So there are a bunch of things that can be done after Prexecutor, which are pretty cool. And so in practice, for one of the games we bought years ago, using Prexecutor made the size of the generic code made out for the size, pretty much. It went down by half. That was a little bit of a pathological case. They had thousands of strings allocated in the global space,
Starting point is 00:39:13 but this stuff can happen if you don't think too much about it. Okay. So can it be used, or do you use it for other possibilities, like pre-executing pure functions, like sine or cosine, or something like that? So I would guess that in the case of sine or cosine, probably they will just be constant
Starting point is 00:39:32 propagated by the compiler itself. I'm not sure, but I think I've seen code for that, at least in some cases. So possibly an interesting expansion would be that so far we deal with everything that happens before main, right? But there is also a bunch of code, usually in the main of a function, which is still initialization. You're still allocating a bunch of either singletons or persistent other structures or whatever. It could be interesting to expand pre-executor to also try and execute as much as possible from the main function itself. So pre-executor, of course, stops as soon as something becomes unpredictable.
Starting point is 00:40:08 If you try to query the time of the day or anything random or access a file or anything which cannot be known at compile time, it will stop. But all the initialization, which does not require any of this input data, it could, in theory, be pre-executed as well. This is something that we've been thinking for a while.
Starting point is 00:40:26 We never got to try and work on this problem, though. It is an interesting possibility. I imagine like a constant folding on steroids, basically, to do everything that could be done, yeah. I guess that's more like how D works. I believe
Starting point is 00:40:41 D is guaranteed to do that, execute anything at compile time that could be executed at compile time. Can you tell us a little bit more about if listeners want to get started with Chirp? We did see on the website that you have a commercial and GPL license. What do those options look like? So the idea is that, well, if you just want to test and try something at home, you can just use the GPL version because you're not releasing anything, so there is no
Starting point is 00:41:07 effect whatsoever if you just want to try it out. The idea is that if you're not comfortable with publishing your code as GPL after you're done with it and you want to publish it, then you need to acquire a commercial license. Of course, we also offer highly discounted licenses for individuals
Starting point is 00:41:23 and indie developers, so I thinked licenses for individuals and indie developers. So I think that part is fair and it works. We really hope that in the future we will be able to relax the licensee requirement. We would like to just release everything under a more permissive license. But so far, we cannot yet commit to that. So we hope that as the company grows, we will be more comfortable in betting that more adoption will just convert more without worrying too much about it. Okay. Sorry, go ahead, Rob.
Starting point is 00:41:55 I was going to say, are there any features that you get if you do pay for the commercial license that aren't present in the GPL? So there are a couple of add-ons that we offer, which we've seen that tend to be more useful for commercial users. In particular, there is some additional support for emulating the file system and a partial compatibility with Emscripten. So there is a bunch of custom headers and libraries from Emscripten
Starting point is 00:42:20 that you can use mostly to interface with JavaScript. So the part that's integrated in SHRP needs special handling in the case of Emscripten. And we provide some compatibility with that to provide that migration path. But mostly the main thing you get is that you don't have to release the code. Okay. And we've mostly been talking about the Chirp WebAssembly compiler, but there's other Chirp products as well. Do you want to tell us a little bit about some of them?
Starting point is 00:42:48 Let's say they're part of a familiar product, but they're not part of Chirp. So they have a similar name, but ChirpJ and ChirpX, they're not truly part of different products. But they are still very connected, though. So the thing is that our technical team is made of four people, including myself. When the intern
Starting point is 00:43:04 comes, we'll be five. So we're a very small team. And nevertheless, we are making three products, which we believe to be sort of state of the art in what they do. And the way we can do this is because there is a lot of synergy between these products. So for example, ChirPacks, which is our virtualization technology that makes it possible to execute x86 binaries safely in the browser, is written in C++ and compiled using SHRP. For SHRPJ, we generate a JavaScript code from Java, in this case, and we use the same JavaScript backend that we use for SHRP. So we recycle the JavaScript backend in that case.
Starting point is 00:43:46 We also have some additional components of ChirpJ, which are still written in C++ and compiled using Chirp. Then there is the file system backend of ChirpJ, which is also used in ChirpX, and so on and so forth. So there is all these sort of components, which are used across the various projects, and which is possible for us to kind of sustain this development process of all these very complex things at the same time.
Starting point is 00:44:11 So ChirpJ compiles Java to JavaScript or to WebAssembly? To JavaScript at this time. The thing is that WebAssembly is not truly a suitable target for Java right now. So pretty much in WebAssembly, you will need to deal with garbage collection yourself. While if you generate JavaScript code, the browser takes care of that. So it's a significant less thing to worry about. We eventually plan to support WebAssembly, of course.
Starting point is 00:44:38 I'm sorry, I was just saying, there are other WebAssembly targets that use garbage collection. Like, isn't there a C- C Sharp to WebAssembly compiler now? I think that's Blazor, right? You can certainly do it. You can always do everything. The question is, what is convenient in the end?
Starting point is 00:44:56 We don't believe that WebAssembly is the right target for Java right now. I'm just so curious what the performance looks like from Java compiled to JavaScript, because JavaScript engines are so crazy optimized now. And I'm not as convinced that as much effort is being put into optimizing JVMs these days as is being put into JavaScript engines. Yeah, you know, back in my university time, I spent some time also working on programming language theory. And actually, from the academic point of view, the JVM is understood correctly. It's recognized as state-of-the-art in machine learning. So the JVM is actually also crazy optimized. Of course, the problem is significantly simpler because JavaScript is much, much more dynamic compared to Java. In practice, the level of slowdown we see with ShipJ is below 2x compared to running it natively.
Starting point is 00:45:50 So it's very fast. Our customers run routinely extremely big swing applications. It's fine. The performance ceiling is great. So you have to recompile all of whatever Java library is also being used into JavaScript. So with ChipJ we actually provide a full OpenJDK compiled to JavaScript.
Starting point is 00:46:12 It's part of our runtime. So it's not just a subset. So there are many projects that try to run Java in various ways in the browser, but most usually they have very strong limitations, like no reflection, no multi-threading, nothing graphical, whatever. In the case of ChipJ, stuff just works out of the box. Pretty much the
Starting point is 00:46:32 only real limitation is that you cannot run Minecraft because it uses native code. So any 3D application will use native code. So no JNI? Yeah, we have JNI, and JNI does not fit in this model, but everything which is pure Java will just work. Okay. And what's JIRPX then? Well, it's one step further. So instead of limiting yourself to just one language,
Starting point is 00:46:57 the idea is that you can run any x86 binary safely in the browser. Okay. x86 binary safely in the browser. So in the first use case that now we are publishing due to timing constraints, the ability of running the actual Flash player binary from Adobe in the browser, even when
Starting point is 00:47:17 plugins are not supported anymore. Of course. As one does. But the thing is that it's not only that, right? I'm not sure if you had the chance to see the demo we published a couple of weeks ago, which is our REPL demos. So if you go to repl.linintech.com, you will be able to run either Node.js or Python or Ruby,
Starting point is 00:47:41 a shell of these three languages, directly client-side in your browser. And this is not pre-compiled WebAssembly. This is just the actual packages from a Linux distribution, from a 32-bit Linux distribution, running in the client. Wow. Do you want to tell us a little bit more about what's going on there? And what type of performance hit that might have? Yeah, so when I started thinking about this project,
Starting point is 00:48:09 something like something, it may be five years ago or something like that, but I started actually working on it. We managed to allocate the time as a company to the project two years ago or so. And when I started, my target, like my objective was to, that I would be happy if we managed to get 10x slowdown
Starting point is 00:48:29 compared to native. The thing is that we are somewhat better than that right now, and we are not done with the project yet. So the level of performance is actually great. I mean, sometimes when, you know, I work on this every single day.
Starting point is 00:48:48 So for me, mostly I tend to be unhappy about the state of performance and I like to make it better. I profile, I optimize all this. But every now and then I manage to look at it from just a step of distance and I realize that already what we have achieved is pretty incredible. And the way this works is that in the end, it's not even, it's just what you would expect, right? There are multi-stage execution systems, multi-stage VM, where you have a fast interpreter and a just-in-time compiler that triggers for sufficiently hot code. And this just-in-time compiler
Starting point is 00:49:20 will convert the binary code to new WebAssembly code that can be executed at almost native speed by the browser. So there is lots of moving parts. It's an incredibly complicated problem. But in the end, the pieces of the puzzle are always the same. This is how you make VMs. Okay, so maybe you know the next question I'm going to ask, but is ChirpX written in Chirp, with Chirp?
Starting point is 00:49:49 Yeah, sure. Okay. So yeah, somehow, I guess it's not something usual for a software company, but I think you could say that we are a vertically integrated software company because we control the whole stack. So all the tools we use are made by ourselves, and we actually are also contributing to the WebAssembly standardization project itself.
Starting point is 00:50:13 So we are making proposals. We like to standardize the branching thing as part of WebAssembly, which is going to be very useful for ChipX. So we try to extend all the way along the stack, both at the top and on the bottom. That's pretty cool, getting to write. I'm assuming you're using C++ to write SharePacks in.
Starting point is 00:50:32 Yeah, right. I imagine that there are a couple of people listening to this who will be applying for internships now, because it sounds like a lot of fun, personally. Oh, that would be great. It's fun. It's also very challenging so pretty much the stuff that we do tend to be things that you will not find the answer to your problem of stack overflow it takes it takes lots of uh of deep understanding of complex systems to this sort of to work on compilers in general. It's not the easiest
Starting point is 00:51:07 of tasks. Right. Yeah. Yeah, okay. What are some of the most complex programs you're able to run through ChirpX? To me, the answer would probably be that I've not yet found something
Starting point is 00:51:24 that doesn't run. So, you know, the Flash plugin is an incredibly complex piece of software which has been written over 20, 25 years of time. At least. Yeah, at least. That works fine. Node.js, to clarify, the Node.js that runs in itself includes the V8 just in dimension. Oh, wow. Yeah, okay. And all this stack of virtual machines work, which is pretty crazy. But actually, the next demo we want to publish is going to be a graphical demo.
Starting point is 00:51:56 So we will actually have the full Xorg server running in SharePacks. And if we manage, I have a prototype already, I need to polish it up. I plan to also actually show a Windows application running under Wine on top of Xorg in the browser. That's my next
Starting point is 00:52:16 target for my next demo. That works. I was going to suggest QEMU running Win3.1 or something like that. That's a good idea, actually, running QEMU. I can consider this. Thank you, Jason. It's cool.
Starting point is 00:52:34 Very cool. I feel like we've gone over a lot. Is there anything else you want to tell us about or plug before we let you go today, Alessandro? No, I just wanted to thank you. Thank you guys for having me here. It's, I think members of my team have been pestering me to get in touch with you somehow and get an interview at various points over the last several months.
Starting point is 00:52:57 So I'm very happy that I can now put them to peace about this. Awesome. It was a lot of fun. Thanks. Yeah, it's great having you on. Thanks, Alessandro. Thanks, guys. Thanks so much for listening in as we chat about C++. We'd love to hear what you think of the podcast. Please let us know if we're discussing the stuff you're interested in,
Starting point is 00:53:15 or if you have a suggestion for a topic, we'd love to hear about that too. You can email all your thoughts to feedback at cppcast.com. We'd also appreciate if you can like CppCast on Facebook and follow CppCast on Twitter. You can also follow me at Rob W. Irving and Jason at Lefticus on Twitter. We'd also like to thank all our patrons who help support the show through Patreon. If you'd like to support us on Patreon, you can do so at patreon.com slash cppcast. And of course, you can find all that info and the show notes on the podcast website at cppcast dot com.
Starting point is 00:53:49 Theme music for this episode was provided by

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.