Friday, August 31. 2018
Comparing rhino and nashorn Java JS engines
A quick entry this time. Some days ago I needed to use the javascript engine in Java (javascript in Java is integrated inside the Scripting API). I realized that the new nashorn engine always compiles the code and, although it is much faster and modern than the older one (rhino was used in previous java 7), in some corner cases it can be worse. Normally in cases where a lot of different javascript chunks are evaluated. The rhino implementation interprets the code and just optimizes the hot parts while nashorn always compiles the code into classes and, therefore, if the piece of javascript is just run a few times the compiling part is a drawback. Bug JDK-8034959 manages this same subject.
In theory the old rhino implementation can be added to the Scripting API. But the problem is that now all java.dev.net is decommissioned and finding the sources is complicated currently. The following steps are needed now.
Download last rhino library 1.7R4. This provides the js.jar library.
Now we have to find the rhino implementation for JSR-223 (Scripting API), and I finally found a github clone, and I could compile it.
git clone https://github.com/scijava/javax-scripting cd javax-scripting/engines/javascript/lib/ cp ${RHINO_HOME}/rhino1_7R4/js.jar . # downloaded in step 1 cd ../make/ ant clean all
A library js-engine.jar is generated inside the build directory.
This little program is used to test. As you see I have to use the rhino engine name (because nashorn is also there).
import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class HelloWorld { public static void main(String[] args) throws ScriptException { ScriptEngine engine = new ScriptEngineManager().getEngineByName("rhino"); System.out.println(engine.getClass()); engine.eval("print('Hello World!');"); } }
With both libraries the simple javascript can be compiled and executed.
java -cp js.jar:js-engine.jar:. HelloWorld class com.sun.phobos.script.javascript.RhinoScriptEngine Hello World!
To completely remove the nashorn engine in JDK 8 it is necessary to remove the library from the JVM. The library is placed in ${JAVA_HOME}/jre/lib/ext/nashorn.jar (it is placed in the ext folder, and all the libraries in that folder are automatically available for the JDK, this way nashorn is always loaded if not deleted). Once it is removed only the rhino engine is available for names like js or JavaScript or mime types like application/javascript.
But, remember this is the last resort. The new nashorn engine is much faster and modern. The js snippets are cached to avoid re-compilation so it's only a problem if the code is really very dynamic (I suppose that you can also maintain the same engine, taking care of the javascript, global vars and global execution). Just to compare both engines I tried with the google octane benchmark (I used this files working a bit over the run-octane.js JDK script). The results are the following for both engines in my laptop.
rhino | nashorn | |||||
---|---|---|---|---|---|---|
test | warmup | avg | max | warmup | avg | max |
box2d | 112 | 195 | 233 | 30 | 474 | 1343 |
code-load | 10164 | 12818 | 13320 | 120 | 152 | 159 |
crypto | N/A | N/A | N/A | 861 | 2664 | 2830 |
deltablue | 6491 | 6822 | 6873 | 28080 | 62742 | 65376 |
earley-boyer | 503 | 519 | 523 | 324 | 4911 | 5581 |
gbemu | N/A | N/A | N/A | 8 | 232 | 325 |
mandreel | N/A | N/A | N/A | 5 | 45 | 61 |
navier-stokes | 351 | 400 | 404 | 738 | 1013 | 1026 |
pdfjs | N/A | N/A | N/A | 11 | 416 | 516 |
raytrace | 766 | 792 | 804 | 681 | 10502 | 11093 |
regexp | 206 | 216 | 225 | 520 | 685 | 731 |
richards | 10124 | 10455 | 10776 | 46848 | 67724 | 68916 |
splay | 17376 | 15632 | 17141 | 45639 | 53368 | 60664 |
typescript | 6 | 10 | 10 | 1 | 13 | 21 |
So it's clear that nashorn is much better, faster and it can execute the whole benchmark (rhino fails in some tests). If you see there are several tests in which the old engine is better during the warmup, but all tests except code-load are faster when executed by nashorn in average and maximum (and code-load can be related to compilation in the end, because I think that it is a test about loading code).
Scripted regards!
Comments