$30 off During Our Annual Pro Sale. View Details »

RustでWasm Runtimeを書いた in WebAssembly night #11

skanehira
September 15, 2023

RustでWasm Runtimeを書いた in WebAssembly night #11

skanehira

September 15, 2023
Tweet

More Decks by skanehira

Other Decks in Programming

Transcript

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

    View Slide

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

    View Slide

  3. Wasm Runtimeを書いたモチベ

    View Slide

  4. Wasm 面白そうだけど

    どう動いているのか

    よくわからん

    View Slide

  5. 実装して完全理解するしかない





    実装してみた
    https://github.com/skanehira/chibiwasm
    ※https://www.w3.org/TR/wasm-core-1/ の仕様まで

    View Slide

  6. デモ

    View Slide

  7. あらためて...


    Wasm(WebAssembly)とは?

    View Slide

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

    View Slide

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

    View Slide

  10. 命令セットはCPU命令の集まり


    x86・ARMなどがある

    View Slide

  11. 仮想命令セットは


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

    View Slide

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

    View Slide

  13. Wasmの仮想命令セットは

    ただのバイトコード

    View Slide

  14. 00000000: 0061 736d 0100 0000 0107 0160 027f 7f01 .asm.......`....


    00000010: 7f03 0201 000a 0901 0700 2000 2001 6a0b .......... . .j.


    00000020: 0a .
    WATからWasmバイナリを生成

    View Slide

  15. View Slide

  16. Wasm Runtimeは

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

    View Slide

  17. Wasm Runtimeは


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

    View Slide

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

    View Slide

  19. 1. *.wasmからRustのデータ構造に落とし込む



    2. 1のデータ構造から実行用のデータ構造を生成する

    3. Wasm Runtimeのメモリの確保や命令処理などを行う

    View Slide

  20. *.wasmのデータ構造

    View Slide

  21. 先頭8バイトがmagic number
    とversion情報

    残りが各種セクション情報

    各種セクションは実行時に
    必要な情報を持つ
    8BTNNPEVMF
    E NBHJDOVNCFS aBTN

    WFSTJPO

    TFDUJPODPEF
    TFDUJPOTJ[F
    BYY TFDUJPOEBUB
    TFDUJPODPEF
    TFDUJPOTJ[F
    YY TFDUJPOEBUB
    EYY

    View Slide

  22. 例)

    type_section


    関数シグネチャ情報


    code_section

    関数の命令群

    View Slide

  23. 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

    View Slide

  24. 例)

    type_section


    関数シグネチャ情報


    code_section

    関数の命令群


    import_section


    他モジュールからインポートす
    る関数やメモリなどの情報

    View Slide

  25. code section をデコード処理する例
    TFDUJPO$PEF

    B TFDUJPODPEF
    TFDUJPOTJ[F
    OVNGVODUJPOT
    GVODCPEZTJ[F
    MPDBMEFDMDPVOU
    B MPDBMHFU
    C MPDBMJOEFY
    D MPDBMHFU
    E MPDBMJOEFY
    FB JBEE
    GC FOE

    View Slide

  26. 実行時データ構造

    View Slide

  27. Store


    実行時に必要なインスタンス達を持つ

    例)関数やメモリのインスタンス


    Runtime


    VMそのものと思ってOK


    Runtime::stack


    処理時の値を保持する


    Runtime::call_stack


    関数呼び出しのフレームを保持する


    フレームごとに命令などの情報をもつ

    View Slide

  28. 命令処理の実装を説明する前に


    スタックマシンについて復習

    View Slide

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

    View Slide

  30. これをRustで表現する

    View Slide

  31. *OTUSVDUJPO

    8BTNͷ໋ྩ܈
    7BMVF

    8BTNͰѻ͑Δ஋

    J΍JɺGͳͲ
    3VOUJNFTUBDL

    ॲཧ࣌ͷ஋Λอ࣋
    3VOUJNFFYFDVUF

    ໋ྩΛॲཧ͢Δؔ਺
    QD

    ϓϩάϥϜΧ΢ϯλ

    ࣍ͷ໋ྩͷ൪஍ʢΠϯσοΫεʣ

    View Slide

  32. 'SBNF

    ؔ਺ͷݺͼग़͠ͷ౓ʹੜ੒͢Δ



    ྫ͑͹ɺ"
    #
    ͷΑ͏ͳؔ਺ݺͼग़͠

    ͕͋Δ৔߹ɺ"
    ͷॲཧதʹ#
    ͷ໋ྩΛ

    ॲཧ͠ɺͦΕ͕ऴΘͬͨΒ"
    ʹ໭Δࡍʹ

    "
    ͷQDʹ໭͢ඞཁ͕͋Δ

    ؔ਺͝ͱʹQDͱ໋ྩΛ·ͱΊͯ'SBNFͰ

    ؅ཧ͢Δ͜ͱͰɺݺͼग़͠ݩʹ໭Δͱ͖

    ͷॲཧ͸'SBNFΛ੾Γସ͑Δ͚ͩͰࡁΉ

    View Slide

  33. 最終的なFrame

    View Slide

  34. -BCFM

    JG΍MPPQͱ͍ͬͨͷ੍ޚߏจΛॲཧ͢ΔͨΊͷ৘ใ

    ྫ͑͹ελοΫΛר͖໭ͨ͢ΊͷελοΫϙΠϯλ

    ͳͲΛ࣋ͭ
    BSJUZ

    ໭Γ஋ͷ਺

    MPPQ΋໭Γ஋Λฦ͢͜ͱ͕Ͱ͖ΔͨΊɺ

    -BCFM΋BSJUZΛ࣋ͭ
    MPDBMT

    ؔ਺ͷҾ਺΍ϩʔΧϧม਺ͷ஋
    ͦͷଞɺॾʑͷ࣮૷ͷৄࡉ͸ˣͷهࣄΛࢀর

    IUUQT[FOOEFWTLBOFIJSBBSUJDMFT
    SVTUXBTNSVOUJNF

    View Slide

  35. ͪͳΈʹ໋ྩͷ਺͸Ҏ্͋Δ

    ͷͰϚΫϩΛۦ࢖࣮ͯ͠૷ྔΛ཈͑ͨ
    3VTUͷϚΫϩ͸͜͏͍͏ͱ͖ʹศར

    View Slide

  36. 実はWasm Runtimeは

    数値の計算とメモリの操作

    しかできない

    View Slide

  37. ファイルといったOSのリソース


    の操作は仕様にない

    View Slide

  38. WebAssembly System Interface


    通称 WASI

    View Slide

  39. WASIは雑にいうと


    システムコールの仕様

    View Slide

  40. POSIX Likeな関数の集まり
    例)


    sock_accept(fd, flags) : ソケット新規接続受け入れ


    fd_write(fd, iovec_array): fdにデータを書き込む


    fd_read(fd, iovec_array) : fdからデータを読み取る

    View Slide

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

    View Slide

  42. つまり...


    WASIをRuntimeに実装することで


    ファイルIOの処理が可能になる

    View Slide

  43. WASIはpreview 1と2がある

    View Slide

  44. preview 1の関数一覧



    https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md

    View Slide

  45. 文字を出力するにはpreview 1の


    fd_write()を実装する必要がある

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  49. ドキュメントを読んでもどう実装したら良いのかさっぱり分からなかった
    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

    View Slide

  50. 宣伝
    同人誌「作って理解 Wasm Runtimeのしくみ」を執筆中です


    Rustで"Hello World"を出力できるWasm RuntimeをRustで実装し
    ていく本になります


    来年のどこかの技術書典などに出せたらと思っています

    View Slide

  51. ありがとうございました

    View Slide