WebAssembly JavaScript 接口

W3C 候选推荐草案,

关于本文件的更多信息
本版本:
https://www.w3.org/TR/2026/CRD-wasm-js-api-2-20261013/
最新发布版本:
https://www.w3.org/TR/wasm-js-api-2/
编辑草案:
https://webassembly.github.io/spec/js-api/
历史记录:
https://www.w3.org/standards/history/wasm-js-api-2/
实现报告:
https://webassembly.org/features/
反馈:
GitHub
规范内标注
编辑者:
Ms2ger (Igalia)
Ryan Hunt (Mozilla 基金会)
问题追踪:
GitHub 问题

摘要

本文档提供了一个用于与 WebAssembly 交互的显式 JavaScript API。

这是相关文档集合的一部分: WebAssembly 核心规范、 WebAssembly JS 接口、 以及 WebAssembly Web API。

本文档状态

本节描述了本文档在 发布时的状态。当前 W3C 出版物列表以及本技术报告的最新修订版 可在 W3C 技术报告 索引 中找到。

本文档由 WebAssembly 工作组 作为候选推荐草案发布,采用了推荐标准轨道。

作为候选推荐发布并不意味着获得 W3C 及其成员的认可。候选推荐草案整合了相较于上一版候选推荐的变更, 这些变更是工作组打算纳入后续候选推荐快照中的内容。

WebAssembly 工作组打算将本出版物维持在候选推荐状态, 并作为“现行标准”持续更新,而不是转入推荐标准状态。

本文档会随时维护和更新。本文档的某些部分仍在进行中。

优先使用 GitHub Issues 来讨论本规范。 所有问题和评论都已 存档。

本文档由 WebAssembly 工作组 制定。

本文档由一个在 W3C 专利政策 下运作的小组制定。 W3C 维护着一份公开列表, 列出与该小组交付成果相关的任何专利披露; 该页面还包含披露专利的说明。 任何实际知晓某项专利且认为该专利包含必要权利要求 的个人, 必须按照W3C 专利政策第 6 节披露相关信息。

本文档受 2025 年 8 月 18 日 W3C 过程文件 约束。

1. 引言

按照设计,WebAssembly 核心规范 [WEBASSEMBLY] 的 范围 不包括描述 WebAssembly 程序如何与其周围执行环境交互。 相反,它定义了 WebAssembly 与其环境之间的抽象嵌入接口, (称为 嵌入器)。 只有通过这个接口,嵌入器才能与 WebAssembly 的语义交互,而 嵌入器负责实现其宿主环境与嵌入 API 之间的连接。 本文档描述了 WebAssembly 嵌入到 JavaScript [ECMASCRIPT] 环境中的方式, 包括如何构造和实例化 WebAssembly 模块、如何调用导入和导出函数、 如何交换数据,以及如何处理错误。 当 JavaScript 环境本身被嵌入到 Web 浏览器中时,Web API 规范 [WASMWEB] 描述了与 Web 环境相关的附加行为。

2. API 用法示例

本节非规范性内容。

给定 demo.wat(编码为 demo.wasm):

(module
    (import "js" "import1" (func $i1))
    (import "js" "import2" (func $i2))
    (func $main (call $i1))
    (start $main)
    (func (export "f") (call $i2))
)

以及下面这段在浏览器中运行的 JavaScript:

var importObj = {js: {
    import1: () => console.log("hello,"),
    import2: () => console.log("world!")
}};
fetch('demo.wasm').then(response =>
    response.arrayBuffer()
).then(buffer =>
    WebAssembly.instantiate(buffer, importObj)
).then(({module, instance}) =>
    instance.exports.f()
);

3. 记法

本规范依赖于 Infra Standard。[INFRA]

WebAssembly 的 序列 类型等同于其中定义的 列表 类型;两者的值 可以透明地相互视为对方的值。

4. 内部存储

4.1. WebAssembly 存储与 JavaScript 的交互

注:WebAssembly 语义是根据一个 抽象的存储来定义的, 它表示 WebAssembly 抽象机器的状态。 WebAssembly 操作接收一个存储并返回一个更新后的存储。

每个 代理 都有一个关联存储。当创建一个新代理时,其关联存储被设为 store_init() 的结果。

注:在本规范中,没有任何与 WebAssembly 相关的 对象、内存或地址可以在一个 代理集群 中的多个代理之间共享。在未来版本的 WebAssembly 中,这一点可能会改变。

WebAssembly 存储中的元素可以与 JavaScript 值对应标识。特别地,每个具有对应 Memory 对象的 WebAssembly 内存实例 都与一个 JavaScript 数据块对应标识;对该数据块的修改等同于将 代理的存储更新为反映这些变更的存储,反之亦然。

4.2. WebAssembly JS 对象缓存

注:有若干 WebAssembly 对象 可能具有对应的 JavaScript 对象。这种对应关系存储在每个代理单独维护的映射中,用于将 WebAssembly 地址映射到 JavaScript 对象。 该映射用于确保,对于给定的 代理,某个特定 WebAssembly 地址至多只存在一个 JavaScript 对象。不过,共享对象不具备这一性质。

每个 代理 都关联有以下有序映射:

5. WebAssembly 命名空间

dictionary WebAssemblyInstantiatedSource {
    required Module module;
    required Instance instance;
};

dictionary WebAssemblyCompileOptions {
    USVString? importedStringConstants = null;
    sequence<USVString> builtins = [];
};

[Exposed=*]
namespace WebAssembly {
    boolean validate([AllowResizable] AllowSharedBufferSource bytes, optional WebAssemblyCompileOptions options = {});
    Promise<Module> compile([AllowResizable] AllowSharedBufferSource bytes, optional WebAssemblyCompileOptions options = {});

    Promise<WebAssemblyInstantiatedSource> instantiate(
        [AllowResizable] AllowSharedBufferSource bytes, optional object importObject, optional WebAssemblyCompileOptions options = {});

    Promise<Instance> instantiate(
        Module moduleObject, optional object importObject);

    readonly attribute Tag JSTag;
};
将源字节 bytes 编译为 WebAssembly 模块时,执行以下步骤:
  1. 设 module 为 module_decode(bytes)。如果 module 是 error,则返回 error。

  2. 如果 module_validate(module) 是 error,则返回 error。

  3. 返回 module。

要验证 WebAssembly 模块的内置功能和导入的 字符串,给定模块 module、已启用的内置功能 builtinSetNames 和 importedStringModule,执行以下步骤:

  1. 如果对 内置功能集名称的验证针对 builtinSetNames 的结果为 false,则返回 false。

  2. 对于每个 import,其来自 module_imports(module),

    1. 如果 importedStringModule 不为 null,且 import[0] 等于 importedStringModule,

      1. 令 importExternType 为 import[2]。

      2. 令 stringExternType 为 global ref extern。

      3. 如果 match_externtype(stringExternType, importExternType) 为 false,则返回 false

    2. 否则,

      1. 如果使用 import 和 builtinSetNames 对导入进行内置功能 验证的结果为 false, 则返回 false。

  3. 返回 true。

validate(bytes, options) 方法 在调用时执行以下步骤:
  1. 设 stableBytes 为缓冲区所持字节的副本 bytes。

  2. 将 stableBytes 编译为 WebAssembly 模块,并将结果存为 module。

  3. 如果 module 是 error,则返回 false。

  4. 设 builtinSetNames 为 options["builtins"]。

  5. 设 importedStringModule 为 options["importedStringConstants"]。

  6. 如果对于 module 以及 builtinSetNames 和 importedStringModule 进行内建项和导入字符串验证 返回 false,则返回 false。

  7. 返回 true。

Module 对象 表示单个 WebAssembly 模块。每个 Module 对象具有以下 内部槽:

从模块 module、源字节 bytes、启用的内建项 builtinSetNames 和 importedStringModule 构造一个 WebAssembly 模块对象时,执行以下步骤:
  1. 设 moduleObject 为一个新的 Module。

  2. 将 moduleObject.[[Module]] 设为 module。

  3. 将 moduleObject.[[Bytes]] 设为 bytes。

  4. 将 moduleObject.[[BuiltinSets]] 设为 builtinSetNames。

  5. 将 moduleObject.[[ImportedStringModule]] 设为 importedStringModule。

  6. 返回 moduleObject。

使用可选的任务源 taskSource, 从源字节 bytes 和 WebAssemblyCompileOptions options 异步编译 WebAssembly 模块时,执行以下步骤:
  1. 设 promise 为一个新的 promise。

  2. 并行运行以下步骤:

    1. 编译 WebAssembly 模块 bytes,并将结果存储为 module。

    2. 如果提供了 taskSource,则在其上排入一个任务,以执行以下步骤:

      1. 如果 module 是错误,则使用 CompileError 异常拒绝 promise,并返回。

      2. 令 builtinSetNames 为 options["builtins"]。

      3. 令 importedStringModule 为 options["importedStringConstants"]。

      4. 如果使用 builtinSetNames 和 importedStringModule 对 module 验证 内置项和导入字符串的结果为 false,则使用 CompileError 异常拒绝 promise。

      5. 否则,

        1. 根据 module、 bytes、builtinSetNames、 importedStringModule 构造一个 WebAssembly 模块对象,并令 moduleObject 为 结果。

        2. 使用 moduleObject 解决 promise。

  3. 返回 promise。

compile(bytes, options) 方法 在调用时执行以下步骤:
  1. 设 stableBytes 为缓冲区所持字节的副本 bytes。

  2. 使用 options 从 stableBytes 异步编译一个 WebAssembly 模块并返回结果。

要使用模块 module 和 importedStringModule 实例化导入的字符串,执行以下步骤:

  1. 断言:importedStringModule 不为 null。

  2. 令 exportsObject 为 OrdinaryObjectCreate(null)。

  3. 对于 module_imports(module) 中的每个(moduleName、componentName、 externtype),

    1. 如果 moduleName 不等于 importedStringModule,则继续。

    2. 令 stringConstant 为 componentName。

    3. 令 status 为 ! CreateDataProperty(exportsObject, stringConstant, stringConstant)。

    4. 断言:status 为 true。

  4. 返回 exportsObject。

