--- 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)に掲載されているサンプルコードを使いました。 > > [![入門WebAssembly](https://github.com/making/blog.ik.am/assets/106908/0825cd6a-05f9-4d3a-9e7e-8c3be783709c)](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でパフォーマンスの比較がしたいですね。