GraalVM includes an ECMAScript compliant JavaScript engine.It is designed to be fully standard compliant, execute applications with high performance, and provide all the benefits from the GraalVM stack, including language interoperability and common tooling.With that engine, GraalVM can execute JavaScript and Node.js applications.
Running JavaScript
GraalVM can execute plain JavaScript code:
js [options] [filename...] -- [args]
Running Node.js apps
GraalVM is adapted to run unmodified Node.js applications. Applications canimport npm modules, including native ones.
To run Node.js-based applications, use the node
utility in the GraalVM distribution:
node [options] [filename] [args]
To install a Node.js module, use the npm
executable in the /bin
folder of theGraalVM package. The npm
command is equivalent to the default Node.jscommand and supports all Node.js APIs.
- Install the
colors
andansispan
modules usingnpm install
asfollows:
npm install colors ansispan
After the modules are installed, you can use them from your application.
- Add the following code snippet to a file named
app.js
and save it in the same directory where you installed Node.js modules:
// RUN-CMD: rm -rf node_modules
// RUN-CMD: npm install ansispan colors
// RUN-CMD: node {file}
// RUN-CMD: rm -r node_modules
// BEGIN-SNIPPET
const http = require("http");
const span = require("ansispan");
require("colors");
http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type": "text/html"});
response.end(span("Hello Graal.js!".green));
}).listen(8000, function() { console.log("Graal.js server running at http://127.0.0.1:8000/".red); });
// END-SNIPPET
setTimeout(function() { console.log("DONE!"); process.exit(); }, 2000);
- Execute it on GraalVM using the
node
command as follows:
node app.js
Interoperability
GraalVM supports several other programming languages, including Ruby, R, Pythonand LLVM. While GraalVM is designed to run Node.js and JavaScript applications,it also provides an API for programming language interoperability that lets youexecute code from any other language that GraalVM supports.
From JavaScript code you can access Java applications, as in the followingexample:
$ node --jvm
> var BigInteger = Java.type('java.math.BigInteger');
> console.log(BigInteger.valueOf(2).pow(100).toString(16));
10000000000000000000000000
You can also call methods in other programming languages that GraalVM supports:
$ node --jvm --polyglot
> console.log(Polyglot.eval('R', 'runif(100)')[0]);
0.8198353068437427
We provide migration guides for code previously targeted to the Rhino or Nashorn engines.See the JavaInterop.md for an overview of supported Java interoperability features.For additional information, see the Polyglot Reference and theEmbedding documentationfor more information about interoperability with other programming languages.
GraalVM JavaScript Compatibility
GraalVM is ECMAScript 2019 compliant and fully compatible with a diverse range of active Node.js (npm) modules.It will also be compliant to ECMAScript 2020 once this updated specification is published (draft spec).More than 100,000 npm packages are regularly tested and are compatible with GraalVM, including modules like express, react, async, request, browserify, grunt, mocha, and underscore.The latest release of GraalVM is based on Node.js version 12.10.0.
Is GraalVM compatible with the JavaScript language?
What version of ECMAScript do we support?
GraalVM is compatible to the ECMAScript 2019 specification.Some features of ECMAScript 2020 including some proposed features and extensions are available as well, but might not be fully implemented, compliant, or stable, yet.
How do we know it?
The compatibility of GraalVM JavaScript is verified by external sources, like the Kangax ECMAScript compatibility table.
On our CI system, we test GraalVM JavaScript against a set of test engines, like the official test suite of ECMAScript, test262, as well as tests published by V8 and Nashorn, Node.js unit tests, and GraalVM’s own unit tests.
For a reference of the JavaScript APIs that GraalVM supports, see GRAAL.JS-API.
Is GraalVM compatible with the original node implementation?
Node.js based on GraalVM is largely compatible with the original Node.js (based on the V8 engine).This leads to a high number of npm-based modules being compatible with GraalVM (out of the 95k modules we test, more than 90% of them pass all tests).Several sources of differences have to be considered.
Setup:GraalVM mostly mimicks the original setup of Node, including the
node
executable,npm
, and similar. However, not all command-line options are supported (or behave exactly identically), you need to (re-)compile native modules against our v8.h file, etc.Internals:GraalVM is implemented on top of a JVM, and thus has a different internal architecture. This implies that some internal mechanisms behave differently and cannot exactly replicate V8 behavior. This will hardly ever affect user code, but might affect modules implemented natively, depending on V8 internals.
Performance:Due to GraalVM being implemented on top of a JVM, performance characteristics vary from the original native implementation. While GraalVM’s peak performance can match V8 on many benchmarks, it will typically take longer to reach the peak (known as warmup). Be sure to give the GraalVM compiler some extra time when measuring (peak) performance.
How do we determine GraalVM’s JavaScript compatibility?
GraalVM is compatible to ECMAScript 2019, guaranteeing compatibility on the language level.In addition, GraalVM uses the following approaches to check and retain compatibility to Node.js code:
- node-compat-table: GraalVM is compared against other engines using the node-compat-table module, highlighting incompatibilities that might break Node.js code.
- automated mass-testing of modules using mocha: in order to test a large set of modules, GraalVM is tested against 95k modules that use the mocha test framework. Using mocha allows automating the process of executing the test and comprehending the test result.
- manual testing of popular modules: a select list of npm modules is tested in a manual test setup. These highly-relevant modules are tested in a more sophisticated manner.
If you want your module to be tested by GraalVM in the future, ensure the module provides some mocha tests (and send us an email so we can ensure it is on the list of tested modules).
How can one verify GraalVM works on their application?
If your module ships with tests, execute them with GraalVM.Of course, this will only test your app, but not its dependencies.You can use the compatibility checker to find whether the module you’re interested in is tested on GraalVM, whether the tests pass successfully and so on.Additionally, you can upload your package-lock.json
or package.json
file into that utility and it’ll analyze all your dependencies at once.
GraalVM JavaScript Options
On the command line, —js.<property>=<value>
sets options that tune language features and extensions.The following options are currently supported:
—js.annex-b
: enables ECMAScript Annex B web compatibility features. Boolean value, default istrue
.—js.array-sort-inherited
: defines whetherArray.protoype.sort
should sort inherited keys (implementation-defined behavior). Boolean value, default istrue
.—js.atomics
: enables ES2017 Atomics. Boolean value, default istrue
.—js.ecmascript-version
: emulates a specific ECMAScript version. Integer value (5
-9
), default is the latest version.—js.intl-402
: enables ECMAScript Internationalization API. Boolean value, default isfalse
.—js.regexp-static-result
: provides staticRegExp
properties containing results of the last successful match, e.g.:RegExp.$1
(legacy). Boolean value, default istrue
.—js.shared-array-buffer
: enables ES2017 SharedArrayBuffer. Boolean value, default isfalse
.—js.strict
: enables strict mode for all scripts. Boolean value, default isfalse
.—js.timezone
: sets the local time zone. String value, default is the system default.—js.v8-compat
: provides better compatibility with Google’s V8 engine. Boolean value, default isfalse
.Use—help:languages
to see the full list of available options.
See the Polyglot Reference for information on how to set options programmatically when embedding.
GraalVM Options
—jvm
executes the application on the JVM instead of in the Native Image.
—vm.<option>
passes VM options and system properties to the Native Image.To pass JVM options to GraalVM you need to provide —jvm
before,i.e., —jvm —vm.<option>
. List all available system properties to the Native Image,JVM and VM options and with —help:vm
.
System properties can be set as follows: —vm.D<name>=<value>
.For example, —vm.Dgraal.TraceTruffleCompilation=true
will print finished compilations.
—compiler.<property>=<value>
passes settings to the compiler.For example, —compiler.CompilationThreshold=<Integer>
sets the minimum number of invocations or loop iterations before a function is compiled.
Polyglot Options
—polyglot
enables you to interoperate with other programming languages.
—<languageID>.<property>=<value>
passes options to guest languages through the GraalVM Polyglot SDK.Use —help:languages
to find out which options are available.
GraalVM JavaScript Operations Manual
What’s the difference between running GraalVM’s JavaScript in a Native Image compared to the JVM?
In essence, the JavaScript engine of GraalVM is a plain Java application.Running it on any JVM (JDK 8 or higher) is possible; for best performance, it should be the GraalVM or a compatible JVMCI-enabled JDK using the GraalVM compiler.This mode gives the JavaScript engine full access to Java at runtime, but also requires the JVM to first (just-in-time) compile the JavaScript engine when executed, just like any other Java application.
Running in a Native Image means that the JavaScript engine, including all its dependencies from, e.g., the JDK, is pre-compiled into a native binary.This will tremendously speed up the startup of any JavaScript application, as GraalVM can immediately start to compile JavaScript code, without itself requiring to be compiled first.This mode, however, will only give GraalVM access to Java classes known at the time of image creation.Most significantly, this means that the JavaScript-to-Java interoperability features are not available in this mode, as they would require dynamic class loading and execution of arbitrary Java code at runtime.
How to achieve the best peak performance?
Optimizing JVM-based applications is a science in itself.Here are a few tips and tricks you can follow to analyse and improve peak performance:
- When measuring, ensure you have given the GraalVM compiler enough time to compile all hot methods before starting to measure peak performance. A useful command line option for that is
—vm.Dgraal.TraceTruffleCompilation=true
– this outputs a message whenever a (JavaScript) method is compiled. As long as this still prints frequently, measurement should not yet start. - Compare the performance between the Native Image and the JVM mode if possible. Depending on the characteristics of your application, one or the other might show better peak performance.
- The Polyglot API comes with several tools and options to inspect the performance of your application:
—cpusampler
and—cputracer
will print a list of the hottest methods when the application is terminated. Use that list to figure out where most time is spent in your application. More details about the command line options for the polyglot commands can be found from the polyglot documentation.—experimental-options —memtracer
can help you understand the memory allocations of your application. Refer to Profiling command line tools reference for more detail.