BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース WebAssemblyランタイムのwastimeがReference Typeを実装、Wasmで複合型の処理が可能に

WebAssemblyランタイムのwastimeがReference Typeを実装、Wasmで複合型の処理が可能に

原文(投稿日:2020/09/12)へのリンク

Nick Fitzgerald氏は先頃、wasmtimeWebAssemblyのReference Typeプロポーザルを実装したと発表した。Reference Typeを使うことで、整数値や浮動小数点値に制限されることなく、複雑なホストオブジェクト(DOMノードやファイルハンドルなど)の参照を処理できるようになるだけでなく、インターフェース型のインポートガベージコレクションモジュールリンクなど、将来的なWebAssembly機能への道を開くことにもなる。

WebAssemblyの最初のバージョン(現在はWeb標準)は、ブラウザのコンテンツ内で使用するための、最小の実行可能な機能(MVP)として公開された。このバージョンのWebAssemblyは、整数型と浮動小数点型のみを理解する(numtype := i32 | i64 | f32 | f64)。

そこで、ホスト言語の複雑な型をこれらの基本的な型に変換する、グルー(glue)コードを記述する必要が生じる。この処理は、ユーザが指定するアノテーションを通じて、コンパイラによって実行される場合もある(Rustの#[wasm_bindgen]など)。このグルーコードは、モジュールが実行される可能性のあるホスト環境毎(Rust、C++など)に開発しなければならないため、Wasmモジュールの作者にとって、大きな労力を伴うものになる可能性がある。また一方では、Wasmモジュールの共用APIを基本型のみで構成しなければならないため、直感的でないインターフェースを公開することになり、これもまた、モジュール利用者にとって不便な点となる。

WebAssembly Interface Typeプロポーザルは、Wasmモジュールとホスト環境や他のモジュールとのやり取りに複雑な型を使用できるようにすることで、このようなWasmモジュールのユーザと作者双方の苦労を取り除こうというものだ。Interface Typeを使用するWasmモジュールは、中間表現(現在の固定的な基本型とは対照的な抽象型)として使用する型に対するマッピングを提供する。Wasmランタイムはこれら抽象型を使用して、指定されたホスト環境を対象としたコードを生成する。

WebAssembly Reference Typeプロポーザルは、ホスト環境との相互運用の、よりシンプルなユースケースに対処するものだ。Interface Typeに関する講義的なプレゼンテーションの中で、MozillaのLin Clark氏が、そのようなユースケースについて説明している。

JavaScipt関数からWebAssemby関数に文字列を渡して、それを別のJavaScript関数に渡すものとしましょう。この処理に必要なのは、次のようなことです。

  1. 最初のJavaScript関数が文字列をJSグルーコードに渡す
  2. JSグルーコードが文字列を複数の数値に変換した上で、その数値を連続するメモリに配置する
  3. 数値(文字列の先頭へのポインタ)をWebAssemblyに渡す
  4. WebAssembly関数がその数値を、逆方向のJSグルーコードに渡す
  5. 2番目のJavaScript関数がそれらの数値を連続メモリから引き出し、デコードして文字列オブジェクトに戻す
  6. その文字列を2番目のJS関数に与える

つまり、JSグルーコードの一方は、もう一方が行ったことを取り消しているだけなのです。基本的に同じオブジェクトを再生するために、多大な労力が払われていることになります。

Reference Typeでは、複雑なオブジェクト(Clark氏の例では文字列)をexternrefという不透明型(opaque type)としてWebAssemblyモジュールに渡したり、同じようにホスト関数に戻すことが可能になる。先に述べたような、複雑なプロセスを実行する必要はない。

Fitzgerald氏は次のような、オープンされたファイルへの参照を処理するWasmモジュールの例を提供している。

;; hello.wat
(module
  ;; Import the write syscall from a hypothetical (and
  ;; simplified) future version of WASI.
  ;;
  ;; It takes a host reference to an open file, an address
  ;; in memory, and byte length and then writes
  ;; `memory[address..(address+length)]` to the file.
  (import "future-wasi" "write"
    (func $write (param externref i32 i32) (result i32)))
  ;; Define a memory that is one page in size (64KiB).
  (memory (export "memory") 1)
  ;; At offset 0x42 in the memory, define our data string.
  (data (i32.const 0x42) "Hello, Reference Types!\n")
  ;; Define a function that writes our hello string to a
  ;; given open file handle.
  (func (export "hello") (param externref)
    (call $write
      ;; The open file handle we were given.
      (local.get 0)
      ;; The address of our string in memory.
      (i32.const 0x42)
      ;; The length of our string in memory.
      (i32.const 24))
    ;; Ignore the return code.
    drop))

上記のWasmモジュールがエクスポートするhello関数は、ホストの提供するファイルハンドルを使って、ホストの提供するwrite関数をコールする。hello関数の最初のパラメータはparam externrefと記述されていて、local.get 0で取得する。Wasmモジュールは$write関数をインポートしているが、この関数の最初のパラメータ(ファイルハンドル)はexternrefと記述されている。$write関数はexternrefホスト参照と2つのパラメータ(Wasmモジュールのメモリ内にある書き込み文字列の先頭アドレス、文字列の長さ)を持って呼び出される。externrefは提供も利用もホスト環境によってそのまま行われるので、Wasmモジュールで複雑な操作を行う必要はない。

Fitzgerald氏はさらに、前述のWasmモジュールをPython、Rust、あるいはWebAssemb環境で、グルーコードを必要とせずに使用する例も提供している。

wasmtimeは、マシンコードにトランスパイル(JIT形式)したWasmコードを実行するWebAssembly用のスタンドアロンのランタイムで、さまざまなホスト言語(RustCPython.NETGoなど)で使用することができる。wasmtimeを学ぶための出発点が、wasmtime guideとして提供されている。

この記事に星をつける

おすすめ度
スタイル

BT