We're using GraalVM.js as a ScriptEngine in our application. The goal is to have a Java JRE that can run user-defined javascript scripts to extend functionality.
MVCE:
ScriptEngine engine = GraalJSScriptEngine.create(null, Context.newBuilder("js"));
String script = "6 * 7";
Object eval = ((Compilable) engine).compile(script).eval();
System.out.println(eval);
The code neatly prints "42" but not before this lengthy warning:
[To redirect Truffle log output to a file use one of the following options:
* '--log.file=<path>' if the option is passed using a guest language launcher.
* '-Dpolyglot.log.file=<path>' if the option is passed using the host Java launcher.
* Configure logging using the polyglot embedding API.]
[engine] WARNING: The polyglot context is using an implementation that does not support runtime compilation.
The guest application code will therefore be executed in interpreted mode only.
Execution only in interpreted mode will strongly impact the guest application performance.
For more information on using GraalVM see https://www.graalvm.org/java/quickstart/.
To disable this warning the '--engine.WarnInterpreterOnly=false' option or use the '-Dpolyglot.engine.WarnInterpreterOnly=false' system property.
I have tried to follow the printed suggestion:
ScriptEngine engine = GraalJSScriptEngine.create(null, Context.newBuilder("js")
.option("engine.WarnInterpreterOnly","false")
);
Unfortunately this fails with an exception:
Exception in thread "main" java.lang.IllegalArgumentException: Option engine.WarnInterpreterOnly is an engine option. Engine level options can only be configured for contexts without a shared engine set. To resolve this, configure the option when creating the Engine or create a context without a shared engine.
at com.oracle.truffle.polyglot.PolyglotEngineException.illegalArgument(PolyglotEngineException.java:131)
at com.oracle.truffle.polyglot.PolyglotContextConfig.findObjectForContextOption(PolyglotContextConfig.java:433)
at com.oracle.truffle.polyglot.PolyglotContextConfig.<init>(PolyglotContextConfig.java:260)
at com.oracle.truffle.polyglot.PolyglotEngineImpl.createContext(PolyglotEngineImpl.java:1697)
at com.oracle.truffle.polyglot.PolyglotEngineDispatch.createContext(PolyglotEngineDispatch.java:159)
at org.graalvm.polyglot.Context$Builder.build(Context.java:1837)
at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.createDefaultContext(GraalJSScriptEngine.java:353)
at com.oracle.truffle.js.scriptengine.GraalJSBindings.initContext(GraalJSBindings.java:91)
at com.oracle.truffle.js.scriptengine.GraalJSBindings.requireContext(GraalJSBindings.java:86)
at com.oracle.truffle.js.scriptengine.GraalJSBindings.entrySet(GraalJSBindings.java:172)
at java.base/java.util.AbstractMap.containsKey(AbstractMap.java:144)
at java.scripting/javax.script.SimpleScriptContext.getAttribute(SimpleScriptContext.java:158)
at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.createSource(GraalJSScriptEngine.java:450)
at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.compile(GraalJSScriptEngine.java:628)
at Scratch.main(scratch_1.java:17)
Process finished with exit code 1
I'm unsure what this exception means and how to solve it. It would be impractical to add a VM option, and the documentation promises it should be possible to pass on options like this: https://www.graalvm.org/22.0/reference-manual/polyglot-programming/#passing-options-programmatically
The log option doesn't work at all:
ScriptEngine engine = GraalJSScriptEngine.create(null, Context.newBuilder("js")
.option("log.file","log\\engine.log")
);
results in
Exception in thread "main" java.lang.IllegalArgumentException: log.file
at com.oracle.truffle.polyglot.PolyglotEngineException.illegalArgument(PolyglotEngineException.java:131)
at com.oracle.truffle.polyglot.PolyglotEngineImpl.parseLoggerName(PolyglotEngineImpl.java:776)
at com.oracle.truffle.polyglot.PolyglotContextConfig.<init>(PolyglotContextConfig.java:257)
at com.oracle.truffle.polyglot.PolyglotEngineImpl.createContext(PolyglotEngineImpl.java:1697)
at com.oracle.truffle.polyglot.PolyglotEngineDispatch.createContext(PolyglotEngineDispatch.java:159)
at org.graalvm.polyglot.Context$Builder.build(Context.java:1837)
at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.createDefaultContext(GraalJSScriptEngine.java:353)
at com.oracle.truffle.js.scriptengine.GraalJSBindings.initContext(GraalJSBindings.java:91)
at com.oracle.truffle.js.scriptengine.GraalJSBindings.requireContext(GraalJSBindings.java:86)
at com.oracle.truffle.js.scriptengine.GraalJSBindings.entrySet(GraalJSBindings.java:172)
at java.base/java.util.AbstractMap.containsKey(AbstractMap.java:144)
at java.scripting/javax.script.SimpleScriptContext.getAttribute(SimpleScriptContext.java:158)
at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.createSource(GraalJSScriptEngine.java:450)
at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.compile(GraalJSScriptEngine.java:628)
at Scratch.main(scratch_1.java:17)
Dependencies:
<!-- https://mvnrepository.com/artifact/org.graalvm.sdk/graal-sdk -->
<dependency>
<groupId>org.graalvm.sdk</groupId>
<artifactId>graal-sdk</artifactId>
<version>22.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.graalvm.js/js -->
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js</artifactId>
<version>22.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.graalvm.js/js-scriptengine -->
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js-scriptengine</artifactId>
<version>22.2.0</version>
</dependency>
Any suggestions?
You can use context eval instead of ScriptEngine which makes it slower performance wise check here. Code below is working for me without the warning.
public static void main(String[] args) {
Engine engine = Engine.newBuilder()
.option("engine.WarnInterpreterOnly", "false")
.build();
Context ctx = Context.newBuilder("js").engine(engine).build();
String script = "6 * 7";
Object eval = ctx.eval("js", script);
System.out.println(eval);
}