GraalVM Java на трюфеле — Исключение NullPointerException из NFIContext.getBackend при выполнении кода Java

#java #android-espresso #truffle #graalvm

Вопрос:

Я пытаюсь динамически запускать java-код внутри java-приложения, используя трюфель из GraalVM. Безуспешно.

Настройки

Я работаю над macOS 11.5.2.

Я проследил за процессом установки GraalVM JDK и установил эспрессо с помощью gu install 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 и Jar. И даже запустите код javascript (в виде строки) в хост-приложении 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)

Но когда я пытаюсь выполнить код, либо как класс, либо как 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)
 

Я не понимаю, что я упустил, и у меня нет подсказок, как решить эту проблему. У кого-нибудь есть идея ?

Ответ №1:

Java на трюфеле (Эспрессо) имеет разные конфигурации: родную и JVM, единый/мультиконтекст… он работает на всех основных операционных системах по крайней мере в одной конфигурации, но не на всех из них.

Собственный эспрессо (без точки доступа), единый контекст, работает на всех платформах. Эспрессо на горячей точке и/или мультиконтекст работает только в Linux на данный момент, это относится к некоторым примерам в документах.

Для запуска Эспрессо в HotSpot одной из основных проблем является изоляция собственных библиотек. В Linux Espresso использует dlmopen glibc для загрузки собственных библиотек в изолированных пространствах имен ссылок, это позволяет загружать одну и ту же библиотеку дважды или более, также при загрузке, например, libjava, мы хотим, чтобы свежая копия связывалась с libjvm Эспрессо, а не с HotSpot.

Мы не нашли аналогичного механизма изоляции на Mac или Windows, хотя альтернатива существует на Android.

Чтобы преодолеть эти ограничения, команда активно работает над бэкэндом Sulong для Эспрессо. Сулонг-это высокопроизводительный интерпретатор битового кода LLVM для GraalVM. Идея состоит в том, чтобы скомпилировать собственные библиотеки OpenJDK в битовый код LLVM и загрузить/запустить их на Sulong, который по дизайну поддерживает изоляцию; уже есть рабочий прототип.

В текущем состоянии Espresso по умолчанию пытается использовать собственный серверный сервер Sulong на macOS, но он еще не полностью функционирует/поставляется, поэтому возникает ошибка.