相互運用性

GraalVMでは、JavaScript、Python、Ruby、Rなど、その他のいくつかのプログラミング言語がサポートされています。GraalVMのlliの実装は、LLVMビットコードを実行するように設計されていますが、他のGraalVMサポート対象言語からコードを実行できるようにする、プログラミング言語の相互運用性のためのAPIも提供しています。

JavaScriptのような動的言語は、通常、オブジェクト・メンバーに名前でアクセスします。通常、名前はLLVMビットコードに保持されないため、デバッグ情報を有効にしてコンパイルする必要があります(GraalVMに付属のLLVMツールチェーンでは、デバッグ情報は自動的に有効になります)。

次の例では、他のプログラミング言語との相互運用性のためにAPIを使用できることを示します。

ポイントのC構造体を定義し、cpart.cという名前のファイルに割当て関数を実装します:

// cpart.c
#include <graalvm/llvm/polyglot.h>

#include <stdlib.h>
#include <stdio.h>

struct Point {
    double x;
    double y;
};

POLYGLOT_DECLARE_STRUCT(Point)

void *allocNativePoint() {
    struct Point *ret = malloc(sizeof(*ret));
    return polyglot_from_Point(ret);
}

void *allocNativePointArray(int length) {
    struct Point *ret = calloc(length, sizeof(*ret));
    return polyglot_from_Point_array(ret, length);
}

void freeNativePoint(struct Point *p) {
    free(p);
}

void printPoint(struct Point *p) {
    printf("Point<%f,%f>\n", p->x, p->y);
}

LLVM_TOOLCHAINがGraalVM LLVMツールチェーン(lli --print-toolchain-path)に解決されることを確認してから、cpart.cをコンパイルします(graalvm-llvmライブラリは、この例で使用されているポリグロットAPI関数を定義します):

$LLVM_TOOLCHAIN/clang -shared cpart.c -lgraalvm-llvm -o cpart.so

その後、他の言語からこのC/C++コードにアクセスできます。たとえば、次のJavaScriptコードをjspart.jsファイルに保存します:

// Load and parse the LLVM bitcode into GraalVM
var cpart = Polyglot.evalFile("llvm" ,"cpart.so");

// Allocate a light-weight C struct
var point = cpart.allocNativePoint();

// Access it as if it was a JS object
point.x = 5;
point.y = 7;

// Pass it back to a native function
cpart.printPoint(point);

// Allocate an array of structs
var pointArray = cpart.allocNativePointArray(15);

// Access this array like it was a JS array
for (var i = 0; i < pointArray.length; i++) {
    var p = pointArray[i];
    p.x = i;
    p.y = 2*i;
}

cpart.printPoint(pointArray[3]);

// Additionally, pass a JS object to a native function
cpart.printPoint({x: 17, y: 42});

// Free the unmanaged data objects
cpart.freeNativePoint(point);
cpart.freeNativePoint(pointArray);

最後に、このJavaScriptファイルを実行します:

js --polyglot jspart.js
Point<5.000000,7.000000>
Point<3.000000,6.000000>
Point<17.000000,42.000000>

ポリグロットC API

Cからポリグロット値に直接アクセスするための下位レベルのAPI関数もあります。詳細は、「ポリグロット・プログラミング」リファレンスおよびpolyglot.hのコメントを参照してください。

たとえば、次のプログラムはJava配列を割り当ててCからアクセスします:

#include <stdio.h>
#include <graalvm/llvm/polyglot.h>

int main() {
    void *arrayType = polyglot_java_type("int[]");
    void *array = polyglot_new_instance(arrayType, 4);
    polyglot_set_array_element(array, 2, 24);
    int element = polyglot_as_i32(polyglot_get_array_element(array, 2));
    printf("%d\n", element);
    return element;
}

LLVMビットコードにコンパイルします:

$LLVM_TOOLCHAIN/clang polyglot.c -lgraalvm-llvm -o polyglot

次に、Java型が使用されているため、JVMモードで実行するための--jvm引数を使用して、これを実行します:

lli --jvm polyglot
24

Javaへの埋込み

GraalVMは、LLVMビットコードをJavaホスト・プログラムに埋め込むために使用することもできます。

たとえば、前の例を実行するために、GraalVMを埋め込むJavaクラスPolyglot.javaを記述します:

import java.io.*;
import org.graalvm.polyglot.*;

class Polyglot {
    public static void main(String[] args) throws IOException {
        Context polyglot = Context.newBuilder().
        		               allowAllAccess(true).build();
        File file = new File("polyglot");
        Source source = Source.newBuilder("llvm", file).build();
        Value cpart = polyglot.eval(source);
        cpart.execute();
    }
}

これをコンパイルして実行します:

javac Polyglot.java
java Polyglot
24

詳細は、「言語の埋込み」リファレンスを参照してください。