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

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

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

本記事はシリーズの第３回である。シリーズ記事の一覧は [第１回] の  **#シリーズ記事一覧** に載せている。シリーズの記事を追加する時は [第１回] の一覧を更新して通知を行うので興味の有る人は [第１回] をストックして欲しい。

# 本記事の概要と過去記事の復習

[第３回] と [第４回] は WebAssembly のコードに状態を持たせる方法について記載した。
今回は WebAssembly に「クラス変数」の様な物を追加するコードを紹介する。

（ [第４回] の最後に「文字列を保持する可変長配列」について予告の様な事をしましたが、その記事は説明の都合上後回しにします。）

「クラス変数」とは「そのクラスの名前空間に保存された変数」の様な物だ。
多くの言語で「そのクラスのインスタンス間で共有する変数」の様な扱いが出来る。

筆者の知る限り、JavaScript にはクラス変数に相当する物は無い。
しかしモジュールの中で定義されたグローバル変数はクラス変数と少し似ているかもしれない。

例えば、以下の様な JavaScript のモジュールを考えてみる。

```javascript
let next_id = 0;
const FIRST_ID = 0;

class Counter {
    constructor() {
        this.__id = next_id;
        next_id += 1;
    }

    get_id() {
        return this.__id;
    }

    is_first() {
        return this.__id === FIRST_ID;
    }
}
```

`Counter` というクラスの全インスタンスは `next_id`, `FIRST_ID` という 2 個の変数を共有している。

WebAssembly も JavaScript と同様にクラス変数に相当する物は存在しない。
しかし、工夫次第で「クラス変数の様な物」を作る事は可能である。

本記事では上記の様な WebAssembly のコードを実行する下記の外部プログラムを作成する。

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

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

# WebAssembly コードの準備

過去記事同様、WebAssembly Text Format で動作確認をする WebAssembly のコードを作成し、wat2wasm でコンパイルする。

## wabt のインストール

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

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

## wasm ファイルの準備

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

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

```wat
(module
    (import "host" "next_id" (global $next_id (mut i64)))
    (import "host" "FIRST_ID" (global $FIRST_ID i64))

    (global $id (mut i64) (i64.const -1))

    (func $init 
        ;; Initialize the 
        global.get $next_id
        global.set $id

        ;; Increment $next_id
        global.get $next_id
        i64.const 1
        i64.add
        global.set $next_id)

    (func (export "get_id") (result i64)
        global.get $id)

    (func (export "is_first") (result i32)
        global.get $FIRST_ID
        global.get $id
        i64.eq)

    (start $init))
```

上記は WebAssembly Text Format という wasm ファイルのソースコードだ。
多くの読者に内容を何となく理解してもらうには、これが良いと思って選択した。

上記コードは大まかに以下の事を行っている。
（以下で `i64` とは「符号付 64 bit 整数」、 `i32` とは「符号付 32 bit 整数」の事である。）

- 外部プログラムから "host.next_id" というグローバル変数を import。このグローバル変数は可変の `i64` 型である。この WebAssembly 内部からは `$next_id` という名前でアクセス可能にしている。
- 外部プログラムから "host.FIRST_ID" というグローバル変数を import。このグローバル変数は不変の `i64` 型である。この WebAssembly 内部からは `$FIRST_ID` という名前でアクセス可能にしている。
- グローバル変数を宣言。このグローバル変数は可変の `i64` 型であり、 `-1` で初期化される。この WebAssembly 内部からは `$id` という名前でアクセス可能にしている。
- 関数を定義。この関数は引数をとらず、戻り値も無い。この WebAssembly 内部からは `$init` という名前でアクセス可能にしている。
- 関数を定義。この関数は引数を取らず、 `i64` 型を 1 個返す。外部プログラムから `get_id` という名前でアクセス可能にしている。
- 関数を定義。この関数は引数をとらず、 `i32` 型を 1 個返す。外部プログラムから `is_first` という名前でアクセス可能にしている。
- インスタンス作成時に関数 `$init` を実行する。

