Skip to content

Add GraalJS engine support alongside Nashorn#1180

Draft
synecdoche wants to merge 1 commit into
jknack:masterfrom
synecdoche:add-graaljs-support-prototype1
Draft

Add GraalJS engine support alongside Nashorn#1180
synecdoche wants to merge 1 commit into
jknack:masterfrom
synecdoche:add-graaljs-support-prototype1

Conversation

@synecdoche

Copy link
Copy Markdown

This is a proof of concept PR for adding GraalJS [1] engine support, written against the 4.5.1 release. Nashorn has been removed from the JDK, and it hasn't received active development, while GraalJS continues to track the ECMAScript standard [2]. Additionally, GraalJS can use the Graal JIT compiler to compile JavaScript to native code, yielding significant benchmark improvements in some cases [3] but may or may not apply to typical Handlebars.java use cases. The pros and cons have GraalJS for Handlebars.java has come up before; see [4].

This implementation selects an engine at runtime, preferring Nashorn by default. There is an additional Java property to select an engine explicitly: hbs.js_engine. However, it's rare that both engines would be available, so it might be better to use the javax APIs to just instantiate whichever is available, which I understand to be possible but haven't yet tried.

I have tested it with Corretto JDK 25 [5] with the following command, and there were no test regressions:

mvn clean verify -pl handlebars -Pgraaljs-jit -Dmaven.test.classpathDependencyExcludes=org.openjdk.nashorn:nashorn-core

If there is interest in taking this, I can clean it up / refactor as needed. I don't have much experience with Handlebars.java as such, so please excuse naiveté on my part, especially regarding how Handlebars.java is typically used.

Thoughts?

[1] https://www.graalvm.org/javascript/
[2] https://www.graalvm.org/latest/reference-manual/js/JavaScriptCompatibility/
[3] https://github.com/simonis/GraalJsTest/#benchmark-results
[4] #696
[5] https://docs.aws.amazon.com/corretto/latest/corretto-25-ug/downloads-list.html

Add support for the GraalJS JavaScript engine as an alternative to
Nashorn, allowing the library to use whichever engine is available at
runtime. GraalJS is tried first, falling back to Nashorn.

GraalJS is configured with three polyglot options:
- polyglot.js.allowAllAccess=true: enables Java.type() interop needed by
  helpers.nashorn.js to bridge Java classes into JavaScript.
- polyglot.js.nashorn-compat=true: enables Nashorn-like bean property
  access so that `bean.name` in JS resolves to `getName()` on Java objects,
  which the existing helper bridge relies on.
- polyglot.js.ecmascript-version=2022: overrides the ES5 default imposed
  by nashorn-compat mode, allowing ES6+ syntax (let, const, arrow functions)
  in user-supplied helper scripts.

The adaptES6Literals() method in DefaultHelperRegistry, which converts
let/const to var for Nashorn's ES5 parser, is now only applied when
actually running on Nashorn. GraalJS handles ES6+ natively with the
ecmascript-version override.

Both engine dependencies (nashorn-core, js-scriptengine + polyglot js) are
marked <optional>true</optional> in handlebars/pom.xml so consumers choose
which engine to include. The handlebars-maven-plugin adds an explicit
nashorn-core dependency since it needs a concrete engine for template
precompilation.

To run tests with a specific engine:
- GraalJS only:  -Dmaven.test.classpathDependencyExcludes=org.openjdk.nashorn:nashorn-core
- Nashorn only:  -Dmaven.test.classpathDependencyExcludes=org.graalvm.js:js-scriptengine
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant