Dear readers! I want to share with you my open-source project, on which I have been working in my spare time for quite some time,
TeaVM . TeaVM is a Java bytecode translator to JavaScript. There are several attempts to create a JVM in JavaScript, one of the most successful is
Doppio . However, apart from the academic, they do not represent any value, since the speed of interpretation of the byte code leaves much to be desired. Moreover, in order to interpret bytecode, it is necessary at least to load this bytecode into the browser, and this degenerates into downloading tens of megabytes of
class
files.
In contrast, TeaVM does not interpret bytecode, but generates JavaScript, which performs exactly what baytcode would do if it were run in a real JVM. Simply put, TeaVM decompiles Java bytecode, but not back to Java, but to JavaScript. Of course, all this is true to certain limits. First, JavaScript simply lacks certain things familiar to Java developers, such as threads, full Unicode support (for example, support for character classes, regular expressions), blocking I / O. Secondly, this is due to the requirements that I imposed on the compiler. For example, in TeaVM, reflection support is very limited. This is a consequence of one of the advantages of TeaVM - the relatively small size of the generated file. No, TeaVM does not generate the lowest possible javascript, however, it will not generate huge multi-megabyte scripts for every sneeze. Reflection makes it impossible for any static analysis, so it was decided to abandon it.
Before I continue, I want to show for the beginning what TeaVM is capable of. Firstly, it is able to
simulate physics in real time. Secondly, he is still able to draw
beautiful pictures in Canvas by this physics. You can see that the javascript files are relatively small. By the way, I didn’t implement the physics calculation myself, I just took the existing
JBox2D library.
TeaVM was conceived as a tool for a developer who would be suitable for developing browser-based Java applications, and not as another academic project. I believe that this kind of tool should have the following characteristics:
- Acceptable performance. No one will wait for the compiler for hours. And even better - a very fast speed of work so that the developer does not wait for a few minutes in order to see if the button has moved after his edits in the code.
- Fast javascript.
- Compact JavaScript. The user will be very angry with the developer when he sees that the page is pulling over megabytes of JavaScript. More precisely, the user will not look at the size, but he will notice a decrease in page loading speed with the naked eye.
- Good support for the JDK class set. Java is not only a programming language, but also a set of classes from the standard library that Java developers are used to using in their daily work.
- Support popular build systems. Such in the Java world is, above all, Maven, although lately Gradle has been gaining popularity.
- Support for popular IDEs: Eclipse, Netbeans, IntelliJ IDEA.
- Ability to debug code, "running" in TeaVM. Believe me, it is very unpleasant to debug generated JavaScript, I personally tried.
- Ability to integrate with existing JavaScript libraries and browser APIs.
All of the above is somehow implemented in TeaVM. True, I can't just take it and implement it all at once, so only Maven is supported from the build systems, while Eclipse is supported from the IDE. Plans to make support for other IDE and build systems.
')
Project creation
I tried to make the creation of a new project as simple as possible. To do this, just execute the following command in the console:
mvn -DarchetypeCatalog=local \ -DarchetypeGroupId=org.teavm \ -DarchetypeArtifactId=teavm-maven-webapp \ -DarchetypeVersion=0.2.1 \ archetype:generate
If you are a Windows user, you will need to rewrite this command slightly. And even easier - take the appropriate details and use them to create a new Maven-project in the IDE. By the way, if your IDE is Eclipse, then it makes sense to install the plugin from the
repository .
With the existing project can play. If you have questions, you can refer to the
documentation . And if you did not find the answer to your question in the documentation, publish it in the form of an issue in GitHub.
Eclipse plugin
The code for production is generated by the build system, but when developing, rebuilding the project each time is not very convenient. After all, this requires each time to launch maven, that is, to start a new JVM, which takes time to warm up. This means that the assembly will be slow. By running the same build in the already-heated JVM in which the IDE runs, you can achieve a significant increase in build speed. In addition, in the IDE, it is possible to start building and publishing JavaScript when the source code changes. In this way, you can achieve the cycle that is traditional for regular JavaScript - you saved and updated the page in the browser. Actually, this feature is implemented in the plugin for Eclipse.
Another thing I consider necessary is the automatic setup of the project. For example, if a new participant comes to the project, then you really do not want to force him to read a long manual on setting up the project in the IDE, which, moreover, contains errors, so you also have to spend your time to help the newcomer. Or, if I wanted to work on a project in the country with a laptop, I really do not want to repeat the steps that I once did in the office. If the project is going to Maven, then IDE will open and configure it as needed. I did not want to deprive this opportunity of developers who use TeaVM, so I also created a configurator for the m2e. This made it possible for the developer to only import the Maven project or create a project from the archetype, after which the project can be run on a ready-made server and enjoy the development, as can be seen from the
tutorial .
Finally, the ability to debug code is very important. GWT has DevMode, which runs the code in the JVM and connects to the browser, passing all native JavaScript calls to it. However, due to the
termination of NPAPI support in some browsers, it became impossible to further support the browser plugin, which accepted connections and executed DevMode commands. I must say that these are not the GWT developers who are so bad that they don’t want to rewrite the plugin, these browser developers are so bad that they won’t figure out how to make friends with JavaScript with synchronous I / O.
Alternatively, the GWT team suggests using
SuperDevMode , which
based on
source maps . Source maps are bad because the developer is forced to debug the code in the wrong place in which he writes it. Moreover, the browser does not provide all the cool chips that are available in the IDE. Finally, source maps simply cannot translate such things as the names of variables, fields, methods, classes.
What did I do? If the browser understands source maps, then let source maps understand the IDE. But just let it be improved source maps. As a result, in addition to the standard source maps, TeaVM generates its debugging information, and also contains a plugin that allows you to use this debugging information in Eclipse. If you want to see what happened, you can
try it yourself.
Summing up, I want to note that the plugin for Eclipse is not just a tool, but also a kind of proof of concept, showing that based on the functionality available in TeaVM, it is quite possible to create plugins for the IDE. Implementing plugins to other IDEs is now a matter of technology.
Plans
In fact, the project is still evolving and developing. There are many plans, just some of them:
- The plan for the near future is to implement an alternative backend for libGDX . GWT does not quite satisfy the authors of the framework, in addition, TeaVM is already running faster, and there is still room for further optimizations.
- Cool library for client development. Now all that is is thin wrappers around some browser-based APIs. Of course, to develop applications you need something more comfortable. TeaVM itself will never include any libraries for developing client applications. This is a completely different project. It may be possible to take a ready-made library that runs on the same GWT, and adapt it for TeaVM. However, there is already one such framework, DukeScript , but I absolutely do not like either its implementation or how it is
not documented; nevertheless, I included his support in TeaVM. - Automatic generation of asynchronous code. I do not like noodles from callbacks. And due to the fact that blocking operations in JavaScript are absent as a class, they can be emulated by special conversion of the code.
- Many optimizations. JavaScript engines have very good optimizers, but they don’t always know about the code what is available to the static optimizer. Due to the fact that TeaVM inside uses the SSA view, various optimizations are implemented quite simply and painlessly.
- Implement even more classes from the JDK.
- Implement support for INVOKEDYNAMIC instructions, in particular, so that you can run lambdas from Java 8.
- Make TeaVM friends with Kotlin and Scala. There is nothing special about the bytecode that they generate, and TeaVM perfectly translates it into JavaScript. However, runtime of these languages use JDK classes that are not implemented in TeaVM. This is solved by either implementing these classes or rewriting the corresponding part of the runtime.
Why not ...
... GWT?
I write quite a lot on GWT, and I am very unhappy with this framework. The idea to generate javascript from source is extremely unfortunate.
- It is necessary to produce crutches at the level of the build system in order to properly connect the sources of all libraries to the build system.
- No support for other languages. For some languages, there is its own GWT analogues, for example, Scala.js and native support in Kotlin . However, they have another drawback: the inability to interact with existing Java libraries.
- GWT does not integrate with utilities that convert or generate bytecode.
In addition, I have a number of complaints about how GWT is implemented, namely:
- The GWT team actually refused to support DevMode - the only way to debug the code. There is a SuperDevMode, but it is extremely inconvenient.
- GWT is pretty slow. And the fact that it also generates permutations makes the assembly unbearably long.
- The idea of keeping generated JavaScript on a separate server leads to crutches and stumble upon all sorts of problems related to the fact that resources (images, CSS), RPC and code are on different servers during debugging, but at the same time on the same server - in combat conditions.
At the same time, I don’t like to write in JavaScript, especially because of the dynamic nature of the language. Therefore, I choose GWT from two evils, but I want something better.
... emscripten?
At first glance, TeaVM is very similar to
emscripten . So why don't I just translate java bytecode into LLVM? After all, LLVM already contains a ready implementation of SSA. The thing is that LLVM is very low-level. This is good, when a program is compiled into a native code, but when it is decompiled into a high-level language, some overhead is obtained. After all, JavaScript already has such concepts as fields, methods, GC. And in LLVM, this would all have to be emulated again in JavaScript. Another reason is that TeaVM is completely written in Java, the compiler can, for example, be zapped, which would not be possible in the case of LLVM and emscripten. Finally, TeaVM uses slightly more powerful decompiling algorithms than the emscripen.