Chicoryを使うとJVM上でWebAssemblyを動かせるということで、RustからWebAssemblyにコンパイルしたコードを動かしてみます。
このときはRustをLLVMビットコードにしてGraalVMで動かしていましたね。
GraalVMでRust動かしたりレイトレをネイティブコンパイルしたり - きしだのHatena
Rustからwasmを作成
まずはRustのプロジェクトを作成。
>cargo new --lib hello-wasm Creating library `hello-wasm` package
lib.rs
というファイルが作成されてadd
関数が定義されているので、no_mangleをつけてu64をi32にします。
#[no_mangle] pub fn add(left: i32, right: i32) -> i32 { left + right }
そしたらビルド
hello-wasm>cargo build --target=wasm32-unknown-unknown --release Compiling hello-wasm v0.1.0 (C:\Users\naoki\Desktop\hello-wasm) Finished `release` profile [optimized] target(s) in 0.44s
ブラウザで試す
とりあえずブラウザで動かしてみます。こんなJS入りHTMLを書く。
<html> <head> <title>Hello wasm</title> <script> const wasm = "./target/wasm32-unknown-unknown/release/hello_wasm.wasm" fetch(wasm) .then(res => res.arrayBuffer()) .then(b => WebAssembly.instantiate(b, {})) .then(res => { alert(res.instance.exports.add(2, 3)) }) </script> </head> </html>
さて、fetchでwasmを読み込んでいるけど、これはファイルシステム経由での読み込みができないので、Webサーバーが必要です。
ここでJava 18で導入されたjwebserver。 https://openjdk.org/jeps/408
ただ、Windowsで起動すると文字化けるです。
hello-wasm>jwebserver 繝・ヵ繧ゥ繝ォ繝医〒繝ォ繝シ繝励ヰ繝・け縺ォ繝舌う繝ウ繝峨@縺セ縺吶ゅ☆縺ケ縺ヲ縺ョ繧、繝ウ繧ソ繝輔ぉ繝シ繧ケ縺ァ"-b 0.0.0.0"縺セ縺溘・"-b ::"繧剃スソ逕ィ縺励∪縺吶・ C:\Users\naoki\Desktop\hello-wasm縺翫h縺ウ繧オ繝悶ョ繧」繝ャ繧ッ繝医Μ繧・27.0.0.1繝昴・繝・000縺ァ菴ソ逕ィ縺励∪縺・URL http://127.0.0.1:8000/
別にコンソールなので文字化けさせておけばいいのだけど、気になるのでchcpコマンドでUTF-8にしておきましょう。
hello-wasm>chcp 65001
気を取り直してjwebserverの起動。
hello-wasm>jwebserver デフォルトでループバックにバインドします。すべてのインタフェースで"-b 0.0.0.0"または"-b ::"を使用します。 C:\Users\naoki\Desktop\hello-wasmおよびサブディレクトリを127.0.0.1ポート8000で使用します URL http://127.0.0.1:8000/
http://localhost:8000/hello.html
にアクセスすると、なんかWebAssemblyが動いてるっぽい。
Chicoryの導入
では、JVMでWebAssemblyを動かすChicoryを導入します。
https://github.com/dylibso/chicory
readmeに従ってdependencyを追加します。
<dependency> <groupId>com.dylibso.chicory</groupId> <artifactId>runtime</artifactId> <version>0.0.12</version> </dependency>
Javaコードで動かす
では、試しに動かしてみましょう。targetの下の方にhello_wasm.wasmができているので、src/main/resourcesにコピーしておきます。
そして次のコードを。ちなみに、現状のChicoryのreadmeに書いてあるParser.parse
を使ったサンプルは、まだ配布バイナリに反映されていません。古い書き方で書く必要があります。
import com.dylibso.chicory.wasm.types.Value; import com.dylibso.chicory.runtime.Module; import java.io.IOException; public class CallWasm { public static void main(String[] args) throws IOException { var wasm = CallWasm.class.getClassLoader().getResourceAsStream("hello_wasm.wasm"); var module = Module.builder(wasm).build(); var instance = module.instantiate(); var add = instance.export("add"); var result = add.apply(Value.i32(3), Value.i32(2)); System.out.println(result[0].asInt()); } }
実行すると5
が表示されて、なにか動いてそう。
まとめ
この記事ではSQLiteをwasmにコンパイルして動かすということもやってます。Cで書かれたコードをJavaで動かしやすくなりそうで、なかなかよさそうですね。
https://www.infoq.com/articles/sqlite-java-integration-webassembly/
ただ、パフォーマンスが必要ならおとなしくネイティブバイナリ使いましょうということになると思うので、テスト用とかですかね。