Slide 1

Slide 1 text

RustでWasm Runtimeを書いた (株)テックリード ゴリラ

Slide 2

Slide 2 text

QSPGJMF \ OBNFΰϦϥ KPC< ΤϯδχΞ ձࣾܦӦ > MJLFT< 3VTU (P 5ZQF4DSJQU %FOP 7JN 8BTN %PDLFS LT > TOT< 9 5XJUUFS IUUQTUXJUUFSDPNHPSJMMB (JU)VCIUUQTHJUIVCDPNTLBOFIJSB [FOOIUUQT[FOOEFWTLBOFIJSB > >

Slide 3

Slide 3 text

Wasm Runtimeを書いたモチベ

Slide 4

Slide 4 text

Wasm 面白そうだけど 
 どう動いているのか 
 よくわからん

Slide 5

Slide 5 text

実装して完全理解するしかない ↓ 実装してみた https://github.com/skanehira/chibiwasm ※https://www.w3.org/TR/wasm-core-1/ の仕様まで

Slide 6

Slide 6 text

デモ

Slide 7

Slide 7 text

あらためて... Wasm(WebAssembly)とは?

Slide 8

Slide 8 text

https://developer.mozilla.org/ja/docs/WebAssembly より

Slide 9

Slide 9 text

狭義的にWasmはブラウザでも動く 仮想命令セット ※文脈によってエコシステム周辺も含めてwasmと呼ぶこともある

Slide 10

Slide 10 text

命令セットはCPU命令の集まり x86・ARMなどがある

Slide 11

Slide 11 text

仮想命令セットは CPUに依存しない命令セット

Slide 12

Slide 12 text

RubyやJVMといった仮想マシンで動作する言語は それぞれが定義した仮想命令セットで動いている

Slide 13

Slide 13 text

Wasmの仮想命令セットは 
 ただのバイトコード

Slide 14

Slide 14 text

00000000: 0061 736d 0100 0000 0107 0160 027f 7f01 .asm.......`.... 00000010: 7f03 0201 000a 0901 0700 2000 2001 6a0b .......... . .j. 00000020: 0a . WATからWasmバイナリを生成

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

Wasm Runtimeは 
 Ruby VMやJVMのような仮想マシン

Slide 17

Slide 17 text

Wasm Runtimeは スタックベースの仮想マシン

Slide 18

Slide 18 text

*.wasmが実行されるまでの流れ

Slide 19

Slide 19 text

1. *.wasmからRustのデータ構造に落とし込む 
 2. 1のデータ構造から実行用のデータ構造を生成する 
 3. Wasm Runtimeのメモリの確保や命令処理などを行う

Slide 20

Slide 20 text

*.wasmのデータ構造

Slide 21

Slide 21 text

先頭8バイトがmagic number とversion情報 
 残りが各種セクション情報 
 各種セクションは実行時に 必要な情報を持つ 8BTNNPEVMF E NBHJDOVNCFS aBTN WFSTJPO TFDUJPODPEF TFDUJPOTJ[F BYY TFDUJPOEBUB TFDUJPODPEF TFDUJPOTJ[F YY TFDUJPOEBUB EYY

Slide 22

Slide 22 text

例) 
 type_section 関数シグネチャ情報 code_section 
 関数の命令群

Slide 23

Slide 23 text

TFDUJPO5ZQF TFDUJPODPEF TFDUJPOTJ[F B OVNUZQFT C GVOD D OVNQBSBNT EG J FG J G OVNSFTVMUT G J TFDUJPO$PEF B TFDUJPODPEF TFDUJPOTJ[F OVNGVODUJPOT GVODCPEZTJ[F MPDBMEFDMDPVOU B MPDBMHFU C MPDBMJOEFY D MPDBMHFU E MPDBMJOEFY FB JBEE GC FOE

Slide 24

Slide 24 text

例) 
 type_section 関数シグネチャ情報 code_section 
 関数の命令群 import_section 他モジュールからインポートす る関数やメモリなどの情報

Slide 25

Slide 25 text

code section をデコード処理する例 TFDUJPO$PEF B TFDUJPODPEF TFDUJPOTJ[F OVNGVODUJPOT GVODCPEZTJ[F MPDBMEFDMDPVOU B MPDBMHFU C MPDBMJOEFY D MPDBMHFU E MPDBMJOEFY FB JBEE GC FOE

Slide 26

Slide 26 text

実行時データ構造

Slide 27

Slide 27 text

Store 実行時に必要なインスタンス達を持つ 
 例)関数やメモリのインスタンス Runtime VMそのものと思ってOK Runtime::stack 処理時の値を保持する Runtime::call_stack 関数呼び出しのフレームを保持する フレームごとに命令などの情報をもつ

Slide 28

Slide 28 text

命令処理の実装を説明する前に スタックマシンについて復習

Slide 29

Slide 29 text

スタックマシン 10 + 13 をスタックを使って計算する場合

Slide 30

Slide 30 text

これをRustで表現する

Slide 31

Slide 31 text

*OTUSVDUJPO 
 8BTNͷ໋ྩ܈ 7BMVF 
 8BTNͰѻ͑Δ஋ 
 J΍JɺGͳͲ 3VOUJNFTUBDL 
 ॲཧ࣌ͷ஋Λอ࣋ 3VOUJNFFYFDVUF 
 ໋ྩΛॲཧ͢Δؔ਺ QD 
 ϓϩάϥϜΧ΢ϯλ 
 ࣍ͷ໋ྩͷ൪஍ʢΠϯσοΫεʣ

Slide 32

Slide 32 text

'SBNF 
 ؔ਺ͷݺͼग़͠ͷ౓ʹੜ੒͢Δ 
 
 ྫ͑͹ɺ" # ͷΑ͏ͳؔ਺ݺͼग़͠ 
 ͕͋Δ৔߹ɺ" ͷॲཧதʹ# ͷ໋ྩΛ 
 ॲཧ͠ɺͦΕ͕ऴΘͬͨΒ" ʹ໭Δࡍʹ 
 " ͷQDʹ໭͢ඞཁ͕͋Δ 
 ؔ਺͝ͱʹQDͱ໋ྩΛ·ͱΊͯ'SBNFͰ 
 ؅ཧ͢Δ͜ͱͰɺݺͼग़͠ݩʹ໭Δͱ͖ 
 ͷॲཧ͸'SBNFΛ੾Γସ͑Δ͚ͩͰࡁΉ

Slide 33

Slide 33 text

最終的なFrame

Slide 34

Slide 34 text

-BCFM 
 JG΍MPPQͱ͍ͬͨͷ੍ޚߏจΛॲཧ͢ΔͨΊͷ৘ใ 
 ྫ͑͹ελοΫΛר͖໭ͨ͢ΊͷελοΫϙΠϯλ 
 ͳͲΛ࣋ͭ BSJUZ 
 ໭Γ஋ͷ਺ 
 MPPQ΋໭Γ஋Λฦ͢͜ͱ͕Ͱ͖ΔͨΊɺ 
 -BCFM΋BSJUZΛ࣋ͭ MPDBMT 
 ؔ਺ͷҾ਺΍ϩʔΧϧม਺ͷ஋ ͦͷଞɺॾʑͷ࣮૷ͷৄࡉ͸ˣͷهࣄΛࢀর 
 IUUQT[FOOEFWTLBOFIJSBBSUJDMFT SVTUXBTNSVOUJNF

Slide 35

Slide 35 text

ͪͳΈʹ໋ྩͷ਺͸Ҏ্͋Δ 
 ͷͰϚΫϩΛۦ࢖࣮ͯ͠૷ྔΛ཈͑ͨ 3VTUͷϚΫϩ͸͜͏͍͏ͱ͖ʹศར

Slide 36

Slide 36 text

実はWasm Runtimeは 
 数値の計算とメモリの操作 
 しかできない

Slide 37

Slide 37 text

ファイルといったOSのリソース の操作は仕様にない

Slide 38

Slide 38 text

WebAssembly System Interface 通称 WASI

Slide 39

Slide 39 text

WASIは雑にいうと システムコールの仕様

Slide 40

Slide 40 text

POSIX Likeな関数の集まり 例) sock_accept(fd, flags) : ソケット新規接続受け入れ fd_write(fd, iovec_array): fdにデータを書き込む fd_read(fd, iovec_array) : fdからデータを読み取る

Slide 41

Slide 41 text

WASIを使えば、ファイルといった OSのリソースを扱えるようになる

Slide 42

Slide 42 text

つまり... WASIをRuntimeに実装することで ファイルIOの処理が可能になる

Slide 43

Slide 43 text

WASIはpreview 1と2がある

Slide 44

Slide 44 text

preview 1の関数一覧 
 https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md

Slide 45

Slide 45 text

文字を出力するにはpreview 1の fd_write()を実装する必要がある

Slide 46

Slide 46 text

fd_write()はWasm Runtimeが持つ メモリ上のデータをfdに書き込む

Slide 47

Slide 47 text

ϝϞϦ͔ΒσʔλΛಡΈऔΔ ಡΈऔͬͨόΠτྻΛGEʹ ॻ͖ग़͢

Slide 48

Slide 48 text

Wasmから見てWASIは wasi_snapshot_preview1という モジュール そのモジュールが持っている fd_write()関数を使う fd_write()を使うとき

Slide 49

Slide 49 text

ドキュメントを読んでもどう実装したら良いのかさっぱり分からなかった WASIの実装の余談 なので↓のdenoのwasiモジュールを見ながらRustで実装した 
 https://deno.land/std/wasi/snapshot_preview1.ts 今なら、GoのWASI実装を参考にできるかも? 
 https://github.com/golang/go/blob/master/src/net/fd_wasip1.go

Slide 50

Slide 50 text

宣伝 同人誌「作って理解 Wasm Runtimeのしくみ」を執筆中です Rustで"Hello World"を出力できるWasm RuntimeをRustで実装し ていく本になります 来年のどこかの技術書典などに出せたらと思っています

Slide 51

Slide 51 text

ありがとうございました