補足すると、WebAssembly には「Boolean 型」と言われる型は存在しない。 `i32` 型の `0` を `False` の様に、 `1` を `True` の様に使用する。

関数 `$init` は `$id` に `$next_id` の値を代入し、その後 `$next_id` の値を `1` 増加させる。 関数 `get_id` は変数 `$id` の値を返す。関数 `is_first` は、 `$id` が `$FIRST_ID` と等しければ `1` を、異なれば `0` を返す。

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

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

# Vanilla JS から実行

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

## 筆者の JavaScript 環境

- nodejs v18.16.1

## Vanilla JS のコード

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

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

// Build Instance
const importObject = {
    host: {
        next_id: new WebAssembly.Global({value: "i64", mutable: true}, BigInt(0)),
        FIRST_ID: new WebAssembly.Global({value: "i64", mutable: false}, BigInt(0)),
    }
};

const counter0 = new WebAssembly.Instance(mod, importObject);
const counter1 = new WebAssembly.Instance(mod, importObject);

// Show the id of counter0 and counter1.
console.log(`The id of counter0 is ${counter0.exports.get_id()}`);
console.log(`The id of counter1 is ${counter1.exports.get_id()}`);

// Show the first instance
if (counter0.exports.is_first()) {
    console.log("counter0 is the first instance.");
}
if (counter1.exports.is_first()) {
    console.log("counter1 is the first instance.");
}
```

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

```sh
$ node call_wasm.js
The id of counter0 is 0
The id of counter1 is 1
counter0 is the first instance.
```

JavaScript のコードを少しずつ読んでみる。
（以下の **太字リンク** は JavaScript のクラス名（コンストラクター名）である事を示す。リンク先は [MDN Web Docs](https://developer.mozilla.org/en-US/) 。）

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

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

ここまでは [第１回] と wasm ファイルのパス以外同じだ。

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

```javascript
// Build Instance
const importObject = {
    host: {
        next_id: new WebAssembly.Global({value: "i64", mutable: true}, BigInt(0)),
        FIRST_ID: new WebAssembly.Global({value: "i64", mutable: false}, BigInt(0)),
    }
};

const counter0 = new WebAssembly.Instance(mod, importObject);
const counter1 = new WebAssembly.Instance(mod, importObject);
```

ここも `importObject` に **[Global][Global_js]** を持たせている事以外は [第２回] と同じだ。

私達の作成した wasm ファイルは `next_id`, `FIRST_ID`, `id` という 3 個のグローバル変数を持っている。
ここでは `counter0` と `counter1` の 2 個のインスタンスを作成しているが、どちらも同じ `importObject` を使用しているので、 `next_id` と `FIRST_ID` は共通の物を参照する。（ `id` は、それぞれ別の変数となる。）
そのため `counter0` の初期化時に `next_id` を更新するが、その更新は `counter1` にも反映される。

例えばこの部分を下記の様なコードにすると、 `counter0` による `next_id` の更新が `counter1` に反映されず、結果として両者の `id` は `0` となるだろう。

```javascript
// Build Instance
const importObject = {
    host: {
        next_id: new WebAssembly.Global({value: "i64", mutable: true}, BigInt(0)),
        FIRST_ID: new WebAssembly.Global({value: "i64", mutable: false}, BigInt(0)),
    }
};
const counter0 = new WebAssembly.Instance(mod, importObject);

importObject.host.next_id = new WebAssembly.Global({value: "i64", mutable: true}, BigInt(0));
const counter1 = new WebAssembly.Instance(mod, importObject1);
```

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

```javascript
// Show the id of counter0 and counter1.
console.log(`The id of counter0 is ${counter0.exports.get_id()}`);
console.log(`The id of counter1 is ${counter1.exports.get_id()}`);

