開発ツールに頼らず 様々な言語から WebAssembly（第１回）

WebAssembly は多くのプログラム言語からライブラリの様に呼び出す事が出来る。
WebAssembly のコードを書く方法は多くの記事で書かれているが、その使い方はフレームワーク等のツールに頼っている事が多い様だ。
本記事では、そのような便利ツールに出来るだけ頼らず JavaScript, Rust, Python, Ruby から WebAssembly を実行する方法を記載する。

WebAssembly は新しい技術である。
目先の最先端ツールに飛びつくのもよいが、その基礎を学んで長く使える知識を身に着けないか？

# シリーズ記事一覧

- 第１回（本記事）
- [第２回](https://qiita.com/wbcchsyn/items/925d11c6fd9111b29851)
- [第３回](https://qiita.com/wbcchsyn/items/47fa89c5b3c4bec24c15)
- [第４回](https://qiita.com/wbcchsyn/items/c5906430fa478345a5e9)
- [第５回](https://qiita.com/wbcchsyn/items/fde5ae4bc30c96381a0d)
- [第６回](https://qiita.com/wbcchsyn/items/e2e2d944034be6dc195f)
- [第７回](https://qiita.com/wbcchsyn/items/ca54eaaa76afcf33d1d7)
- [番外編第１回](https://qiita.com/wbcchsyn/items/8946fa50319be0806901)

シリーズ記事が追加された時はこの記事一覧を編集して通知を行うので、ご興味を持っていただけましたら本記事をストックしてください。

# WebAssembly を動かす為に必要な物

JavaScript には WebAssembly を動かすためのグローバルオブジェクト `WebAssembly` が既に言語仕様に組み込まれている。
そのため、フレームワークもライブラリも無しに WebAssembly のコードを実行する事が可能である。

WebAssembly 最初に「JavaScript で動かす」事から始まった。「WebAssembly の出来る事」とは本原稿執筆時（2023 年 6 月）では「JavaScript のグローバルオブジェクト `WebAssembly` で出来る事」とほぼ同義であると筆者は認識している。

残念な事に他の言語では JavaScript の様な例は少ない様だ。
例えば Rust では（コンパイラーが有れば）特別なツール無しに WebAssembly のコードを書く事は出来るのだが、書かれた WebAssembly のコードを動かすには別途ライブラリが必要になってしまう。

[wasmtime][link_wasmtime] は多くのプログラミング言語で使用可能な WebAssembly を動かす低レイヤーのライブラリだ。
多くの有名なフレームワークや開発ツールも、内部的に [wasmtime][link_wasmtime] を使用している事が多い。
使ってみると、JavaScript のグローバルオブジェクト `WebAssembly` を移植したような印象を受ける。

wasmtime の開発には WebAssembly や WebAssembly System Interface の仕様策定のコアなメンバーが関わっている。
近い将来「WebAssembly の出来る事」が「wasmtime で出来る事」と同義になるかもしれないと筆者は予想している。

蛇足だが「wasmtime は WebAssembly System Interface のランタイムではないか？」と疑問に思う人も居るかもしれない。
筆者も以前 [別の記事](https://qiita.com/wbcchsyn/items/153327b0946358694061) でそのように書いた。
上記はライブラリの wasmtime を用いて実装した、WebAssembly System Interface のランタイムの事だ。
混乱を避けるため、ランタイムの事を wasmtime-cli と呼ぶ事も有る。
（本記事には wasmtime-cli は登場しない。）

本記事では、下記の方法を紹介する。

- Vanilla JS （フレームワークやライブラリを使わない、そのままの JavaScript）から WebAssembly を実行する
- Rust, Python, Ruby からライブラリの [wasmtime][link_wasmtime] を使って WebAssembly を実行する

なお、説明の都合上 [Vanilla JS から実行](#vanilla-js-から実行) の章は JavaScript に興味が無くとも読んでほしい。
（そんなに難しい事はやっていないので JavaScript を知らなくとも本質的な部分は理解できるはずだ。）
それ以外の興味の無い言語の章については、読み飛ばして問題無い。

# 復習

本章は下記の記事の簡単なまとめです。
詳細は記事をご覧ください。

- [WEBASSEMBLY - What's the right thing to write?](https://qiita.com/wbcchsyn/items/7ba098a7c1551b7549de)
- [WebAssembly のメモリ構造][link_qiita_MemoryStructure]

## System Call と User Land

OS の上で動くアプリケーションの処理は大きく 2 種類に分かれる。

- OS へのリクエスト (System Call)
    - Input / Output
    - Memory 確保、解放
    - ...
- CPU と Memory を直接つかった計算 (User Land 上の処理)
    - 四則演算
    - 確保済みの Memory へのアクセス (Read / Write)
    - ...

## WebAssembly の方針

WebAssembly とは、多くのコンピューターで動作する事を目指した VM の仕様である。
しかし System Call を行うと、その処理は OS 依存となってしまいポータビリティーを下げる。

それを防ぐため、WebAssembly は User Land 上の処理しか出来ないように規格で定められている。
そして System Call が使えないという制限を補うために WebAssembly は他のプログラム言語から起動する事を前提としている。

WebAssembly の使い方としては、下記の 2 通りになる。

- WebAssembly では System Call を使わない部分のコードだけを記載、外部プログラムからライブラリの様に使用する
- WebAssembly では外部プログラムの関数を import し、WebAssembly からその関数をライブラリの様に使用する

## プログラマー目線の WebAssembly

WebAssembly のコードは「プログラム言語共通のクラス定義」の様な物だ。
外部プログラムから使用する際は、下記の様な特徴を持つ。

- instance 化してから使う
- 同じ WebAssembly のコードから複数の instance を作成する事が可能
- 各 instance の property に（アクセス権が有れば）アクセス（read/write）可能
- パブリックな関数（メソッド）を呼び出す事が可能

# WebAssembly コードの準備

最初に、各言語から使用する WebAssembly のコードを用意する。
今回は WebAssembly Text Format という低レイヤーの言語を用いる。

## wabt のインストール

[github](https://github.com/WebAssembly/wabt) の README.md を読んでコンパイルする。
C++ のコンパイル環境が必要なので注意。

**wat2wasm** というコマンドがコンパイルされるので、必要に応じて Path を通しておくと良いだろう。

## wasm ファイルの準備

wasm ファイルとは、WebAssembly の規格に沿ったバイナリファイルの事である。
最初に各種言語から動かして動作確認するための wasm ファイルを用意しよう。

テキストエディタで以下の様な内容のファイルを作成し、 **/tmp/addition.wat** という名前で保存する。

```wat
(module
  (func (export "addition") (param $a i64) (param $b i64) (result i64)
    local.get $a
    local.get $b
    i64.add))
```

上記は WebAssembly Text Format という wasm ファイルの低レイヤーのソースコードであり、`addition` という名前で関数を公開している。（public なメソッドを定義している。）
この関数 `addition` は引数として `i64` （符号付き 64 bit 整数）を 2 個とり、1 個の `i64` を返す。

この wat ファイルを以下の様に wat2wasm コマンドでコンパイルすると **/tmp/addition.wasm** というバイナリファイルが出来る。

```sh
$ wat2wasm -o /tmp/addition.wasm /tmp/addition.wat
$ ls /tmp/addition.wasm
/tmp/addition.wasm
```

# Vanilla JS から実行

説明の都合上、本章は JavaScript に興味の無い人でも斜めに読んで欲しい。

## Vanilla JS から実行する処理の概要

前述の様に WebAssembly は「プログラム言語共通のクラス定義」の様な物だ。
そのため（JavaScript に限らず多くの環境では）実際の使用は下記の様なフローになるだろう。
（ **太字リンク** は JavaScript のクラス名（コンストラクター名）である事を示す。リンク先は [MDN Web Docs](https://developer.mozilla.org/en-US/) 。）

1. addition.wasm から **[Module][link_mdn_Module]** を作成
1. **[Module][link_mdn_Module]** オブジェクトから **[Instance][link_mdn_Instance]** を作成
1. **[Instance][link_mdn_Instance]** オブジェクトで公開されている関数 `addition` を取得
1. 取得した関数 `addition` を実行

**[Module][link_mdn_Module]** とは「プログラム言語共通のクラス定義」である wasm ファイルを JavaScript で使用できる形にコンパイルした物だ。
（私たちは既に wat ファイルをコンパイルして wasm ファイルを作成した。ここでは、その wasm ファイルを再度コンパイルする事になる。）
つまり **[Module][link_mdn_Module]** の各オブジェクトは直感的には JavaScript のクラスの様な物だ。

**[Instance][link_mdn_Instance]** の各オブジェクトは、直感的には wasm ファイルで定義されたクラスで作成されたインスタンスの様な物だ。

## 筆者の JavaScript 環境

- nodejs v18.16.1

## Vanilla JS のコード

nodejs から WebAssembly を実行するコードは、例えば下記の様になる。

```javascript
// Build Module
const fs = require('fs');
const wasm = fs.readFileSync('/tmp/addition.wasm');
const mod = new WebAssembly.Module(wasm);

// Build Instance
const importObject = {};
const instance = new WebAssembly.Instance(mod, importObject);

// Call function addition
const addition = instance.exports.addition;
const answer = addition(BigInt(7), BigInt(4));
console.log(`7 + 4 = ${answer}`);
```

上記のファイルを `call_wasm.js` という名前で保存して実行すると、下記の様な結果を得る。

```sh
$ node --version
v18.16.1
$ node call_wasm.js
7 + 4 = 11
```

上記のコードを少しずつ紹介していく。
最初に以下の行に注目しよう。

```javascript
// Build Module
const fs = require('fs');
const wasm = fs.readFileSync('/tmp/addition.wasm');
const mod = new WebAssembly.Module(wasm);
```

上記は wasm ファイルを読み込み、**[Module][link_mdn_Module]** のオブジェクト `mod` を作成している。
（wasm ファイルを JavaScript 用にコンパイルしている。）

続いて、次の行を読んでみる。

```javascript
// Build Instance
const importObject = {};
const instance = new WebAssembly.Instance(mod, importObject);
```

`WebAssembly.Instance` は **[Instance][link_mdn_Instance]** のオブジェクト（直感的には wasm のインスタンス）を作成するビルダー関数だ。

前述の様に、WebAssembly は外部プログラム（今回は `call_wasm`）から関数等を import 可能だ。
`WebAssembly.Instance` は **[Module][link_mdn_Module]** と import する対象を引数にとる。

しかし私たちが書いた wat ファイルでは何も import していない。
なので importObject として `{}` を渡している。

個人的には `let instance = new mod(importObject)` の様に書ければ直感的で良いと思うのだが、残念な事にそこまでは出来ない様だ。

なお、ブラウザーの JavaScript で **[Module][link_mdn_Module]** や **[Instance][link_mdn_Instance]** を作成する際は [WebAssembly.instantiateStreaming][link_mdn_instantiateStreaming] を使った方が良いかもしれない。

最後に以下の行を読んでみる。

```javascript
// Call function addition
const addition = instance.exports.addition;
const answer = addition(BigInt(7), BigInt(4));
console.log(`7 + 4 = ${answer}`);
```

**[Instance][link_mdn_Instance]** が公開している物は、全て `exports` というプロパティーに入っている。
私たちの書いた wat ファイルでは `addition` という名前で `i64` （符号付き 64 bit 整数）を 2 個とり、 `i64` を 1 個返す関数を公開している。
筆者の nodejs 環境では exports を見ると、下記の様になっていた。
（`[Function: 0]` が気になる人は [前回の記事][link_qiita_MemoryStructure] をご参照ください。）

```
> instance.exports
[Object: null prototype] { addition: [Function: 0] }
```

この関数 `addition` の実行結果を `answer` という変数に保存する。
JavaScript から WebAssembly へ `i64` の受け渡しをする際は `BigInt` を用いる。
（BigInt の下位 64 bit のみが渡される。桁あふれ注意。）
`answer` の型も `BigInt` になる。

# wasmtime から実行

本章は wasmtime を使うにあたって Rust, Python, Ruby で共通の説明である。

wasmtime は JavaScript のグローバルオブジェクト **[WebAssembly][link_mdn_WebAssembly]** を拡張したような構造をしている。
wasmtime を使用する場合、どの言語でも大体下記の様なフローになるだろう。
（ **太字リンク** は wasmtime で定義されたクラス名である事を示し、「作成」とはそのクラスのインスタンス作成の事である。リンク先は便宜上 Rust 用の公式ドキュメントを指している。）

1. **[Engine][link_docs.rs_Engine]** を作成
1. addition.wasm から **[Module][link_docs.rs_Module]** を作成
1. **[Store][link_docs.rs_Store]** を作成
1. **[Instance][link_docs.rs_Instance]** を作成
1. **[Instance][link_docs.rs_Instance]** のインスタンスから公開されている関数 `addition` を取得
1. 取得した関数 `addition` を実行

**[Engine][link_docs.rs_Engine]** は wasm ファイルを該当言語で使用可能な状態にするコンパイラーの様な物だ。
**[Engine][link_docs.rs_Engine]** のインスタンスには「クラッシュ時の挙動」、「非同期機能をサポート有無」等の設定が出来る。
（JavaScript ではこのような設定は出来ないので、このようなクラスは存在しなかった。）

**[Module][link_docs.rs_Module]** は JavaScript の **[Module][link_mdn_Module]** とほぼ同じだ。
直感的には **[Module][link_docs.rs_Module]** の各インスタンスは wasm ファイルで定義されたクラスの様にふるまう。

説明の順番が前後するが、 **[Instance][link_docs.rs_Instance]** は JavaScript の **[Instance][link_mdn_Instance]** とほぼ同じだ。
直感的には **[Instance][link_docs.rs_Instance]** の各インスタンスは wasm ファイルで定義されたクラスのインスタンスの様にふるまう。

最後に **[Store][link_docs.rs_Store]** だが、これに相当する物は JavaScript には存在しない。
**[Store][link_docs.rs_Store]** の存在理由は、例えば下記であると筆者は考えている。

- wasmtime のコア部分を実装している Rust では、JavaScript と違って Garbage Collection が存在しない。複数の **[Instance][link_docs.rs_Instance]** インスタンスに関わるメタプログラミングの様な事をする可能性を考えると、適切にメモリ管理をするためには **[Instance][link_docs.rs_Instance]** の各インスタンスが使用するデータのコンテナクラスが有った方が良い。
- WebAssembly コード実行時の hook 設定等、WebAssembly のコードを制御する外部プログラムのコードを書く余地を残しておくべき。（今後の拡張にも有用である。）

難しければ、とりあえず「wasmtime を使うには **[Store][link_docs.rs_Store]** という『おまじない』が必要」と覚えておけばよい。

なお、「 **[Store][link_docs.rs_Store]** インスタンス」と「 **[Instance][link_docs.rs_Instance]** インスタンス」の関係は 1 対 多 である。
メモリ効率を無視すれば、プログラム全体で 1 個の **[Store][link_docs.rs_Store]** をグローバル変数として使用する事が可能だ。

以降の章では wasmtime を使って [Rust から実行](#rust-から実行), [Python から実行](#python-から実行), [Ruby から実行](#ruby-から実行) 方法について、それぞれ説明している。
不要な章は読み飛ばしても大丈夫だ。

## Rust から実行

### 筆者の Rust 環境

- cargo 1.70.0
- rustup 1.26.0
- rustc 1.70.0 stable-x86_64-unknown-linux-gnu

### Rust のコード

下記の様に call_addition というプロジェクトを作成する。

```sh
$ cargo new call_addition
$ cd call_addition
```

Cargo.toml の `[dependencies]` セクションに wasmtime をの設定を加える。
筆者の環境では Cargo.toml は下記の様になった。

```toml
[package]
name = "call_addition"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
wasmtime = "10.0.1"
```

Rust から WebAssembly を実行するコードは、例えば下記の様になる。

```rust
use std::fs;
use wasmtime::*;

fn main() -> wasmtime::Result<()> {
    // Build `Engine`.
    let engine = Engine::default();

    // Build `Module`.
    let wasm = fs::read("/tmp/addition.wasm").unwrap();
    let module = Module::new(&engine, wasm)?;

    // Build `Store`.
    let mut store = Store::new(&engine, ());

    // Build `Instance`
    let instance = Instance::new(&mut store, &module, &[])?;

    // Acquire function exported as `addition`
    let addition = instance.get_typed_func::<(i64, i64), i64>(&mut store, "addition")?;

    // Call addition
    let answer = addition.call(&mut store, (7, 4))?;
    println!("7 + 4 = {}", &answer);

    Ok(())
}
```

上記の内容で `src/main.rs` を上書きして実行すると、実行結果は以下の様になる

```sh
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/call_addition`
7 + 4 = 11
```

上記の Rust コードを少しずつ解説していく。
まずはコードの全体像を把握しよう。

```rust
use std::fs;
use wasmtime::*;

fn main() -> wasmtime::Result<()> {
...
}
```

見ての通り、本コードは main 関数が定義してあるだけである。
以下、main 関数の中身を上から少しずつ読んでみる。

```rust
    // Build `Engine`.
    let engine = Engine::default();
```

最初に **[Engine][link_docs.rs_Engine]** のインスタンスを作成している。
そんなに難しい事をするわけでは無いので、今回はデフォルトで作成する。

次に以下の行を読んでみる。

```rust
    // Build `Module`.
    let wasm = fs::read("/tmp/addition.wasm").unwrap();
    let module = Module::new(&engine, wasm)?;
```

ここでは **[Module][link_docs.rs_Module]** を作成している。
やっている事は wasm ファイルを Rust 用にコンパイルしているのだが、そのコンパイラーとして先ほど作成した **[Engine][link_docs.rs_Engine]** インスタンスを使用している。

続いて以下の行を読んでみる。

```rust
    // Build `Store`.
    let mut store = Store::new(&engine, ());
```

ここでは **[Store][link_docs.rs_Store]** を作成している。
2 個目の引数は、この **[Store][link_docs.rs_Store]** に持たせるデータだ。
特殊な事をする時に使用する事も出来るのだが、今回の様に単純に WebAssembly を実行するだけならば使わない。
なので Rust で「空のデータ」を意味する `()` を渡した。

続けて下記の行を読んでみる。

```rust
    // Build `Instance`
    let instance = Instance::new(&mut store, &module, &[])?;
```
ここでは **[Instance][link_docs.rs_Instance]** のインスタンスを作成している。
前述の様に、WebAssembly は外部プログラム（今回は Rust）から関数等を import 可能だ。
関数 `Instance::new` の 3 個目の引数は、その import する対象への参照一覧だ。

しかし私たちが書いた wat ファイルでは何も import していない。
なので `&[]` を渡している。

次に以下の行を読んでみる。

```rust
    // Acquire function exported as `addition`
    let addition = instance.get_typed_func::<(i64, i64), i64>(&mut store, "addition")?;
```

**[Instance][link_docs.rs_Instance]** のインスタンスが出来たので、ここでは関数 `addition` を取得している。
WebAssembly としては名前さえ指定すれば exports している物は取得できるようになっているのだが、Rust は静的型付けの言語だ。
プログラマーは、今回取得しようとするものが関数である事、その引数が `i64` 型 2 個である事、戻り値が `i64` 1 個である事を（外部プログラムの） Rust コードに教える必要が有る。
そのために `get_typed_func` というメソッドを使用し、その引数と戻り値の型を `<(i64, i64), i64>` で指定している。

蛇足だが WebAssembly はが公開出来るのは関数、抽象ポインターテーブル、線形メモリ、グローバル変数のいずれかだ。
`addition` という名前で公開されている物を取得するには型情報を知る必要は無い。
しかし取得した後で `addition` が関数である事や、その引数や戻り値の型情報を得る事が出来る。
詳細は [前回の記事][link_qiita_MemoryStructure] を参照して欲しい。

最後に以下の行を読んでみる。

```rust
    // Call addition
    let answer = addition.call(&mut store, (7, 4))?;
    println!("7 + 4 = {}", &answer);
```

関数 `addition` が取得出来たら後は実行するだけだ。
注意点としてはメソッド `addition.call` の引数の取り方くらいだと思う。

引数の 1 個目は **[Store][link_docs.rs_Store]** への参照であり、『おまじない』である。
2 個目の引数に、wasm ファイルの `addition` の取る引数をまとめて渡している。

## Python から実行

### 筆者の Python 環境

- Python 3.11.2
- pip 23.0.1

### Python のコード

最初に Python の version と環境に応じた方法で wasmtime をインストールする。

```sh
$ pip install wasmtime
Collecting wasmtime
  Downloading wasmtime-9.0.0-py3-none-manylinux1_x86_64.whl (6.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.6/6.6 MB 2.1 MB/s eta 0:00:00
Installing collected packages: wasmtime
Successfully installed wasmtime-9.0.0
```

Python から WebAssembly を実行するコードは、例えば下記の様になる。

```python
from wasmtime import Engine, Module, Store, Instance

# Build Engine
engine = Engine()

# Build Module
wasm = open('/tmp/addition.wasm', 'rb').read()
module = Module(engine, wasm)

# Build Store
store = Store(engine)

# Build Instance
instance = Instance(store, module, ())

# Acquire function exported as addition
addition = instance.exports(store)['addition']

# Call addition
answer = addition(store, 7, 4)
print("7 + 4 = %d" % answer)
```

ほとんど Rust のコードと同じであり説明の必要も無いかもしれないが、一応上から説明していく。
以下では **太字のリンク** は wasmtime で定義されたクラスである事を示す。リンク先は [Python 版 wasmtime の公式ドキュメント](https://bytecodealliance.github.io/wasmtime-py/) である。

最初に以下の行を読んでみる。

```python
# Build Engine
engine = Engine()
```

ここでは **[Engine][link_wasmtimepy_Engine]** のインスタンスを作成している。
今回はそんなに難しい事をするわけでは無いのでデフォルト引数で作成する。

次に以下の行を読んでみる。

```python
# Build Module
wasm = open('/tmp/addition.wasm', 'rb').read()
module = Module(engine, wasm)
```

ここでは **[Module][link_wasmtimepy_Module]** を作成している。
やっている事は wasm ファイルを Python 用にコンパイルしているのだが、そのコンパイラーとして先ほど作成した Engine インスタンスを使用している。

続いて以下の行を読んでみる。

```python
# Build Store
store = Store(engine)
```

ここでは **[Store][link_wasmtimepy_Store]** のインスタンスを作成している。

Rust の説明でも記載したが、 `Store()` の引数 `data` を使う事で **[Store][link_wasmtimepy_Store]** のインスタンスには任意のデータを持たせる事が出来る。
今回の様に特殊な事はせず wasm ファイルを使うだけであれば、このデータは必要ない。
引数を省略する事でデフォルトの `None` を渡している。

ところで [公式ドキュメント][link_wasmtimepy_Store] を読めば分かるが、デフォルトの **[Engine][link_wasmtimepy_Engine]** を使用する場合は引数の `engine` を省略できる。
しかし、**[Store][link_wasmtimepy_Store]** のプロパティーの `engine` と、対応する `Module()` の引数に渡す `engine` はアドレスが一致している必要が有るので注意して欲しい。

つまり **[Module][link_wasmtimepy_Module]** と **[Store][link_wasmtimepy_Store]** のインスタンス作成は下記方法でも行う事が可能だ。
（ **[Engine][link_wasmtimepy_Engine]** を明示的に作成する必要が無いので、コードが 1 ステップ減る。）

```python
# Build Store
store = Store()

# Build Module
wasm = open('/tmp/addition.wasm', 'rb').read()
module = Module(store.engine, wasm)
```

しかし以下の方法で行うと `Store()` と `Module()` がそれぞれ別の **[Engine][link_wasmtimepy_Engine]** を作成するのでアドレスが異なってしまう。
後で **[Instance][link_wasmtimepy_Instance]** 作成時にエラーになってしまう。

```python
# Build Store
store = Store()

# Build Module
wasm = open('/tmp/addition.wasm', 'rb').read()
module = Module(Engine(), wasm)
```

Python の柔軟であるが故に発生しやすいバグだと思う。

次に以下の行を読んでみる。

```python
# Build Instance
instance = Instance(store, module, ())
```

ここでは **[Instance][link_wasmtimepy_Instance]** を作成している。

前述の様に、WebAssembly は外部プログラム（今回は Python）から関数等を import 可能だ。
関数 `Instance()` の 3 個目の引数は、その import する対象への参照だ。

しかし私たちが書いた wat ファイルでは何も import していない。
なので `()` を渡している。

続いて以下の行を読んでみる。

```python
# Acquire function exported as addition
addition = instance.exports(store)['addition']
```

ここでは、関数 `addition` を取得している。
Python は JavaScript の様に動的型付け言語なので、名前を指定するだけで取得可能だ。
（Rust と異なり、コードに型情報を教える必要は無い。）

最後に以下の行を読んでみる。

```python
# Call addition
answer = addition(store, 7, 4)
print("7 + 4 = %d" % answer)
```

ここでは関数 `addition` を実行している。
`addition()` には最初の引数に『おまじない』として `store` を渡しているが、それ以降は wasm の `addition` に渡す引数である。

なお Python は動的型付け言語だが WebAssembly は静的型付けを行う。
Python の `addition()` 経由で渡す引数の数や型情報が異なると、ちゃんと例外を投げてくれる。

## Ruby から実行

### 筆者の Ruby 環境

- ruby 3.1.2p20

### Ruby のコード

最初に gem で wasmtime をインストールする。
（必要に応じて bundler 等を使うと良いだろう。）

```sh
gem install wasmtime
Fetching wasmtime-9.0.1-x86_64-linux.gem
Successfully installed wasmtime-9.0.1-x86_64-linux
Parsing documentation for wasmtime-9.0.1-x86_64-linux
Installing ri documentation for wasmtime-9.0.1-x86_64-linux
Done installing documentation for wasmtime after 0 seconds
1 gem installed
```

Ruby から WebAssembly を実行するコードは、例えば下記の様になる。

```ruby
require 'wasmtime'

# Build Engine
engine = Wasmtime::Engine.new

# Build Module
wasm = open('/tmp/addition.wasm', 'rb').read
mod = Wasmtime::Module.new(engine, wasm)

# Build Store
store = Wasmtime::Store.new(engine)

# Build instance
instance = Wasmtime::Instance.new(store, mod)

# Acquire function exported as 'addition'
addition = instance.export('addition').to_func

# Call function addition
answer = addition.call(7, 4)
puts("7 + 4 = %d" % answer)
```

Python コードのコピペと見間違える様なコードだが、一応説明していく。
以下では **太字のリンク** は wasmtime で定義されたクラスである事を示す。リンク先は [Ruby 版 wasmtime の公式ドキュメント](https://bytecodealliance.github.io/wasmtime-rb/latest/top-level-namespace.html) である。

最初に以下の行を読んでみる。

```ruby
require 'wasmtime'

# Build Engine
engine = Wasmtime::Engine.new
```

ここでは **[Engine][link_wasmtimerb_Engine]** のインスタンスを作成している。
今回はそんなに難しい事をするわけでは無いのでデフォルト引数で作成する。

続いて以下の行を読んでみる。

```ruby
# Build Module
wasm = open('/tmp/addition.wasm', 'rb').read
mod = Wasmtime::Module.new(engine, wasm)
```

ここでは **[Module][link_wasmtimerb_Module]** を作成している。
やっている事は wasm ファイルを Ruby 用にコンパイルしているのだが、そのコンパイラーとして先ほど作成した Engine インスタンスを使用している。

続いて以下の行を読んでみる。

```ruby
# Build Store
store = Wasmtime::Store.new(engine)
```

ここでは **[Store][link_wasmtimerb_Store]** のインスタンスを作成している。

Rust の説明でも記載したが、 `Store.new` の引数 `data` を使う事で `Store` のインスタンスには任意のデータを持たせる事が出来る。
今回の様に特殊な事はせず wasm ファイルを使うだけであれば、このデータは必要ない。
引数を省略する事でデフォルトの `nil` を渡している。

ところで、 **[Store][link_wasmtimerb_Store]** のドキュメントを読むと Ruby には **[WasiCtxBuilder][link_wasmtimerb_WasiCtxBuilder]** というクラスが有る事に気が付く。
（執筆時点では wasmtime の Rust や Python 版のドキュメントに、このようなクラスは見つからなかった。）
これが何なのか筆者も良く分からないが、今後 wasmtime が拡張する予定なのかもしれない。
現段階では省略する事でデフォルトの `nil` を渡している。

続いて以下の行を読んでみる。

```ruby
# Build instance
instance = Wasmtime::Instance.new(store, mod)
```

ここでは **[Instance][link_wasmtimerb_Instance]** を作成している。

前述の様に、WebAssembly は外部プログラム（今回は Ruby）から関数等を import 可能だ。
関数 `Instance.new` は 3 個目の引数で、その import する対象への参照を受け取る事が出来る。

しかし私たちが書いた wat ファイルでは何も import していない。
なので省略してデフォルト引数の `[]` を渡している。

続いて以下の行を読んでみる。

```ruby
# Acquire function exported as 'addition'
addition = instance.export('addition').to_func
```

ここでは関数 `addition` を取得している。
Ruby の場合は `.to_func` で **[Func][link_wasmtimerb_Func]** に明示的に型変換を行う必要がある。
WebAssembly が export する可能性が有るのは関数だけでは無いからだ。
（Python や JavaScript では、この様な型変換は必要ない。）

Ruby は動的型付け言語だが、型にはうるさい。
Ruby の文化を良く反映したコードだと思う。

最後に以下の行を読んでみる。

```ruby
# Call function addition
answer = addition.call(7, 4)
puts("7 + 4 = %d" % answer)
```

ここでは取得した関数 `addition` を実行している。
他の言語とは異なり、 `addition.call` には『おまじない』の store を渡していない。

なお Ruby は動的型付け言語だが WebAssembly は静的型付けを行う。
Ruby の `addition.call` 経由で渡す引数の数や型情報が異なると、ちゃんと例外を投げてくれる。

# まとめ

筆者は開発ツール等を使って手を抜く事は好きなのだが、ツールに「自分の理解できない何か」を勝手にやられる事が好きではない。（この考えに共感してくれるプログラマーは少なくないと思う。）
なので、「開発ツールが何をやっているか」を知るために少し低レイヤーの事を調べてみた。

以前書いた [WebAssembly のメモリ構造][link_qiita_MemoryStructure] という記事を合わせて読むと本記事の理解も深まると思う。
興味のある人は、そちらも是非読んで欲しい。

[link_qiita_MemoryStructure]: https://qiita.com/wbcchsyn/items/3c9f331cefbd139a239e
[link_wasmtime]: https://github.com/bytecodealliance/wasmtime
[link_mdn_WebAssembly]: https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface
[link_mdn_Module]: https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Module
[link_mdn_Instance]: https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Instance
[link_mdn_instantiateStreaming]: https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiateStreaming
[link_docs.rs_Engine]: https://docs.rs/wasmtime/10.0.1/wasmtime/struct.Engine.html
[link_docs.rs_Module]: https://docs.rs/wasmtime/10.0.1/wasmtime/struct.Module.html
[link_docs.rs_Store]: https://docs.rs/wasmtime/10.0.1/wasmtime/struct.Store.html
[link_docs.rs_Instance]: https://docs.rs/wasmtime/10.0.1/wasmtime/struct.Instance.html
[link_wasmtimepy_Engine]: https://bytecodealliance.github.io/wasmtime-py/#wasmtime.Engine
[link_wasmtimepy_Module]: https://bytecodealliance.github.io/wasmtime-py/#wasmtime.Module
[link_wasmtimepy_Store]: https://bytecodealliance.github.io/wasmtime-py/#wasmtime.Store
[link_wasmtimepy_Instance]: https://bytecodealliance.github.io/wasmtime-py/#wasmtime.Instance
[link_wasmtimerb_Engine]: https://bytecodealliance.github.io/wasmtime-rb/latest/Wasmtime/Engine.html
[link_wasmtimerb_Module]: https://bytecodealliance.github.io/wasmtime-rb/latest/Wasmtime/Module.html
[link_wasmtimerb_Store]: https://bytecodealliance.github.io/wasmtime-rb/latest/Wasmtime/Store.html
[link_wasmtimerb_WasiCtxBuilder]: https://bytecodealliance.github.io/wasmtime-rb/latest/Wasmtime/WasiCtxBuilder.html
[link_wasmtimerb_Instance]: https://bytecodealliance.github.io/wasmtime-rb/latest/Wasmtime/Instance.html
[link_wasmtimerb_Func]: https://bytecodealliance.github.io/wasmtime-rb/latest/Wasmtime/Func.html