前記事ではChicoryを使ってwasmをJava上で実行しましたが、
同じことがGraalVM (GraalWasm)でもできました。
前記事の内容をGraalWasmでやり直します。
以下の依存ライブラリを追加することでJavaアプリ上でwasmの読み込み・実行ができるようになります。
<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>polyglot</artifactId>
<version>24.0.1</version>
</dependency>
<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>wasm-community</artifactId>
<version>24.0.1</version>
<type>pom</type>
</dependency>
サンプルのwasmファイルをWATファイルから作ります。次のファイルSumSquared.watを作ります。
二つのi32のパラメータを加算して二乗した値を返します。
(module
(func (export "SumSquared")
(param $value_1 i32) (param $value_2 i32)
(result i32)
(local $sum i32)
(i32.add (local.get $value_1) (local.get $value_2))
local.set $sum
(i32.mul (local.get $sum) (local.get $sum))
)
)
wat2wasmでwasmに変換します。
wat2wasm SumSquared.wat
SumSquared.wasmが生成されます。このwasmをJavaで読み込んで実行します。
package org.example;
import java.io.IOException;
import java.net.URL;
import java.util.Objects;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
public class Main {
public static void main(String[] args) throws IOException {
try (Context context = Context.newBuilder().allowAllAccess(true).build()) {
context.initialize("wasm");
URL resource = Main.class.getClassLoader().getResource("SumSquared.wasm");
Source source = Source.newBuilder("wasm", Objects.requireNonNull(resource)).name("main").build();
context.eval(source);
Value sumSquared = context.getBindings("wasm").getMember("main").getMember("SumSquared");
Value result = sumSquared.execute(2, 3);
System.out.println("Result: " + result.asInt()); // should print "Result: 25" (= (2 + 3)^2)
}
}
}
Javaアプリを実行します。
$ mvn -q compile exec:java -Dexec.mainClass=org.example.Main
Result: 25
このアプリは、RuntimeがGraalVMでなくとも動作します。 最適化の違いはこちらのドキュメントを参照してください。
RuntimeがGraalVMではない場合、次のようなWARNログが出力されます。
[To redirect Truffle log output to a file use one of the following options:
* '--log.file=<path>' if the option is passed using a guest language launcher.
* '-Dpolyglot.log.file=<path>' if the option is passed using the host Java launcher.
* Configure logging using the polyglot embedding API.]
[engine] WARNING: The polyglot engine uses a fallback runtime that does not support runtime compilation to native code.
Execution without runtime compilation will negatively impact the guest application performance.
The following cause was found: JVMCI is not enabled for this JVM. Enable JVMCI using -XX:+EnableJVMCI.
For more information see: https://www.graalvm.org/latest/reference-manual/embed-languages/#runtime-optimization-support.
To disable this warning use the '--engine.WarnInterpreterOnly=false' option or the '-Dpolyglot.engine.WarnInterpreterOnly=false' system property.
次のJVMオプションを加えることでログを抑止できます。
MAVEN_OPTS="-XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -Dpolyglot.engine.WarnInterpreterOnly=false" mvn -q compile exec:java -Dexec.mainClass=org.example.Main
全ソースコードはこちらです。
Chicory、GraalWasm、wasmtime-javaでパフォーマンスの比較がしたいですね。