Node JS application running on GraalVM — interoperating with Java, Python, R and more

When you install GraalVM, one of the things you get is a Node runtime environment (GraalVM 19.2.1 is based on Node 10.16.3 — with support for the core Node libraries and un understanding of NPM modules — and has a JavaScript engine that is ECAMScript 2019 compliant). Instead of V8, the usual JavaScript execution engine, this GraalVM environment leverages GraalJS and the JVM as execution platform. GraalJS runs Java Byte code on JVM. This GraalJS engine is a Java application that works on any Java 8+ implementation. Compared to V8, it can run faster and is better scalable to big memory structures. However: it may need some warmup time to reach peak performance: run time optimizations that can make Java applications run faster after some time now also apply to JavaScript execution.

GraalVM is among other things a polyglot language runtime. That means for JavaScript applications running on GraalVM that they can embed and call out to code written in JVM languages like Java, Scala, Groovy and Kotlin as well as non-JVM languages such as Python, R, Ruby and LLVM.

In this article, I will take a brief look at running Node applications on GraalVM and specifically their polyglot interaction on GraalVM with other languages, specifically Java, Python and R (only scratching the surface).

Polyglot Node Application calling out to Java

The Java Class can be tried out:

java -cp application-bundle.jar nl.amis.js2java.Joker

The Node application is implemented in Joker2.js. It is very straightforward. The Java Class is loaded with the Java.type call. Subsequently, a single Joker object is instantiated with the new statement. In function getJoke(), a call is made to the getJoke() method on javaJoker1 — the Java method that returns a random element from the jokes collection.

The application can be run with this command line:

node -jvm -vm.cp application-bundle.jar joker2.js

This is visualized as follows:

The JVM with GraalVM is the runtime environment where the Java Byte code is executed and optimized. The JavaScript code is interpreted by GraalJS and turned into an AST (abstract syntax tree) representation in Java Byte code. Because the JVM is the runtime engine, and the -jvm switch is passed, all Java 8 APIs are available at runtime and can be engaged from the JavaScript code. With the -vm.cp switch, the classpath is defined to indicate where at runtime additional (custom and 3rd party) Java Classes should be looked for. In this case, JAR file application-bundle.jar is passed in. Finally the Node application’s entry file is provided as well (joker2.js).

The program flow at runtime can be visualized as follows:

Polyglot Node Application embedding Python, Ruby and R

The next file is a JavaScript application that can be run with the node or the js runtime. It does not use anything Node specific. The application — polyglot.js — evaluates code snippets in three languages, using the Polyglot object’s eval function. It also loads and evaluates a separate Python library library.py.

The most interesting parts to me are the definition of function Fibonacci: the function is defined in the library.py (def Fibonacci…) — loaded in line 11 — but it takes the evaluation and assignment to fibFunc — line 12 -to make the function executable from JavaScript. It is executed in line 13. That is JavaScript calling a recursive function written in Python and loaded from an external file. In line 16, another Python function object is created using a lambda expression. In line 18, this function is executed. In line 20 — a function is defined in R. In line 23, JavaScript invokes a function that is actually an R based function. Pretty cool if you ask me.

The file is executed with this command

js -polyglot -jvm polyglot.js

The output:

Polyglot Node Application calling out to Java that calls out to JavaScript

The Java Class that calls out to JavaScript is ValidateThroughNPMValidator.java:

The class is bundled in the same application-bundle.jar file we saw before, including the validator-bundled.js file that it loads at runtime.

The salient part of the Node application that leverages the Postal Code capabilities of the Java Class is shown below:

Of course here we do not see that real validation goodness is not actually coming from Java but from JavaScript. The GraalVM engine turns both Java and JavaScript to a byte code that is just executed, regardless of their origin.

Resources

GraalVM Docs on Node / JavaScript https://www.graalvm.org/docs/reference-manual/languages/js/

GraalVM Docs — interoperability from JavaScript — https://www.graalvm.org/docs/reference-manual/languages/js/#interoperability

GraalVM Docs — Polyglot including JavaScript / Node as target and as starting language: https://www.graalvm.org/docs/reference-manual/polyglot/

GitHub Home of GraalJS — https://github.com/graalvm/graaljs

JavaDocs for GraalVM Polyglot — https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/package-summary.html

Originally published at https://technology.amis.nl on November 5, 2019.

Lucas Jellema is solution architect and CTO at AMIS, The Netherlands. He is Oracle ACE Director, Groundbreaker Ambassador, JavaOne Rockstar and programmer