GraalJS:如何消除这些警告?

4
我们在应用程序中使用GraalVM.js作为ScriptEngine。目标是拥有一个可以运行用户定义的JavaScript脚本以扩展功能的Java JRE。
MVCE:
        ScriptEngine engine = GraalJSScriptEngine.create(null, Context.newBuilder("js"));

        String script = "6 * 7";
        Object eval = ((Compilable) engine).compile(script).eval();
        System.out.println(eval);

这段代码可以完美地打印出 "42",但在此之前会有一长串的警告信息:

[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.

我尝试按照印刷的建议进行操作:

    ScriptEngine engine = GraalJSScriptEngine.create(null, Context.newBuilder("js")
        .option("engine.WarnInterpreterOnly","false")
    );

很不幸,这个操作失败并抛出了异常:

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

我不确定这个异常的含义以及如何解决它。添加虚拟机选项是不切实际的,文档承诺应该可以通过编程方式传递这样的选项:https://www.graalvm.org/22.0/reference-manual/polyglot-programming/#passing-options-programmatically
日志选项根本不起作用:
    ScriptEngine engine = GraalJSScriptEngine.create(null, Context.newBuilder("js")
        .option("log.file","log\\engine.log")
    );

导致

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)

依赖项:

    <!-- 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>

有什么建议吗?
2个回答

4
您可以使用 context eval 而不是 ScriptEngine,这会使性能变慢,请在 这里 进行检查。下面的代码对我来说可以正常工作且无警告。
    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);
    }

在我的IntelliJ中,输出看起来像下面这样: {{link1:graalvm js engine output from intellij}}

1
很有趣。至少,现在错误对我来说更清晰了。我不知道引擎可以在上下文之前创建,然后稍后附加。看起来我们正在做相反的事情:创建上下文然后请求引擎。我不确定这么做是否有好处。无论如何,看起来我们不能重复使用上下文,因为我们希望所有脚本执行彼此独立(不重用变量等)。但是现在错误已经消失了,谢谢! - colouredmirrorball
1
请考虑编辑此帖子,因为它实际上并未解决潜在的问题,而只是通过.option("engine.WarnInterpreterOnly", "false")来抑制警告。 - Jordan LaPrise
问题是“如何消除这些警告?”Bruce的答案表明它具有相同的性能。 - ozkanpakdil

3

您需要将选项设置在引擎上,而不是上下文(构建器)上。

因此,

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

唯一的区别在于ozkanpakdil的答案使用了ScriptEngine (javax.script) 的 API,而另一个答案则使用 graalvm 的 Context (org.graalvm.polyglot) 来提供纯 graalvm API。
例如在 eval 方法中,一个需要传递 Reader 因为它不知道 graalvm 的 Source,而另一个可以直接使用这个对象。或者一个允许您传递 Writer 以便引擎写出输出,而 graalvm 使用 OutputStream
话虽如此,在两种情况下性能是相同的,因为源代码都将以解释模式运行(因此会有警告)。
如果 JS 代码需要良好的性能,则可能需要切换到 GraalVM 分发版,或修改 java 命令行以切换编译器到 Graal(需要通过 -XX:+EnableJVMCI -XX:+UseJVMCICompiler 启用编译器接口,并修改模块路径以使用 graal 和 truffle 的 jar 包)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接