.

Tags:

rhino
The most recent Java 8 release came with lots of new features, one of them is the brand-new JavaScript engine to replace the aging Rhino. This new engine, called Nashorn (German for rhinoceros), is high-performant and specification compliant. It is definitely useful whenever you want to mix-and-match your Java and JavaScript code.

To check the performance of Nashorn, I use it to run Esprima and let it parse some large code base (unminified jQuery, 268 KB). This quick, rather non-scientific test exercises two aspects of JavaScript run-time environment: continuous memory allocation (for the syntax nodes) and non-linear code execution (recursive-descent parsing).

If you want to follow along, check the repository bitbucket.org/ariya/nashorn-speedtest. Assuming you have JDK 8 installed properly, run the following:

javac -cp rhino.jar speedtest.java
java -cp .:rhino.jar speedtest

This test app will execute Esprima parser and tokenizer on the content of the test file. Rhino gets the first chance, Nashorn follows right after (each engine gets 30 runs). In the beginning, Rhino’s first run is 2607 ms and slowly it speeds up and finally this parsing is completed in just 824 ms. Nashorn timings have a different characteristic. When it is cold, Nashorn initially takes 5328 ms to carry out the operation but it quickly picks up the pace and before you know, it starts moving full steam ahead, reaching 208 ms per run.

Behind the scene, Nashorn compiles your JavaScript code into Java bytecodes and run them on the JVM itself. On top of that, Nashorn is taking advantage of invokedynamic instruction (from the Da Vinci Machine Project, part of Java 7) to permit "efficient and flexible execution" in a dynamic environment such as JavaScript. Other JVM languages, notably here JRuby, also benefit from this new invokedynamic feature.

speedtest

What about Nashorn vs V8? It is not terribly fair to compare both, V8 is designed specifically for JavaScript while Nashorn leverages the battle-hardened, multi-language JVM. But for the fun of it, the Git repo also includes a JavaScript implementation of the test app which can be executed with V8 shell. On the same machine, V8 can complete the task in about 110 ms. Nashorn is not as mature as V8 yet, it is quite an achievement that it is only twice as slow as V8 for this specific test.

As a high-performance JavaScript on the JVM, Nashorn has many possible applications. It serves as a nice platform to play and experiment with JavaFX. Yet, it is powerful enough to be part of a web service stack (Vert.x, Project Avatar). On a less ambitious level, having another fast implementation of JavaScript is always good so that there is an alternative to run various JavaScript tools in an environment where Node.js is not available or not supported. As an illustration, check my previous blog post on a simple Ant task to validate JavaScript code.

Next time you have the urge to herd some rhinos, consider Nashorn!

  • MOB_i_L

    Can you use the Rhino-debugger with Nashorn?

    • aplatypus

      Just a guess, but it sounds like you ought to be able to use the Java debugger. Worth checking the Nashorn specs to see.

  • Avatar1337

    You can’t compare Nashorn with V8. V8 is implemented in C++. Nashorn becomes completely platform independent. V8 is not, if you use it to run modules. You can run Java modules from Nashorn, keeping it completely platform independent. They are designed for different things.

    • http://ariya.ofilabs.com/ Ariya Hidayat

      It is perfectly valid to compare them. They are JavaScript engines and we compare their behavior as a JavaScript engine (in the above case, with respect to its JavaScript execution speed).

      • Avatar1337

        But V8 should have a better performance, not because it is more mature, but because it is implemented in machine code (C++). Thus, I do not think it is fair to compare the two.

        • http://ariya.ofilabs.com/ Ariya Hidayat

          That’s incorrect. In both cases, the execution speed depends on the generated code by the JIT compiler. V8 and JVM are very capable to generate optimized compiled code.

          • Avatar1337

            Nashorn is compiled to Java binary which is in turn compiled to machine code with the built in JIT of the VM. V8 is compiled with a JIT to machine code directly. There is an extra step with Nashorn.

          • http://ariya.ofilabs.com/ Ariya Hidayat

            That’s a perfectly valid statement. And yet, we’re not interested in the code generation time, only the code execution time.

          • Avatar1337

            When you run java -cp .:rhino.jar speedtest, you let the VM load a JS file. That JS file is during runtime generated to Java binary, because it is a dynamic language. So the code generation of Nashorn to Java binary occurs during runtime, not compile time. That is why code generation time matters during execution.

          • http://ariya.ofilabs.com/ Ariya Hidayat

            Yeah but check the code. We’re not measuring that at all.

          • Avatar1337

            //Rhino

            tree = context.evaluateString(scope, “esprima.parse($code)”, source, line, null);
            tokens = context.evaluateString(scope, “esprima.tokenize($code)”, source, line, null);

            //Nashorn

            tree = inv.invokeMethod(esprima, “parse”, code);
            tokens = inv.invokeMethod(esprima, “tokenize”, code);

            You are executing JS and measuring the time. But It is done dynamically, so you will measure code generation time as well simultaneously. It is inevitable. Java has one more abstraction level, that’s what makes it platform independent. This time it is the JS interpreter that is platform independent. V8 JS interpreter is not platform independent. You have to write a new one for each platform.

          • http://ariya.ofilabs.com/ Ariya Hidayat

            The code generation time only matters in the first runs. After that, both engines will just executed the cached generated code.

          • Avatar1337

            Yeah, if it is using cached Java binary then it would be the same amount of interpretation layers compared to V8 running in realtime, however, wouldn’t V8 use cached machine code then? Then you would have cached Java binary compared to cached machine code. Once again, an unfair advantage.

          • http://ariya.ofilabs.com/ Ariya Hidayat

            JVM will turn those Java bytecodes into machine codes.

          • Avatar1337

            Yes in realtime I know, but you have “turning Java bytecode into machine code during runtime” vs “just running cached machine code”. Which do you think will be faster?

          • Avatar1337

            The only way for them to be comparable is if JVM caches machine code and not Java binary from the Nashorn script. Then V8 and Nashorn would be on the same level. In the end, it still becomes a Java application vs a native application.

  • Emanon

    I am a Javascript Developer and our stack never included Java until now… SO, I am COMPLETELY new to the idea of Nashorn. What exactly does it enable you to do on the “front end” – I am completely missing the power of Nashan here. Would you edit the html OR edit the Hello.class file? From a complete beginner standpoint, how can I understand the usage of Nashorn?