// Show the first instance
if (counter0.exports.is_first()) {
    console.log("counter0 is the first instance.");
}
if (counter1.exports.is_first()) {
    console.log("counter1 is the first instance.");
}
```

ここは [第１回] と同様の方法で関数 `get_id` と `is_first` を実行している。

# wasmtime から実行

以降の章では 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_person というプロジェクトを作成する。

```sh
$ cargo new call_counter
$ cd call_counter
```

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

```toml
[package]
name = "call_person"
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/counter.wasm").unwrap();
    let module = Module::new(&engine, wasm)?;

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

    // Create Global `next_id` and `first_id`
    let next_id_ty = GlobalType::new(ValType::I64, Mutability::Var);
    let next_id = Global::new(&mut store, next_id_ty, Val::I64(0))?;
    let first_id_ty = GlobalType::new(ValType::I64, Mutability::Const);
    let first_id = Global::new(&mut store, first_id_ty, Val::I64(0))?;

    // Build `Instance`. (`Linker` is builder class.)
    let mut linker = Linker::new(&engine);
    linker.define(&store, "host", "next_id", next_id)?;
    linker.define(&store, "host", "FIRST_ID", first_id)?;
    let counter0 = linker.instantiate(&mut store, &module)?;
    let counter1 = linker.instantiate(&mut store, &module)?;

    // Show the `id` of `counter0` and `counter1`.
    let get_id = counter0.get_typed_func::<(), i64>(&mut store, "get_id")?;
    println!("The id of counter0 is {}", &get_id.call(&mut store, ())?);
    let get_id = counter1.get_typed_func::<(), i64>(&mut store, "get_id")?;
    println!("The id of counter1 is {}", &get_id.call(&mut store, ())?);

    // Show the first instance.
    let is_first = counter0.get_typed_func::<(), i32>(&mut store, "is_first")?;
    if is_first.call(&mut store, ())? == 1 {
        println!("counter0 is the first instance.");
    }
    let is_first = counter1.get_typed_func::<(), i32>(&mut store, "is_first")?;
    if is_first.call(&mut store, ())? == 1 {
        println!("counter1 is the first instance.");
    }

    Ok(())
}
```

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

```sh
$ cargo run
   Compiling call_counter v0.1.0 (/home/wbcchsyn/tmp/class_variable/call_counter)
    Finished dev [unoptimized + debuginfo] target(s) in 3.44s
     Running `target/debug/call_counter`
The id of counter0 is 0
The id of counter1 is 1
counter0 is the first instance.
```

上記の Rust コードを少しずつ解説していく。
以下で **太字のリンク** は wasmtime で定義されたクラスである事を示す。リンク先は [Rust 版 wasmtime の公式ドキュメント](https://docs.rs/wasmtime/10.0.1/wasmtime/index.html) 。

まずはコードの全体像を把握しよう。

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

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

見ての通り、本コードは main 関数が定義してあるだけである。

以下、main 関数の中身を上から少しずつ読んでみる
まずは以下の行からだ。

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

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

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

ここは [第１回] と wasm ファイルのパス以外同じだ。

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

```rust
    // Create Global `next_id` and `first_id`
    let next_id_ty = GlobalType::new(ValType::I64, Mutability::Var);
    let next_id = Global::new(&mut store, next_id_ty, Val::I64(0))?;
    let first_id_ty = GlobalType::new(ValType::I64, Mutability::Const);
    let first_id = Global::new(&mut store, first_id_ty, Val::I64(0))?;

    // Build `Instance`. (`Linker` is builder class.)
    let mut linker = Linker::new(&engine);
    linker.define(&store, "host", "next_id", next_id)?;
    linker.define(&store, "host", "FIRST_ID", first_id)?;
    let counter0 = linker.instantiate(&mut store, &module)?;
    let counter1 = linker.instantiate(&mut store, &module)?;
