GraalJS - Cannot build ScriptEngine from jar

977 Views Asked by At

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

1

There are 1 best solutions below

0
On BEST ANSWER

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