JVM/JS

0 0

Yeah, hi. My name is Joa, it's an unusual name, it’s not Joachim, it's just Joa. I did a lot of flash development back in the day days but yeah you know flash is dying all that stuff, so a little bit application if you need a way to convert it to the web. So that's why I started building a project to compile Java bytecode to JavaScript. So let's have a look at the technology landscape, what I am talking about today is mostly these question marks because that's where the magic happens everything outside is done by different tools. So we are actually here it takes Java byte code there are some other solutions as well, takes Java source code, there's scaler.js which is tied to scaler compiler, and there's TVM which is the other project also using Java bytecode, they all have different subtleties. Most source code is compiled directly to JavaScript, only unity is compiling.net, byte code to SE.js. SE.js we don't do it because its in Firefox but in general there's some big issue because there no garbage collection you all know that Java is like JavaScript language, and so we leave that on the web assembly I think this could be a huge opportunity but whoever is sitting here and implementing it please remember there's more than C and C++. Ruby and other implementations. We do everything ahead of time, so you could also choose to do this all just-in-time, the difference is ahead of time means we take the Java byte code and compare it to JavaScript source code instead of doing it at run time which means we could load the byte code in a browser and while the application is running we could convert this to JavaScript code, so you could do it basically if you want to do just-in-time if you want to executable codes you could simply create new functions from existing JavaScript source code you can apply a lot of different optimisation that we can't apply, you could make optimistic assumption, here is a class I know nobody extends this class so I think that's final, you can reinvalidate those assumptions which is called the deoptimisation, you could also support class loaders in Java. You could at run time define a new class, load bytecode, do all that at run time. Well, in fact it's feasible to do it right now because we have workers now and the problem with the jet compiling specially in JavaScript would be that you have all those optimisation and executing them takes a lot of time, you could do it in a worker, and if anybody is interested in doing that I guess it would be a really interesting project, but we don't do it, we do ahead of time because we want the browser to concentrate just on user, because if you do it just-in-time the browser would have to optimise your thing that converts to Java bytecode. Also Java statistically. Trace and compiler which will I will explain in a second what that means, basically it means it goes through the core graph of the programme, and it also knows that at this point there isn't a class extended by a different class. In our case, because we don't just support JavaScript but also other platforms it's nicer because as long as the optimisations are done ahead of time we don't have to write out in JavaScript and can apply to all different platforms. How does the compiler look, what does it do, I hope you can see that. I will try to simplify this as much as I could, but just a quick overview. Basically the compiler creates a class file, also sorry that I am talking so fast, but there is a lot of stuff we have to go through. So, the class file actually is first it's read by our completer, what we call completing is reading basically the byte code which will give us the structure of the class it fields and methods, although things can be read as well by our completer, and every time they are accessed we resolve those symbols. Which basically means that the first methods symbol we resolve is the main function and from there on everything else is getting resolved. So, the function goes into code parser which creates a couple of graphs, at the end it exports a tree, which is kind of a legacy thing for us because we just went to a tree and just the optimiser was going into a special kind of graph structure, we want to get rid of this, and do everything on this graph but right now we are in a tree form. Go through some generic phases that modify the tree, and if the optimiser is enabled, we apply the optimisation if it's not we apply most of the platform specific phaser that make the Java code run in the browser as JavaScript which behaves like Java. Ok I want to give you maybe a little bit of an example to understand how this looks. If you are compiler writing don't spoil the fun because you will already know what happens. So that's like a simple method, with a loop, and it looks quite complex so the first thing we do is we take the byte code, split it into graphs so we know what's going on where is stuff happening, and you can already see it goes from up here, down into loop and jumps back and then becomes the exit part and hello, and you know there are a lot of gotos here and arbitrary jumps how do you represent those in JavaScript. Kind of looks like this if you see you can always do this stuff you can always do a go to in JavaScript as well. You can be the first to write that and everybody will quote you afterwards. Anyways, from this graph structure we also build a tree structure that gives you an information about how is the code actually structured, where is the loop, how do they follow source code manner. This is our first estimate of the JavaScript code, it looks horrible, specially if you look at the loop, you will always generate a wide through which has a lot of break and continue statements, so fast forward like 20 phases, we can always apply a lot of, well simplify and have you simple loop. This is what we put it in the optimiser, this is simplified version of what it sees, again a graph so we go graph to tree to graph. Which is stupid but another thing that we have to solve later. The optimiser, well, does its stuff it has a lot of knowledge about what's going on, and as you can see it can get rid of a lot of stuff, especially in this example. So, when it gets out of the optimiser we're left with this little piece which basically says, well it's here it prints just one. The JavaScript code we finally generate will look like this we also do some renaming so it will probably in the end look like this which is quite nice for such a big method, and the optimiser can prove a lot of stuff is unnecessary, so that's what we want to achieve. So what's the big problem in all of this? Semantics. We have to implement all the, JVM semantics in JavaScript, there's a lot of stuff here, the lazy - there's no time, lazy initialisation, and yeah, just quickly want to explain what all that stuff is. What we don't want to do is we don't want to add too much over head that's what making the Java code in fact run slow and inside of JavaScript. One thing is the class initialiser. It's always executed when a class is first been loading in Java, this where all static variables are being initialised and all that kind of stuff. So when you write this kind of code in Java what actually happens is the base class of system which is object will get it's initialiser called then a system class will get it's initialiser called but any if it's not been called before. We have to do the same when compiling to JavaScript. The most simple way to do it you can add a property to your class, which simply does all this work and we tried different aspects of what works best across browsers, this one where the method is really finding itself it just returns itself, but that didn't work out so great performance wise. In the end this is JavaScript that we generated. So it's in tight, but there's the problem because if you run this stuff in a loop, well, now I would have 10 times for instance this call to initialiser. And the question is can we prove that the loop is taken at least once, because if we can prove this, which we can of course prove is that we can take the initialiser out of the loop for instance and apply just once for a loop so if the loop runs thousand times we don't have to execute the initialiser thousand times. This is very important stuff to do, to make it fly actually you can do even more you can take the access of the system out, variable out, of the loop as well, and pretty good actually you won't notice that is class initialiser is actually running. There is another thing, in stance initialisation where you have a class, all properties like the x property are initialised with value, we wanted to do it smart first and we thought, ok, if you have more than four properties, I think, then we define the variable for this, to minify the JavaScript that we output and then we assign it to those things if you have 50 variables in a class, the code is well, it's smaller, but the problem is you learn that JavaScript JMs might guess the size of your object based on how often they see this.x = y , not a local variable but this equals something, so you are back to software one, the JavaScript - well... make the best guess. That's like a kind of example of what you can do. Numerics are a different thing, in JavaScript you have a long type, well, already solved you can basically put it an to an object you can say I have the high part and the low part and I too all that stuff and it's quite boring, what's more interesting is the other simplifications you can do. For instance if you have a method like, give me the current time in milliseconds and it comes to an end. We implement current and milliseconds on the double, we cast it back to the long. In fact the method would look like this, date now, class it to long, class it to end, you can already see where it's going, it's probably unnecessary to create the long. So, we have a method that converts a double to a long and then we access the low bits of the long, now we have created an object that's totally useless. We want to convert the double into an integer, which is what happens and saves the long. So the main story is always simplify, try to simplify it make it as tight as possible and give rid of everything that's not totally necessary. The integer, first we thought, yeah we love integers they are really cool, a+ b, simple, at the ‘on’ operator, the integer is 30, you need the overflow when you do additional, multiplication, thank you to AMS.js, we can use integer multiplication, that's nice, if you have a double, of course, just - or not. In fact there is a subtle differences when you talk about doubles in JavaScript for instance, if you have a double and apply the or operator to the non-value, the zero, which is the same for Java, if you positive infinity, any value under the maximum integer, JavaScript, well for positive infinity, JavaScript will give you zero, if you 'Or', it whereas an Java you will get the maximum integer, all of a sudden it's not that simple any more to convert your double to an integer. We had this little method written, convert a double to an integer, which did exactly that. Well, we were quite... umm... quite an interesting moment because we had a benchmark and we found around the benchmark, because it didn't convert a double correct, we implemented the method and the benchmark was 10 per second slower, we thought, the second because we didn't convert the double correct, you can already see this method is a little bit stupid, infinity is already greater than the maximum integer and the negative is lower than the minimum integer. So we tried to change this method just a little bit and all of a sudden we had a 10 frames per second performance boost, I don't know why the seconds, but I guess somebody could explain, I guess it must have to do with the infinity values that it treats it a little bit different, but you never know. So, there is one last thing that we don't do, but that we will have to do eventually in the future, it allows you to, well you divide by zero it throws an exception, which is crazy, but it does that. Well, in order to do that you would have to have a method that checks if it's zero or not and throws an exception, otherwise you would have to prove that some value is never zero. Null point exception, is also quite interesting, because, I don't know anybody who is doing that at the moment, basically it means this, you have maybe a unit test, do some stuff, you say ok, my tests only pass if null point exception is raised. So how do you do this in JavaScript? The most obvious way would be to say, ok, I simply check if something is null, right and then I raise an exception, but it's quite stupid if you have a lot of changed stuff. You can also go on and say I'll correct a method that does a null check for me, but that also doesn't scale very well. The cruel thing is in JavaScript you are free to do what you want to do and you can modify the prototype of type error to fit into a class system, whenever we see a type error from the JavaScript, we already know it's a null point exception and it behaves like a null point exception, so in our case, the equivalent, so the extra Java null point exception is from the perspective of the application always thrown just when the type error is thrown. Last little odd thing, is undefined, because in Java you don't have undefined, but in JavaScript you have methods that return undefined and this is also nothing new but, well what does this print. It will be false, because undefined is not strictly equal to null, but it is non-- so if I just have two of those it would be true. In fact we always want to use strict equality, because that's more like what the Java operator would be - so when you too stuff like this, you would get a weird exception, because Foo is not now, but it's undefined, if you just use a strict operator. So you want to use the non-strict operator, in those cases where it can be null. Well, it's a little bit more complicated with strings and all that's, because this would also cause now, when you compare a string and an object to convert your object to a string and we also don't want to have that, but in fact, when we implemented this, we got a five times improvement in a benchmark in Firefox, the only reason why I could explain that, if you do a strict equality check that means it's not null, it means that Firefox, well, you can still be undefined so I don't know what to do, whereas where you use a non-strict operator, if you definitely know that the object is well... not null or non-defined, maybe there is a hot path that can be triggered and we were quite surprised that this actually happened, I would have thought the strict equality would be much simpler for a JavaScript engine. What's the moral of the story? In the end you want to write, when you generate JavaScript you should mimic handwritten JavaScript so to the browser it should always look like a user has written the code, not a machine some what translated it. You always have to clean up and simplify after you, because well, otherwise all the semantics will slow the application down. How much time do I have left? Is there somebody who knows? Nobody knows. Ten, cool. Yet you should always try and take short cuts as much as possible, like with a type error. Use what is available and, well, you have to test and measure your performance and I can't stress this enough, it applies also to everything that you do in normal JavaScript, which is you have to measure, so when you apply some optimisations manually, that's, well, if you don't measure what happens, it will be quite, yeah... umm... well surprising results can come out of this. So, I just have ten minutes so I'll quickly skip over this, the optimiser, it does everything you would expect from an optimiser, there is some cool stuff, so when you write this in Java, we usually need for the integer the 'Or' operator but we already know it won't overflow, we don't need the operator and we can simply use the implement. You can also prove it in this case where you have the integer j, which is growing with i, so you would also not need the operator, but when you are looking to the sources of the JavaScript JMs you well figure at they know this stuff but not as good, probably because this happens just in time and they can't spend as much time in all those analysis. Also we don't do it for the browser, because the browser, should think it's still an integer. This is also quite surprising actually when you write this in Java, Java will always create a new string for you and use the - string concatenation, function what we have to do for JavaScript, we have to find that there is a string builder, so we can reconstruct the JavaScript string concatenation. This one is one that's actually looks quite simple on the board, in the slides, but actually a lot of different optimisations have to play together, so this is the short iterator in Java and the compiler in the byte code will expand it to something like this, while you have the iterator in the list, while it gets the next element you get the next element you write this stuff a lot in Java code it would be nice to get rid of it, we will generate this code-based out of it, what has to happen is the code has to be in lined and you have to prove the iterator is not escaping the method, you have to know what values get into the iterator and what's taken out of, it like if you have all those 20 things ready, you are finally pleased with a result like this. The cool thing is, if you do it in a generic way it will apply to all of the code that you insert and that's quite nice. Even if you write your own list this would happen. This is much, much easier when you actually have source code, in source code you just see the special kind of loop and you know, oh, ok, I don't, I generate it differently. So, yeah. That's not so smart in the output. Last but not least, gene this optimisation, you can prove that, well, if you like to write code in a functional style, you can, you can actually let the compiler transform that back into a loop, it can know that some stuff is in a tail position, so we can rewrite it into a loop, simplify the loop and have a final result like this. So, most browsers don't do this, but they do most of the normal optimisations that you would expect, actually optimising JavaScript code by hand isn't necessarily something you should do these days. So we compile it to Java, that's what it looks like, it's basically what all the browsers use to generate the {inaudible}, Java code comes out of it, the question is which one do you use, Blink, Servo, Firefox, they all have their own with extensions, if you compile all the web URL and test it in a browser for once, different browsers you well run to an enormous amount of inconsistencies, it's just annoying, yeah. Workers, it can be quite interesting, the JavaScript you generate can be directly fed into a worker, most of the time you can simply say instead of the window just use the 'Self' variable, that makes a lot of sense. Also we were quite surprised we also have to check for types, if you have some code like things a worker, instruct mode, you will immediately get an error like this for some reason error event isn't defined, you the XML, but not the error event, when we have the of check we have to again rate some stuff like this so it works immediately in the worker. That's it mostly for the compiler, I wanted to talk about the framework around it, the display list, I did a lot of network back in the day, what was really cool was that you had a display list where you could sensory impairment lie range stuff and move it around, we wanted to have that too. Basically, I think that a lot of frameworks that do something similar, where you have a tree-like structure and you can arrange all your objects and again you can apply, like the same ideas that you use for opt my zing code, to something that happens at run time. So we don't want to walk the tree all the time when we render some stuff to the web, so we want a flat representation, we do that basically concatenating all the stuff together in a kind of, well specialised structure, but in this case we also cache all the information of the vertices, where they would go on WebGL, it's quite a thing, it's what, what an optimiser would do as well, it has to figure out, does it make sense to apply an optimisation at the time or not make sense, we have to render in simply about mode or put all the stuff to reference cards - oh, just 2 minutes - I'll just go and, yeah, cache all the virtual information and - so you get really fast results. So we rush through the slides, I wanted to show you some demos from the display list, I hope it works. In that case we can see one object is moving, so the display list would switch, when everything moves it goes into a rendering stage, it's nice for applications as well as games. You get those words. Just the double thing, ten FPS slower, well, it uses the infinity thing, so instead of 50 frames, we were at 40 frames. And because I'm out of time, I just want to show you this really quickly, we did a lot of the web idea stuff concatenated it to Java, those guys that I was working on earlier, converted this big flash application, audio tool to Java and then we compiled the Java code to JavaScript and I hope I've got some internet - but I don't... well that's too bad. No internet. Ok, maybe it loads in the end. So, because when I wanted to show you, this is just a smaller version of the whole thing and speed wise we have enough speed now to generate real time audio and JavaScript and render all that stuff on the graphics card. So I can do all this, well tweak a lot of stuff and it does it all in real time, and so this is like one of the cool things now that we have the ability to take the existing stuff and compile it to JavaScript. There is also another one, so we also have that in Flash, that's all now running, it's just pure JavaScript and it's also at run time parsing all the mega files, so basically just a load of computations and you can play your old favourite... yeah... music. Ok. So let me see if this last... nope... ah... ok. So the cool thing here is... come on, come on, this has web artists and live collaboration. Ok. I talked about the guys from audio tool they are now all here. You can say hello. Ok. >> Hello! So this application is now running in a browser and the artists can actually move everything around, do some stuff so I don't have to do anything right now, they can make some music, you have to be quick, I'm already out of time. So if you know the Flash application this was actually quite a big thing, so here we have WebGL, let's, it's running very smooth and very nice and I can turn all the knobs, do all the routing and for me the good thing is to see now that we basically have this running in the browser without Flash, it was a big struggle to get this running in Flash, we implemented our own garbage collection because the Flash was, well, bad, so a lot of things to get this working. {music}. I'm actually not doing anything, they can all do it in the live collaboration, which is done by a web artist. You can even hook the midi stuff to it, it's really brave it shows the browser is very good at supporting application that are very demanding when it comes to resources, it shows you can do what you want now, we have this timeline here, which you can - ah, I have to exit this mode. Ok, so that was something that we never did in Flash, you can simply adopt the timeline, so when you have a second monitor you can now split that application, you can close it and it flips just right back and this is well, actually simply amazing. {Applause}. Right, thank you. Yeah. So I'm guess I'm done. Thanks. Thanks for listening. Well, if you have any questions feel free to come by. Thank you. {Applause}. .