- 適用於 JDK 23 的 GraalVM (最新)
- 適用於 JDK 24 的 GraalVM (搶先體驗)
- 適用於 JDK 21 的 GraalVM
- 適用於 JDK 17 的 GraalVM
- 封存
- 開發版本
多語言程式設計
GraalVM 允許使用者撰寫多語言應用程式,透過 Truffle 語言實作架構 (以下簡稱 “Truffle”),將值從一種語言無縫傳遞到另一種語言。
Truffle 是一個 Java 函式庫,用於將程式語言實作為自修改抽象語法樹的直譯器。當使用 Truffle 撰寫語言直譯器時,它會自動使用 Graal 編譯器作為該語言的即時編譯器。透過存取此架構,例如,Ruby 應用程式可以與 Java 應用程式在同一個 JVM 上執行。此外,基於主機 JVM 的語言和客體語言可以直接互相操作,並在同一個記憶體空間中來回傳遞資料。
為了在 Truffle 實作的語言中提供外部多語言值,開發了所謂的多語言互通協定。這個互通協定包含一組標準化的訊息,每個語言都會實作並用於外部多語言值。此協定允許 GraalVM 支援任何語言組合之間的互通性,而不需要它們彼此了解。如需更多詳細資訊,請參閱 多語言執行時間中的高效能跨語言互通性 論文。
在本節中,您將學習如何使用 GraalVM 多語言 API 組合多種語言。
執行多語言應用程式 #
下列範例旨在協助您開始使用基本的多語言應用程式。為您的起始語言選擇一個區段,然後為目標語言選擇一個索引標籤。
以下範例預期可從 JVM 或原生獨立發行版本正常運作。對於使用 Java 作為目標語言並存取 Java 陣列以外的類別的原生啟動器和原生可執行檔,需要重新編譯映像並提供 反射組態檔。
注意:若要使用 LLVM 作為目標語言啟動應用程式,請確保預先編譯下面提供的 polyglot.c 檔案。
從 JavaScript / Node.js 開始 #
建立檔案 polyglot.js
// BEGIN-SNIPPET
var array = Polyglot.eval("R", "c(1,2,42,4)")
console.log(array[2]);
// END-SNIPPET
// BEGIN-SNIPPET
var array = Polyglot.eval("ruby", "[1,2,42,4]")
console.log(array[2]);
// END-SNIPPET
// BEGIN-SNIPPET
var array = Polyglot.eval("python", "[1,2,42,4]")
console.log(array[2]);
// END-SNIPPET
// BEGIN-SNIPPET
var array = new (Java.type("int[]"))(4);
array[2] = 42;
console.log(array[2])
// END-SNIPPET
// BEGIN-SNIPPET
var cpart = Polyglot.evalFile("llvm", "polyglot");
cpart.main()
// END-SNIPPET
執行
js polyglot.js
42
node polyglot.js
42
起始語言 R #
建立檔案 polyglot.R
# BEGIN-SNIPPET
array <- eval.polyglot("js", "[1,2,42,4]")
print(array[3L])
# END-SNIPPET
# BEGIN-SNIPPET
array <- eval.polyglot("ruby", "[1,2,42,4]")
print(array[3L])
# END-SNIPPET
# BEGIN-SNIPPET
array <- eval.polyglot("python", "[1,2,42,4]")
print(array[3L])
# END-SNIPPET
# BEGIN-SNIPPET
array <- new("int[]", 4)
array[3L] <- 42
print(array[3L])
# END-SNIPPET
# BEGIN-SNIPPET
cpart <- eval.polyglot("llvm", path="polyglot")
cpart$main()
# END-SNIPPET
執行
Rscript polyglot.R
[1] 42
起始語言 Ruby #
建立檔案 polyglot.rb
# BEGIN-SNIPPET
array = Polyglot.eval('js', '[1,2,42,4]')
puts array[2]
# END-SNIPPET
# BEGIN-SNIPPET
array = Polyglot.eval('R', 'c(1L,2L,42L,4L)')
puts array[2]
# END-SNIPPET
# BEGIN-SNIPPET
array = Polyglot.eval('python', '[1,2,42,4]')
puts array[2]
# END-SNIPPET
# BEGIN-SNIPPET
array = Java.type('int[]').new(4)
array[2] = 42
print(array[2])
# END-SNIPPET
# BEGIN-SNIPPET
cpart = Polyglot.eval_file('llvm', 'polyglot')
cpart.main()
# END-SNIPPET
執行
ruby polyglot.rb
42
起始語言 Python #
建立檔案 polyglot.py
# BEGIN-SNIPPET
import polyglot
array = polyglot.eval(language="js", string="[1,2,42,4]")
print(array[2])
# END-SNIPPET
# BEGIN-SNIPPET
import polyglot
array = polyglot.eval(language="R", string="c(1L,2L,42L,4L)")
print(array[2])
# END-SNIPPET
# BEGIN-SNIPPET
import polyglot
array = polyglot.eval(language="ruby", string="[1,2,42,4]")
print(array[2])
# END-SNIPPET
# BEGIN-SNIPPET
import java
array = java.type("int[]")(4)
array[2] = 42
print(array[2])
# END-SNIPPET
# BEGIN-SNIPPET
import polyglot
cpart = polyglot.eval(language="llvm", path="polyglot")
cpart.main()
# END-SNIPPET
執行
graalpy polyglot.py
42
起始語言 Java #
建立檔案 Polyglot.java
// BEGIN-SNIPPET
import org.graalvm.polyglot.*;
class Polyglot {
public static void main(String[] args) {
Context polyglot = Context.create();
Value array = polyglot.eval("js", "[1,2,42,4]");
int result = array.getArrayElement(2).asInt();
System.out.println(result);
}
}
// END-SNIPPET
// BEGIN-SNIPPET
import org.graalvm.polyglot.*;
class Polyglot {
public static void main(String[] args) {
Context polyglot = Context.newBuilder().
allowAllAccess(true).build();
Value array = polyglot.eval("R", "c(1,2,42,4)");
int result = array.getArrayElement(2).asInt();
System.out.println(result);
}
}
// END-SNIPPET
// BEGIN-SNIPPET
import org.graalvm.polyglot.*;
class Polyglot {
public static void main(String[] args) {
Context polyglot = Context.newBuilder().
allowAllAccess(true).build();
Value array = polyglot.eval("ruby", "[1,2,42,4]");
int result = array.getArrayElement(2).asInt();
System.out.println(result);
}
}
// END-SNIPPET
// BEGIN-SNIPPET
import org.graalvm.polyglot.*;
class Polyglot {
public static void main(String[] args) {
Context context = Context.newBuilder().allowIO(true).build();
Value array = context.eval("python", "[1,2,42,4]");
int result = array.getArrayElement(2).asInt();
System.out.println(result);
}
}
// END-SNIPPET
// BEGIN-SNIPPET
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();
}
}
// END-SNIPPET
執行
javac Polyglot.java
java Polyglot
42
起始語言 C #
建立檔案 polyglot.c
// BEGIN-SNIPPET
#include <stdio.h>
#include <graalvm/llvm/polyglot.h>
int main() {
void *array = polyglot_eval("js", "[1,2,42,4]");
int element = polyglot_as_i32(polyglot_get_array_element(array, 2));
printf("%d\n", element);
return element;
}
// END-SNIPPET
// BEGIN-SNIPPET
#include <stdio.h>
#include <graalvm/llvm/polyglot.h>
int main() {
void *array = polyglot_eval("R", "c(1,2,42,4)");
int element = polyglot_as_i32(polyglot_get_array_element(array, 2));
printf("%d\n", element);
return element;
}
// END-SNIPPET
// BEGIN-SNIPPET
#include <stdio.h>
#include <graalvm/llvm/polyglot.h>
int main() {
void *array = polyglot_eval("ruby", "[1,2,42,4]");
int element = polyglot_as_i32(polyglot_get_array_element(array, 2));
printf("%d\n", element);
return element;
}
// END-SNIPPET
// BEGIN-SNIPPET
#include <stdio.h>
#include <graalvm/llvm/polyglot.h>
int main() {
void *array = polyglot_eval("python", "[1,2,42,4]");
int element = polyglot_as_i32(polyglot_get_array_element(array, 2));
printf("%d\n", element);
return element;
}
// END-SNIPPET
// BEGIN-SNIPPET
#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, 42);
int element = polyglot_as_i32(polyglot_get_array_element(array, 2));
printf("%d\n", element);
return element;
}
// END-SNIPPET
範例 C 程式碼必須使用 LLVM 前端 (例如 clang
) 編譯為 LLVM 位元碼。使用者可以使用來自預建 隨 GraalVM LLVM 執行時間提供的 LLVM 工具鏈 的 clang
export LLVM_TOOLCHAIN=$(lli --print-toolchain-path)
執行
$LLVM_TOOLCHAIN/clang polyglot.c -lgraalvm-llvm -o polyglot
lli polyglot
42
多語言選項 #
您可以設定語言引擎以獲得更好的輸送量或啟動效能。
--engine.Mode=default
設定引擎的執行模式。執行模式會自動調整多語言引擎以達到延遲或輸送量。throughput
會收集最大量的設定檔資訊,並使用最大數量的最佳化來編譯。此模式會導致應用程式啟動速度較慢,但輸送量較佳。如果未另外指定,此模式會使用編譯器組態community
或enterprise
。default
使用平衡的引擎組態。如果未另外指定,此模式會使用編譯器組態community
或enterprise
。latency
僅收集最少的設定檔資訊,並盡可能使用較少最佳化產生的程式碼快速編譯。此模式會導致應用程式啟動速度較快,但輸送量較不理想。如果未另外指定,此模式會使用編譯器組態economy
。
將選項傳遞給語言啟動器 #
每個語言啟動器都已擴充一組所謂的多語言選項。多語言選項允許任何語言啟動器的使用者存取 GraalVM 支援的其他語言的選項 (使用 Truffle 語言實作架構實作)。格式為:--<languageID>.<property>=<value>
。例如,R
啟動器也支援 --js.atomics=true
JavaScript 選項。
languageID
的允許值為
js
:JavaScript 的選項python
:Python 的選項r
:R 的選項ruby
:Ruby 的選項llvm
:LLVM 的選項
使用 --help:languages
來找出哪些選項可用。
多語言工具的選項以相同的方式運作,格式如下:--<toolID>.<property>=<value>
。
<toolID>
的允許值為
inspect
:允許使用 Chrome 開發人員工具進行偵錯cpusampler
:收集有關 CPU 使用率的資料cputracer
:擷取有關 CPU 使用率的追蹤資訊memtracer
:擷取有關記憶體使用率的追蹤資訊
使用 --help:tools
來找出哪些選項可用。
以程式設計方式傳遞選項 #
也可以使用 Java 多語言 API 以程式設計方式傳遞選項。
建立名為 OptionsTest.java
的檔案
import org.graalvm.polyglot.*;
class OptionsTest {
public static void main(String[] args) {
Context polyglot = Context.newBuilder()
.allowExperimentalOptions(true)
.option("js.shared-array-buffer", "true")
.build();
// the use of shared array buffer requires the 'js.shared-array-buffer' option to be 'true'
polyglot.eval("js", "new SharedArrayBuffer(1024)");
}
}
執行
javac OptionsTest.java
java OptionsTest
注意:工具選項可以相同方式傳遞。建立內容後,無法修改選項。
使用 JVM 引數傳遞選項 #
每個多語言選項也可以作為 Java 系統屬性傳遞。每個可用的選項都會轉換為具有 polyglot.
字首的系統屬性。例如,-Dpolyglot.js.strict=true
為在 JVM 中執行的所有 JavaScript 程式碼設定嚴格解譯的預設值。以程式設計方式設定的選項優先於 Java 系統屬性。對於語言,可以使用以下格式:-Dpolyglot.<languageID>.<property>=<value>
,對於工具則是:-Dpolyglot.<toolID>.<property>=<value>
。
建立名為 SystemPropertiesTest.java
的檔案
import org.graalvm.polyglot.*;
class SystemPropertiesTest {
public static void main(String[] args) {
Context polyglot = Context.newBuilder()
.allowExperimentalOptions(true)
.build();
// the use of shared array buffer requires the 'js.shared-array-buffer' option to be 'true'
polyglot.eval("js", "new SharedArrayBuffer(1024)");
}
}
執行
javac SystemPropertiesTest.java
java -Dpolyglot.js.strict=true SystemPropertiesTest
注意:建立多語言內容時,系統屬性會讀取一次。後續變更沒有任何作用。
相關文件 #
- 從 嵌入語言文件深入瞭解客體和 Java 主機語言的互通性