GraalJS: how to get rid of these warnings?

4.1k views Asked by At

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?

2

There are 2 answers

3
ozkanpakdil On BEST ANSWER

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);
    }

output looks like below in my intellij graalvm js engine output from intellij

0
bric3 On

You need to set the option on the engine, not the context (builder).

So

GraalJSScriptEngine.create(
        Engine.newBuilder()
              .option("engine.WarnInterpreterOnly", "false")
              .build(),
        Context.newBuilder("js")
               .allowIO(false)
               .option(JSContextOptions.ECMASCRIPT_VERSION_NAME, "2022")
)

The only difference between ozkanpakdil's answer is that the above code use the API of the ScriptEngine (javax.script), while in the other answer using graalvm's Context (org.graalvm.polyglot) will give you a pure graalvm API.

There's some differences e.g in the eval method one requires a Reader as it doesn't know graalvm's Source, while the other can use this object directly. Or one allows you to pass Writers for the engine to write output, while graalvm uses OutputStreams.

That said the performance is the same as in both case the source will run in interpreted mode (hence the warning).


If the JS code needs to have good performance then it might be required to either switch to GraalVM distribution, or to modify the java command line to switch the compiler to to Graal (requires to enable Compiler Interface via -XX:+EnableJVMCI -XX:+UseJVMCICompiler and modify the module path with the jars of graal and truffle in particular).