要读取导入 从 WebAssembly 模块 module、导入对象 importObject、已启用的内置功能 builtinSetNames 和 importedStringModule,执行以下步骤:
  1. 如果 module_imports(module) 非空,且缺少 importObject,则抛出一个 TypeError 异常。

  2. 令 builtinOrStringImports 为有序映射 «[ ]»。

  3. 对于每个 builtinSetName,其来自 builtinSetNames,

    1. 令 builtinSetQualifiedName 为添加了 "wasm:" 前缀的 builtinSetName

    2. 断言:builtinOrStringImports 不包含 builtinSetQualifiedName

    3. 如果 builtinSetName 不引用内置功能集,则继续。

    4. 令 exportsObject 为使用 builtinSetName 实例化 内置功能集的结果

    5. 将 设置 builtinOrStringImports[builtinSetQualifiedName] 为 exportsObject

  4. 如果 importedStringModule 不为 null,

    1. 令 exportsObject 为使用 module 和 importedStringModule 实例化导入的字符串的结果

    2. 将 设置 builtinOrStringImports[importedStringModule] 为 exportsObject

  5. 令 imports 为 « »。

  6. 对于每个 (moduleName, componentName, externtype),其来自 module_imports(module),

    1. 如果 builtinOrStringImports[moduleName] 存在,

      1. 令 o 为 builtinOrStringImports[moduleName]。

      2. 如果 o 不是对象,或者如果 ? HasProperty(o, componentName) 为 false,

        1. 将 o 设置为 ? Get(importObject, moduleName)。

    2. 否则,

      1. 令 o 为 ? Get(importObject, moduleName)。

    3. 如果 o 不是对象,则抛出一个 TypeError 异常。

    4. 令 v 为 ? Get(o, componentName)。

    5. 如果 externtype 的形式为 func functype,

      1. 如果 IsCallable(v) 为 false,则抛出一个 LinkError 异常。

      2. 如果 v 具有 [[FunctionAddress]] 内部槽,因此是一个导出函数,

        1. 令 funcaddr 为 v 的 [[FunctionAddress]] 内部槽的值。

      3. 否则,

        1. 根据 v 和 functype 创建宿主函数,并令 funcaddr 为 其结果。

        2. 令 index 为 imports 中外部函数的数量 。此值 index 称为 宿主函数的索引 funcaddr。

      4. 令 externfunc 为外部值 func funcaddr。

      5. 将 externfunc 追加到 imports。

    6. 如果 externtype 的形式为 global mut valtype,

      1. 如果 v 实现了 Global,

        1. 令 globaladdr 为 v.[[Global]]。

      2. 否则,

        1. 如果 valtype 为 i64,且 v 不是 BigInt,

          1. 抛出一个 LinkError 异常。

        2. 如果 valtype 为 i32、f32 或 f64 之一,且 v 不是 Number,

          1. 抛出一个 LinkError 异常。

        3. 如果 valtype 为 v128,

          1. 抛出一个 LinkError 异常。

        4. 令 value 为 ToWebAssemblyValue(v, valtype)。如果此操作抛出一个 TypeError, 则捕获该异常,并抛出一个 LinkError 异常。

        5. 令 store 为周围代理的关联存储。

        6. 令 (store, globaladdr) 为 global_alloc(store, valtype, value)。

        7. 将周围代理的关联存储设置为 store。

      3. 令 externglobal 为 global globaladdr。

      4. 将 externglobal 追加到 imports。

    7. 如果 externtype 的形式为 mem memtype,

      1. 如果 v 没有实现 Memory, 则抛出一个 LinkError 异常。

      2. 令 externmem 为外部值 mem v.[[Memory]]。

      3. 将 externmem 追加到 imports。

    8. 如果 externtype 的形式为 table tabletype,

      1. 如果 v 没有实现 Table, 则抛出一个 LinkError 异常。

      2. 令 tableaddr 为 v.[[Table]]。

      3. 令 externtable 为外部值 table tableaddr。

      4. 将 externtable 追加到 imports。

    9. 如果 externtype 的形式为 tag functype,

      1. 如果 v 没有实现 Tag, 则抛出一个 LinkError 异常。

      2. 令 tagaddr 为 v.[[Address]]。

      3. 令 externtag 为外部值 tag tagaddr。

      4. 将 externtag 追加到 imports。

  7. 返回 imports。

注:此算法仅验证传入的 JavaScript 值是否属于正确的 类型。 WebAssembly 类型要求的验证则推迟到 “实例化 WebAssembly 模块的核心 部分”算法中进行。

要从 WebAssembly 模块 module 和实例 instance 创建一个 导出对象, 执行以下步骤:
  1. 令 exportsObject 为 OrdinaryObjectCreate(null)。

  2. 对于每个 (name, externtype),其来自 module_exports(module),

    1. 令 externval 为 instance_export(instance, name)。

    2. 断言:externval 不是 error。

    3. 如果 externtype 的形式为 func functype,

      1. 断言:externval 的形式为 func funcaddr。

      2. 令 func funcaddr 为 externval。

      3. 令 func 为根据 funcaddr 创建一个新的 导出函数的结果。

      4. 令 value 为 func。

    4. 如果 externtype 的形式为 global mut globaltype,

      1. 断言:externval 的形式为 global globaladdr。

      2. 令 global globaladdr 为 externval。

      3. 令 global 为根据 globaladdr 创建的一个新的 Global 对象 。

      4. 令 value 为 global。

    5. 如果 externtype 的形式为 mem memtype,

      1. 断言:externval 的形式为 mem memaddr。

      2. 令 mem memaddr 为 externval。

      3. 令 memory 为根据 memaddr 创建的一个新的 Memory 对象 。

      4. 令 value 为 memory。

    6. 如果 externtype 的形式为 table tabletype,

      1. 断言:externval 的形式为 table tableaddr。

      2. 令 table tableaddr 为 externval。

      3. 令 table 为根据 tableaddr 创建的一个新的 Table 对象 。

      4. 令 value 为 table。

    7. 如果 externtype 的形式为 tag functype,

      1. 断言:externval 的形式为 tag tagaddr。

      2. 令 tag tagaddr 为 externval。

      3. 令 tag 为根据 tagaddr 创建的一个新的 Tag 对象 。

      4. 令 value 为 tag。

    8. 令 status 为 ! CreateDataProperty(exportsObject, name, value)。

    9. 断言:status 为 true。

    注:在 WebAssembly 模块验证期间执行的有效性和唯一性检查确保每个属性名称 都是有效的,并且没有属性被重复定义。

  3. 执行 ! SetIntegrityLevel(exportsObject, "frozen")。

  4. 返回 exportsObject。

要使用 WebAssembly 模块 module 和实例 instance 初始化 实例对象 instanceObject, 执行以下步骤:
  1. 从 module 和 instance 创建导出对象, 并令 exportsObject 为其结果。

  2. 将 instanceObject.[[Instance]] 设置为 instance。

  3. 将 instanceObject.[[Exports]] 设置为 exportsObject。

要从模块 module 和导入项 imports 实例化 WebAssembly 模块的核心部分,执行以下步骤:
  1. 令 store 为外围代理的关联存储。

  2. 令(store,result)为 module_instantiate(store, module, imports)。

  3. 如果 result 为 error,则抛出适当的异常类型:

    • 对于链接期间发生的大多数情况,抛出 LinkError 异常。

    • 如果错误发生在运行启动函数时,对于源自 WebAssembly 的大多数错误,抛出 RuntimeError; 或者抛出从内部 ECMAScript 代码传播出来的错误对象。

    • 如果适用,则抛出其他错误类型,例如内存不足异常,如 WebAssembly 错误映射中所述。

  4. 将外围代理的关联存储设置为 store。

  5. 返回 result。

要根据 Module moduleObject 和导入 importObject 异步实例化 WebAssembly 模块,执行以下步骤:
  1. 令 promise 为一个新的 promise。

  2. 令 module 为 moduleObject.[[Module]]。

  3. 令 builtinSetNames 为 moduleObject.[[BuiltinSets]]。

  4. 令 importedStringModule 为 moduleObject.[[ImportedStringModule]]。

  5. 使用导入 importObject、 builtinSetNames 和 importedStringModule 读取 module 的导入,并令 imports 为 结果。 如果此操作抛出异常,则捕获它,使用该异常拒绝 promise,并返回 promise。

  6. 并行运行以下步骤:

    1. 排入一个任务以执行以下步骤: 注意:可以在此处执行特定于实现的工作。

      1. 使用 imports 实例化 WebAssembly 模块的核心 module, 并令 instance 为结果。 如果这抛出异常,则捕获它,使用该异常拒绝 promise,并 终止这些子步骤。

      2. 令 instanceObject 为一个新的 Instance。

      3. 根据 module 和 instance 初始化 instanceObject。 如果这抛出异常,则捕获它,使用该异常拒绝 promise,并 终止这些子步骤。

      4. 使用 instanceObject 解决 promise。

  7. 返回 promise。

要使用导入 importObject 实例化模块的 promise promiseOfModule,执行以下步骤:
  1. 令 promise 为一个新的 promise。

  2. 对 promiseOfModule 作出反应:

    • 如果 promiseOfModule 已以值 module 兑现:

      1. 使用导入 importObject 实例化 WebAssembly 模块 module, 并令 innerPromise 为结果。

      2. 对 innerPromise 作出反应:

    • 如果 promiseOfModule 已以原因 reason 被拒绝:

      1. 使用 reason 拒绝 promise。

  3. 返回 promise。

instantiate(bytes, importObject, options) 方法在调用时执行以下步骤:
  1. 令 stableBytes 为缓冲区 bytes 所保存字节的副本。

  2. 使用 options 根据 stableBytes 异步编译 WebAssembly 模块,并令 promiseOfModule 为结果。

  3. 使用导入 importObject 实例化 promiseOfModule 并返回结果。

instantiate(moduleObject, importObject) 方法在调用时执行以下步骤:
  1. 使用导入 importObject 异步实例化 WebAssembly 模块 moduleObject,并返回 结果。

注意:后续的流式 API 记录在 WebAssembly Web API 中。

WebAssembly Namespace 的 JSTag 属性的 getter 在调用时执行以下步骤:

  1. 令 JSTagAddr 为获取 JavaScript 异常 tag的结果。

  2. 令 JSTagObject 为根据 JSTagAddr 创建 Tag 对象的结果。

  3. 返回 JSTagObject。

5.1. 模块

enum ImportExportKind {
  "function",
  "table",
  "memory",
  "global",
  "tag"
};

enum AddressType {
  "i32",
  "i64",
};

typedef any AddressValue;

dictionary ModuleExportDescriptor {
  required USVString name;
  required ImportExportKind kind;
  // Note: Other fields such as signature may be added in the future.
};

