WebAssemblyでクロージャ実現にWeak<T>を使ってみる

ラノベのような雰囲気のタイトルになってしまった。 順番にいきましょう。

RustのWeak<T>

RustのWeak<T>に関しては、公式がすばらしい文章を日本語で出してくれています。本当に感謝しかないです。とにかく読みましょう。

doc.rust-jp.rs

WebAssemblyのクロージャ

さて、それはさておいて、突然クロージャの話になりました。クロージャとはざっくりいうと環境付きの関数ということですが、この場合はStoreが環境にあたります。ほかのプログラミング言語だと環境がネストできたりしますが、今回はグローバル環境(=Store)だけが対象の話です。

Rustで実装しようとすると困るのが、以下のように、参照関係が循環していることです。

f:id:ironoir:20210224125520p:plain

storeは関数実体のリストであるfuncsを所有しています。そして、その関数実体ひとつひとつからは、環境であるmoduleinstが参照されています。moduleinstの中身はほとんどがstore実体へのポインタなので、当然moduleinstからstoreへの参照も存在します。こんな時にはRustだとWeak<T>を使うとよいみたいです。

それを踏まえると、宣言は以下のようになる感じでしょうか。

struct Store {
    funcs: Vec<FuncInst>,
    tables: Vec<TableInst>,
    mems: Vec<MemInst>,
    globals: Vec<GlobalInst>,
}

struct FuncInst {
    tp: FuncType,
    module: ModuleInst,
    code: Func,
}

struct ModuleInst {
    funcaddrs: Weak<Vec<FuncInst>>,
    tableaddrs: Weak<Vec<TableInst>>,
    memaddrs: Weak<Vec<MemInst>>,
    globaladdrs: Weak<Vec<GlobaInst>>,
}

木構造の子から親を見たいときにWeak<T>を使うのが最もオーソドックスなユースケースだと思いますが、今回もたぶん、そうですね。このままうまくいくかどうか、実装を続けたいと思います。

PlantUMLコード

@startuml

rectangle store
rectangle funcs
rectangle moduleinst

store -up-> funcs
funcs -up-> moduleinst
moduleinst .up.> store
@enduml