```

ここも [第２回] とほとんど同じだ。
違いは `linker.define` の引数に **[Global][Global_rs]** を渡している事だけである。

（`first_id` を大文字では無く小文字にした事に大きな理由は無い。大文字にすると Rust のコンパイラーが警告を出したので小文字にした。）

JavaScript の所でも説明したが、 `counter0` と `counter1` は同じ **[Global][Global_rs]** を参照している。そのため `counter0` の初期化時に `next_id` の値を更新するが、その更新は `counter1` にも反映される。

ところで、ここで **[Store][Store_rs]** に関する制限が有る。

**[Global][Global_rs]** と **[Instance][Instance_rs]** の各インスタンスは many-to-many の関係で紐づいている。
それとは別に、 **[Store][Store_rs]** と **[Global][Global_rs]** や **[Instance][Instance_rs]** は one-to-many の関係で紐づいている。

ここで関連する（紐づいている） **[Global][Global_rs]** や **[Instance][Instance_rs]** の各インスタンスは、全て同じ **[Store][Store_rs]** に紐づいている必要がある。

つまり、今回作成した `next_id`, `first_id`, `counter0`, `counter1` は、同一の **[Store][Store_rs]** に紐づいている必要が有る。

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

```rust
    // Show the `id` of `counter0` and `counter1`.
    let get_id = counter0.get_typed_func::<(), i64>(&mut store, "get_id")?;
    println!("The id of counter0 is {}", &get_id.call(&mut store, ())?);
    let get_id = counter1.get_typed_func::<(), i64>(&mut store, "get_id")?;
    println!("The id of counter1 is {}", &get_id.call(&mut store, ())?);

    // Show the first instance.
    let is_first = counter0.get_typed_func::<(), i32>(&mut store, "is_first")?;
    if is_first.call(&mut store, ())? == 1 {
        println!("counter0 is the first instance.");
    }
    let is_first = counter1.get_typed_func::<(), i32>(&mut store, "is_first")?;
    if is_first.call(&mut store, ())? == 1 {
        println!("counter1 is the first instance.");
    }
```

ここでは [第１回] と同じ方法で関数 `get_id` と `is_first` を実行している。

## 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, Global, GlobalType, Linker, Module, Store, Val,
                      ValType)

# Build Engine.
engine = Engine()

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

# Build Store.
store = Store(engine)

# Create Global next_id and FIRST_ID.
next_id_ty = GlobalType(ValType.i64(), True)
next_id = Global(store, next_id_ty, Val.i64(0))
FIRST_ID_ty = GlobalType(ValType.i64(), False)
FIRST_ID = Global(store, FIRST_ID_ty, Val.i64(0))

# Build Instance. (Linker is builder class.)
linker = Linker(engine)
linker.define(store, "host", "next_id", next_id)
linker.define(store, "host", "FIRST_ID", FIRST_ID)
counter0 = linker.instantiate(store, module)
counter1 = linker.instantiate(store, module)

# Show the id of counter0 and counter1.
print("The id of counter0 is %d" % counter0.exports(store)['get_id'](store))
print("The id of counter1 is %d" % counter1.exports(store)['get_id'](store))

# Show the first instance.
if counter0.exports(store)['is_first'](store):
    print("counter0 is the first instance.")
if counter1.exports(store)['is_first'](store):
    print("counter1 is the first instance.")
```

上記の内容を call_wasm.py というファイル名で保存すると、実行結果は以下の様になる。

```sh
$ python call_wasm.py
The id of counter0 is 0
The id of counter1 is 1
counter0 is the first instance.
```

