Node.js v18.20.0 文档


WebAssembly 系统接口 (WASI)#

¥WebAssembly System Interface (WASI)

稳定性: 1 - 实验性的

¥Stability: 1 - Experimental

源代码: lib/wasi.js

WASI API 提供了 WebAssembly 系统接口 规范的实现。WASI 让沙盒化的 WebAssembly 应用通过一系列类似 POSIX 的函数访问底层操作系统。

¥The WASI API provides an implementation of the WebAssembly System Interface specification. WASI gives sandboxed WebAssembly applications access to the underlying operating system via a collection of POSIX-like functions.

import { readFile } from 'node:fs/promises';
import { WASI } from 'wasi';
import { argv, env } from 'node:process';

const wasi = new WASI({
  args: argv,
  env,
  preopens: {
    '/sandbox': '/some/real/path/that/wasm/can/access',
  },
});

// Some WASI binaries require:
//   const importObject = { wasi_unstable: wasi.wasiImport };
const importObject = { wasi_snapshot_preview1: wasi.wasiImport };

const wasm = await WebAssembly.compile(
  await readFile(new URL('./demo.wasm', import.meta.url)),
);
const instance = await WebAssembly.instantiate(wasm, importObject);

wasi.start(instance);'use strict';
const { readFile } = require('node:fs/promises');
const { WASI } = require('wasi');
const { argv, env } = require('node:process');
const { join } = require('node:path');

const wasi = new WASI({
  args: argv,
  env,
  preopens: {
    '/sandbox': '/some/real/path/that/wasm/can/access',
  },
});

// Some WASI binaries require:
//   const importObject = { wasi_unstable: wasi.wasiImport };
const importObject = { wasi_snapshot_preview1: wasi.wasiImport };

(async () => {
  const wasm = await WebAssembly.compile(
    await readFile(join(__dirname, 'demo.wasm')),
  );
  const instance = await WebAssembly.instantiate(wasm, importObject);

  wasi.start(instance);
})();

要运行上面的示例,则新建一个名为 demo.wat 的 WebAssembly 文本格式文件:

¥To run the above example, create a new WebAssembly text format file named demo.wat:

(module
    ;; Import the required fd_write WASI function which will write the given io vectors to stdout
    ;; The function signature for fd_write is:
    ;; (File Descriptor, *iovs, iovs_len, nwritten) -> Returns number of bytes written
    (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))

    (memory 1)
    (export "memory" (memory 0))

    ;; Write 'hello world\n' to memory at an offset of 8 bytes
    ;; Note the trailing newline which is required for the text to appear
    (data (i32.const 8) "hello world\n")

    (func $main (export "_start")
        ;; Creating a new io vector within linear memory
        (i32.store (i32.const 0) (i32.const 8))  ;; iov.iov_base - This is a pointer to the start of the 'hello world\n' string
        (i32.store (i32.const 4) (i32.const 12))  ;; iov.iov_len - The length of the 'hello world\n' string

        (call $fd_write
            (i32.const 1) ;; file_descriptor - 1 for stdout
            (i32.const 0) ;; *iovs - The pointer to the iov array, which is stored at memory location 0
            (i32.const 1) ;; iovs_len - We're printing 1 string stored in an iov - so one.
            (i32.const 20) ;; nwritten - A place in memory to store the number of bytes written
        )
        drop ;; Discard the number of bytes written from the top of the stack
    )
) 

使用 wabt 编译 .wat.wasm

¥Use wabt to compile .wat to .wasm

$ wat2wasm demo.wat 

类:WASI#

¥Class: WASI

WASI 类提供了 WASI 系统调用 API 和其他方便的方法来使用基于 WASI 的应用。每个 WASI 实例代表一个不同的沙箱环境。出于安全考虑,每个 WASI 实例都必须显式地配置其命令行参数、环境变量、以及沙箱目录结构。

