SVX日記
2023-10-12(Thu) WebAssembly $41
偶然「RubyがWebAssemblyで動く」という記事を目にした。「WebAssembly」と聞くとブラウザ上で機械語が動くらしい印象を受けるが、具体的にはサッパリわからない。一般的なブラウザでRubyが動くなら実に喜ばしいことだが。しかし、Rubyを動かすためにはファイルシステムが……みたいな話になっている。よく理解できない。フムン。まずはRuby抜きでWebAssembly自体について学んでみたくなってきたな。
そもそも、自分は8bitの頃にコンピュータを始めたクチで、その頃はBASICを理解したら、次は機械語というのが定番のルートだった。自分はSHARP党だったので、X1ではZ80、X68000ではMC68000、Oh!XキッカケでPICマイコンのアセンブラにも手を染めたことがあるが、そもそもWebAssemblyの「Assembly」はアセンブラの意味で正しいのだろうか?
調べ始めると、どうもそれで正しいらしい。JavaScriptよりも高速な処理を目指したもので、そのバイナリは仮想マシンで処理されるものの、数倍の性能が得られるらしい。数倍……か。Z80の頃には、BASICと機械語では軽く数十倍以上の性能が得られたことに比べればずいぶん控えめな値ではあるが。
しかし驚いたのは、あらゆるI/O機能が「ない」ことだ。つまり計算やメモリ操作しかできない。そんなもん何に使ったらいいのか。せっかく懐かしくアセンブラに手を染められるかと思ったのに、使い道のないものを学んでも仕方がない……ん? いや、あるッ! ひとつだけ思いついたぞ。うむ、じゃ、やってみるか。
ということで、Web上でWebAssemblyの記事を探すと、CやRustから使う記事が多い。いや、そうじゃないんだ。せっかくなんだから、直接にニーモニック(mnemonic)を書きたいんだ。で、しつこく探すとそういう記事も多少は見つかる。
;; https://developer.mozilla.org/ja/docs/WebAssembly/Understanding_the_text_format
(module
(func (param $lhs i32) (param $rhs i32) (result i32)
local.get $lhs
local.get $rhs
i32.add
)
)
# dnf search webassem
wabt.x86_64 : The WebAssembly Binary Toolkit
# dnf install wabt
# wat2wasm add.wat
# ndump add.wasm
#Address +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F 'Character
#00000000 = 00 61 73 6D 01 00 00 00 01 07 01 60 02 7F 7F 01 '.asm....:...`....
#00000010 = 7F 03 02 01 00 0A 09 01 07 00 20 00 20 01 6A 0B '........:.. . .j.
# wasm2wat add.wasm
(module
(type (;0;) (func (param i32 i32) (result i32)))
(func (;0;) (type 0) (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add))
しかし、なにしろ動かしてみないことには面白くない。なんでも、wasmバイナリを動かすには、ブラウザでJavaScriptを実行し、そこから呼び出す形式になるらしい。まさに昔、BASICプログラムから機械語サブルーチンを呼び出す場合の「CALL」や「USR」と同じ形式ということだな。
;; https://developer.mozilla.org/ja/docs/WebAssembly/Understanding_the_text_format
(module
(func (export "add") (param $lhs i32) (param $rhs i32) (result i32)
local.get $lhs
local.get $rhs
i32.add
)
)
<!-- https://developer.mozilla.org/ja/docs/WebAssembly/Understanding_the_text_format -->
<HTML>
<HEAD>
<TITLE>WebAssembly Add Test</TITLE>
</HEAD>
<BODY>
<SCRIPT>
WebAssembly.instantiateStreaming(fetch("add.wasm")).then(
(obj) => {
console.log(obj.instance.exports.add(1, 2));
}
);
</SCRIPT>
</BODY>
</HTML>
JavaScriptを含むhtmlと、機械語サブルーチンであるwasmは、/var/www/htmlの下に配置し、手元でApacheを上げ、ブラウザからhttp://localhost/add.htmlでアクセスする。何も画面に表示されなくても焦ってはいけない。「Chrome」なら右クリックからの「検証」「Console」し、ログに結果である「3」が……アレ? 出てないな。代わりにエラーが出ている。
Uncaught (in promise) TypeError: Failed to execute 'compile' on 'WebAssembly':
Incorrect response MIME type. Expected 'application/wasm'.
TypeError: Response has unsupported MIME type
よく読めばChromeの方が(ちょっと過剰にw)わかりやすい。Apacheがwasmを返す時の「MIME type」は「application/wasm」じゃないの? って言ってるワケだ。これは、Apache側に設定追加してやる必要がある。
/etc/httpd/conf/httpd.conf
<IfModule mime_module>
:
AddType application/wasm .wasm
:
</IfModule>