互操作性

GraalVM 支持多种其他编程语言,包括 JavaScript、Python、Ruby 和 R。虽然 GraalVM 的 lli 实现旨在运行 LLVM 位码,但它还提供编程语言互操作性的 API,使您可以执行任何其他 GraalVM 支持语言的代码。

像 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 库定义了示例中使用的 Polyglot 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>

Polyglot C API #

还有一些更低级的 API 函数可以直接从 C 访问 polyglot 值。有关更多详细信息,请参阅 Polyglot 编程 参考和 polyglot.h 中的注释。

例如,此程序从 C 分配和访问 Java 数组

#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

然后运行它

lli polyglot
24

嵌入到 Java 中 #

您可以在 Java 宿主应用程序中嵌入 LLVM 位码。

例如,编写一个 Java 类 Polyglot.java,它嵌入 LLVM 位码以运行前面的示例

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

有关更多信息,请参阅 嵌入语言 参考。

联系我们