dictionary ModuleImportDescriptor {
  required USVString module;
  required USVString name;
  required ImportExportKind kind;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Module {
  constructor([AllowResizable] AllowSharedBufferSource bytes, optional WebAssemblyCompileOptions options = {});
  static sequence<ModuleExportDescriptor> exports(Module moduleObject);
  static sequence<ModuleImportDescriptor> imports(Module moduleObject);
  static sequence<ArrayBuffer> customSections(Module moduleObject, DOMString sectionName);
};
外部类型的字符串 值 type 为
exports(moduleObject) 方法在调用时, 执行以下步骤:
  1. 设 module 为 moduleObject.[[Module]]。

  2. 设 exports 为 « »。

  3. 对 module_exports(module) 中的每个 (name, type),逐一执行:

    1. 设 kind 为该 type 的外部类型字符串值。

    2. 设 obj 为 «[ "name" → name, "kind" → kind ]»。

    3. 将 obj 追加到 exports。

  4. 返回 exports。

imports(moduleObject) 方法在调用时, 执行以下步骤:
  1. 设 module 为 moduleObject.[[Module]]。

  2. 设 builtinSetNames 为 moduleObject.[[BuiltinSets]]。

  3. 设 importedStringModule 为 moduleObject.[[ImportedStringModule]]。

  4. 设 imports 为 « »。

  5. 对 module_imports(module) 中的每个 (moduleName, name, type),逐一执行:

    1. 如果对于 (moduleName, name, type) 在 builtinSetNames 中找到一个内建项, 且 builtinSetNames 不为 null,则继续。

    2. 如果 importedStringModule 不为 null 且 moduleName 等于 importedStringModule,则继续。

    3. 设 kind 为该 type 的外部类型字符串值。

    4. 设 obj 为 «[ "module" → moduleName, "name" → name, "kind" → kind ]»。

    5. 将 obj 追加到 imports。

  6. 返回 imports。

customSections(moduleObject, sectionName) 方法在调用时执行以下步骤:
  1. 设 bytes 为 moduleObject.[[Bytes]]。

  2. 设 customSections 为 « »。

  3. 对按照模块语法解释的 bytes 中每个 自定义段 customSection,逐一执行,

    1. 设 name 为 customSection 的 name, 按 UTF-8 解码。

    2. 断言:name 不是 failure (moduleObject.[[Module]] 是有效的)。

    3. 如果 name 作为字符串值等于 sectionName,

      1. 将一个新的 ArrayBuffer 追加到 customSections,该缓冲区包含 bytes 中与此 customsec 产生式匹配范围内字节的副本。

  4. 返回 customSections。

Module(bytes, options) 构造函数在 调用时执行以下步骤:
  1. 设 stableBytes 为缓冲区所持字节的副本 bytes。

  2. 将 stableBytes 编译为 WebAssembly 模块, 并将结果存为 module。

  3. 如果 module 是 error,则抛出一个 CompileError 异常。

  4. 设 builtinSetNames 为 options["builtins"]。

  5. 设 importedStringModule 为 options["importedStringConstants"]。

  6. 如果对于 module 以及 builtinSetNames 和 importedStringModule 的内建项和导入字符串验证返回 false,则抛出一个 CompileError 异常。

  7. 将 this.[[Module]] 设为 module。

  8. 将 this.[[Bytes]] 设为 stableBytes。

  9. 将 this.[[BuiltinSets]] 设为 builtinSetNames。

  10. 将 this.[[ImportedStringModule]] 设为 importedStringModule。

注:某些实现会对 bytes 强制施加大小限制。相比之下,更推荐使用异步 API, 不鼓励使用此 API。

5.2. 实例

[LegacyNamespace=WebAssembly, Exposed=*]
interface Instance {
  constructor(Module module, optional object importObject);
  readonly attribute object exports;
};
Instance(moduleObject, importObject) 构造函数在调用时运行以下步骤:
  1. 设 builtinSetNames 为 moduleObject.[[BuiltinSets]]。

  2. 设 importedStringModule 为 moduleObject.[[ImportedStringModule]]。

  3. 设 module 为 moduleObject.[[Module]]。

  4. 使用导入 importObject、 builtinSetNames 和 importedStringModule 对 module 读取 导入,并将结果记为 imports。

  5. 用 imports 对 module 实例化 WebAssembly 模块的核心,并将 instance 记为结果。

  6. 从 module 和 instance 初始化 this。

注:不鼓励使用此同步 API, 因为某些实现有时会在实例化期间执行耗时较长的编译工作。

Instance 的 exports 属性的 getter 返回 this.[[Exports]]。

5.3. 内存

dictionary MemoryDescriptor {
  required AddressValue initial;
  AddressValue maximum;
  AddressType address;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Memory {
  constructor(MemoryDescriptor descriptor);
  AddressValue grow(AddressValue delta);
  ArrayBuffer toFixedLengthBuffer();
  ArrayBuffer toResizableBuffer();
  readonly attribute ArrayBuffer buffer;
};

Memory 对象 表示一个单独的内存实例, 它可以同时被多个 Instance 对象引用。 每个 Memory 对象具有 以下内部槽:

要从一个内存地址 memaddr 创建固定长度内存缓冲区,执行以下步骤:
  1. 设 block 为一个 Data Block,其与 memaddr 的底层 内存对应标识。

  2. 设 buffer 为一个新的 ArrayBuffer, 带有内部槽 [[ArrayBufferData]]、[[ArrayBufferByteLength]] 和 [[ArrayBufferDetachKey]]。

  3. 将 buffer.[[ArrayBufferData]] 设为 block。

  4. 将 buffer.[[ArrayBufferByteLength]] 设为 block 的长度。

  5. 将 buffer.[[ArrayBufferDetachKey]] 设为 "WebAssembly.Memory"。

  6. 返回 buffer。

要从一个内存地址 memaddr 和一个 maxsize 创建可调整大小的 内存缓冲区,执行以下步骤:
  1. 设 block 为一个 Data Block,其与 memaddr 的底层 内存对应标识。

  2. 设 length 为 block 的长度。

  3. 设 buffer 为一个新的 ArrayBuffer, 带有内部槽 [[ArrayBufferData]]、[[ArrayBufferByteLength]]、 [[ArrayBufferMaxByteLength]] 和 [[ArrayBufferDetachKey]]。

  4. 将 buffer.[[ArrayBufferData]] 设为 block。

  5. 将 buffer.[[ArrayBufferByteLength]] 设为 length。

  6. 将 buffer.[[ArrayBufferMaxByteLength]] 设为 maxsize。

  7. 将 buffer.[[ArrayBufferDetachKey]] 设为 "WebAssembly.Memory"。

  8. 返回 buffer。

要从一个内存地址 memaddr 初始化一个 Memory 对象 memory,执行以下步骤:
  1. 设 map 为外围代理关联的 Memory 对象缓存。

  2. 断言:map[memaddr] 不存在。

  3. 设 buffer 为通过创建固定长度内存缓冲区 从 memaddr 得到的结果。

  4. 将 memory.[[Memory]] 设为 memaddr。

  5. 将 memory.[[BufferObject]] 设为 buffer。

  6. 设定 map[memaddr] 为 memory。

要从一个内存地址 memaddr 创建一个 Memory 对象,执行以下步骤:
  1. 设 map 为外围代理关联的 Memory 对象缓存。

  2. 如果 map[memaddr] 存在,

    1. 返回 map[memaddr]。

  3. 设 memory 为一个新的 Memory。

  4. 初始化 memory,来源为 memaddr。

  5. 返回 memory。

调用 Memory(descriptor) 构造函数时, 执行以下步骤:
  1. 如果 descriptor["address"] 存在,则令 addrtype 为 ToValueType(descriptor["address"]);否则,令 addrtype 为 i32。

  2. 令 initial 为 ? AddressValueToU64(descriptor["initial"], addrtype)。

  3. 如果 descriptor["maximum"] 存在,则令 maximum 为 ? AddressValueToU64(descriptor["maximum"], addrtype);否则,令 maximum 为空。

  4. 令 memtype 为内存类型 addrtype [initial .. maximum] page。

  5. 如果 memtype 无效,则抛出一个 RangeError 异常。

  6. 令 store 为周围代理的关联存储。

  7. 令 (store, memaddr) 为 mem_alloc(store, memtype)。如果 分配失败,则抛出一个 RangeError 异常。

  8. 将周围代理的关联存储设置为 store。

  9. 初始化 this,使用 memaddr。

要刷新 Memory 缓冲区,针对 memaddr 执行以下步骤:
  1. 令 map 为周围代理所关联的Memory 对象缓存。

  2. 断言:map[memaddr] 存在。

  3. 令 memory 为 map[memaddr]。

  4. 令 buffer 为 memory.[[BufferObject]]。

  5. 如果 IsFixedLengthArrayBuffer(buffer) 为 true,

    1. 执行 ! DetachArrayBuffer(buffer, "WebAssembly.Memory")。

    2. 令 buffer 为根据 memaddr 创建固定长度内存 缓冲区的结果。

    3. 将 memory.[[BufferObject]] 设置为 buffer。

  6. 否则,

    1. 令 block 为一个数据块,它被标识为与 memaddr 的底层内存相同。

    2. 将 buffer.[[ArrayBufferData]] 设置为 block。

    3. 将 buffer.[[ArrayBufferByteLength]] 设置为 block 的长度。

要扩展内存 缓冲区,该缓冲区与内存地址 memaddr 关联,扩展量为 delta,执行 以下步骤:
  1. 令 store 为周围代理的关联存储。

  2. 令 ret 为 mem_size(store, memaddr)。

  3. 令 store 为 mem_grow(store, memaddr, delta)。

  4. 如果 store 为 error,则抛出一个 RangeError 异常。

  5. 将周围代理的关联存储设置为 store。

  6. 刷新内存缓冲区,其关联地址为 memaddr。

  7. 返回 ret。

调用 grow(delta) 方法时,执行 以下步骤:
  1. 令 memaddr 为 this.[[Memory]]。

  2. 令 store 为周围代理的关联存储。

  3. 令 (addrtype, limits) 为 mem_type(store, memaddr)。

  4. 令 delta64 为 ? AddressValueToU64(delta, addrtype)。

  5. 令 ret 为扩展内存缓冲区的结果,该缓冲区与 memaddr 关联,扩展量为 delta64。

  6. 返回 U64ToAddressValue(ret, addrtype)。

在 WebAssembly memory.grow x 指令执行后立即执行以下 步骤:

  1. 如果栈顶不是 i32.const (−1),且栈顶不是 i64.const (−1),

    1. 令 frame 为当前帧。

    2. 断言:由于验证,frame.module.memaddrs[x] 存在。

    3. 令 memaddr 为内存地址 frame.module.memaddrs[x]。

    4. 刷新 memaddr 的内存缓冲区。

toFixedLengthBuffer() 方法在调用时, 执行以下步骤:
  1. 令 buffer 为 this.[[BufferObject]]。

  2. 如果 IsFixedLengthArrayBuffer(buffer) 为 true,则返回 buffer。

  3. 令 memaddr 为 this.[[Memory]]。

  4. 令 fixedBuffer 为从 memaddr 创建固定长度内存缓冲区 的结果。

  5. 执行 ! DetachArrayBuffer(buffer, "WebAssembly.Memory")。

  6. 将 this.[[BufferObject]] 设置为 fixedBuffer。

  7. 返回 fixedBuffer。

toResizableBuffer() 方法在调用时,执行 以下步骤:
  1. 令 memaddr 为 this.[[Memory]]。

  2. 令 store 为周围代理的关联存储。

  3. 令 memtype 为 mem_type(store, memaddr)。

  4. 如果 memtype 没有 max,

    1. 抛出 TypeError 异常。

  5. 令 buffer 为 this.[[BufferObject]]。

  6. 如果 IsFixedLengthArrayBuffer(buffer) 为 false,则返回 buffer。

  7. 断言:memtype 具有 max。

  8. 令 maxsize 为 memtype 中的 max 值 * 65536。

  9. 令 resizableBuffer 为从 memaddr 和 maxsize 创建可调整大小的内存缓冲区的结果 。

  10. 执行 ! DetachArrayBuffer(buffer, "WebAssembly.Memory")。

  11. 将 this.[[BufferObject]] 设置为 resizableBuffer。

  12. 返回 resizableBuffer。

由 Memory 对象返回的 ArrayBuffer 对象的大小必须是 WebAssembly 页 大小(常量 65536)的倍数。因此,HostResizeArrayBuffer 被重新定义如下。

抽象 操作 HostResizeArrayBuffer 接受参数 buffer(一个 ArrayBuffer) 和 newLength。调用时,它执行以下步骤。

  1. 如果 buffer.[[ArrayBufferDetachKey]] 为 "WebAssembly.Memory",

    1. 令 map 为周围代理的关联Memory 对象缓存。

    2. 断言:buffer 恰好是 map 中一个值的 [[BufferObject]] 。

    3. 对于 map 中的每个 memaddr → mem,

      1. 如果 SameValue(mem.[[BufferObject]], buffer) 为 true,

        1. 断言:buffer.[[ArrayBufferByteLength]] 模 65536 为 0。

        2. 令 lengthDelta 为 newLength - buffer.[[ArrayBufferByteLength]]。

        3. 如果 lengthDelta < 0 或 lengthDelta 模 65536 不为 0,

          1. 抛出 RangeError 异常。

        4. 令 delta 为 lengthDelta ÷ 65536。

        5. 将与 memaddr 关联的内存缓冲区增长 delta。

    4. 返回 handled。

  2. 否则,返回 unhandled。

Memory 的 buffer 属性的 getter 返回 this.[[BufferObject]]。

5.4. 表

enum TableKind {
  "externref",
  "anyfunc",
  // 注:未来迭代中可能会增加更多值,
  // 例如,带类型的函数引用、带类型的 GC 引用
};

dictionary TableDescriptor {
  required TableKind element;
  required AddressValue initial;
  AddressValue maximum;
  AddressType address;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Table {
  constructor(TableDescriptor descriptor, optional any value);
  AddressValue grow(AddressValue delta, optional any value);
  any get(AddressValue index);
  undefined set(AddressValue index, optional any value);
  readonly attribute AddressValue length;
};

Table 对象 表示一个单独的表实例,它可以同时被 多个 Instance 对象引用。 每个 Table 对象具有 一个 [[Table]] 内部槽,它是一个 表地址。

要从一个表地址 tableaddr 初始化一个 Table 对象 table,执行以下步骤:
  1. 设 map 为外围代理关联的 Table 对象缓存。

  2. 断言:map[tableaddr] 不存在。

  3. 将 table.[[Table]] 设为 tableaddr。

  4. 设定 map[tableaddr] 为 table。

要从一个表地址 tableaddr 创建一个表 对象,执行以下步骤:
  1. 设 map 为外围代理关联的 Table 对象缓存。

  2. 如果 map[tableaddr] 存在,

    1. 返回 map[tableaddr]。

  3. 设 table 为一个新的 Table。

  4. 初始化 table,来源为 tableaddr。

  5. 返回 table。

调用 Table(descriptor, value) 构造函数时, 执行以下步骤:
  1. 令 elementtype 为 ToValueType(descriptor["element"])。

  2. 如果 elementtype 不是 reftype,

    1. 抛出一个 TypeError 异常。

  3. 如果 descriptor["address"] 存在,则令 addrtype 为 ToValueType(descriptor["address"]);否则,令 addrtype 为 i32。

  4. 令 initial 为 ? AddressValueToU64(descriptor["initial"], addrtype)。

  5. 如果 descriptor["maximum"] 存在,则令 maximum 为 ? AddressValueToU64(descriptor["maximum"], addrtype);否则,令 maximum 为空。

  6. 令 type 为表类型 addrtype [initial .. maximum] elementtype。

  7. 如果 type 无效,则抛出一个 RangeError 异常。

  8. 如果缺少 value,

    1. 令 ref 为 DefaultValue(elementtype)。

    2. 断言:ref 不是 error。

  9. 否则,

    1. 令 ref 为 ? ToWebAssemblyValue(value, elementtype)。

  10. 令 store 为周围代理的关联存储。

  11. 令 (store, tableaddr) 为 table_alloc(store, type, ref)。如果分配失败,则抛出一个 RangeError 异常。

  12. 将周围代理的关联存储设置为 store。

  13. 使用 tableaddr 初始化 this 。

调用 grow(delta, value) 方法时, 执行以下步骤:
  1. 令 tableaddr 为 this.[[Table]]。

  2. 令 store 为周围代理的关联存储。

  3. 令 initialSize 为 table_size(store, tableaddr)。

  4. 令 (addrtype, limits, elementtype) 为 table_type(store, tableaddr)。

  5. 令 delta64 为 ? AddressValueToU64(delta, addrtype)。

  6. 如果缺少 value,

    1. 令 ref 为 DefaultValue(elementtype)。

    2. 如果 ref 为 error,则抛出一个 TypeError 异常。

  7. 否则,

    1. 令 ref 为 ? ToWebAssemblyValue(value, elementtype)。

  8. 令 result 为 table_grow(store, tableaddr, delta64, ref)。

  9. 如果 result 为 error,则抛出一个 RangeError 异常。

    注:上述异常可能是由于 内存不足或大小参数无效而发生的。

  10. 将周围代理的关联存储设置为 result。

  11. 返回 U64ToAddressValue(initialSize, addrtype)。

调用 Table 的 length 属性的获取器时, 执行以下步骤:
  1. 令 tableaddr 为 this.[[Table]]。

  2. 令 store 为周围代理的关联存储。

  3. 令 (addrtype, limits, elementtype) 为 table_type(store, tableaddr)。

  4. 令 length64 为 table_size(store, tableaddr)。

  5. 返回 U64ToAddressValue(length64, addrtype)。

调用 get(index) 方法时,执行以下 步骤:
  1. 令 tableaddr 为 this.[[Table]]。

  2. 令 store 为周围代理的关联存储。

  3. 令 (addrtype, limits, elementtype) 为 table_type(store, tableaddr)。

  4. 如果 elementtype 匹配 exnref,

    1. 抛出一个 TypeError 异常。

  5. 令 index64 为 ? AddressValueToU64(index, addrtype)。

  6. 令 result 为 table_read(store, tableaddr, index64)。

  7. 如果 result 为 error,则抛出一个 RangeError 异常。

  8. 返回 ToJSValue(result)。

调用 set(index, value) 方法时, 执行以下步骤:
  1. 令 tableaddr 为 this.[[Table]]。

  2. 令 store 为周围代理的关联存储。

  3. 令 (addrtype, limits, elementtype) 为 table_type(store, tableaddr)。

  4. 如果 elementtype 匹配 exnref,

    1. 抛出一个 TypeError 异常。

  5. 令 index64 为 ? AddressValueToU64(index, addrtype)。

  6. 如果缺少 value,

    1. 令 ref 为 DefaultValue(elementtype)。

    2. 如果 ref 为 error,则抛出一个 TypeError 异常。

  7. 否则,

    1. 令 ref 为 ? ToWebAssemblyValue(value, elementtype)。

  8. 令 store 为 table_write(store, tableaddr, index64, ref)。

  9. 如果 store 为 error,则抛出一个 RangeError 异常。

  10. 将周围代理的关联存储设置为 store。

5.5. 全局

enum ValueType {
  "i32",
  "i64",
  "f32",
  "f64",
  "v128",
  "externref",
  "anyfunc",
};

注:此类型在未来版本的 WebAssembly 中 可能会扩展更多情况。

dictionary GlobalDescriptor {
  required ValueType value;
  boolean mutable = false;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Global {
  constructor(GlobalDescriptor descriptor, optional any v);
  any valueOf();
  attribute any value;
};

Global 对象 表示一个单独的全局实例, 它可以同时被多个 Instance 对象引用。 每个 Global 对象具有 一个内部槽:

要从一个全局地址 globaladdr 初始化一个 Global 对象 global,执行以下步骤:
  1. 设 map 为外围代理关联的 Global 对象缓存。

  2. 断言:map[globaladdr] 不存在。

  3. 将 global.[[Global]] 设为 globaladdr。

  4. 设定 map[globaladdr] 为 global。

要从一个全局地址 globaladdr 创建一个全局 对象,执行以下步骤:
  1. 设 map 为外围代理关联的 Global 对象缓存。

  2. 如果 map[globaladdr] 存在,

    1. 返回 map[globaladdr]。

  3. 设 global 为一个新的 Global。

  4. 初始化 global,来源为 globaladdr。

  5. 返回 global。

算法 ToValueType(s) 执行以下步骤:
  1. 如果 s 等于 "i32",则返回 i32。

  2. 如果 s 等于 "i64",则返回 i64。

  3. 如果 s 等于 "f32",则返回 f32。

  4. 如果 s 等于 "f64",则返回 f64。

  5. 如果 s 等于 "v128",则返回 v128。

  6. 如果 s 等于 "anyfunc",则返回 funcref。

  7. 如果 s 等于 "externref",则返回 externref。

  8. 断言:不会执行到此步骤。

算法 DefaultValue(valuetype) 执行以下步骤:
  1. 如果 valuetype 等于 externref,则返回 ! ToWebAssemblyValue(undefined, valuetype)。

  2. 返回 val_default(valuetype)。

调用 Global(descriptor, v) 构造函数时, 执行以下步骤:
  1. 令 mutable 为 descriptor["mutable"]。

  2. 令 valuetype 为 ToValueType(descriptor["value"])。

  3. 如果 valuetype 匹配 v128 或 exnref,

    1. 抛出一个 TypeError 异常。

  4. 如果缺少 v,

    1. 令 value 为 DefaultValue(valuetype)。

    2. 断言:value 不是 error。

  5. 否则,

    1. 令 value 为 ? ToWebAssemblyValue(v, valuetype)。

  6. 如果 mutable 为 true,则令 globaltype 为 mut valuetype;否则,令 globaltype 为 valuetype。

  7. 令 store 为周围代理的关联存储。

  8. 令 (store, globaladdr) 为 global_alloc(store, globaltype, value)。

  9. 将周围代理的关联存储设置为 store。

  10. 使用 globaladdr 初始化 this 。

算法 GetGlobalValue(Global global) 执行以下步骤:
  1. 令 store 为周围代理的关联存储。

  2. 令 globaladdr 为 global.[[Global]]。

  3. 令 globaltype 为 global_type(store, globaladdr)。

  4. 如果 globaltype 的形式为 mut valuetype,其中 valuetype 匹配 v128 或 exnref,则抛出一个 TypeError。

  5. 令 value 为 global_read(store, globaladdr)。

  6. 返回 ToJSValue(value)。

调用 Global 的 value 属性的获取器时, 执行以下步骤:
  1. 返回 GetGlobalValue(this)。

调用 Global 的 value 属性的设置器时, 执行以下步骤:
  1. 令 store 为周围代理的关联存储。

  2. 令 globaladdr 为 this.[[Global]]。

  3. 令 mut valuetype 为 global_type(store, globaladdr)。

  4. 如果 valuetype 匹配 v128 或 exnref,则抛出一个 TypeError。

  5. 如果 mut 为空,则抛出一个 TypeError。

  6. 令 value 为 ? ToWebAssemblyValue(给定值, valuetype)。

  7. 令 store 为 global_write(store, globaladdr, value)。

  8. 如果 store 为 error,则抛出一个 RangeError 异常。

  9. 将周围代理的关联存储设置为 store。

调用 valueOf() 方法时,执行以下步骤:
  1. 返回 GetGlobalValue(this)。

5.6. 导出函数

WebAssembly 函数在 JavaScript 中以导出函数的形式提供。 导出函数是内建函数对象,它们不是构造器,并且 具有 [[FunctionAddress]] 内部槽。 该槽保存了一个相对于外围代理关联存储的函数地址。

WebAssembly 函数名称 funcaddr 通过执行以下步骤找到:
  1. 令 store 为周围代理的关联存储。

  2. 令 funcinst 为 store.funcs[funcaddr]。

  3. 如果 funcinst 的形式为 {type functype, hostcode hostfunc},

    1. 断言:hostfunc 是 JavaScript 对象且 IsCallable(hostfunc) 为 true。

    2. 令 index 为 funcaddr 的宿主函数索引 。

  4. 否则,

    1. 令 moduleinst 为 funcinst.module。

    2. 断言:funcaddr 包含在 moduleinst.funcs 中。

    3. 令 index 为在 moduleinst.funcs 中找到 funcaddr 的索引。

  5. 返回 ! ToString(index)。

要根据 WebAssembly 函数地址 funcaddr 创建一个新的 导出函数,执行以下步骤:
  1. 令 map 为周围代理所关联的导出函数 缓存。

  2. 如果 map[funcaddr] 存在,

    1. 返回 map[funcaddr]。

  3. 令 steps 为“调用导出函数 funcaddr 并传入参数。”

  4. 令 realm 为当前 Realm。

  5. 令 store 为周围代理的关联存储。

  6. 令 functype 为 func_type(store, funcaddr)。

  7. 令 func paramTypes → resultTypes 为 functype 的展开结果。

  8. 令 arity 为 paramTypes 的大小。

  9. 令 name 为 WebAssembly 函数的名称 funcaddr。

  10. 令 function 为 CreateBuiltinFunction(steps, arity, name, « [[FunctionAddress]] », realm)。

  11. 将 function.[[FunctionAddress]] 设置为 funcaddr。

  12. 将 设置 map[funcaddr] 为 function。

  13. 返回 function。

要调用一个 导出函数,给定函数地址 funcaddr 和 JavaScript 参数列表 argValues,执行以下步骤:
  1. 令 store 为周围代理的关联存储。

  2. 令 functype 为 func_type(store, funcaddr)。

  3. 令 func parameters → results 为 functype 的展开结果。

  4. 如果 parameters 或 results 中的任何类型匹配 v128 或 exnref,则抛出一个 TypeError。

    注:每次 调用 [[Call]] 方法时都会抛出上述错误。

  5. 令 args 为 « »。

  6. 令 i 为 0。

  7. 对于每个 parameters 中的 t,

    1. 如果 argValues 的大小 > i,则令 arg 为 argValues[i]。

    2. 否则,令 arg 为 undefined。

    3. 将 追加 ? ToWebAssemblyValue(arg, t) 到 args。

    4. 将 i 设置为 i + 1。

  8. 令 (store, ret) 为 func_invoke(store, funcaddr, args) 的结果。

  9. 将周围代理的关联存储设置为 store。

  10. 如果 ret 为 error,则抛出异常。该异常应为 WebAssembly RuntimeError 异常,除非WebAssembly 错误映射另有规定。

  11. 如果 ret 的形式为 exception exnaddr,则

    1. 令 tagaddr 为 exn_tag(store, exnaddr)。

    2. 令 payload 为 exn_read(store, exnaddr)。

    3. 令 jsTagAddr 为获取 JavaScript 异常 标签的结果。

    4. 如果 tagaddr 等于 jsTagAddr,

      1. 抛出 ToJSValue(payload[0])。

    5. 否则,

      1. 令 exception 为根据 exnaddr 创建的一个 新的 Exception 对象。

      2. 抛出 exception。

  12. 令 outArity 为 ret 的大小。

  13. 如果 outArity 为 0,则返回 undefined。

  14. 否则,如果 outArity 为 1,则返回 ToJSValue(ret[0])。

  15. 否则,

    1. 令 values 为 « »。

    2. 对于每个 ret 中的 r,

      1. 将 追加 ToJSValue(r) 到 values。

    3. 返回 CreateArrayFromList(values)。

注:调用导出 函数会在被调用的导出函数的 [[Realm]] 中执行,这符合内置函数对象的定义。

注:导出函数不具有 [[Construct]] 方法,因此无法使用 new 运算符调用它。

要根据 JavaScript 对象 func、类型 functype 和列表中的WebAssembly 值 arguments 运行宿主 函数,执行以下步骤:
  1. 令 func parameters → results 为 functype 的展开结果。

  2. 如果 parameters 或 results 中的任何类型匹配 v128 或 exnref,则抛出一个 TypeError。

  3. 令 jsArguments 为 « »。

  4. 对于每个 arguments 中的 arg,

    1. 将 追加 ToJSValue(arg) 到 jsArguments。

  5. 令 ret 为 ? Call(func, undefined, jsArguments)。

  6. 令 resultsSize 为 results 的大小。

  7. 如果 resultsSize 为 0,则返回 « »。

  8. 否则,如果 resultsSize 为 1,则返回 « ? ToWebAssemblyValue(ret, results[0]) »。

  9. 否则,

    1. 令 method 为 ? GetMethod(ret, %Symbol.iterator%)。

    2. 如果 method 为 undefined,则抛出一个 TypeError。

    3. 令 values 为 ? IteratorToList(? GetIteratorFromMethod(ret, method))。

    4. 令 wasmValues 为一个新的空列表。

    5. 如果 values 的大小 不等于 resultsSize,则抛出一个 TypeError 异常。

    6. 对于 values 和 results 中按顺序一一配对的每个 value 和 resultType, 依次执行以下步骤:

      1. 将 追加 ? ToWebAssemblyValue(value, resultType) 到 wasmValues。

    7. 返回 wasmValues。

要创建宿主 函数,根据 JavaScript 对象 func 和类型 functype,执行 以下步骤:
  1. 断言:IsCallable(func)。

  2. 令 stored settings 为现任设置对象。

  3. 令 hostfunc 为一个宿主函数,当使用参数 arguments 调用时,执行以下步骤:

    1. 令 realm 为 func 的关联 Realm。

    2. 令 relevant settings 为 realm 的设置对象。

    3. 使用 relevant settings 准备运行脚本。

    4. 使用 stored settings 准备运行回调 。

    5. 令 result 为根据 func、functype 和 arguments 运行宿主 函数的结果。

    6. 使用 stored settings 在运行回调后执行清理 。

    7. 使用 relevant settings 在运行脚本后执行清理 。

    8. 断言:result.[[Type]] 为 throw 或 normal。

    9. 令 store 为周围代理的关联存储。

    10. 如果 result.[[Type]] 为 throw,则:

      1. 令 v 为 result.[[Value]]。

      2. 如果 v 实现了 Exception,

        1. 令 address 为 v.[[Address]]。

      3. 否则,

        1. 令 type 为获取 JavaScript 异常标签的结果。

        2. 令 payload 为 ! ToWebAssemblyValue(v, externref)。

        3. 令 (store, address) 为 exn_alloc(store, type, « payload »)。

        4. 将周围代理的关联存储设置为 store。

      4. 执行 WebAssembly 指令(ref.exn address)(throw_ref)。

    11. 否则,返回 result.[[Value]]。

  4. 令 store 为周围代理的关联存储。

  5. 令 (store, funcaddr) 为 func_alloc(store, functype, hostfunc)。

  6. 将周围代理的关联存储设置为 store。

  7. 返回 funcaddr。

算法 ToJSValue(w) 通过执行以下步骤,将WebAssembly 值转换为 JavaScript 值:
  1. 断言:w 的形式不是 v128.const v128。

  2. 断言:w 的形式不是 ref.exn exnaddr。

  3. 如果 w 的形式为 i64.const u64,

    1. 令 i64 为 signed_64(u64)。

    2. 返回 ℤ(将 i64 解释为数学值)。

  4. 如果 w 的形式为 i32.const u32,

    1. 令 i32 为 signed_32(u32)。

    2. 返回 𝔽(将 i32 解释为数学值)。

  5. 如果 w 的形式为 f32.const f32,

    1. 如果 f32 为 +∞ 或 −∞,则分别返回 +∞𝔽 或 -∞𝔽。

    2. 如果 f32 为 nan,则返回 NaN。

    3. 返回 𝔽(将 f32 解释为数学值)。

  6. 如果 w 的形式为 f64.const f64,

    1. 如果 f64 为 +∞ 或 −∞,则分别返回 +∞𝔽 或 -∞𝔽。

    2. 如果 f64 为 nan,则返回 NaN。

    3. 返回 𝔽(将 f64 解释为数学值)。

  7. 如果 w 的形式为 ref.null,则返回 null。

  8. 如果 w 的形式为 ref.i31 u31,

    1. 令 i31 为 signed_31(u31)。

    2. 返回 𝔽(将 i31 解释为数学值)。

  9. 如果 w 的形式为 ref.struct structaddr,则返回根据 structaddr 和 "struct" 创建一个新的导出 GC 对象的结果, 。

  10. 如果 w 的形式为 ref.array arrayaddr,则返回根据 arrayaddr 和 "array" 创建一个新的导出 GC 对象的结果, 。

  11. 如果 w 的形式为 ref.func funcaddr,则返回根据 funcaddr 创建一个 新的导出函数的结果。

  12. 如果 w 的形式为 ref.host hostaddr,则返回根据 hostaddr 检索宿主值的结果。

  13. 如果 w 的形式为 ref.extern ref,则返回 ToJSValue(ref)。

注:等于 NaN 的 Number 值可能具有 各种可观察的 NaN 载荷;有关详细信息,请参阅 NumericToRawBytes。

要从宿主地址 hostaddr 检索 宿主值,执行以下步骤:

  1. 令 map 为周围代理所关联的宿主值缓存。

  2. 断言:map[hostaddr] 存在。

  3. 返回 map[hostaddr]。

算法 ToWebAssemblyValue(v, type) 通过执行以下步骤,将 JavaScript 值转换为WebAssembly 值:
  1. 断言:type 不是 v128。

  2. 断言:type 不匹配 exnref。

  3. 如果 type 为 i64,

    1. 令 i64 为 ? ToBigInt64(v)。

    2. 令 u64 为满足 i64 等于 signed_64(u64) 的无符号整数。

    3. 返回 i64.const u64。

  4. 如果 type 为 i32,

    1. 令 i32 为 ? ToInt32(v)。

    2. 令 u32 为满足 i32 等于 signed_32(u32) 的无符号整数。

    3. 返回 i32.const u32。

  5. 如果 type 为 f32,

    1. 令 number 为 ? ToNumber(v)。

    2. 如果 number 为 NaN,

      1. 令 n 为一个由实现定义的整数,满足 canon32 ≤ n < 2signif(32)。

      2. 令 f32 为 nan(n)。

    3. 否则,

      1. 令 f32 为使用 IEEE 754-2019 的就近舍入、遇中间值取偶数模式,将 number 舍入到最接近的可表示 值。[IEEE-754]

    4. 返回 f32.const f32。

  6. 如果 type 为 f64,

    1. 令 number 为 ? ToNumber(v)。

    2. 如果 number 为 NaN,

      1. 令 n 为一个由实现定义的整数,满足 canon64 ≤ n < 2signif(64)。

      2. 令 f64 为 nan(n)。

    3. 否则,

      1. 令 f64 为 number。

    4. 返回 f64.const f64。

  7. 如果 type 的形式为 ref null heaptype,

    1. 如果 v 为 null,

      1. 令 r 为 ref.null。

    2. 否则,如果 match_valtype(type, ref null extern) 为 true,

      1. 令 ref 为 ! ToWebAssemblyValue(v, ref any)。

      2. 令 r 为 ref.extern ref。

    3. 否则,如果 v 是一个导出函数,且 match_valtype(type, ref null func) 为 true,

      1. 令 funcaddr 为 v 的 [[FunctionAddress]] 内部槽的值。

      2. 令 r 为 ref.func funcaddr。

    4. 否则,如果 v 是 Number,且 v 等于 ? ToInt32(v),且 ℝ(v) < 230,且 ℝ(v) ⩾ -230,

      1. 令 i31 为 ? ToInt32(v)。

      2. 令 u31 为满足 i31 等于 signed_31(u31) 的无符号整数。

      3. 令 r 为 ref.i31 u31。

    5. 否则,如果 v 是一个导出 GC 对象,

      1. 令 objectaddr 为 v 的 [[ObjectAddress]] 内部槽的值。

      2. 令 objectkind 为 v 的 [[ObjectKind]] 内部 槽的值。

      3. 如果 objectkind 为 "array",

        1. 令 r 为 ref.array objectaddr。

      4. 否则,如果 objectkind 为 "struct",

        1. 令 r 为 ref.struct objectaddr。

    6. 否则,

      1. 令 map 为周围代理所关联的宿主值缓存。

      2. 如果存在一个宿主地址 hostaddr, 使得 map[hostaddr] 与 v 相同,

        1. 返回 ref.host hostaddr。

      3. 令 hostaddr 为满足以下条件的最小宿主地址: map[hostaddr] 存在为 false。

      4. 将 设置 map[hostaddr] 为 v。

      5. 令 r 为 ref.host hostaddr。

    7. 令 store 为周围代理的关联存储。

    8. 令 actualtype 为 ref_type(store, r)。

    9. 如果 match_valtype(actualtype, type) 为 false,

      1. 抛出一个 TypeError。

    10. 返回 r。

  8. 断言:不会执行到此步骤。

算法 AddressValueToU64(v, addrtype) 将 IDL 值 转换为 WebAssembly u64,以供嵌入操作使用。它被设计为模拟 [EnforceRange] unsigned long 在 AddressType "i32" 下的行为,并将这些语义扩展到 AddressType "i64",具体执行以下步骤:
  1. 令 jsValue 为已转换为 JavaScript 值的 v。

    注:IDL any 类型是一个 可辨识联合类型,而不是 JavaScript 值的透明包装器。

  2. 如果 addrtype 为 i32,

    1. 令 n 为 ? ConvertToInt(jsValue, 32, "unsigned"),其中目标类型关联了 [EnforceRange]。

      注:这等效于 JS 转换规则,适用于 [EnforceRange] unsigned long。

    2. 将 ℝ(n) 作为 WebAssembly u64 返回。

  3. 如果 addrtype 为 i64,

    1. 令 n 为 ? ToBigInt(jsValue)。

    2. 令 r 为 ℝ(n)。

    3. 如果 r < 0 或 r > 264 − 1,则抛出一个 TypeError。

      注:此操作旨在 模拟 [EnforceRange]。

    4. 将 r 作为 WebAssembly u64 返回。

  4. 断言:不会执行到此步骤。

算法 U64ToAddressValue(v, addrtype) 将 WebAssembly 嵌入操作产生的u64 值转换为 AddressValue 的正确变体,以对应 AddressType, 具体执行以下步骤:
  1. 如果 addrtype 为 i32,则返回 𝔽(将 v 解释为数学值)。

  2. 否则,如果 addrtype 为 i64,则返回 ℤ(将 v 解释为数学值)。

  3. 断言:不会执行到此步骤。

5.7. 标签

5.7.1. 标签类型

dictionary TagType {
  required sequence<ValueType> parameters;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Tag {
  constructor(TagType type);
};

Tag 值表示一个 异常标签。

要从一个标签地址 tagAddress 初始化一个 Tag 对象 tag,执行以下步骤:

  1. 设 map 为外围代理关联的 Tag 对象缓存。

  2. 断言:map[tagAddress] 不存在。

  3. 将 tag.[[Address]] 设为 tagAddress。

  4. 设定 map[tagAddress] 为 tag。

要从一个标签地址 tagAddress 创建一个 Tag 对象,执行以下步骤:
  1. 设 map 为外围代理关联的 Tag 对象缓存。

  2. 如果 map[tagAddress] 存在,

    1. 返回 map[tagAddress]。

  3. 设 tag 为一个新的 Tag。

  4. 初始化 tag,来源为 tagAddress。

  5. 返回 tag。

调用 new Tag(type) 构造函数时,执行以下步骤:

  1. 令 parameters 为 type["parameters"]。

  2. 令 wasmParameters 为 «»。

  3. 对于每个 parameters 中的 paramType,

    1. 将 追加 ToValueType(paramType) 到 wasmParameters。

  4. 令 tagtype 为一个定义类型,使得 func wasmParameters → « » 是 展开结果,由 tagtype 得到。

  5. 令 store 为周围代理的关联存储。

  6. 令 (store, tagAddress) 为 tag_alloc(store, tagtype)。

  7. 将周围代理的关联存储设置为 store。

  8. 初始化 this,使用 tagAddress。

5.8. 垃圾回收对象

WebAssembly 结构体或数组在 JavaScript 中以导出 GC 对象的形式提供。 导出 GC 对象是一种异质对象,它包装了一个垃圾回收的 WebAssembly 引用值。 JavaScript 对 导出 GC 对象 的大多数操作都会抛出异常或返回 undefined。

Note: 这些操作未来可能会被细化,以允许 JavaScript 与 WebAssembly 结构体和数组之间进行更丰富的交互。

导出 GC 对象 包含一个 [[ObjectAddress]] 内部槽,它保存一个相对于 外围代理关联存储的对象地址, 以及一个 [[ObjectKind]] 内部槽,它保存字符串值 "struct" 或 "array"。

导出 GC 对象的内部方法使用以下实现。

导出 GC 对象的 [[GetPrototypeOf]] 内部方法 O 不接受参数并返回 null。调用时执行以下 步骤:
  1. 返回 null。

导出 GC 对象的 [[SetPrototypeOf]] 内部方法 O 接受参数 V(对象或 null)并返回一个 boolean。调用时执行以下步骤:
  1. 返回 false。

导出 GC 对象的 [[IsExtensible]] 内部方法 O 不接受参数并返回一个 boolean。调用时执行以下 步骤:
  1. 返回 false。

导出 GC 对象的 [[PreventExtensions]] 内部方法 O 不接受参数并返回一个 boolean。调用时执行以下 步骤:
  1. 返回 false。

导出 GC 对象的 [[GetOwnProperty]] 内部方法 O 接受参数 P(属性键)并返回 undefined。调用时执行以下步骤:
  1. 返回 undefined。

导出 GC 对象的 [[DefineOwnProperty]] 内部方法 O 接受参数 P(属性键)和 Desc(属性描述符)并返回一个 boolean。调用时执行以下步骤:
  1. 返回 false。

导出 GC 对象的 [[HasProperty]] 内部方法 O 接受参数 P(属性键)并返回一个 boolean。调用时 执行以下步骤:
  1. 返回 false。

导出 GC 对象的 [[Get]] 内部方法 O 接受参数 P(属性键)和 Receiver(ECMAScript 语言 值)并返回 undefined。调用时执行以下步骤:
  1. 返回 undefined。

导出 GC 对象的 [[Set]] 内部方法 O 接受参数 P(属性键)、V(ECMAScript 语言值)以及 Receiver(ECMAScript 语言值)并抛出一个异常。调用时执行以下步骤 :
  1. 抛出一个 TypeError。

导出 GC 对象的 [[Delete]] 内部方法 O 接受参数 P(属性键)并抛出一个异常。它 在调用时执行以下步骤:
  1. 抛出一个 TypeError。

导出 GC 对象的 [[OwnPropertyKeys]] 内部方法 O 不接受参数并返回一个列表。调用时执行以下 步骤:
  1. 返回 « »。

要从一个 WebAssembly 对象地址 objectaddr 和一个字符串 objectkind 创建新的 导出 GC 对象,执行以下步骤:
  1. 断言:objectkind 是 "array" 或 "struct" 之一。

  2. 设 map 为外围代理关联的 导出 GC 对象 缓存。

  3. 如果 map[objectaddr] 存在,

    1. 返回 map[objectaddr]。

  4. 设 object 为 MakeBasicObject(« [[ObjectAddress]], [[ObjectKind]] »)。

  5. 将 object.[[ObjectAddress]] 设为 objectaddr。

  6. 将 object.[[ObjectKind]] 设为 objectkind。

  7. 将 object.[[GetPrototypeOf]] 设为 导出 GC 对象的 [[GetPrototypeOf]] 内部方法中指定的内容。

  8. 将 object.[[SetPrototypeOf]] 设为 导出 GC 对象的 [[SetPrototypeOf]] 内部方法中指定的内容。

  9. 将 object.[[IsExtensible]] 设为 导出 GC 对象的 [[IsExtensible]] 内部方法中指定的内容。

  10. 将 object.[[PreventExtensions]] 设为 导出 GC 对象的 [[PreventExtensions]] 内部方法中指定的内容。

  11. 将 object.[[GetOwnProperty]] 设为 导出 GC 对象的 [[GetOwnProperty]] 内部方法中指定的内容。

  12. 将 object.[[DefineOwnProperty]] 设为 导出 GC 对象的 [[DefineOwnProperty]] 内部方法中指定的内容。

  13. 将 object.[[HasProperty]] 设为 导出 GC 对象的 [[HasProperty]] 内部方法中指定的内容。

  14. 将 object.[[Get]] 设为 导出 GC 对象的 [[Get]] 内部方法中指定的内容。

  15. 将 object.[[Set]] 设为 导出 GC 对象的 [[Set]] 内部方法中指定的内容。

  16. 将 object.[[Delete]] 设为 导出 GC 对象的 [[Delete]] 内部方法中指定的内容。

  17. 将 object.[[OwnPropertyKeys]] 设为 导出 GC 对象的 [[OwnPropertyKeys]] 内部方法中指定的内容。

  18. 设定 map[objectaddr] 为 object。

  19. 返回 object。

5.9. 异常

dictionary ExceptionOptions {
  boolean traceStack = false;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Exception {
  constructor(Tag exceptionTag, sequence<any> payload, optional ExceptionOptions options = {});
  any getArg(Tag exceptionTag, [EnforceRange] unsigned long index);
  boolean is(Tag exceptionTag);
  readonly attribute (DOMString or undefined) stack;
};

Exception 值表示一个异常。

要从一个Exception 地址 exnAddress 初始化一个 Exception 对象 exn,执行以下 步骤:

  1. 设 map 为外围代理关联的 Exception 对象 缓存。

  2. 断言:map[exnAddress] 不存在。

  3. 将 exn.[[Address]] 设为 exnAddress。

  4. 设定 map[exnAddress] 为 exn。

  5. 设 store 为外围代理的关联存储。

  6. 设 tagaddr 为 exn_tag(store, exnAddress)。

  7. 设 payload 为 exn_read(store, exnAddress)。

  8. 将 exn.[[Type]] 设为 tagaddr。

  9. 将 exn.[[Payload]] 设为 payload。

  10. 将 exn.[[Stack]] 设为 undefined。

要从一个异常地址 exnAddress 创建一个 Exception 对象,执行以下步骤:

  1. 设 map 为外围代理关联的 Exception 对象 缓存。

  2. 如果 map[exnAddress] 存在,

    1. 返回 map[exnAddress]。

  3. 设 exn 为一个新的 Exception。

  4. 初始化 exn,来源为 exnAddress。

  5. 返回 exn。

调用 new Exception(exceptionTag, payload, options) 构造函数时,执行以下步骤:

  1. 令 JSTagAddr 为获取 JavaScript 异常标签的结果。

  2. 如果 exceptionTag.[[Address]] 等于 JSTagAddr,

    1. 抛出一个 TypeError。

  3. 令 store 为周围代理的关联存储。

  4. 令 func types → « » 为展开结果,其来自 tag_type(store, exceptionTag.[[Address]])。

  5. 如果 types 的大小不等于 payload 的大小,

    1. 抛出一个 TypeError。

  6. 令 wasmPayload 为 « »。

  7. 对于每个 value 和 resultType,分别来自 payload 和 types,并按顺序一一配对,

    1. 如果 resultType 匹配 v128 或 exnref,

      1. 抛出一个 TypeError。

    2. 将 追加 ? ToWebAssemblyValue(value, resultType) 到 wasmPayload。

  8. 令 (store, exceptionAddr) 为 exn_alloc(store, exceptionTag.[[Address]], wasmPayload)。

  9. 将周围代理的关联存储设置为 store。

  10. 使用 exceptionAddr 初始化 this。

  11. 如果 options["traceStack"] 为 true,

    1. 将 this.[[Stack]] 设置为当前调用栈的 DOMString 表示形式或 undefined,两者之一。

调用 getArg(exceptionTag, index) 方法时,执行以下步骤:

  1. 令 store 为周围代理的关联存储。

  2. 如果 this.[[Type]] 不等于 exceptionTag.[[Address]],

    1. 抛出一个 TypeError。

  3. 令 tagaddr 为 exn_tag(store, this.[[Address]])。

  4. 令 payload 为 exn_read(store, this.[[Address]])。

  5. 断言:tagaddr 等于 this.[[Type]]。

  6. 如果 index ≥ payload 的大小,

    1. 抛出一个 RangeError。

  7. 令 func types → « » 为展开结果,其来自 tag_type(store, tagaddr)。

  8. 如果 types[index] 匹配 v128 或 exnref,

    1. 抛出一个 TypeError。

  9. 返回 ToJSValue(payload[index])。

调用 is(exceptionTag) 方法时,执行以下步骤:

  1. 如果 this.[[Type]] 不等于 exceptionTag.[[Address]],

    1. 返回 false。

  2. 返回 true。

调用 stack 获取器时,执行以下步骤:

  1. 返回 this.[[Stack]]。

5.9.1. JavaScript 异常

JavaScript 异常标签 是一个与标签地址,关联于 周围代理。它在该代理的关联存储中于 首次使用时分配并缓存。它始终具有标签类型 « externref » → « »。

要获取 JavaScript 异常标签,执行以下步骤:

  1. 如果周围代理关联的JavaScript 异常 标签已初始化,

    1. 返回周围代理关联的JavaScript 异常标签

  2. 令 tagtype 为一个定义类型,使得 func « externref » → « » 是 展开结果,由 tagtype 得到。

  3. 令 store 为周围代理的关联存储。

  4. 令 (store, tagAddress) 为 tag_alloc(store, tagtype)。

  5. 将周围代理的关联存储设置为 store。

  6. 将周围代理关联的JavaScript 异常 标签设置为 tagAddress。

  7. 返回 tagAddress。

5.10. 错误对象

WebAssembly 定义了以下 Error 类:CompileError、LinkError,以及 RuntimeError。

当为 WebAssembly 命名空间创建命名空间对象时, 必须运行以下步骤:
  1. 设 namespaceObject 为该命名空间对象。

  2. 对于 « "CompileError", "LinkError", "RuntimeError" » 中的每个 error,

    1. 设 constructor 为一个新对象,实现 NativeError 对象结构,其中 NativeError 被设为 error。

    2. ! DefineMethodProperty(namespaceObject, error, constructor, false)。

Note: 这会在 WebAssembly 命名空间上定义 CompileError、 LinkError 和 RuntimeError 类,它们由本规范中定义的 API 产生。 它们暴露出的接口与原生 JavaScript 错误(如 TypeError 和 RangeError) 相同。

Note: 目前尚无法使用 Web IDL 定义这种 行为。

6. 内建项

JS-API 定义了若干组内建函数,这些函数可在编译模块时通过 options 导入。WebAssembly 内建函数映射现有的 JavaScript 内建函数,但会将它们调整为可直接作为 WebAssembly 函数使用,并尽量降低开销。

所有内建函数都被分组为集合。每个内建项集合都有一个用于 WebAssemblyCompileOptions 的名称, 以及一个带有 wasm: 前缀、用于导入查找的限定名称。

要获取名称为 builtinSetName 的内建项集合中的 内建项,执行以下步骤:

  1. 返回一个 (name, funcType, steps) 的列表, 对应于本节中定义的名称为 builtinSetName 的集合。

要根据 import 和启用的内建项 builtinSetNames 查找一个内建项, 执行以下步骤:

  1. 断言:验证内建项集合名称 builtinSetNames 的结果为 true。

  2. 设 importModuleName 为 import[0]。

  3. 设 importName 为 import[1]。

  4. 对于 builtinSetNames 中的每个 builtinSetName,

    1. 如果 builtinSetName 未指向一个内建项集合,则 继续。

    2. 设 builtinSetQualifiedName 为在 builtinSetName 前加上前缀 "wasm:"。

    3. 如果 importModuleName 等于 builtinSetQualifiedName,

      1. 设 builtins 为获取一个内建项集合中的内建项 builtinSetName 的结果。

      2. 对于 builtins 中的每个 builtin,

        1. 设 builtinName 为 builtin[0]。

        2. 如果 importName 等于 builtinName,则返回 (builtinSetName, builtin)。

  5. 返回 null。

要根据 builtinSetNames 验证 内建项集合名称,执行以下步骤:

  1. 如果 builtinSetNames 包含任何重复项,则返回 false。

  2. 返回 true。

要根据类型 funcType 和执行步骤 steps 创建一个 内建函数,执行以下步骤:

  1. 设 hostfunc 为一个宿主函数,调用时执行 steps。

  2. 设 store 为外围代理的关联存储。

  3. 设 (store, funcaddr) 为 func_alloc(store, funcType, hostfunc)。

  4. 将外围代理的关联存储设为 store。

  5. 返回 funcaddr。

要使用名称 builtinSetName 实例化 内置项集合,执行以下步骤:

  1. 令 builtins 为获取内置项集合的内置项 builtinSetName 的结果。

  2. 令 exportsObject 为 OrdinaryObjectCreate(null)。

  3. 对于 builtins 中的每个(name、funcType、 steps),

    1. 令 funcaddr 为使用 funcType 和 steps 创建 内置函数的结果。

    2. 令 func 为从 funcaddr 创建新的导出 函数的结果。

    3. 令 value 为 func。

    4. 令 status 为 ! CreateDataProperty(exportsObject, name, value)。

    5. 断言:status 为 true。

  4. 返回 exportsObject。

要使用 import 和已启用的内置项 builtinSetNames 验证内置项的导入项, 执行以下步骤:

  1. 断言:验证内置项集合名称 builtinSetNames 为 true。

  2. 令 maybeBuiltin 为针对 import 和 builtinSetNames 查找内置项的结果。

  3. 如果 maybeBuiltin 为 null,则返回 true。

  4. 令 importExternType 为 import[2]。

  5. 令 builtinFuncType 为 maybeBuiltin[1][1]。

  6. 令 builtinExternType 为 func |builtinFuncType|。

  7. 返回 match_externtype(builtinExternType, importExternType)。

6.1. 字符串内建项

字符串内建项调整了 String 内建 对象的接口。该集合的名称是 js-string,其限定名称是 wasm:js-string。

注:本节中的算法引用了定义在 String 上的 JS 内建项。这些引用指向实际的内建项,而不会在 String 对象上执行动态查找。

6.1.1. 抽象操作

调用 UnwrapString(v) 抽象操作时, 执行以下步骤:

  1. 如果 v 不是字符串,

    1. 抛出一个 RuntimeError 异常,就像执行了一个陷阱一样。

  2. 返回 v

FromCharCode(v) 抽象操作在调用时, 执行以下步骤:

  1. 断言:v 的类型为 i32。

  2. 返回 ! Call(String.fromCharCode, undefined, « ToJSValue(v) »)。

CharCodeAt(string, index) 抽象 操作在调用时,执行以下步骤:

  1. 断言:index 的类型为 i32。

  2. 返回 ! Call(String.prototype.charCodeAt, string, « ToJSValue(index) »)。

6.1.2. cast

该内建项的 funcType 是 (rec (type (func (param externref) (result (ref extern))))).0。

当使用参数 v 调用该内建项时,必须执行以下步骤:

  1. 返回 ? UnwrapString(v)

6.1.3. test

该内建项的 funcType 是 (rec (type (func (param externref) (result i32)))).0。

当使用参数 v 调用该内建项时,必须执行以下步骤:

  1. 如果 v 不是字符串,

    1. 返回 0。

  2. 返回 1。

6.1.4. fromCharCodeArray

设 arrayType 为 (rec (type (array (mut i16)))).0。

该内建项的 funcType 是 (rec (type (func (param (ref null arrayType) i32 i32) (result (ref extern))))).0。

当使用参数 array、start 和 end 调用该内建项时,必须执行 以下步骤:

  1. 如果 array 是 null,

    1. 抛出一个 RuntimeError 异常,就像执行了一个陷阱一样。

  2. 设 length 为 array 中元素的个数。

  3. 如果 start > end 或 end > length,

    1. 抛出一个 RuntimeError 异常,就像执行了一个陷阱一样。

  4. 设 result 为空字符串。

  5. 设 i 为 start。

  6. 当 i < end 时:

    1. 设 charCode 为 array 中索引 i 处存储元素的值。

    2. 设 charCodeString 为 FromCharCode(charCode)。

    3. 设 result 为 result 与 charCodeString 的拼接结果。

    4. 将 i 设为 i + 1。

  7. 返回 result。

6.1.5. intoCharCodeArray

设 arrayType 为 (rec (type (array (mut i16)))).0。

该内建项的 funcType 是 (rec (type (func (param externref (ref null arrayType) i32) (result i32)))).0。

当使用参数 string、array 和 start 调用该内建项时, 必须执行以下步骤:

  1. 如果 array 是 null,

    1. 抛出一个 RuntimeError 异常,就像执行了一个陷阱一样。

  2. 设 string 为 ? UnwrapString(string)。

  3. 设 stringLength 为 string 的长度。

  4. 设 arrayLength 为 array 中元素的个数。

  5. 如果 start + stringLength > arrayLength,

    1. 抛出一个 RuntimeError 异常,就像执行了一个陷阱一样。

  6. 设 i 为 0。

  7. 当 i < stringLength 时:

    1. 设 charCode 为 CharCodeAt(string, i)。

    2. 将 array 中索引 start + i 处的元素设为 ToWebAssemblyValue(charCode, i32)。

    3. 将 i 设为 i + 1。

  8. 返回 stringLength。

6.1.6. fromCharCode

该内建项的 funcType 是 (rec (type (func (param i32) (result (ref extern))))).0。

当使用参数 v 调用该内建项时,必须执行以下步骤:

  1. 返回 FromCharCode(v)。

6.1.7. fromCodePoint

该内建项的 funcType 是 (rec (type (func (param i32) (result externref)))).0。

当使用参数 v 调用该内建项时,必须执行以下步骤:

  1. 如果 v > 0x10ffff,

    1. 抛出一个 RuntimeError 异常,就像执行了一个陷阱一样。

  2. 返回 ! Call(String.fromCodePoint, undefined, « ToJSValue(v) »)。

6.1.8. charCodeAt

该函数的类型是 (rec (type (func (param externref i32) (result i32)))).0。

当使用参数 string 和 index 调用该内建项时,必须执行以下步骤 :

  1. 设 string 为 ? UnwrapString(string)。

  2. 设 length 为 string 的长度。

  3. 如果 index >= length,

    1. 抛出一个 RuntimeError 异常,就像执行了一个陷阱一样。

  4. 返回 CharCodeAt(string, index)。

6.1.9. codePointAt

该函数的类型是 (rec (type (func (param externref i32) (result i32)))).0。

当使用参数 string 和 index 调用该内建项时,必须执行以下步骤 :

  1. 设 string 为 ? UnwrapString(string)。

  2. 设 length 为 string 的长度。

  3. 如果 index >= length,

    1. 抛出一个 RuntimeError 异常,就像执行了一个陷阱一样。

  4. 返回 ! Call(String.prototype.codePointAt, string, « ToJSValue(index) »)。

6.1.10. length

该内建项的 funcType 是 (rec (type (func (param externref) (result i32)))).0。

当使用参数 v 调用该内建项时,必须执行以下步骤:

  1. 设 string 为 ? UnwrapString(v)。

  2. 返回 string 的长度。

6.1.11. concat

该内建项的 funcType 是 (rec (type (func (param externref externref) (result (ref extern))))).0。

当使用参数 first 和 second 调用此内置项时,必须执行以下步骤 :

  1. 令 first 为 ? UnwrapString(first)。

  2. 令 second 为 ? UnwrapString(second)。

  3. 返回 ! Call(String.prototype.concat, first, « second »)。

6.1.12. substring

该内建项的 funcType 是 (rec (type (func (param externref i32 i32) (result (ref extern))))).0。

当使用参数 string、start 和 end 调用此内置项时, 必须执行以下步骤:

  1. 令 string 为 ? UnwrapString(string)。

  2. 令 length 为 string 的长度 。

  3. 如果 start > end 或 start > length,

    1. 返回空字符串。

  4. 返回 ! Call(String.prototype.substring, string, « ToJSValue(start), ToJSValue(end) »)。

6.1.13. equals

该内建项的 funcType 是 (rec (type (func (param externref externref) (result i32)))).0。

注:明确允许对 null 字符串进行相等性比较, 因为这具有意义。

当使用参数 first 和 second 调用此内置项时,必须执行以下步骤 :

  1. 如果 first 不为 null 且 first 不是 String,

    1. 抛出 RuntimeError 异常,如同执行了陷阱一样。

  2. 如果 second 不为 null 且 second 不是 String,

    1. 抛出 RuntimeError 异常,如同执行了陷阱一样。

  3. 如果 IsStrictlyEqual(first, second) 为 true,

    1. 返回 1。

  4. 返回 0。

6.1.14. compare

该内建项的 funcType 是 (rec (type (func (param externref externref) (result i32)))).0。

当使用参数 first 和 second 调用此内置项时,必须执行以下步骤 :

  1. 令 first 为 ? UnwrapString(first)。

  2. 令 second 为 ? UnwrapString(second)。

  3. 如果 IsStrictlyEqual(first, second) 为 true,

    1. 返回 0。

  4. 如果 ! IsLessThan(first, second, true) 为 true,

    1. 返回 -1。

  5. 返回 1。

7. 错误 条件到 JavaScript 的映射

运行 WebAssembly 程序时会遇到某些事件,这些事件会终止 WebAssembly 代码的执行。 WebAssembly 代码(目前) 无法捕获这些情况,因此异常必然会 传播到外层的非 WebAssembly 调用者(无论是浏览器、 JavaScript 还是另一个运行时系统),并在那里像普通 JavaScript 异常一样处理。

如果 WebAssembly 通过导入调用 JavaScript,而 JavaScript 抛出 一个异常,则该异常会穿过 WebAssembly 激活记录传播到 外层调用者。

由于 JavaScript 异常可以被处理,并且 JavaScript 可以在 陷阱被处理后继续调用 WebAssembly 导出,因此陷阱通常 不会阻止未来的执行。

7.1. 栈溢出

每当 WebAssembly 代码中发生 栈溢出时,抛出的异常类别与 JavaScript 中发生栈溢出时 相同。这里的具体异常在两种情况下都由实现定义。

注:ECMAScript 没有规定栈溢出时的任何行为; 已观察到的实现会抛出 RangeError、 InternalError 或 Error。这里任意一种都有效。

7.2. 内存不足

每当验证、编译或实例化过程中内存耗尽时, 抛出的异常类别与 JavaScript 中内存不足情况 相同。这里的具体异常在两种情况下都由实现定义。

注:ECMAScript 没有规定内存不足时的任何行为; 已观察到的实现会抛出 OOMError 或直接崩溃。这里两种情况都有效 。

大型表或内存分配失败可能会导致 在未来修订中,我们可能会重新考虑为大规模内存分配提供 更可靠且可恢复的错误。

更多讨论请参见 Issue 879。

8. 实现定义的限制

WebAssembly 核心规范允许实现对模块的语法结构定义限制。 虽然 WebAssembly 的每种嵌入都可以选择定义其自身的限制,但为了可预测性, 本文档描述的标准 WebAssembly JavaScript 接口定义了以下精确限制。 如果模块超过以下任一限制,实现必须以 CompileError 拒绝该模块。 在实践中,即使模块在这些限制之下,实现也可能因资源耗尽而失败。

如果运行时超出以下任一限制,实现必须抛出一个 RuntimeError : 在实践中,即使模块在这些限制之下,实现也可能因资源耗尽而失败。

9. 安全性和隐私注意事项

本节为非规范性内容。

本文档为 WebAssembly 定义了一个宿主环境。它允许 WebAssembly 实例从导入对象中导入 JavaScript 对象和函数,但除此之外不提供对嵌入环境的任何访问 。因此,WebAssembly 实例受到与 JavaScript 相同的约束。

10. 变更历史

本节为非规范性内容。

自 WebAssembly 规范最初的 1.0 版本发布以来, 已集成了若干扩展提案。 以下各节概述了已发生的变化。

10.1. 版本 2.0

多值

多个值可以作为 Array 对象,在 JavaScript 函数之间传入和返回。

BigInt 集成

WebAssembly i64 值可以作为 BigInt 对象,在 JavaScript 与 WebAssembly 之间传递(通过导入或导出的 全局、表的 get 或 set 操作、函数返回值或参数)。

引用类型

JavaScript 值可以作为 externref 值,在 JavaScript 与 WebAssembly 之间传递(通过导入或导出的全局、表的 set 或 get 操作,以及函数参数或返回值)。

多表

多个表可以在 JavaScript 与 WebAssembly 之间导出和导入。

10.2. 版本 3.0

多内存

多个内存可以在 JavaScript 与 WebAssembly 之间导出和导入。

JS 字符串内建项

在编译模块时添加了一个 builtins 选项,以及一组用于操作 JS 字符串的内建函数。

一致性

文档 约定

一致性要求通过 描述性断言 和 RFC 2119 术语的组合来表达。 本文档规范性部分中的关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、 “MAY”和“OPTIONAL” 应按 RFC 2119 中的说明进行解释。 但是,为了可读性, 本规范中这些词并不全部使用大写字母出现。

本规范的所有文本均为规范性内容 ,除非某些章节被明确标记为非规范性内容、示例和注释。[RFC2119]

本规范中的示例以前缀词“for example”引出 ,或通过 class="example" 与规范性文本区分开来, 如下所示:

这是一个资料性示例。

资料性注释以“Note”一词开头 ,并通过 class="note" 与规范性文本区分开来, 如下所示:

注:这是一条资料性注释。

符合规范的 算法

在算法中以祈使句形式表述的要求 (例如“strip any leading space characters” 或“return false and abort these steps”) 应根据引入该算法时所使用的关键词 (“must”、“should”、“may”等) 的含义进行解释。

以算法或具体步骤形式表述的一致性要求 可以用任何方式实现, 只要最终结果等价即可。 特别是,本规范中定义的算法 旨在便于理解 ,并不以高性能为目标。 鼓励实现者进行优化。

索引

本规范定义的术语

通过引用定义的术语

参考文献

规范性参考文献

[ECMASCRIPT]
ECMAScript 语言规范. URL: https://tc39.es/ecma262/multipage/
[ENCODING]
Anne van Kesteren. 编码标准. Living Standard. URL: https://encoding.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML 标准. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. RFC 中用于指示要求级别的关键词. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBASSEMBLY]
WebAssembly 核心规范. Draft. URL: https://webassembly.github.io/spec/core/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. Living Standard. URL: https://webidl.spec.whatwg.org/

资料性参考文献

[IEEE-754]
IEEE 浮点运算标准. 22 July 2019. URL: https://ieeexplore.ieee.org/document/8766229
[WASMWEB]
WebAssembly Web API 规范. Draft. URL: https://webassembly.github.io/spec/web-api/

IDL 索引

dictionary WebAssemblyInstantiatedSource {
    required Module module;
    required Instance instance;
};

dictionary WebAssemblyCompileOptions {
    USVString? importedStringConstants = null;
    sequence<USVString> builtins = [];
};

[Exposed=*]
namespace WebAssembly {
    boolean validate([AllowResizable] AllowSharedBufferSource bytes, optional WebAssemblyCompileOptions options = {});
    Promise<Module> compile([AllowResizable] AllowSharedBufferSource bytes, optional WebAssemblyCompileOptions options = {});

    Promise<WebAssemblyInstantiatedSource> instantiate(
        [AllowResizable] AllowSharedBufferSource bytes, optional object importObject, optional WebAssemblyCompileOptions options = {});

    Promise<Instance> instantiate(
        Module moduleObject, optional object importObject);

    readonly attribute Tag JSTag;
};

enum ImportExportKind {
  "function",
  "table",
  "memory",
  "global",
  "tag"
};

enum AddressType {
  "i32",
  "i64",
};

typedef any AddressValue;

dictionary ModuleExportDescriptor {
  required USVString name;
  required ImportExportKind kind;
  // Note: Other fields such as signature may be added in the future.
};

dictionary ModuleImportDescriptor {
  required USVString module;
  required USVString name;
  required ImportExportKind kind;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Module {
  constructor([AllowResizable] AllowSharedBufferSource bytes, optional WebAssemblyCompileOptions options = {});
  static sequence<ModuleExportDescriptor> exports(Module moduleObject);
  static sequence<ModuleImportDescriptor> imports(Module moduleObject);
  static sequence<ArrayBuffer> customSections(Module moduleObject, DOMString sectionName);
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Instance {
  constructor(Module module, optional object importObject);
  readonly attribute object exports;
};

dictionary MemoryDescriptor {
  required AddressValue initial;
  AddressValue maximum;
  AddressType address;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Memory {
  constructor(MemoryDescriptor descriptor);
  AddressValue grow(AddressValue delta);
  ArrayBuffer toFixedLengthBuffer();
  ArrayBuffer toResizableBuffer();
  readonly attribute ArrayBuffer buffer;
};

enum TableKind {
  "externref",
  "anyfunc",
  // Note: More values may be added in future iterations,
  // e.g., typed function references, typed GC references
};

dictionary TableDescriptor {
  required TableKind element;
  required AddressValue initial;
  AddressValue maximum;
  AddressType address;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Table {
  constructor(TableDescriptor descriptor, optional any value);
  AddressValue grow(AddressValue delta, optional any value);
  any get(AddressValue index);
  undefined set(AddressValue index, optional any value);
  readonly attribute AddressValue length;
};

enum ValueType {
  "i32",
  "i64",
  "f32",
  "f64",
  "v128",
  "externref",
  "anyfunc",
};

dictionary GlobalDescriptor {
  required ValueType value;
  boolean mutable = false;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Global {
  constructor(GlobalDescriptor descriptor, optional any v);
  any valueOf();
  attribute any value;
};

dictionary TagType {
  required sequence<ValueType> parameters;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Tag {
  constructor(TagType type);
};

dictionary ExceptionOptions {
  boolean traceStack = false;
};

[LegacyNamespace=WebAssembly, Exposed=*]
interface Exception {
  constructor(Tag exceptionTag, sequence<any> payload, optional ExceptionOptions options = {});
  any getArg(Tag exceptionTag, [EnforceRange] unsigned long index);
  boolean is(Tag exceptionTag);
  readonly attribute (DOMString or undefined) stack;
};

问题索引

大型表或内存分配失败可能会导致 在未来修订中,我们可能会重新考虑为大规模内存分配提供更可靠且可恢复的错误。

更多讨论请参见 Issue 879。

↵