Project Nashorn

You’ve probably read or heard about some of the key features of the upcoming Java SE 8 and JDK 8 already:

  • Project Lambda (JSR 335), which makes it easier to write code for multi-core processors,
  • a set of Compact Profiles, which allow Java SE 8 implementations to scale down easily,
  • a new Date and Time API (JSR 310), and
  • the removal of the “permanent generation” from the HotSpot JVM.

All of these features were very large engineering efforts. Project Nashorn, another key feature of JDK 8, is no exception: it introduces a new lightweight, high-performance implementation of JavaScript and integrates it into the JDK.

You may be wondering: JavaScript? In the JDK!?, so I’ll better begin at the beginning.

JavaScript on the JVM

In the beginning, there was JSR 223: Scripting for the Java Platform. That JSR defined the javax.script API, which was first included in the Java SE 6 platform release. The javax.script API provides a scripting language independent way to use such languages directly from Java. Oracle JDK 6 and JDK 7 are co-bundled with a Mozilla Rhino based JSR 223 script engine for JavaScript.

Mozilla Rhino is an open source implementation of JavaScript implemented in the Java programming language. It takes its name from the rhinoceros on a cover of a popular book teaching developers how to write code in JavaScript. Over the years, though, its performance had fallen far behind that of other JavaScript engines. To improve performance, Rhino would need to rewritten to fully exploit the capabilities of the modern Java platform.

Rather then undertaking a major rewrite of the very old Rhino code, at the JVM Language Summit in 2011, Jim Laskey, Oracle’s Multi-language Lead in the Java Language and Tools Group, announced that Oracle was working on a fresh implementation of JavaScript for the JVM, called Nashorn (‘rhinoceros’ in German). Nashorn would be based on ECMAScript-262 Edition 5.1 language specification, and provide an example of using new technologies in Java SE 7 like JSR 292 and the new invokedynamic bytecode instruction for low-overhead scripting language implementations.

By late 2012, there was a Nashorn Project in the OpenJDK community, and the code making up the implementation was open source. It attracted early adopters and rapidly improved to the point of passing all of ECMAScript compliance tests. Nashorn eventually replaced Rhino during the development of the upcoming JDK 8 release in 2013, and has evolved into one of the key features of that release.

JavaScript, too, has evolved in the past years, and seen a lot more use outside its original niche inside web browsers. That may make a fully compatible, highly performant implementation of JavaScript on the JVM increasingly appealing to Java and JavaScript developers alike.

Availability

Like all JDK 8 features, the Nashorn JavaScript engine is currently available in binary form as part of the regularly updated JDK 8 Early Access Release binaries. You can find binaries for Microsoft Windows, OS X, Linux and Oracle Solaris operating systems at http://jdk8.java.net.

The open source code that Nashorn is composed of can be found in the OpenJDK Project Nashorn Mercurial repositories.

Once you install a JDK 8 Early Access Release, or build your own installation from the source code in OpenJDK, you’ll be able to use the Nashorn JavaScript engine through the javax.script API and the jrunscript tool, just as you could with Rhino. In addition, Nashorn comes with a new command line application called jjs, which lives in the bin directory of a JDK 8 installation. The jjs tool can be used to run and evaluate JavaScript programs directly, making it easy to use JavaScript to write shell scripts, prototype code on the command line, and even write JavaFX applications in JavaScript.

Features

While the Nashorn JavaScript engine is a drop-in replacement for Mozilla Rhino in JDK 8, it also offers a number of additional features that make it an attractive option for new projects being developed in JavaScript.

Interoperable

Rather then being just another JavaScript engine, Nashorn provides interoperability between the Java and JavaScript worlds. That means your Java code can call JavaScript code, and vice versa.

Nashorn provides global objects to access and instantiate Java classes from JavaScript. Their members can be accessed using the familiar ‘.’ notation as in Java. Getters and setters in JavaBeans are exposed as equivalent JavaScript properties. Bounds-checked Java arrays can be instantiated and accessed from JavaScript, while JavaScript arrays can be converted to regular Java arrays when needed. You can use for and for each to traverse through both types of arrays. Strings and numbers are handled transparently, by interpreting them as instances of the corresponding Java classes, depending on the operation performed. Finally, collections are interpreted as arrays.

