Truffle 上的 GraalVM Java - 执行 Java 代码时来自 NFIContext.getBackend 的 NullPointerException

GraalVM Java on truffle - NullPointerException from NFIContext.getBackend when executing Java code

我正在尝试使用来自 GraalVM 的 Truffle 运行 Java 在 Java 应用程序中动态编码,但没有成功。

设置

我正在使用 MacOs 11.5.2。

我跟进了 GraalVM JDK 安装过程,并使用 gu install espresso 安装了 espresso。

$ java -version
openjdk version "11.0.13" 2021-10-19
OpenJDK Runtime Environment GraalVM CE 21.3.0 (build 11.0.13+7-jvmci-21.3-b05)
OpenJDK 64-Bit Server VM GraalVM CE 21.3.0 (build 11.0.13+7-jvmci-21.3-b05, mixed mode, sharing)
$ java -truffle -version
openjdk version "11.0.13" 2021-10-19
OpenJDK Runtime Environment GraalVM CE 21.3.0 (build 11.0.13+7-jvmci-21.3-b05)
Espresso 64-Bit VM GraalVM CE 21.3.0 (build 11-espresso-21.3.0, mixed mode)

我已经能够 运行 一个简单的 Hello World Class 和 Jar。甚至 运行 Java Java 主机应用程序中的脚本代码(作为字符串)。

问题

但是当我尝试执行这个程序时出现错误:

package com.host;

import java.io.IOException;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;

public class Main {
  public static void main(String[] args) throws IOException {
    Context polyglot = Context.newBuilder("java").allowAllAccess(true).build();

    Value java_lang_Math = polyglot.getBindings("java").getMember("java.lang.Math"); // <- Faulty line
    double sqrt2 = java_lang_Math.invokeMember("sqrt", 2).asDouble();
    double pi = java_lang_Math.getMember("PI").asDouble();
    System.out.println(sqrt2);
    System.out.println(pi);
  }
}

顺便说一下,这段代码来自他们的文档 (https://www.graalvm.org/reference-manual/java-on-truffle/interoperability/#embedding-in-host-java)

但是当我尝试以 class 或 Jar 的形式执行代码时,我收到此错误:

$ java -jar target/host-code-1.0-SNAPSHOT.jar
Exception in thread "main" org.graalvm.polyglot.PolyglotException: java.lang.NullPointerException
    at com.oracle.truffle.nfi.NFIContext.getBackend(NFIContext.java:83)
    at com.oracle.truffle.nfi.NFIRootNode.execute(NFIRootNode.java:147)
    at org.graalvm.sdk/org.graalvm.polyglot.Context.getBindings(Context.java:540)
    at com.host.Main.main(Main.java:13)
Original Internal Error:
java.lang.NullPointerException
    at com.oracle.truffle.nfi.NFIContext.getBackend(NFIContext.java:83)
    at com.oracle.truffle.nfi.NFIRootNode.execute(NFIRootNode.java:147)
    at jdk.internal.vm.compiler/org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.executeRootNode(OptimizedCallTarget.java:650)
    at jdk.internal.vm.compiler/org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.profiledPERoot(OptimizedCallTarget.java:622)
    at jdk.internal.vm.compiler/org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callBoundary(OptimizedCallTarget.java:555)
    at jdk.internal.vm.compiler/org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.doInvoke(OptimizedCallTarget.java:539)
    at jdk.internal.vm.compiler/org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callIndirect(OptimizedCallTarget.java:463)
    at jdk.internal.vm.compiler/org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.call(OptimizedCallTarget.java:444)
    at com.oracle.truffle.espresso.ffi.nfi.NFINativeAccess.loadLibraryHelper(NFINativeAccess.java:180)
    at com.oracle.truffle.espresso.ffi.nfi.NFISulongNativeAccess.loadLibrary(NFISulongNativeAccess.java:44)
    at com.oracle.truffle.espresso.ffi.NativeAccess.loadLibrary(NativeAccess.java:77)
    at com.oracle.truffle.espresso.jni.JniEnv.<init>(JniEnv.java:316)
    at com.oracle.truffle.espresso.jni.JniEnv.create(JniEnv.java:364)
    at com.oracle.truffle.espresso.runtime.EspressoContext.getJNI(EspressoContext.java:685)
    at com.oracle.truffle.espresso.runtime.EspressoContext.spawnVM(EspressoContext.java:463)
    at com.oracle.truffle.espresso.runtime.EspressoContext.initializeContext(EspressoContext.java:423)
    at com.oracle.truffle.espresso.EspressoLanguage.initializeContext(EspressoLanguage.java:144)
    at com.oracle.truffle.espresso.EspressoLanguage.initializeContext(EspressoLanguage.java:64)
    at org.graalvm.truffle/com.oracle.truffle.api.TruffleLanguage$Env.postInit(TruffleLanguage.java:3606)
    at org.graalvm.truffle/com.oracle.truffle.api.LanguageAccessor$LanguageImpl.postInitEnv(LanguageAccessor.java:301)
    at org.graalvm.truffle/com.oracle.truffle.polyglot.PolyglotLanguageContext.ensureInitialized(PolyglotLanguageContext.java:661)
    at org.graalvm.truffle/com.oracle.truffle.polyglot.PolyglotContextImpl.getBindings(PolyglotContextImpl.java:969)
    at org.graalvm.truffle/com.oracle.truffle.polyglot.PolyglotContextDispatch.getBindings(PolyglotContextDispatch.java:97)
    at org.graalvm.sdk/org.graalvm.polyglot.Context.getBindings(Context.java:540)
    at com.host.Main.main(Main.java:13)
Caused by: Attached Guest Language Frames (1)

我不明白我错过了什么,我也不知道如何解决这个问题。有人有想法吗?

Java 在 Truffle (Espresso) 上有不同的配置:本机和 JVM,single/multi 上下文...它 运行 在所有主要 OS 中至少一种配置,但不是全部。

Espresso 原生(无 HotSpot),单一上下文,在所有平台中 运行s。 Espresso on HotSpot and/or 多上下文目前仅适用于 Linux,这适用于文档中的一些示例。

对于 运行 Espresso on HotSpot,主要挑战之一是隔离本地库。在 Linux 上,Espresso 依靠 glibc 的 dlmopen 在独立的链接命名空间中加载本机库,这允许加载相同的库两次或更多次,例如加载时也是如此。 libjava,我们想要一个链接到 Espresso 的 libjvm 而不是 HotSpot 的新副本。

我们还没有在 Mac 或 Windows 上找到类似的隔离机制,尽管 an alternative exists on Android

为了克服这个限制,团队正在积极开发 Espresso 的 Sulong 本机后端。 Sulong 是用于 GraalVM 的高性能 LLVM 位码解释器。 想法是将 OpenJDK 本地库编译为 LLVM 位码,并 load/run 它们在 Sulong 上,Sulong 在设计上支持隔离;已经有一个工作原型。

在当前状态下,Espresso 默认尝试在 MacOS 上使用 Sulong 本机后端,但尚未完全 functional/shipped,因此出现错误。