WebAssembly JavaScript 接口

W3C 候选推荐草案,

关于本文件的更多信息
本版本:
https://www.w3.org/TR/2026/CRD-wasm-js-api-2-20260514/
最新发布版本:
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;
    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. modulemodule_decode(bytes)。如果 moduleerror,则返回 error

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

  3. 返回 module

对于模块 module、启用的内建项 builtinSetNames 以及 importedStringModule,要验证 WebAssembly 模块的内建项和导入字符串, 请执行以下步骤:

  1. 如果对 builtinSetNames 进行内建项集合名称验证的结果为 false,则返回 false。

  2. module_imports(module) 的每个 import逐一执行:

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

      1. importExternTypeimport[2]。

      2. stringExternTypeglobal const (ref extern)

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

    2. 否则,

      1. 如果使用 importbuiltinSetNames 进行内建项导入验证的结果为 false, 则返回 false。

  3. 返回 true。

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

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

  3. 如果 moduleerror,则返回 false。

  4. builtinSetNamesoptions["builtins"]。

  5. importedStringModuleoptions["importedStringConstants"]。

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

  7. 返回 true。

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

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

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

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

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

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

  6. 返回 moduleObject

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

  2. 并行运行以下步骤:

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

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

      1. 如果 moduleerror,则用一个 CompileError 异常拒绝 promise,并返回。

      2. builtinSetNamesoptions["builtins"]。

      3. importedStringModuleoptions["importedStringConstants"]。

      4. 如果对于 module 以及 builtinSetNamesimportedStringModule内建项和导入字符串验证结果为 false,则用一个 CompileError 异常拒绝 promise

      5. 否则,

        1. modulebytesbuiltinSetNamesimportedStringModule 构造一个 WebAssembly 模块对象,并将结果记为 moduleObject

        2. 兑现 promise,其值为 moduleObject

  3. 返回 promise

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

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

使用模块 moduleimportedStringModule 实例化导入字符串时,执行以下步骤:

  1. 断言:importedStringModule 不为 null。

  2. exportsObject! OrdinaryObjectCreate(null) 的结果。

  3. module_imports(module) 中的每个 (moduleName, componentName, externtype),逐一执行:

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

    2. stringConstantcomponentName

    3. status! CreateDataProperty(exportsObject, stringConstant, stringConstant) 的结果。

    4. 断言:status 为 true。

  4. 返回 exportsObject

