Migrating from Nashorn to GraalJS: Lessons Learn

Pedro Sanders
3 min readMay 23, 2019

Migrating from Nashorn to GraalJS isn’t tricky. GraalJS provides a compatibility mode that does most of the work for you. However, there are a few things that you still have to do. In this post, I cover some of the friction points I found while migrating to GraalJS and ways to solve them.

Storytime!

I first learn about Nashorn back in 2011 and immediately saw the potential in the new Javascript implementation.

I was particularly interested in the ability to run insecure code in a “sandbox” to provide controlled access to a hidden infrastructure. I came to use this feature several times.

In 2016, I needed a SIP server and saw an opportunity to try Nashorn in a larger project. I began my research to learn more about the mechanics of the SIP protocol, and and Routr was born.

Routr is a lightweight sip proxy, location server, and registrar that provides a reliable and scalable SIP infrastructure for telephony carriers.

Why did I migrated from Nashorn?

Nashorn brought the flexibility and beauty of Javascript to the JVM. However, as you are aware, the Javascript ecosystem moves faster than any other, and Nashorn could not keep up.

The following are some paint points of using Nashorn:

  • Limited tooling — No much tooling is available for Nashorn, nor documentation on how to take advantage of the existing Javascript ecosystem.
  • Outdated — Nashorn can’t keep up with the evolution of Javascript.
  • Startup time is very slow— To the point that it is unusable for some use cases.
  • Could soon disappear — JEP 335 deprecates Nashorn, and beyond JDK 11 it may not be included.

I documented my approach to overcome some of this issues in the Github repository nashorn-app-starter.

Enter GraalJS

Last year I learned about GraalJS. A new implementation of JavaScript that promised better performance and better compatibility with the Javascript language.

I was happy with the news and continued to monitor the progress of the project over the following months.

What where the friction points of migrating?

Although GraalJS is better than Nashorn in many ways, migration still came with some pain. The most significant issue was GraalJS approach to multithreading.

GraalJS prevents concurrent access to the same runtime

Take for example the following code:

It works in Nashorn. However, in GraalJS the same code will result in the following Exception:

java.lang.IllegalStateException: Multi-threaded access requested by thread Thread[main,0,main] but is not allowed for language(s) js!

The reason for the error is that GraalJS strives to stay within boundaries set by the programming language.

Concurrent access to the same runtime is not allowed in JS

Solution: The solution rather simple. You must run the Thread with a Runnable implemented in Java.

Preventing the script from exiting

I could not find a way to prevent a script from exiting while using pure Javascript. For example, if using GraalJS, the following script exits immediately:

Solution: An easy way to prevent this is to use Java as the host language by creating a wrapper of the application. In the wrapper have a Context pointing to the entry point of your application. Here is an example:

No official support to load NPM modules

There is no official support to load NPM modules in pure Javascript. In other words, It is not possible to use requireor importout of the box.

Luckily, GraalJS has a load function similar to the one in Nashorn.

Solution: I used an old trick I learn with Nashorn. That is, one can use Nodyn’s package loader to bring NPM packages to GraalJS. The next examples illustrate the approach:

From there, you can use requireas usual.

If you are interested in bring NPM packages to pure Javascript in GraalJS, please take a look at my repo graaljs-with-npm.

Conclusion

Migrating a Nashorn base application to run in GraalVM isn’t tricky. The primary friction point for me was GraalJS support to multithreading compare with Nashorn.

If you are thinking in migrating your application from Nashorn to GraalJS, consider the following:

  • Use Nashorn compatibility mode from start
  • Re-implement your Runnable objects in Java
  • Wrap your code in Java to avoid exiting the application
  • Use Nodyn’s package loader to allow NPM packages if needed

--

--

Pedro Sanders

Founder at @fonoster · Building the Open-Source alternative to Twilio · Posts about my journey with COSS & SaaS.