Open2

Rust 勉強ログ

mizchimizchi

Rust の wasi ビルドを javascript から実行する

https://fits.hatenablog.com/entry/2020/04/29/210734

cargo new で生成される println するだけのコードを wasi ビルドしてみる。

# wasi とwasmtime の準備
$ cargo install wasi
$ curl https://wasmtime.dev/install.sh -sSf | bash
$ cargo new try-wasi

$ cd try-wasi
$ cargo wasi run     
info: downloading component 'rust-std' for 'wasm32-wasi'
info: installing component 'rust-std' for 'wasm32-wasi'
   Compiling try-wasi v0.1.0 (/Users/mizchi/mizchi/study-rust/try-wasi)
    Finished dev [unoptimized + debuginfo] target(s) in 0.29s
     Running `/Users/mizchi/.cargo/bin/cargo-wasi target/wasm32-wasi/debug/try-wasi.wasm`
     Running `target/wasm32-wasi/debug/try-wasi.wasm`
Hello, world!
$ cargo wasi build

wasi binary を実行する

元の記事を参考に deno で書いた。deno なのはプリミティブな操作しかしないのと、環境構築が楽だから

import { join, dirname } from "https://deno.land/std@0.107.0/path/mod.ts";
const wasmFile = join(
  dirname(new URL(import.meta.url).pathname),
  "target/wasm32-wasi/debug/try-wasi.wasm"
);

const run = async () => {
  const buffer = await Deno.readFile(wasmFile);
  const module = await WebAssembly.compile(buffer);

  let memory: WebAssembly.Memory = null as any;
  const wasiImpl = {
    fd_write: (fd: number, iovs: number, iovsLen: number, nwritten: number) => {
      console.log(
        `*** call fd_write: fd=${fd}, iovs=${iovs}, iovsLen=${iovsLen}, nwritten=${nwritten}`
      );
      const mem = memory.buffer;
      const view = new DataView(mem);

      const sizeList = Array.from(Array(iovsLen), (_, i) => {
        const ptr = iovs + i * 8;
        const bufStart = view.getUint32(ptr, true);
        const bufLen = view.getUint32(ptr + 4, true);
        const buf = new Uint8Array(mem, bufStart, bufLen);
        const msg = new TextDecoder().decode(buf);
        console.log(msg);
        return buf.byteLength;
      });
      const totalSize = sizeList.reduce((acc, v) => acc + v);

      view.setUint32(nwritten, totalSize, true);
      return 0;
    },
    proc_exit: () => {},
    fd_prestat_get: () => {},
    fd_prestat_dir_name: () => {},
    environ_sizes_get: () => {},
    environ_get: () => {},
  };

  const imports = {
    wasi_snapshot_preview1: wasiImpl,
  };
  const instance = await WebAssembly.instantiate(module, imports);
  memory = instance.exports.memory as unknown as WebAssembly.Memory;
  (instance.exports as any).main();
};

run().catch((err) => console.error(err));
$ deno run --allow-read run.ts 
*** call fd_write: fd=1, iovs=1048320, iovsLen=1, nwritten=1048300
Hello, world!