---
title: GraalWasmでJavaからWebAssemblyを呼び出すメモ
tags: ["Java", "WebAssembly", "GraalWasm"]
categories: ["Programming", "WebAssembly", "Java", "GraalWasm", "GraalVM"]
date: 2024-07-01T15:08:11Z
updated: 2024-07-01T15:09:10Z
---
[前記事](/entries/806)では[Chicory](https://github.com/dylibso/chicory)を使ってwasmをJava上で実行しましたが、
同じことがGraalVM ([GraalWasm](https://www.graalvm.org/latest/reference-manual/wasm/))でもできました。
前記事の内容をGraalWasmでやり直します。
以下の依存ライブラリを追加することでJavaアプリ上でwasmの読み込み・実行ができるようになります。
```xml
org.graalvm.polyglot
polyglot
24.0.1
org.graalvm.polyglot
wasm-community
24.0.1
pom
```
サンプルのwasmファイルをWATファイルから作ります。次のファイル`SumSquared.wat`を作ります。
二つのi32のパラメータを加算して二乗した値を返します。
```lisp
(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))
)
)
```
> [!TIP]
> [入門WebAssembly](https://www.amazon.co.jp/%E5%85%A5%E9%96%80WebAssembly-Rick-Battagline-ebook/dp/B09MQ6CSBG?crid=2F88E3ZRLB9ML&keywords=webassembly&qid=1688271177&sprefix=WebAssembly%2Caps%2C260&sr=8-6&linkCode=li2&tag=ikam-22&linkId=9a9576034b15b62f172d59f69c3f1784&language=ja_JP&ref_=as_li_ss_il)に掲載されているサンプルコードを使いました。
>
> [](https://www.amazon.co.jp/%E5%85%A5%E9%96%80WebAssembly-Rick-Battagline-ebook/dp/B09MQ6CSBG?crid=2F88E3ZRLB9ML&keywords=webassembly&qid=1688271177&sprefix=WebAssembly%2Caps%2C260&sr=8-6&linkCode=li2&tag=ikam-22&linkId=9a9576034b15b62f172d59f69c3f1784&language=ja_JP&ref_=as_li_ss_il)
`wat2wasm`でwasmに変換します。
```
wat2wasm SumSquared.wat
```
`SumSquared.wasm`が生成されます。このwasmをJavaで読み込んで実行します。
```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でなくとも動作します。 最適化の違いは[こちらのドキュメント](https://www.graalvm.org/latest/reference-manual/embed-languages/#runtime-optimization-support)を参照してください。
RuntimeがGraalVMではない場合、次のようなWARNログが出力されます。
```
[To redirect Truffle log output to a file use one of the following options:
* '--log.file=' if the option is passed using a guest language launcher.
* '-Dpolyglot.log.file=' 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
```
全ソースコードは[こちら](https://github.com/making/hello-graalwasm)です。
Chicory、GraalWasm、wasmtime-javaでパフォーマンスの比較がしたいですね。