I'm stuck with a problem involving GraalJS. I'm trying to use it as my JavaScript backend. It works flawlessly while I run in from IntelliJ, but as soon as I export a runnable .jar, it stops working. I've been debugging this issue for a few days now, below are my findings.
Should be mentioned that I generate my runnable .jar by making use of a gradle command that comes packaged with libGdx called desktop:dist.
First, these are the dependencies that I use
// GraalVM
compile group: 'org.graalvm.js', name: 'js', version: '20.2.0'
compile group: 'org.graalvm.js', name: 'js-scriptengine', version: '20.2.0'
compile group: 'org.graalvm.sdk', name: 'graal-sdk', version: '20.2.0'
compile group: 'org.graalvm.truffle', name: 'truffle-api', version: '20.2.0'
implementation 'com.ibm.icu:icu4j:51.1'
This is how I build my ScriptEngine
private fun getGraalEngine() = GraalJSScriptEngine.create(
Engine.newBuilder()
.allowExperimentalOptions(false)
.useSystemProperties(false)
.build(),
Context.newBuilder("js")
.allowHostAccess(HostAccess.ALL)
.allowHostClassLookup { true }
.allowAllAccess(true))
Now, when I run the program from the .jar, I get this exception:
java.lang.IllegalArgumentException: Could not find option with name js.script-engine-global-scope-import.
at com.oracle.truffle.polyglot.PolyglotEngineException.illegalArgument(PolyglotEngineException.java:128)
at com.oracle.truffle.polyglot.OptionValuesImpl.failNotFound(OptionValuesImpl.java:283)
at com.oracle.truffle.polyglot.PolyglotContextConfig.findLanguageForOption(PolyglotContextConfig.java:239)
at com.oracle.truffle.polyglot.PolyglotContextConfig.<init>(PolyglotContextConfig.java:129)
at com.oracle.truffle.polyglot.PolyglotEngineImpl.createContext(PolyglotEngineImpl.java:1434)
at org.graalvm.polyglot.Context$Builder.build(Context.java:1598)
After some debugging, I came to the conlusion that this happens when PolyglotContextConfig
tries to find a PolyglotLanguage
for the optionName js
. Turns out that this is the difference between IntelliJ and running from a runnable .jar. IntelliJ contains the support for JavaScript PolyglotLanguage
, while the .jar does not. Here's what I found
By looking at Engine -> impl -> idToLanguage
(I accessed these package private fields via reflection) I get the following results
Intellij :
id to lang: {regex=PolyglotLanguage [id=regex, name=REGEX, host=false], js=PolyglotLanguage [id=js, name=JavaScript, host=false]}
Runnable .jar:
id to lang: {regex=PolyglotLanguage [id=regex, name=REGEX, host=false]}
Turns out the support for JavaScript just... misses?
Because of this, when PolyglotContextConfig.findLanguageForOption()
tries to match the js
optionName to the JavaScript PolyglotLanguage
, the exception occurs.
I'm not sure how to proceed or why this could be happening. Perhaps something regarding classloaders? Either way, any help would be greately appreciated
The following link answered my question: https://github.com/oracle/graaljs/issues/125
Turns out that during the .jar packaging process, the PolyglotLanguage entries for REGEX and Javascript get overwritten somehow. This means that you have to create a file inside your .jar at META-INF/truffle/language
and add the contents from the answer. Note, for me the contents from the github link didn't quite work. I needed to change them to
#https://github.com/graalvm/graaljs/issues/125
language2.characterMimeType.0=application/javascript
language2.characterMimeType.1=application/javascript+module
language2.characterMimeType.2=text/javascript
language2.className=com.oracle.truffle.js.lang.JavaScriptLanguage
language2.defaultMimeType=application/javascript
language2.dependentLanguage.0=regex
language2.fileTypeDetector0=com.oracle.truffle.js.lang.JSFileTypeDetector
language2.id=js
language2.implementationName=GraalVM JavaScript
language2.interactive=true
language2.internal=false
language2.name=JavaScript
language2.version=inherit