SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|07|08|09|10|11|

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)を書きたいんだ。で、しつこく探すとそういう記事も多少は見つかる。

  なんにせよ、まずは動かしてみないことには面白くない。ちょっと調べると、WebAssemblyにおける「hello, world」は足し算をするものらしい。

;; 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
    )
)

  そうそう。まずはニーモニックを知りたいんだよ。んが、WebAssemblyではニーモニックとは言わず、単にテキスト形式(text format)というらしい。拡張子は「wat」だ。

  watを書いたら、アセンブラでバイナリ形式に変換することになるが、Fedoraには関連ツールをまとめたパッケージが用意されている。「wabt」パッケージだ。

# dnf search webassem
wabt.x86_64 : The WebAssembly Binary Toolkit
# dnf install wabt

  いわゆるアセンブラに当たるのが「wat2wasm」だ。こうやってアセンブルする。

# wat2wasm add.wat

  バイナリ形式に変換後の拡張子は「wasm」だ。なるほど。バイナリに変換されている。

# 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」という逆アセンブラもある。

# 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」と同じ形式ということだな。

  JavaScriptからWebAssemblyの関数を呼び出したい場合、WebAssembly側で関数を「export」する必要がある。WebAssembly観点での「輸出」だな。

;; 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'.

  ブラウザ依存かしら。「Firefox」で同じページを開き「要素を調査」「コンソール」で……アレ? こっちもか。「3」ではなくエラーが出ている。

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>

  改めてブラウザからアクセスする。どちらのブラウザでも「3」が出力された。よっしゃよっしゃ。最初の任務は完了である。