In addition, you can extend Java classes by providing a JavaScript function that implements a new method. Nashorn can automatically extend single abstract method classes if you provide the new method’s implementation in the constructor. This leads to some very compact code for action listeners, for example.

Embeddable

Nashorn comes included with the JDK. All you need to do to use Nashorn is to install JDK 8, and its right there, ready for your JavaScript code. Accordingly, it’s very easy to use Nashorn to extend your Java applications with JavaScript code as there are no third party libraries to track down, add to a project and keep track of.

In addition, since Nashorn is written in the Java programming language, it can be run on any supported platform for JDK 8 - that includes tiny ARM Linux devices like the Raspberry Pi, where the ability to use JavaScript to write parts of your application in conjunction with Java may provide a more rapid prototyping, development and deployment cycle.

Compatible

Compatibility matters, as Java developers know very well. The ECMAScript 5.1 standard has a corresponding test suite, available at http://test262.ecmascript.org. Nashorn passes all the compliance tests, as compatibility has been a primary goal of the implementation from the beginning.

It’s important to note that Nashorn does not include support for a browser plugin API, DOM/CSS or any related libraries. The goal pursued by the Nashorn team is not to provide a fast JavaScript implementation for a specific browser - it’s to provide a very fast implementation for server-side JavaScript applications and scripts embedded in Java applications.

Performant

Under the hood, Nashorn uses the invokedynamic JVM instruction to implement all of its invocations. That is a major component of the comparative improvement of performance and memory usage regarding Mozilla Rhino.

Since JavaScript does not have a ‘native’ bytecode format, JavaScript source code is first parsed to construct an immediate representation (AST/IR). The AST/IR is then lowered to something closer to JVM bytecode by transformation of controls, reduction of expressions to primitive operations, and simplification of calls, to be efficiently translated to JVM instructions, and securely loaded into the JVM. Generated code and call history are cached by the linker, to make lookup and invocation faster on successive relinks - JavaScript being a dynamic language, the actual code that needs to be ran by the JVM for a function being invoked at a given point in the code may change over time, and need to be recompiled and relinked. Nashorn takes care of all that under the hood using high quality third party helper libraries.

It does so very efficiently - it currently performs about 2x till 10x better than Mozilla Rhino on individual JavaScript engine benchmarks from the Octane benchmark suite.

Shell Scripting

Nashorn comes with a number of small extensions to make it easier to use JavaScript for shell scripting. They are enabled by passing the -scripting flag to the jjs application. But if your script starts with the shebang (#!) characters and the direct path to the jjs application, you don’t need to pass the flag.

You can use string interpolation (${var}) to use the values of variables or expressions to construct strings within double quotation marks. You can also use a here document (heredoc) to specify strings that preserve line breaks and indentation. Environment variables, command line arguments, output and error strings are available as global objects, as well as the script’s exit code and a global function to run commands.

Additionally, Nashorn provides several built-in functions to exit the script, print and read lines from standard output and input, read files, load scripts, and bind properties of objects.

JavaFX

You can write JavaFX applications entirely in JavaScript using Nashorn. In order to let the jjs application know that your script is a JavaFX application, you need to pass the -fx flag to it.That way, Nashorn automatically takes care of calling the right JavaFX methods to setup the application, and eliminates the need to provide boiler plate code.

In addition, JavaFX code can become more compact using Nashorn, as there is no need to declare value types, import packages, use annotations, specify a class name or declare a main method, and only the JavaFX classes that are instantiated in the code have to be declared. Given that Nashorn provides access to JavaBeans getters and setters as JavaScript properties, and JavaScript uses closures instead of anonymous inner classes, the corresponding application can end up being much shorter.

Finally, access to the JavaFX primary stage is provided through a global property.

Summary

Nashorn is an exciting new feature in the upcoming JDK 8. It provides a timely update of performance and capabilities of the co-bundled JavaScript engine.

Resources

About the Authors

dalibor topic

Dalibor Topic
Oracle