从导入对象 importObject 中,为 WebAssembly 模块 module 读取导入, 启用的内建项为 builtinSetNames,导入字符串模块为 importedStringModule, 执行以下步骤:
  1. 如果 module.imports 非空, 且 importObject 为 undefined,则抛出一个 TypeError 异常。

  2. builtinOrStringImports 为有序映射 « »。

  3. builtinSetNames 中的每个 builtinSetName逐一执行:

    1. builtinSetQualifiedName 为带有前缀 "wasm:" 的 builtinSetName

    2. 断言:builtinOrStringImports 不包含 builtinSetQualifiedName

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

    4. exportsObject 为使用 builtinSetName 实例化一个内建项集合 的结果

    5. 设定 builtinOrStringImports[builtinSetQualifiedName] 为 exportsObject

  4. 如果 importedStringModule 不为 null,

    1. exportsObject 为使用 moduleimportedStringModule 实例化导入字符串 的结果

    2. 设定 builtinOrStringImports[importedStringModule] 为 exportsObject

  5. imports 为 « »。

  6. module_imports(module) 中的每个 (moduleName, componentName, externtype),逐一执行:

    1. 如果 builtinOrStringImports 包含 moduleName

      1. obuiltinOrStringImports[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. funcaddrv 的 [[FunctionAddress]] 内部槽的值。

      3. 否则,

        1. 根据 vfunctype 创建一个宿主函数,并将结果记为 funcaddr

        2. indeximports 中外部函数的数量。这个值 index 被称为宿主函数 funcaddr索引

      4. externfunc外部值 func funcaddr

      5. externfunc 追加imports

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

      1. 如果 v 实现了 Global

        1. globaladdrv.[[Global]]。

      2. 否则,

        1. 如果 valtypei64v 不是 BigInt

          1. 抛出一个 LinkError 异常。

        2. 如果 valtypei32f32f64 之一,且 v 不是 Number

          1. 抛出一个 LinkError 异常。

        3. 如果 valtypev128

          1. 抛出一个 LinkError 异常。

        4. valueToWebAssemblyValue(v, valtype)。如果此操作抛出一个 TypeError, 则捕获它,并抛出一个 LinkError 异常。

        5. store外围代理关联存储

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

        7. 外围代理关联存储设为 store

      3. externglobalglobal 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. tableaddrv.[[Table]]。

      3. externtable外部值 table tableaddr

      4. externtable 追加imports

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

      1. 断言:attributeexception

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

      3. tagaddrv.[[Address]]。

      4. externtag外部值 tag tagaddr

      5. externtag 追加imports

  7. 返回 imports

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

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

  2. module_exports(module) 中的每个 (name, externtype),逐一执行:

    1. externvalinstance_export(instance, name)。

    2. 断言:externval 不是 error

    3. 如果 externtype 的形式为 func functype

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

      2. func funcaddrexternval

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

      4. valuefunc

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

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

      2. global globaladdrexternval

      3. global 为从 globaladdr 创建一个新的 Global 对象 的结果。

      4. valueglobal

    5. 如果 externtype 的形式为 mem memtype

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

      2. mem memaddrexternval

      3. memory 为从 memaddr 创建一个新的 Memory 对象 的结果。

      4. valuememory

    6. 如果 externtype 的形式为 table tabletype

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

      2. table tableaddrexternval

      3. table 为从 tableaddr 创建一个新的 Table 对象 的结果。

      4. valuetable

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

      1. 断言:attributeexception

      2. 断言:externval 的形式为 tag tagaddr

      3. tag tagaddrexternval

      4. tag 为从 tagaddr 创建一个新的 Tag 对象 的结果。

      5. valuetag

    8. status! CreateDataProperty(exportsObject, name, value) 的结果。

    9. 断言:status 为 true。

    注:WebAssembly 模块验证期间执行的有效性和唯一性检查 可确保每个属性名都有效,且没有任何属性被定义两次。

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

  4. 返回 exportsObject

从 WebAssembly 模块 module 和实例 instance 初始化一个实例对象 instanceObject 时,执行以下步骤:
  1. moduleinstance 创建一个导出对象,并将结果记为 exportsObject

  2. instanceObject.[[Instance]] 设为 instance

  3. instanceObject.[[Exports]] 设为 exportsObject

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

  2. resultmodule_instantiate(store, module, imports)。

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

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

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

    • 如有适用,抛出另一种错误类型,例如 WebAssembly 错误映射中说明的内存不足异常。

  4. 设 (store, instance) 为 result

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

  6. 返回 instance

从一个 Module moduleObject 和导入 importObject 异步实例化一个 WebAssembly 模块时,执行以下步骤:
  1. promise一个新的 promise

  2. modulemoduleObject.[[Module]]。

  3. builtinSetNamesmoduleObject.[[BuiltinSets]]。

  4. importedStringModulemoduleObject.[[ImportedStringModule]]。

  5. 使用导入 importObjectbuiltinSetNamesimportedStringModulemodule 读取 导入,并将结果记为 imports。 如果此操作抛出异常,则捕获该异常,拒绝 promise,并返回 promise

  6. 并行运行以下步骤:

    1. 排入一个任务来执行以下步骤: 注:这里可以执行特定于实现的工作。

      1. importsmodule 实例化 WebAssembly 模块的核心, 并将结果记为 instance。 如果这一步抛出异常,则捕获该异常,拒绝 promise,并 终止这些子步骤。

      2. instanceObject 为一个新的 Instance

      3. moduleinstance 初始化 instanceObject。 如果这一步抛出异常,则捕获该异常,拒绝 promise,并 终止这些子步骤。

      4. 兑现 promise,其值为 instanceObject

  7. 返回 promise

使用导入 importObjectpromiseOfModule 实例化一个模块 promise时, 执行以下步骤:
  1. promise一个新的 promise

  2. promiseOfModule 作出响应

    • 如果 promiseOfModule 以值 module fulfilled:

      1. 用导入 importObjectmodule 实例化 WebAssembly 模块, 并将结果记为 innerPromise

      2. innerPromise 作出响应

        • 如果 innerPromise 以值 instance fulfilled。

          1. resultWebAssemblyInstantiatedSource 值 «[ "module" → module, "instance" → instance ]»。

          2. 兑现 promise,其值为 result

        • 如果 innerPromise 以原因 reason rejected:

          1. 拒绝 promise,原因是 reason

    • 如果 promiseOfModule 以原因 reason rejected:

      1. 拒绝 promise,原因是 reason

  3. 返回 promise

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

  2. 使用 optionsstableBytes 异步编译一个 WebAssembly 模块,并将结果记为 promiseOfModule

  3. 使用导入 importObjectpromiseOfModule 实例化, 并返回结果。

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

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

WebAssembly 命名空间中 JSTag 属性的 getter 在调用时执行以下步骤:

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

  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. modulemoduleObject.[[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. modulemoduleObject.[[Module]]。

  2. builtinSetNamesmoduleObject.[[BuiltinSets]]。

  3. importedStringModulemoduleObject.[[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. bytesmoduleObject.[[Bytes]]。

  2. customSections 为 « »。

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

    1. namecustomSectionname, 按 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. 如果 moduleerror,则抛出一个 CompileError 异常。

  4. builtinSetNamesoptions["builtins"]。

  5. importedStringModuleoptions["importedStringConstants"]。

  6. 如果对于 module 以及 builtinSetNamesimportedStringModule内建项和导入字符串验证返回 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. builtinSetNamesmoduleObject.[[BuiltinSets]]。

  2. importedStringModulemoduleObject.[[ImportedStringModule]]。

  3. modulemoduleObject.[[Module]]。

  4. 使用导入 importObjectbuiltinSetNamesimportedStringModulemodule 读取 导入,并将结果记为 imports

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

  6. moduleinstance 初始化 this

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

Instanceexports 属性的 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. lengthblock 的长度。

  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"] 存在,则令 addrtypedescriptor["address"];否则,令 addrtype 为 "i32"。

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

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

  4. memtype内存类型 addrtype { min initial, max maximum }。

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

  6. store外围代理关联存储

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

  8. 外围代理关联存储设为 store

  9. 初始化 this,来源为 memaddr

要对 memaddrMemory 缓冲区进行刷新,执行以下步骤:
  1. map外围代理关联的 Memory 对象缓存

  2. 断言:map[memaddr] 存在

  3. memorymap[memaddr]。

  4. buffermemory.[[BufferObject]]。

  5. 如果 IsFixedLengthArrayBuffer(buffer) 为 true,

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

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

    3. memory.[[BufferObject]] 设为 buffer

  6. 否则,

    1. block 为一个 Data Block,其与 memaddr 的 底层内存对应标识

    2. buffer.[[ArrayBufferData]] 设为 block

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

要将与一个内存地址 memaddr 关联的 内存 缓冲区扩展 delta,执行以下步骤:
  1. store外围代理关联存储

  2. retmem_size(store, memaddr)。

  3. storemem_grow(store, memaddr, delta)。

  4. 如果 storeerror,则抛出一个 RangeError 异常。

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

  6. 刷新内存缓冲区 memaddr

  7. 返回 ret

当调用 grow(delta) 方法时,执行以下 步骤:
  1. memaddrthis.[[Memory]]。

  2. store外围代理关联存储

  3. addrtype地址类型,取自 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. bufferthis.[[BufferObject]]。

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

  3. memaddrthis.[[Memory]]。

  4. fixedBuffer 为通过创建固定长度内存缓冲区memaddr 得到的结果。

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

  6. this.[[BufferObject]] 设为 fixedBuffer

  7. 返回 fixedBuffer

当调用 toResizableBuffer() 方法时,执行 以下步骤:
  1. memaddrthis.[[Memory]]。

  2. store外围代理关联存储

  3. memtypemem_type(store, memaddr)。

  4. 如果 memtype 没有 max,

    1. 抛出一个 TypeError 异常。

  5. bufferthis.[[BufferObject]]。

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

  7. 断言:memtype 有 max。

  8. maxsizememtype 中的 max 值 * 65536。

  9. resizableBuffer 为通过创建可调整大小的内存缓冲区memaddrmaxsize 得到的结果。

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

  11. this.[[BufferObject]] 设为 resizableBuffer

  12. 返回 resizableBuffer

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

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

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

    1. map外围代理关联的 Memory 对象缓存

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

    3. map 中的每个 memaddrmem逐一执行 ,

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

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

        2. lengthDeltanewLength - buffer.[[ArrayBufferByteLength]]。

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

          1. 抛出一个 RangeError 异常。

        4. deltalengthDelta ÷ 65536。

        5. 扩展内存缓冲区 ,该缓冲区与 memaddr 关联,扩展量为 delta

    4. 返回 handled

  2. 否则,返回 unhandled

Memorybuffer 属性的 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. elementtypeToValueType(descriptor["element"])。

  2. 如果 elementtype 不是一个 reftype

    1. 抛出一个 TypeError 异常。

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

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

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

  6. type表类型 addrtype { min initial, max maximum } elementtype

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

  8. 如果缺少 value

    1. refDefaultValue(elementtype)。

    2. 断言:ref 不是 error

  9. 否则,

    1. ref? ToWebAssemblyValue(value, elementtype)。

  10. store外围代理关联存储

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

  12. 外围代理关联存储设为 store

  13. 初始化 this,来源为 tableaddr

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

  2. store外围代理关联存储

  3. initialSizetable_size(store, tableaddr)。

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

  5. delta64? AddressValueToU64(delta, addrtype)。

  6. 如果缺少 value

    1. refDefaultValue(elementtype)。

    2. 如果 referror,则抛出一个 TypeError 异常。

  7. 否则,

    1. ref? ToWebAssemblyValue(value, elementtype)。

  8. resulttable_grow(store, tableaddr, delta64, ref)。

  9. 如果 resulterror,则抛出一个 RangeError 异常。

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

  10. 外围代理关联存储设为 result

  11. 返回 U64ToAddressValue(initialSize, addrtype)。

当调用 Tablelength 属性的 getter 时, 执行以下步骤:
  1. tableaddrthis.[[Table]]。

  2. store外围代理关联存储

  3. addrtype地址类型,取自 table_type(store, tableaddr)。

  4. length64table_size(store, tableaddr)。

  5. 返回 U64ToAddressValue(length64, addrtype)。

当调用 get(index) 方法时,执行以下 步骤:
  1. tableaddrthis.[[Table]]。

  2. store外围代理关联存储

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

  4. 如果 elementtype 匹配 exnref

    1. 抛出一个 TypeError 异常。

  5. index64? AddressValueToU64(index, addrtype)。

  6. resulttable_read(store, tableaddr, index64)。

  7. 如果 resulterror,则抛出一个 RangeError 异常。

  8. 返回 ! ToJSValue(result)。

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

  2. store外围代理关联存储

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

  4. 如果 elementtype 匹配 exnref

    1. 抛出一个 TypeError 异常。

  5. index64? AddressValueToU64(index, addrtype)。

  6. 如果缺少 value

    1. refDefaultValue(elementtype)。

    2. 如果 referror,则抛出一个 TypeError 异常。

  7. 否则,

    1. ref? ToWebAssemblyValue(value, elementtype)。

  8. storetable_write(store, tableaddr, index64, ref)。

  9. 如果 storeerror,则抛出一个 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. mutabledescriptor["mutable"]。

  2. valuetypeToValueType(descriptor["value"])。

  3. 如果 valuetype 匹配 v128exnref

    1. 抛出一个 TypeError 异常。

  4. 如果缺少 v

    1. valueDefaultValue(valuetype)。

    2. 断言:value 不是 error

  5. 否则,

    1. value? ToWebAssemblyValue(v, valuetype)。

  6. 如果 mutable 为 true,则令 globaltypevar valuetype;否则,令 globaltypeconst valuetype

  7. store外围代理关联存储

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

  9. 外围代理关联存储设为 store

  10. 初始化 this,来源为 globaladdr

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

  2. globaladdrglobal.[[Global]]。

  3. globaltypeglobal_type(store, globaladdr)。

  4. 如果 globaltype 的形式为 mut valuetype,且 valuetype 匹配 v128exnref,则抛出一个 TypeError

  5. valueglobal_read(store, globaladdr)。

  6. 返回 ! ToJSValue(value)。

当调用 Globalvalue 属性的 getter 时, 执行以下步骤:
  1. 返回 GetGlobalValue(this)。

Global 的 value 属性的 setter 在调用时,执行以下步骤:

  1. store外围代理关联存储

  2. globaladdrthis.[[Global]]。

  3. mut valuetypeglobal_type(store, globaladdr)。

  4. 如果 valuetype 匹配 v128exnref,则抛出一个 TypeError

  5. 如果 mutconst,则抛出一个 TypeError

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

  7. storeglobal_write(store, globaladdr, value)。

  8. 如果 storeerror,则抛出一个 RangeError 异常。

  9. 外围代理关联存储设为 store

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

5.6. 导出函数

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

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

  2. funcinststore.funcs[funcaddr]。

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

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

    2. index 为宿主函数 索引 funcaddr

  4. 否则,

    1. moduleinstfuncinst.module。

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

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

  5. 返回 ! ToString(index)。

要从 WebAssembly 函数地址 funcaddr 创建新的 导出函数,执行以下步骤:
  1. map外围代理关联的 导出函数 缓存

  2. 如果 map[funcaddr] 存在

    1. 返回 map[funcaddr]。

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

  4. realm当前 Realm

  5. store外围代理关联存储

  6. functypefunc_type(store, funcaddr)。

  7. 设 [paramTypes] → [resultTypes] 为 functype

  8. arityparamTypes大小

  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. functypefunc_type(store, funcaddr)。

  3. 设 [parameters] → [results] 为 functype

  4. 如果 parametersresults 中任一类型匹配 v128exnref,则抛出一个 TypeError

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

  5. args 为 « »。

  6. i 为 0。

  7. 对于 parameters 中的每个 t

    1. 如果 argValues大小 > i,则令 argargValues[i]。

    2. 否则,令 arg 为 undefined。

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

    4. i 设为 i + 1。

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

  9. 外围代理关联存储设为 store

  10. 如果 reterror,则抛出一个异常。除非 WebAssembly 错误映射 另有说明,该异常应为 WebAssembly RuntimeError 异常。

  11. 如果 retexception exnaddr,则

    1. tagaddrexn_tag(store, exnaddr)。

    2. payloadexn_read(store, exnaddr)。

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

    4. 如果 tagaddr 等于 jsTagAddr

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

    5. 否则,

      1. exception 为从 exnaddr 创建的新 Exception

      2. 抛出 exception

  12. outArityret大小

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

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

  15. 否则,

    1. values 为 « »。

    2. 对于 ret 中的每个 r

      1. 追加 ! ToJSValue(r) 到 values

    3. 返回 CreateArrayFromList(values)。

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

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

要从 JavaScript 对象 func、类型 functype列表WebAssembly 值 arguments 运行一个宿主 函数,执行以下步骤:
  1. 设 [parameters] → [results] 为 functype

  2. 如果 parametersresults 中任一类型匹配 v128exnref,则抛出一个 TypeError

  3. jsArguments 为 « »。

  4. 对于 arguments 中的每个 arg

    1. 追加 ! ToJSValue(arg) 到 jsArguments

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

  6. resultsSizeresults大小

  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. valuesresults 中线性配对的每个 valueresultType

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

    7. 返回 wasmValues

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

  2. stored settings现任 settings object

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

    1. realmfunc关联 Realm

    2. relevant settingsrealmsettings object

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

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

    5. result 为从 funcfunctypearguments 运行一个宿主 函数的结果。

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

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

    8. 断言:result.[[Type]] 是 thrownormal

    9. store外围代理关联存储

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

      1. vresult.[[Value]]。

      2. 如果 v 实现了 Exception

        1. addressv.[[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. i64signed_64(u64)。

    2. 返回 (i64 解释为一个数学值)。

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

    1. i32signed_32(u32)。

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

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

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

    2. 如果 f32nan,则返回 NaN

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

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

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

    2. 如果 f64nan,则返回 NaN

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

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

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

    1. i31signed_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)。

Note: 等于 NaN 的 Number 值可能具有 各种可观察到的 NaN payload;详见 NumericToRawBytes

对于从宿主地址 hostaddr 检索一个 宿主值,执行以下步骤:

  1. map外围代理关联的 宿主值缓存

  2. 断言:map[hostaddr] 存在

  3. 返回 map[hostaddr]。

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

  2. 断言:type匹配 exnref

  3. 如果 typei64

    1. i64? ToBigInt64(v)。

    2. u64 为无符号整数,使得 i64signed_64(u64)。

    3. 返回 i64.const u64

  4. 如果 typei32

    1. i32? ToInt32(v)。

    2. u32 为无符号整数,使得 i32signed_32(u32)。

    3. 返回 i32.const u32

  5. 如果 typef32

    1. number? ToNumber(v)。

    2. 如果 numberNaN

      1. n 为一个实现定义的整数,使得 canon32n < 2signif(32)

      2. f32nan(n)。

    3. 否则,

      1. f32 为将 number 按 IEEE 754-2019 舍入到最接近的可表示值, 并使用 round to nearest, ties to even 模式得到的结果。[IEEE-754]

    4. 返回 f32.const f32

  6. 如果 typef64

    1. number? ToNumber(v)。

    2. 如果 numberNaN

      1. n 为一个实现定义的整数,使得 canon64n < 2signif(64)

      2. f64nan(n)。

    3. 否则,

      1. f64number

    4. 返回 f64.const f64

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

    1. 如果 v 为 null,

      1. rref.null heaptype

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

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

      2. rref.extern ref

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

      1. funcaddrv 的 [[FunctionAddress]] 内部槽的值。

      2. rref.func funcaddr

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

      1. i31? ToInt32(v)。

      2. u31 为无符号整数,使得 i31signed_31(u31)。

      3. rref.i31 u31

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

      1. objectaddrv 的 [[ObjectAddress]] 内部槽的值。

      2. objectkindv 的 [[ObjectKind]] 内部槽的值。

      3. 如果 objectkind 是 "array",

        1. rref.array objectaddr

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

        1. rref.struct objectaddr

    6. 否则,

      1. map外围代理关联的 宿主值缓存

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

        1. 返回 ref.host hostaddr

      3. 宿主地址 hostaddr 为满足 map[hostaddr] 不存在的最小地址。

      4. 设定 map[hostaddr] 为 v

      5. rref.host hostaddr

    7. store外围代理关联存储

    8. actualtyperef_type(store, r)。

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

      1. 抛出一个 TypeError

    10. 返回 r

  8. 断言:不会到达这一步。

算法 AddressValueToU64(v, addrtype) 将 JavaScript 值转换为用于嵌入操作的 WebAssembly u64。它被设计为在 AddressType 为 "i32" 时,其行为类似于 [EnforceRange] unsigned long,并通过执行以下步骤将这些语义扩展到 AddressType "i64":
  1. 如果 addrtype 是 "i32",

    1. n? ConvertToInt(v, 32, "unsigned"),其中目标类型与 [EnforceRange] 相关联。

      Note: 这等价于 JS 转换规则 中对于 [EnforceRange] unsigned long 的规定。

    2. 返回 (n) 作为一个 WebAssembly u64

  2. 如果 addrtype 是 "i64",

    1. n? ToBigInt(v)。

    2. 如果 n < 0 或 n > 264 − 1,则抛出一个 TypeError

      Note: 此操作被设计为 模拟 [EnforceRange]

    3. 返回 (n) 作为一个 WebAssembly u64

  3. 断言:不会到达这一步。

算法 U64ToAddressValue(v, addrtype) 将来自 WebAssembly 嵌入操作的 u64 值转换为适用于某个 AddressType 的正确 AddressValue 变体,执行以下步骤:
  1. 如果 addrtype 是 "i32",则返回 𝔽(v 解释为一个 数学值)。

  2. 否则如果 addrtype 是 "i64",则返回 (v 解释为一个 数学值)。

  3. 断言:不会到达这一步。

5.7. 标签

5.7.1. 标签类型

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

[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
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. parameterstype["parameters"]。

  2. wasmParameters 为 «»。

  3. 对于 parameters 中的每个 paramType

    1. 追加 ToValueType(paramType) 到 wasmParameters

  4. store外围代理关联存储

  5. 设 (store, tagAddress) 为 tag_alloc(store, wasmParameters → « »)。

  6. 外围代理关联存储设为 store

  7. 初始化 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. 令 keys 为一个新的空列表。

  2. 返回 keys。

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

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

  3. 如果 map[objectaddr] 存在

    1. 返回 map[objectaddr]。

  4. objectMakeBasicObject(« [[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=(Window,Worker,Worklet)]
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. tagaddrexn_tag(store, exnAddress)。

  7. payloadexn_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. 设 [types] → [] 为 tag_type(store, exceptionTag.[[Address]])。

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

    1. 抛出一个 TypeError

  6. wasmPayload 为 « »。

  7. 对于 payloadtypes 中按线性方式配对的每个 valueresultType

    1. 如果 resultType 匹配 v128exnref

      1. 抛出一个 TypeError

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

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

  9. 外围代理关联存储设为 store

  10. 初始化 this,来源为 exceptionAddr

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

    1. this.[[Stack]] 设为当前调用栈的 DOMString 表示形式,或设为 undefined。

getArg(exceptionTag, index) 方法步骤如下:

  1. store外围代理关联存储

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

    1. 抛出一个 TypeError

  3. tagaddrexn_tag(store, this.[[Address]])。

  4. payloadexn_read(store, this.[[Address]])。

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

  6. 如果 indexpayload大小

    1. 抛出一个 RangeError

  7. 设 [types] → [] 为 tag_type(store, tagaddr)。

  8. 如果 types[index] 匹配 v128exnref

    1. 抛出一个 TypeError

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

is(exceptionTag) 方法步骤如下:

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

    1. 返回 false。

  2. 返回 true。

stack getter 步骤如下:

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

5.9.1. JavaScript 异常

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

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

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

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

  2. store外围代理关联存储

  3. 设 (store, tagAddress) 为 tag_alloc(store, « externref » → « »)。

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

  5. 外围代理关联的 JavaScript 异常 标签设为 tagAddress

  6. 返回 tagAddress

5.10. 错误对象

WebAssembly 定义了以下 Error 类:CompileErrorLinkError,以及 RuntimeError

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

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

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

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

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

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

6. 内建项

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

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

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

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

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

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

  2. importModuleNameimport[0]。

  3. importNameimport[1]。

  4. 对于 builtinSetNames 中的每个 builtinSetName

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

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

    3. 如果 importModuleName 等于 builtinSetQualifiedName

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

      2. 对于 builtins 中的每个 builtin

        1. builtinNamebuiltin[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 为使用 funcTypesteps 创建一个 内建函数 的结果。

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

    3. valuefunc

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

    5. 断言:status 为 true。

  4. 返回 exportsObject

要根据 import 和启用的内建项 builtinSetNames 验证一个内建项导入,执行以下步骤:

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

  2. maybeBuiltin 为对 importbuiltinSetNames 查找一个内建项 的结果。

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

  4. importExternTypeimport[2]。

  5. builtinFuncTypemaybeBuiltin[1][1]。

  6. builtinExternTypefunc |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

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

  1. 如果 array 是 null,

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

  2. lengtharray 中元素的个数。

  3. 如果 start > endend > length

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

  4. result 为空字符串。

  5. istart

  6. i < end 时:

    1. charCodearray 中索引 i 处存储元素的值。

    2. charCodeStringFromCharCode(charCode)。

    3. resultresultcharCodeString 的拼接结果。

    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

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

  1. 如果 array 是 null,

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

  2. string? UnwrapString(string)。

  3. stringLengthstring长度

  4. arrayLengtharray 中元素的个数。

  5. 如果 start + stringLength > arrayLength

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

  6. i 为 0。

  7. i < stringLength 时:

    1. charCodeCharCodeAt(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

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

  1. string? UnwrapString(string)。

  2. lengthstring长度

  3. 如果 index >= length

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

  4. 返回 CharCodeAt(string, index)。

6.1.9. codePointAt

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

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

  1. string? UnwrapString(string)。

  2. lengthstring长度

  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

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

  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

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

  1. string? UnwrapString(string)。

  2. lengthstring长度

  3. 如果 start > endstart > 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 字符串进行相等性比较, 因为这具有意义。

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

  1. 如果 first 不为 null,且 first 不是字符串

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

  2. 如果 second 不为 null,且 second 不是字符串

    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

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

  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;
    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=(Window,Worker,Worklet)]
interface Tag {
  constructor(TagType type);
};

dictionary ExceptionOptions {
  boolean traceStack = false;
};

[LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)]
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