上記の Python コードを少しずつ解説していく。
以下では **太字のリンク** は wasmtime で定義されたクラスである事を示す。リンク先は [Python 版 wasmtime の公式ドキュメント](https://bytecodealliance.github.io/wasmtime-py/) である。

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

```python
from wasmtime import (Engine, Global, GlobalType, Linker, Module, Store, Val,
                      ValType)

# Build Engine.
engine = Engine()

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

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

ここでは [第１回] と wasm ファイルのパス以外は同じだ。

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

```python
# Create Global next_id and FIRST_ID.
next_id_ty = GlobalType(ValType.i64(), True)
next_id = Global(store, next_id_ty, Val.i64(0))
FIRST_ID_ty = GlobalType(ValType.i64(), False)
FIRST_ID = Global(store, FIRST_ID_ty, Val.i64(0))

# Build Instance. (Linker is builder class.)
linker = Linker(engine)
linker.define(store, "host", "next_id", next_id)
linker.define(store, "host", "FIRST_ID", FIRST_ID)
counter0 = linker.instantiate(store, module)
counter1 = linker.instantiate(store, module)
```

ここも [第２回] とほとんど同じだ。
違いは `linker.define()` の引数に **[Global][Global_py]** を渡している事だけである。

JavaScript の所でも説明したが、 `counter0` と `counter1` は同じ **[Global][Global_py]** を参照している。そのため `counter0` の初期化時に `next_id` の値を更新するが、その更新は `counter1` にも反映される。

ところで、ここで **[Store][Store_py]** に関する制限が有る。

**[Global][Global_py]** と **[Instance][Instance_py]** の各インスタンスは many-to-many の関係で紐づいている。
それとは別に、 **[Store][Store_py]** と **[Global][Global_py]** や **[Instance][Instance_py]** は one-to-many の関係で紐づいている。

ここで関連する（紐づいている） **[Global][Global_py]** や **[Instance][Instance_py]** の各インスタンスは、全て同じ **[Store][Store_py]** に紐づいている必要がある。

つまり、今回作成した `next_id`, `FIRST_ID`, `counter0`, `counter1` は、同一の **[Store][Store_py]** に紐づいている必要が有る。

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

```python
# Show the id of counter0 and counter1.
print("The id of counter0 is %d" % counter0.exports(store)['get_id'](store))
print("The id of counter1 is %d" % counter1.exports(store)['get_id'](store))

# Show the first instance.
if counter0.exports(store)['is_first'](store):
    print("counter0 is the first instance.")
if counter1.exports(store)['is_first'](store):
    print("counter1 is the first instance.")
```

ここでは [第１回] と同じ方法で関数 `get_id` と `is_first` を実行している。

## 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/counter.wasm', 'rb').read
mod = Wasmtime::Module.new(engine, wasm)

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

# Create Global next_id and FIRST_ID.
next_id = Wasmtime::Global.var(store, :i64, 0)
FIRST_ID = Wasmtime::Global.const(store, :i64, 0)

# Build instance (Linker is builder Class)
linker = Wasmtime::Linker.new(engine)
linker.define(store, "host", "next_id", next_id)
linker.define(store, "host", "FIRST_ID", FIRST_ID)
counter0 = linker.instantiate(store, mod)
counter1 = linker.instantiate(store, mod)

# Show the id of counter0 and counter1.
puts("The id of counter0 is %d" % counter0.export('get_id').to_func.call)
puts("The id of counter1 is %d" % counter1.export('get_id').to_func.call)

# Show the first instance.
if counter0.export('is_first').to_func.call == 1 then 
    puts("counter0 is the first instance.")
end
if counter1.export('is_first').to_func.call == 1 then
    puts("counter1 is the first instance.")
end
```

上記の内容を call_wasm.rb というファイル名で保存すると、実行結果は以下の様になる。

```sh
$ ruby call_wasm.rb
The id of counter0 is 0
The id of counter1 is 1
counter0 is the first instance.
```

上記の Ruby コードを少しずつ解説していく。
以下では **太字のリンク** は wasmtime で定義されたクラスである事を示す。リンク先は [Ruby 版 wasmtime の公式ドキュメント](https://bytecodealliance.github.io/wasmtime-rb/latest/top-level-namespace.html) である。


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

```ruby
require 'wasmtime'

# Build Engine
engine = Wasmtime::Engine.new

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

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

ここでは [第１回] と wasm ファイルのパス以外は同じだ。

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

```ruby
# Create Global next_id and FIRST_ID.
next_id = Wasmtime::Global.var(store, :i64, 0)
FIRST_ID = Wasmtime::Global.const(store, :i64, 0)

# Build instance (Linker is builder Class)
linker = Wasmtime::Linker.new(engine)
linker.define(store, "host", "next_id", next_id)
linker.define(store, "host", "FIRST_ID", FIRST_ID)
counter0 = linker.instantiate(store, mod)
counter1 = linker.instantiate(store, mod)
```

ここも [第２回] とほとんど同じだ。
違いは `linker.define` の引数に **[Global][Global_rb]** を渡している事だけである。

JavaScript の所でも説明したが、 `counter0` と `counter1` は同じ **[Global][Global_rb]** を参照している。そのため `counter0` の初期化時に `next_id` の値を更新するが、その更新は `counter1` にも反映される。

ところで、ここで **[Store][Store_rb]** に関する制限が有る。

**[Global][Global_rb]** と **[Instance][Instance_rb]** の各インスタンスは many-to-many の関係で紐づいている。
それとは別に、 **[Store][Store_rb]** と **[Global][Global_rb]** や **[Instance][Instance_rb]** は one-to-many の関係で紐づいている。

ここで関連する（紐づいている） **[Global][Global_rb]** や **[Instance][Instance_rb]** の各インスタンスは、全て同じ **[Store][Store_rb]** に紐づいている必要がある。

つまり、今回作成した `next_id`, `FIRST_ID`, `counter0`, `counter1` は、同一の **[Store][Store_rb]** に紐づいている必要が有る。

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

```ruby
# Show the id of counter0 and counter1.
puts("The id of counter0 is %d" % counter0.export('get_id').to_func.call)
puts("The id of counter1 is %d" % counter1.export('get_id').to_func.call)

# Show the first instance.
if counter0.export('is_first').to_func.call == 1 then 
    puts("counter0 is the first instance.")
end
if counter1.export('is_first').to_func.call == 1 then
    puts("counter1 is the first instance.")
end
```

ここでは [第１回] と同じ方法で関数 `get_id` と `is_first` を実行している。

# まとめ

今回は 2 個以上の wasm ファイルのインスタンス間でグローバル変数を共有する方法について説明した。
WebAssembly はグローバル変数の他にも関数、抽象ポインター、線形メモリを import できる。
つまり、これらの値は複数のインスタンス間で共有できる。
（ [第２回] では関数の import を、 [第４回] では線形メモリの import を紹介した。）

これらを上手く活用すれば「メタプログラミング」と呼ばれる様な強力なコーディングを行う事が可能だ。
フレームワークの作成などで便利だろう。

一方で import や export を多用すると、それは WebAssembly と外部プログラムが密結合になってしまう。
一般的に平凡でシンプルな方法で実装できるなら、その方が良いと筆者は個人的には考えている。
「知識をひけらかす」事を目的にコーディングすると、悪い結果につながるかもしれない。

次回以降はメタプログラミング的な方法を紹介した後で、 [第４回] の続きとして線形メモリの実践的な使い方を紹介する予定だ。

[wasmtime]: https://github.com/bytecodealliance/wasmtime
[第１回]: https://qiita.com/wbcchsyn/items/e1f699bb86c466411e36
[第２回]: https://qiita.com/wbcchsyn/items/925d11c6fd9111b29851
[第３回]: https://qiita.com/wbcchsyn/items/47fa89c5b3c4bec24c15
[第４回]: https://qiita.com/wbcchsyn/items/c5906430fa478345a5e9

[Global_js]: https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Global

[Global_rs]: https://docs.rs/wasmtime/10.0.1/wasmtime/struct.Global.html
[Store_rs]: https://docs.rs/wasmtime/10.0.1/wasmtime/struct.Store.html
[Instance_rs]: https://docs.rs/wasmtime/10.0.1/wasmtime/struct.Instance.html

[Global_py]: https://bytecodealliance.github.io/wasmtime-py/#wasmtime.Global
[Store_py]: https://bytecodealliance.github.io/wasmtime-py/#wasmtime.Store
[Instance_py]: https://bytecodealliance.github.io/wasmtime-py/#wasmtime.Instance

[Global_rb]: https://bytecodealliance.github.io/wasmtime-rb/latest/Wasmtime/Global.html
[Store_rb]: https://bytecodealliance.github.io/wasmtime-rb/latest/Wasmtime/Store.html
[Instance_rb]: https://bytecodealliance.github.io/wasmtime-rb/latest/Wasmtime/Instance.html