WebAssemblyのcode section

Binary Formatを読み込むパーサを書いていますが、ようやく、code sectionを残すだけとなりました。Text Formatよりも手順が少ないのですぐ書けますね(慣れてきたのもあります)。

とはいえ、一番肝心なsectionなので、ちょっとどういう仕様なのか、解読しようと思います。

f:id:ironoir:20210208124734p:plain

  • section idは10(section idについては以下を見てね)

ironoir.hatenablog.com

  • code sectionはcodeの配列
  • codeの中身はローカル変数を表すvaltypeの配列と、実際のコードが入っているexprからできている。
  • codeひとつがだいたい、ひとつの関数の内容に対応している

ここまでは、あーなるほどねーそーだよねーと読んでたんですが、微妙に気になる記述がありますね。

Here, code ranges over pairs (valtype,expr). The meta function concat((𝑡)) concatenates all sequences 𝑡𝑖 in ** (𝑡 ) . Any code for which the length of the resulting sequence is out of bounds of the maximum size of a vector is malformed.

そう、ローカル変数が、単なる一重の配列ではなく、配列の配列になっているんですね。加えて言うと、同じ型(WebAssemblyで使える値の型は、現時点では任意のビット数の整数と浮動小数点数ですが、実質はそれぞれ32ビット、64ビットの合計4種類です)のローカル変数は1つの配列にまとめることができます。その型ごとの配列がいくつかあるので、全体としては配列の配列になっているわけです。Any code〜以降は単純に、全体をconcatした際にvectorの最大数を超えてはいけないよ、という当たり前のことが書いてあるだけです(ちなみに最大数は2の32乗)。

内容はわかったんですが、目的はなんでしょうか。最適化とかですかね。めちゃくちゃたくさんローカル変数がある場合にまとめられますね(ランレングス)。ちなみに、この「ローカル変数」は、WebAssemblyの場合は関数の引数も含んでいます(とはいえ、引数はそこまで多くならないのでは?いや、わからんな)。

仕様上は、最短ではない形で上記の二重配列を作ることも許されていそうです。例えば、i32が2つ、f64が1つ、i32が1つみたいに、引数の順番的にまとめられない場合です(例ではi32)。普通は、最適化でここを最短にまとめたりもするんやろな。

仕様がなんとなく理解できてきたので、作ってみようと思います!