¥The WASI class provides the WASI system call API and additional convenience methods for working with WASI-based applications. Each WASI instance represents a distinct sandbox environment. For security purposes, each WASI instance must have its command-line arguments, environment variables, and sandbox directory structure configured explicitly.

new WASI([options])#

  • options <Object>

    • args <Array> WebAssembly 应用将视为命令行参数的字符串数组。第一个参数是 WASI 命令本身的虚拟路径。默认值:[]

      ¥args <Array> An array of strings that the WebAssembly application will see as command-line arguments. The first argument is the virtual path to the WASI command itself. Default: [].

    • env <Object> 类似于 process.env 的对象,WebAssembly 应用将其视为其环境。默认值:{}

      ¥env <Object> An object similar to process.env that the WebAssembly application will see as its environment. Default: {}.

    • preopens <Object> 此对象表示 WebAssembly 应用的沙箱目录结构。preopens 的字符串键被视为沙箱中的目录。preopens 中对应的值是宿主机上这些目录的真实路径。

      ¥preopens <Object> This object represents the WebAssembly application's sandbox directory structure. The string keys of preopens are treated as directories within the sandbox. The corresponding values in preopens are the real paths to those directories on the host machine.

    • returnOnExit <boolean> 默认情况下,WASI 应用通过 __wasi_proc_exit() 函数终止 Node.js 进程。将此选项设置为 true 会导致 wasi.start() 返回退出代码而不是终止进程。默认值:false

      ¥returnOnExit <boolean> By default, WASI applications terminate the Node.js process via the __wasi_proc_exit() function. Setting this option to true causes wasi.start() to return the exit code rather than terminate the process. Default: false.

    • stdin <integer> 在 WebAssembly 应用中用作标准输入的文件描述符。默认值:0

      ¥stdin <integer> The file descriptor used as standard input in the WebAssembly application. Default: 0.

    • stdout <integer> 在 WebAssembly 应用中用作标准输出的文件描述符。默认值:1

      ¥stdout <integer> The file descriptor used as standard output in the WebAssembly application. Default: 1.

    • stderr <integer> 在 WebAssembly 应用中用作标准错误的文件描述符。默认值:2

      ¥stderr <integer> The file descriptor used as standard error in the WebAssembly application. Default: 2.

wasi.start(instance)#

尝试通过调用 _start() 导出来开始执行 instance 作为 WASI 命令。如果 instance 不包含 _start() 导出,或者 instance 包含 _initialize() 导出,则抛出异常。

¥Attempt to begin execution of instance as a WASI command by invoking its _start() export. If instance does not contain a _start() export, or if instance contains an _initialize() export, then an exception is thrown.

start() 要求 instance 导出名为 memoryWebAssembly.Memory。如果 instance 没有 memory 导出,则抛出异常。

¥start() requires that instance exports a WebAssembly.Memory named memory. If instance does not have a memory export an exception is thrown.

如果 start() 被多次调用,则抛出异常。

¥If start() is called more than once, an exception is thrown.

wasi.initialize(instance)#

尝试通过调用 _initialize() 导出(如果存在)将 instance 初始化为 WASI 反应器。如果 instance 包含 _start() 导出,则抛出异常。

¥Attempt to initialize instance as a WASI reactor by invoking its _initialize() export, if it is present. If instance contains a _start() export, then an exception is thrown.

initialize() 要求 instance 导出名为 memoryWebAssembly.Memory。如果 instance 没有 memory 导出,则抛出异常。

¥initialize() requires that instance exports a WebAssembly.Memory named memory. If instance does not have a memory export an exception is thrown.

如果 initialize() 被多次调用,则抛出异常。

¥If initialize() is called more than once, an exception is thrown.

wasi.wasiImport#

wasiImport 是实现 WASI 系统调用 API 的对象。此对象应在 WebAssembly.Instance 实例化期间作为 wasi_snapshot_preview1 导入传入。

¥wasiImport is an object that implements the WASI system call API. This object should be passed as the wasi_snapshot_preview1 import during the instantiation of a WebAssembly.Instance.