Open25

AssemblyScript に入門する

Sosuke SuzukiSosuke Suzuki

WebAssembly っぽいものはおもしろいなーと思いつつも、wasm コンパイルできる言語で有名なもの(C,C++,Rust,Go等)で、慣れている言語がなかったので、TypeScript のサブセットから wasm にコンパイルできるらしい AssemblyScript に入門してみる。

ちなみに今の段階の自分の WebAssembly への理解は、「任意の言語からコンパイルできかつブラウザ動くバイナリフォーマットで、C や C++ 等の資産が活かせる上に実行速度が速かったり速くなかったりするらしい」という感じ。
Emscripten というのを使うと C や C++ から WebAssembly にコンパイルすることができるらしいというのも知っている。
Rust からも WebAssembly にコンパイルできるらしくてなんか流行ってるという印象がある。

他のことは知らない。

Sosuke SuzukiSosuke Suzuki

Binaryen は C++ で記述された WebAssembly 用のコンパイラおよびツールチェインインフラストラクチャライブラリらしい
WebAssembly へのコンパイルを Easy, Fast, Effective にするのが目的
何から WebAssembly へのコンパイラなんだ?

Sosuke SuzukiSosuke Suzuki

https://github.com/WebAssembly/binaryen#tools いろんなツールがあるっぽい

  • wasm-opt
    • WebAssembly を読み込んで Binaryen IR を実行
  • wasm-as
    • S式のテキストフォーマット WebAssembly をバイナリフォーマットにアセンブルする
  • wasm-dis
    • バイナリフォーマットの WebAssembly をテキストフォーマットに逆アセンブルする
  • wasm2js
    • WebAssembly から JavaScript へのコンパイラ
  • wasm-reduce
    • なんかよくわからん wasm ファイルがある場合、それと同じような挙動をしつつデバッグしやすい wasm ファイルをゲットできるんかな、わからん
  • wasm-shell
    • WebAssembly コードをロードして解釈できるシェル
  • wasm-ctor-eval
    • C++グローバルコンストラクタを事前に実行できるらしい
    • よくわからないけど Emscripten から使われている
  • binaryen.js
    • WASM モジュールを作成および最適化するための Binaryen メソッドを公開するスタンドアローンの JavaScript ライブラリ

雰囲気はなんとなくわかった。本当にコンパイラーツールチェインという感じ

Sosuke SuzukiSosuke Suzuki

ところで、WebAssembly と WASM と wasm は厳密に使い分ける必要がある用語なんだろうか

Sosuke SuzukiSosuke Suzuki

うーん、なんか具体的に Binaryen が AssemblyScript からどんな感じで使われているのかまだピンとこない。
TypeScript のサブセットで型チェックを行うってことは、どっかで TypeScript Compiler API とか叩いているだろうしそのへんのやりとりがどうなってるのかわからん

Sosuke SuzukiSosuke Suzuki

Portable compiler sources that compile to both JavaScript using tsc and WebAssembly using asc.

なるほど tsc を使って TS(のサブセット)を JS にして、asc を使って WebAssembly にするコンパイラ

Sosuke SuzukiSosuke Suzuki

結構ガチの TS 用 tokenizer と parser があるからパースは tsc でやってるわけじゃないのか

Sosuke SuzukiSosuke Suzuki

あれ、なんか ./cli/asc.jsts-node を使っているな。しかも transpileOnly で。全然ちゃんと読んでいないがもしかして ts-node でトランスパイルしているのか?

https://github.com/AssemblyScript/assemblyscript/blob/86dc8df740aa94d2c44b0811dc373fe819dd97bf/cli/asc.js#L513

Sosuke SuzukiSosuke Suzuki

どうやらこれは、JS 版 AssemblyScript も wasm 版 AssemblyScript も存在しない場合は入力のコードをそのまま ts-node で実行するという話みたい

Sosuke SuzukiSosuke Suzuki

まあよくわからないので手元で console.log 仕込んで流れを追うかー

Sosuke SuzukiSosuke Suzuki

意図的に型エラーを発生させてみた

$  ./bin/asc ./_tmptmptmp.fib.ts -b fib.wasm -O3
ERROR TS2322: Type '~lib/string/String' is not assignable to type 'i32'.

   return "foo";
          ~~~~~
 in _tmptmptmp.fib.ts(12,10)

FAILURE 1 compile error(s)

ここからエラーをおうと

https://github.com/AssemblyScript/assemblyscript/blob/86dc8df740aa94d2c44b0811dc373fe819dd97bf/cli/asc.js#L1244-L1287 でこのエラーが出力されていることがわかり、さらに https://github.com/AssemblyScript/assemblyscript/blob/86dc8df740aa94d2c44b0811dc373fe819dd97bf/cli/asc.js#L1247 でエラーを取得していそう

Sosuke SuzukiSosuke Suzuki

emitDiagnosticで意図的に throw new Error() してスタックトレースを見るとこう(もっと前からこれをやればよかった

▌ Error: 
▌     at Compiler.emitDiagnostic (/assemblyscript/src/diagnostics.ts:317:11)
▌     at Compiler.error (/assemblyscript/src/diagnostics.ts:399:10)
▌     at Compiler.convertExpression (/assemblyscript/src/compiler.ts:3579:12)
▌     at Compiler.compileExpression (/assemblyscript/src/compiler.ts:3506:21)
▌     at Compiler.compileReturnStatement (/assemblyscript/src/compiler.ts:2796:19)
▌     at Compiler.compileStatement (/assemblyscript/src/compiler.ts:2185:21)
▌     at Compiler.compileStatements (/assemblyscript/src/compiler.ts:2249:23)
▌     at Compiler.compileFunctionBody (/assemblyscript/src/compiler.ts:1585:20)
▌     at Compiler.compileFunction (/assemblyscript/src/compiler.ts:1515:17)
▌     at Compiler.compileElement (/assemblyscript/src/compiler.ts:994:38)
Sosuke SuzukiSosuke Suzuki

さらに compileElement でやるとこう

▌ Error: 
▌     at Compiler.compileElement (/assemblyscript/src/compiler.ts:1027:11)
▌     at Compiler.compileExports (/assemblyscript/src/compiler.ts:1037:62)
▌     at Compiler.compile (/assemblyscript/src/compiler.ts:482:14)
▌     at Object.compile (/assemblyscript/src/index.ts:276:32)
▌     at /assemblyscript/cli/asc.js:833:31
▌     at measure (/assemblyscript/cli/asc.js:1331:3)
▌     at Object.main (/assemblyscript/cli/asc.js:831:24)
▌     at /assemblyscript/bin/asc:19:47

まあなんか普通に compile でエラーを emit しているっぽい。tsc はそこにいるのか...

Sosuke SuzukiSosuke Suzuki

そしてスタックトレースが ts のまま見れて便利だし、明示的にビルドせずにそのまま動いているっぽい?よくわかんないけど開発体験が良い