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 >; }; [Exposed=*]builtins 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 ; };
-
设 module 为 module_decode(bytes)。如果 module 是 error,则返回 error。
-
如果 module_validate(module) 是 error,则返回 error。
-
返回 module。
对于模块 module、启用的内建项 builtinSetNames 以及 importedStringModule,要验证 WebAssembly 模块的内建项和导入字符串, 请执行以下步骤:
-
如果对 builtinSetNames 进行内建项集合名称验证的结果为 false,则返回 false。
-
对 module_imports(module) 的每个 import,逐一执行:
-
如果 importedStringModule 不为 null 且 import[0] 等于 importedStringModule,
-
设 importExternType 为 import[2]。
-
设 stringExternType 为
global const (ref extern)。 -
如果 match_externtype(stringExternType, importExternType) 为 false,则返回 false
-
-
否则,
-
如果使用 import 和 builtinSetNames 进行内建项导入验证的结果为 false, 则返回 false。
-
-
-
返回 true。
validate(bytes, options) 方法
在调用时执行以下步骤:
-
设 stableBytes 为缓冲区所持字节的副本 bytes。
-
将 stableBytes 编译为 WebAssembly 模块,并将结果存为 module。
-
如果 module 是 error,则返回 false。
-
设 builtinSetNames 为 options["builtins"]。
-
设 importedStringModule 为 options["importedStringConstants"]。
-
如果对于 module 以及 builtinSetNames 和 importedStringModule 进行内建项和导入字符串验证 返回 false,则返回 false。
-
返回 true。
Module 对象
表示单个 WebAssembly 模块。每个 Module 对象具有以下
内部槽:
-
[[Module]]:一个 WebAssembly 模块
-
[[Bytes]]:[[Module]] 的源字节。
-
[[BuiltinSets]]:内建项集合名称的有序集合
-
[[ImportedStringModule]]:一个可选的模块说明符字符串,任意字符串常量都可以从其中导入。
WebAssemblyCompileOptions
options 异步编译 WebAssembly 模块时,执行以下步骤:
-
设 promise 为一个新的 promise。
-
并行运行以下步骤:
-
编译 WebAssembly 模块 bytes,并将结果存为 module。
-
如果提供了 taskSource,则在其上排入一个任务,执行以下步骤:
-
如果 module 是 error,则用一个
CompileError异常拒绝 promise,并返回。 -
设 builtinSetNames 为 options["builtins"]。
-
设 importedStringModule 为 options["importedStringConstants"]。
-
如果对于 module 以及 builtinSetNames 和 importedStringModule 的内建项和导入字符串验证结果为 false,则用一个
CompileError异常拒绝 promise。 -
否则,
-
从 module、 bytes、builtinSetNames 和 importedStringModule 构造一个 WebAssembly 模块对象,并将结果记为 moduleObject。
-
兑现 promise,其值为 moduleObject。
-
-
-
-
返回 promise。
compile(bytes, options) 方法
在调用时执行以下步骤:
-
设 stableBytes 为缓冲区所持字节的副本 bytes。
-
使用 options 从 stableBytes 异步编译一个 WebAssembly 模块并返回结果。
使用模块 module 和 importedStringModule 实例化导入字符串时,执行以下步骤:
-
断言:importedStringModule 不为 null。
-
设 exportsObject 为 ! OrdinaryObjectCreate(null) 的结果。
-
对 module_imports(module) 中的每个 (moduleName, componentName, externtype),逐一执行:
-
如果 moduleName 不等于 importedStringModule,则继续。
-
设 stringConstant 为 componentName。
-
设 status 为 ! CreateDataProperty(exportsObject, stringConstant, stringConstant) 的结果。
-
断言:status 为 true。
-
-
返回 exportsObject。
-
如果 module.imports 非空, 且 importObject 为 undefined,则抛出一个
TypeError异常。 -
设 builtinOrStringImports 为有序映射 « »。
-
对 builtinSetNames 中的每个 builtinSetName,逐一执行:
-
设 builtinSetQualifiedName 为带有前缀 "wasm:" 的 builtinSetName
-
断言:builtinOrStringImports 不包含 builtinSetQualifiedName
-
如果 builtinSetName 未指向一个内建项集合,则继续。
-
设 exportsObject 为使用 builtinSetName 实例化一个内建项集合 的结果
-
设定 builtinOrStringImports[builtinSetQualifiedName] 为 exportsObject
-
-
如果 importedStringModule 不为 null,
-
设 imports 为 « »。
-
对 module_imports(module) 中的每个 (moduleName, componentName, externtype),逐一执行:
-
如果 builtinOrStringImports 包含 moduleName,
-
设 o 为 builtinOrStringImports[moduleName]。
-
如果 o 不是对象,或 HasProperty(o, componentName) 为 false,
-
-
否则,
-
如果 externtype 的形式为 func functype,
-
如果 externtype 的形式为 global mut valtype,
-
-
设 globaladdr 为 v.[[Global]]。
-
-
否则,
-
如果 valtype 是 i64 且 v 不是 BigInt,
-
抛出一个
LinkError异常。
-
-
如果 valtype 是 i32、f32 或 f64 之一,且 v 不是 Number,
-
抛出一个
LinkError异常。
-
-
如果 valtype 是 v128,
-
抛出一个
LinkError异常。
-
-
设 value 为 ToWebAssemblyValue(v, valtype)。如果此操作抛出一个
TypeError, 则捕获它,并抛出一个LinkError异常。 -
设 (store, globaladdr) 为 global_alloc(store, const valtype, value)。
-
-
设 externglobal 为 global globaladdr。
-
将 externglobal 追加到 imports。
-
-
如果 externtype 的形式为 mem memtype,
-
如果 externtype 的形式为 table tabletype,
-
如果 externtype 的形式为 tag attribute functype,
-
-
返回 imports。
注:该算法仅验证 传入的 JavaScript 值类型是否正确。 对 WebAssembly 类型要求的验证将推迟到 “实例化 WebAssembly 模块核心” 算法中进行。
-
设 exportsObject 为 ! OrdinaryObjectCreate(null) 的结果。
-
对 module_exports(module) 中的每个 (name, externtype),逐一执行:
-
设 externval 为 instance_export(instance, name)。
-
断言:externval 不是 error。
-
如果 externtype 的形式为 func functype,
-
如果 externtype 的形式为 global mut globaltype,
-
断言:externval 的形式为 global globaladdr。
-
设 global globaladdr 为 externval。
-
设 global 为从 globaladdr 创建一个新的 Global 对象 的结果。
-
设 value 为 global。
-
-
如果 externtype 的形式为 mem memtype,
-
断言:externval 的形式为 mem memaddr。
-
设 mem memaddr 为 externval。
-
设 memory 为从 memaddr 创建一个新的 Memory 对象 的结果。
-
设 value 为 memory。
-
-
如果 externtype 的形式为 table tabletype,
-
断言:externval 的形式为 table tableaddr。
-
设 table tableaddr 为 externval。
-
设 table 为从 tableaddr 创建一个新的 Table 对象 的结果。
-
设 value 为 table。
-
-
如果 externtype 的形式为 tag attribute functype,
-
断言:attribute 是 exception。
-
断言:externval 的形式为 tag tagaddr。
-
设 tag tagaddr 为 externval。
-
设 tag 为从 tagaddr 创建一个新的 Tag 对象 的结果。
-
设 value 为 tag。
-
-
设 status 为 ! CreateDataProperty(exportsObject, name, value) 的结果。
-
断言:status 为 true。
注:在 WebAssembly 模块验证期间执行的有效性和唯一性检查 可确保每个属性名都有效,且没有任何属性被定义两次。
-
-
执行 ! SetIntegrityLevel(exportsObject,
"frozen")。 -
返回 exportsObject。
-
从 module 和 instance 创建一个导出对象,并将结果记为 exportsObject。
-
将 instanceObject.[[Instance]] 设为 instance。
-
将 instanceObject.[[Exports]] 设为 exportsObject。
-
设 result 为 module_instantiate(store, module, imports)。
-
如果 result 是 error,则抛出适当的异常类型:
-
对于链接期间发生的大多数情况,抛出一个
LinkError异常。 -
如果错误发生在运行启动函数时,则对于大多数来自 WebAssembly 的错误, 抛出一个
RuntimeError, 或抛出从内部 ECMAScript 代码传播出来的错误对象。 -
如有适用,抛出另一种错误类型,例如 WebAssembly 错误映射中说明的内存不足异常。
-
-
设 (store, instance) 为 result。
-
返回 instance。
Module
moduleObject 和导入 importObject
异步实例化一个 WebAssembly
模块时,执行以下步骤:
-
设 promise 为一个新的 promise。
-
设 module 为 moduleObject.[[Module]]。
-
设 builtinSetNames 为 moduleObject.[[BuiltinSets]]。
-
设 importedStringModule 为 moduleObject.[[ImportedStringModule]]。
-
使用导入 importObject、 builtinSetNames 和 importedStringModule 对 module 读取 导入,并将结果记为 imports。 如果此操作抛出异常,则捕获该异常,拒绝 promise,并返回 promise。
-
并行运行以下步骤:
-
返回 promise。
-
设 promise 为一个新的 promise。
-
对 promiseOfModule 作出响应:
-
如果 promiseOfModule 以值 module fulfilled:
-
用导入 importObject 对 module 实例化 WebAssembly 模块, 并将结果记为 innerPromise。
-
对 innerPromise 作出响应:
-
如果 innerPromise 以值 instance fulfilled。
-
设 result 为
WebAssemblyInstantiatedSource值 «[ "module" → module, "instance" → instance ]»。 -
兑现 promise,其值为 result。
-
-
如果 innerPromise 以原因 reason rejected:
-
拒绝 promise,原因是 reason。
-
-
-
-
如果 promiseOfModule 以原因 reason rejected:
-
拒绝 promise,原因是 reason。
-
-
-
返回 promise。
instantiate(bytes, importObject, options)
方法在调用时执行以下步骤:
-
设 stableBytes 为缓冲区所持字节的副本 bytes。
-
使用 options 从 stableBytes 异步编译一个 WebAssembly 模块,并将结果记为 promiseOfModule。
-
使用导入 importObject 对 promiseOfModule 实例化, 并返回结果。
instantiate(moduleObject, importObject)
方法在调用时执行以下步骤:
-
使用导入 importObject 异步实例化 WebAssembly 模块 moduleObject,并返回 结果。
注:后续的流式 API 记录在 WebAssembly Web API 中。
WebAssembly
命名空间中 JSTag 属性的 getter
在调用时执行以下步骤:
-
设 JSTagAddr 为 获取 JavaScript 异常标签 的结果。
-
设 JSTagObject 为从 JSTagAddr 创建一个 Tag 对象 的结果。
-
返回 JSTagObject。
5.1. 模块
enum {ImportExportKind ,"function" ,"table" ,"memory" ,"global" };"tag" enum {AddressType ,"i32" , };"i64" typedef any ;AddressValue dictionary {ModuleExportDescriptor required USVString ;name required ImportExportKind ; // Note: Other fields such as signature may be added in the future. };kind 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
exports(moduleObject) 方法在调用时,
执行以下步骤:
imports(moduleObject) 方法在调用时,
执行以下步骤:
-
设 module 为 moduleObject.[[Module]]。
-
设 builtinSetNames 为 moduleObject.[[BuiltinSets]]。
-
设 importedStringModule 为 moduleObject.[[ImportedStringModule]]。
-
设 imports 为 « »。
-
对 module_imports(module) 中的每个 (moduleName, name, type),逐一执行:
-
返回 imports。
customSections(moduleObject, sectionName)
方法在调用时执行以下步骤:
-
设 bytes 为 moduleObject.[[Bytes]]。
-
设 customSections 为 « »。
-
对按照模块语法解释的 bytes 中每个 自定义段 customSection,逐一执行,
-
设 name 为 customSection 的
name, 按 UTF-8 解码。 -
断言:name 不是 failure (moduleObject.[[Module]] 是有效的)。
-
如果 name 作为字符串值等于 sectionName,
-
将一个新的
ArrayBuffer追加到 customSections,该缓冲区包含 bytes 中与此 customsec 产生式匹配范围内字节的副本。
-
-
-
返回 customSections。
Module(bytes, options) 构造函数在
调用时执行以下步骤:
-
设 stableBytes 为缓冲区所持字节的副本 bytes。
-
将 stableBytes 编译为 WebAssembly 模块, 并将结果存为 module。
-
如果 module 是 error,则抛出一个
CompileError异常。 -
设 builtinSetNames 为 options["builtins"]。
-
设 importedStringModule 为 options["importedStringConstants"]。
-
如果对于 module 以及 builtinSetNames 和 importedStringModule 的内建项和导入字符串验证返回 false,则抛出一个
CompileError异常。 -
将 this.[[Module]] 设为 module。
-
将 this.[[Bytes]] 设为 stableBytes。
-
将 this.[[BuiltinSets]] 设为 builtinSetNames。
-
将 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)
构造函数在调用时运行以下步骤:
-
设 builtinSetNames 为 moduleObject.[[BuiltinSets]]。
-
设 importedStringModule 为 moduleObject.[[ImportedStringModule]]。
-
设 module 为 moduleObject.[[Module]]。
-
使用导入 importObject、 builtinSetNames 和 importedStringModule 对 module 读取 导入,并将结果记为 imports。
-
用 imports 对 module 实例化 WebAssembly 模块的核心,并将 instance 记为结果。
-
从 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 对象具有
以下内部槽:
-
[[Memory]]:一个 内存地址
-
[[BufferObject]]:一个
ArrayBuffer, 其 Data Block 与上述内存地址对应标识
-
设 block 为一个 Data Block,其与 memaddr 的底层 内存对应标识。
-
设 buffer 为一个新的
ArrayBuffer, 带有内部槽 [[ArrayBufferData]]、[[ArrayBufferByteLength]] 和 [[ArrayBufferDetachKey]]。 -
将 buffer.[[ArrayBufferData]] 设为 block。
-
将 buffer.[[ArrayBufferByteLength]] 设为 block 的长度。
-
将 buffer.[[ArrayBufferDetachKey]] 设为 "WebAssembly.Memory"。
-
返回 buffer。
-
设 block 为一个 Data Block,其与 memaddr 的底层 内存对应标识。
-
设 length 为 block 的长度。
-
设 buffer 为一个新的
ArrayBuffer, 带有内部槽 [[ArrayBufferData]]、[[ArrayBufferByteLength]]、 [[ArrayBufferMaxByteLength]] 和 [[ArrayBufferDetachKey]]。 -
将 buffer.[[ArrayBufferData]] 设为 block。
-
将 buffer.[[ArrayBufferByteLength]] 设为 length。
-
将 buffer.[[ArrayBufferMaxByteLength]] 设为 maxsize。
-
将 buffer.[[ArrayBufferDetachKey]] 设为 "WebAssembly.Memory"。
-
返回 buffer。
-
设 map 为外围代理关联的 Memory 对象缓存。
-
断言:map[memaddr] 不存在。
-
设 buffer 为通过创建固定长度内存缓冲区 从 memaddr 得到的结果。
-
将 memory.[[Memory]] 设为 memaddr。
-
将 memory.[[BufferObject]] 设为 buffer。
-
设定 map[memaddr] 为 memory。
Memory(descriptor) 构造函数时,
执行以下步骤:
-
如果 descriptor["address"] 存在,则令 addrtype 为 descriptor["address"];否则,令 addrtype 为 "i32"。
-
设 initial 为 ? AddressValueToU64(descriptor["initial"], addrtype)。
-
如果 descriptor["maximum"] 存在,则令 maximum 为 ? AddressValueToU64(descriptor["maximum"], addrtype);否则,令 maximum 为空。
-
设 memtype 为 内存类型 addrtype { min initial, max maximum }。
-
如果 memtype 不有效,则抛出一个
RangeError异常。 -
设 (store, memaddr) 为 mem_alloc(store, memtype)。如果 分配失败,则抛出一个
RangeError异常。 -
初始化 this,来源为 memaddr。
-
设 map 为外围代理关联的 Memory 对象缓存。
-
断言:map[memaddr] 存在。
-
设 memory 为 map[memaddr]。
-
设 buffer 为 memory.[[BufferObject]]。
-
如果 IsFixedLengthArrayBuffer(buffer) 为 true,
-
执行 ! DetachArrayBuffer(buffer, "WebAssembly.Memory")。
-
设 buffer 为通过创建固定长度内存 缓冲区从 memaddr 得到的结果。
-
将 memory.[[BufferObject]] 设为 buffer。
-
-
否则,
-
设 block 为一个 Data Block,其与 memaddr 的 底层内存对应标识。
-
将 buffer.[[ArrayBufferData]] 设为 block。
-
将 buffer.[[ArrayBufferByteLength]] 设为 block 的长度。
-
grow(delta) 方法时,执行以下
步骤:
-
设 memaddr 为 this.[[Memory]]。
-
设 delta64 为 ? AddressValueToU64(delta, addrtype)。
-
设 ret 为通过扩展内存缓冲区得到的结果,该缓冲区与 memaddr 关联,扩展量为 delta64。
-
返回 U64ToAddressValue(ret, addrtype)。
在一条 WebAssembly memory.grow x 指令执行之后,立即执行以下 步骤:
toFixedLengthBuffer() 方法时,
执行以下步骤:
-
设 buffer 为 this.[[BufferObject]]。
-
如果 IsFixedLengthArrayBuffer(buffer) 为 true,则返回 buffer。
-
设 memaddr 为 this.[[Memory]]。
-
设 fixedBuffer 为通过创建固定长度内存缓冲区 从 memaddr 得到的结果。
-
执行 ! DetachArrayBuffer(buffer, "WebAssembly.Memory")。
-
将 this.[[BufferObject]] 设为 fixedBuffer。
-
返回 fixedBuffer。
toResizableBuffer() 方法时,执行
以下步骤:
-
设 memaddr 为 this.[[Memory]]。
-
设 memtype 为 mem_type(store, memaddr)。
-
如果 memtype 没有 max,
-
设 buffer 为 this.[[BufferObject]]。
-
如果 IsFixedLengthArrayBuffer(buffer) 为 false,则返回 buffer。
-
断言:memtype 有 max。
-
设 maxsize 为 memtype 中的 max 值 * 65536。
-
设 resizableBuffer 为通过创建可调整大小的内存缓冲区从 memaddr 和 maxsize 得到的结果。
-
执行 ! DetachArrayBuffer(buffer, "WebAssembly.Memory")。
-
将 this.[[BufferObject]] 设为 resizableBuffer。
-
返回 resizableBuffer。
ArrayBuffer
对象由 Memory
对象返回时,大小必须是
WebAssembly 页大小
(常量 65536)的倍数。因此,HostResizeArrayBuffer 被重新定义如下。
抽象操作
HostResizeArrayBuffer 接受参数
buffer(一个 ArrayBuffer)
和 newLength。调用时执行以下步骤。
-
如果 buffer.[[ArrayBufferDetachKey]] 是 "WebAssembly.Memory",
-
设 map 为外围代理关联的 Memory 对象缓存。
-
断言:buffer 恰好是 map 中某一个值的 [[BufferObject]]。
-
对 map 中的每个 memaddr → mem,逐一执行 ,
-
如果 SameValue(mem.[[BufferObject]], buffer) 为 true,
-
断言:buffer.[[ArrayBufferByteLength]] 模 65536 等于 0。
-
设 lengthDelta 为 newLength - buffer.[[ArrayBufferByteLength]]。
-
如果 lengthDelta < 0 或 lengthDelta 模 65536 不等于 0,
-
抛出一个
RangeError异常。
-
-
设 delta 为 lengthDelta ÷ 65536。
-
扩展内存缓冲区 ,该缓冲区与 memaddr 关联,扩展量为 delta。
-
-
-
返回
handled 。
-
-
否则,返回
unhandled 。
Memory 的
buffer 属性的 getter 返回
this.[[BufferObject]]。
5.4. 表
enum {TableKind ,"externref" , // 注:未来迭代中可能会增加更多值, // 例如,带类型的函数引用、带类型的 GC 引用 };"anyfunc" 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]] 内部槽,它是一个 表地址。
-
设 map 为外围代理关联的 Table 对象缓存。
-
断言:map[tableaddr] 不存在。
-
将 table.[[Table]] 设为 tableaddr。
-
设定 map[tableaddr] 为 table。
Table(descriptor, value) 构造函数时,
执行以下步骤:
-
设 elementtype 为 ToValueType(descriptor["element"])。
-
如果 elementtype 不是一个 reftype,
-
如果 descriptor["address"] 存在,则令 addrtype 为 descriptor["address"];否则,令 addrtype 为 "i32"。
-
设 initial 为 ? AddressValueToU64(descriptor["initial"], addrtype)。
-
如果 descriptor["maximum"] 存在,则令 maximum 为 ? AddressValueToU64(descriptor["maximum"], addrtype);否则,令 maximum 为空。
-
设 type 为 表类型 addrtype { min initial, max maximum } elementtype。
-
如果 type 不有效,则抛出一个
RangeError异常。 -
如果缺少 value,
-
设 ref 为 DefaultValue(elementtype)。
-
断言:ref 不是 error。
-
-
否则,
-
设 ref 为 ? ToWebAssemblyValue(value, elementtype)。
-
-
设 (store, tableaddr) 为 table_alloc(store, type, ref)。如果分配失败,则抛出一个
RangeError异常。 -
初始化 this,来源为 tableaddr。
grow(delta, value) 方法时,
执行以下步骤:
-
设 tableaddr 为 this.[[Table]]。
-
设 initialSize 为 table_size(store, tableaddr)。
-
设 (addrtype, limits, elementtype) 为 table_type(store, tableaddr)。
-
设 delta64 为 ? AddressValueToU64(delta, addrtype)。
-
如果缺少 value,
-
设 ref 为 DefaultValue(elementtype)。
-
-
否则,
-
设 ref 为 ? ToWebAssemblyValue(value, elementtype)。
-
-
设 result 为 table_grow(store, tableaddr, delta64, ref)。
-
如果 result 是 error,则抛出一个
RangeError异常。注:上述异常可能由于 内存不足或大小参数无效而发生。
-
返回 U64ToAddressValue(initialSize, addrtype)。
Table 的
length 属性的 getter 时,
执行以下步骤:
-
设 tableaddr 为 this.[[Table]]。
-
设 addrtype 为 地址类型,取自 table_type(store, tableaddr)。
-
设 length64 为 table_size(store, tableaddr)。
-
返回 U64ToAddressValue(length64, addrtype)。
get(index) 方法时,执行以下
步骤:
-
设 tableaddr 为 this.[[Table]]。
-
设 (addrtype, limits, elementtype) 为 table_type(store, tableaddr)。
-
-
抛出一个
TypeError异常。
-
-
设 index64 为 ? AddressValueToU64(index, addrtype)。
-
设 result 为 table_read(store, tableaddr, index64)。
-
如果 result 是 error,则抛出一个
RangeError异常。
set(index, value) 方法时,
执行以下步骤:
-
设 tableaddr 为 this.[[Table]]。
-
设 (addrtype, limits, elementtype) 为 table_type(store, tableaddr)。
-
-
抛出一个
TypeError异常。
-
-
设 index64 为 ? AddressValueToU64(index, addrtype)。
-
如果缺少 value,
-
设 ref 为 DefaultValue(elementtype)。
-
-
否则,
-
设 ref 为 ? ToWebAssemblyValue(value, elementtype)。
-
-
设 store 为 table_write(store, tableaddr, index64, ref)。
-
如果 store 是 error,则抛出一个
RangeError异常。
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 对象具有
一个内部槽:
-
[[Global]]:一个 全局地址
-
设 map 为外围代理关联的 Global 对象缓存。
-
断言:map[globaladdr] 不存在。
-
将 global.[[Global]] 设为 globaladdr。
-
设定 map[globaladdr] 为 global。
-
如果 valuetype 等于 externref,返回 ! ToWebAssemblyValue(undefined, valuetype)。
-
返回 val_default(valuetype)。
Global(descriptor, v) 构造函数时,
执行以下步骤:
-
设 mutable 为 descriptor["mutable"]。
-
设 valuetype 为 ToValueType(descriptor["value"])。
-
如果 valuetype 匹配 v128 或 exnref,
-
抛出一个
TypeError异常。
-
-
如果缺少 v,
-
设 value 为 DefaultValue(valuetype)。
-
断言:value 不是 error。
-
-
否则,
-
设 value 为 ? ToWebAssemblyValue(v, valuetype)。
-
-
如果 mutable 为 true,则令 globaltype 为 var valuetype;否则,令 globaltype 为 const valuetype。
-
设 (store, globaladdr) 为 global_alloc(store, globaltype, value)。
-
初始化 this,来源为 globaladdr。
Global
global) 执行以下步骤:
-
设 globaladdr 为 global.[[Global]]。
-
设 globaltype 为 global_type(store, globaladdr)。
-
如果 globaltype 的形式为 mut valuetype,且 valuetype 匹配 v128 或 exnref,则抛出一个
TypeError。 -
设 value 为 global_read(store, globaladdr)。
Global 的
value 属性的 getter 时,
执行以下步骤:
-
返回 GetGlobalValue(this)。
Global 的 value
属性的 setter 在调用时,执行以下步骤:
-
设 globaladdr 为 this.[[Global]]。
-
设 mut valuetype 为 global_type(store, globaladdr)。
-
设 value 为 ? ToWebAssemblyValue(给定的值, valuetype)。
-
设 store 为 global_write(store, globaladdr, value)。
-
如果 store 是 error,则抛出一个
RangeError异常。
valueOf() 方法时,执行以下步骤:
-
返回 GetGlobalValue(this)。
5.6. 导出函数
WebAssembly 函数在 JavaScript 中以导出函数的形式提供。 导出函数是内建函数对象,它们不是构造器,并且 具有 [[FunctionAddress]] 内部槽。 该槽保存了一个相对于外围代理关联存储的函数地址。
-
设 funcinst 为 store.funcs[funcaddr]。
-
如果 funcinst 的形式为 {type functype, hostcode hostfunc},
-
断言:hostfunc 是一个 JavaScript 对象,且 IsCallable(hostfunc) 为 true。
-
设 index 为宿主函数 索引 funcaddr。
-
-
否则,
-
设 moduleinst 为 funcinst.module。
-
断言:funcaddr 包含在 moduleinst.funcaddrs 中。
-
设 index 为在 moduleinst.funcaddrs 中找到 funcaddr 的索引。
-
-
如果 map[funcaddr] 存在,
-
返回 map[funcaddr]。
-
-
设 steps 为“调用导出函数 funcaddr 并传入参数。”
-
设 realm 为当前 Realm。
-
设 functype 为 func_type(store, funcaddr)。
-
设 [paramTypes] → [resultTypes] 为 functype。
-
设 arity 为 paramTypes 的大小。
-
设 name 为 WebAssembly 函数 名称 funcaddr。
-
设 function 为 ! CreateBuiltinFunction(steps, arity, name, « [[FunctionAddress]] », realm)。
-
将 function.[[FunctionAddress]] 设为 funcaddr。
-
设定 map[funcaddr] 为 function。
-
返回 function。
-
设 functype 为 func_type(store, funcaddr)。
-
设 [parameters] → [results] 为 functype。
-
如果 parameters 或 results 中任一类型匹配 v128 或 exnref,则抛出一个
TypeError。Note: 每次调用 [[Call]] 方法时,都会抛出上述错误。
-
设 args 为 « »。
-
设 i 为 0。
-
对于 parameters 中的每个 t,
-
如果 argValues 的大小 > i,则令 arg 为 argValues[i]。
-
否则,令 arg 为 undefined。
-
追加 ? ToWebAssemblyValue(arg, t) 到 args。
-
将 i 设为 i + 1。
-
-
设 (store, ret) 为 func_invoke(store, funcaddr, args) 的结果。
-
如果 ret 是 error,则抛出一个异常。除非 WebAssembly 错误映射 另有说明,该异常应为 WebAssembly
RuntimeError异常。 -
如果 ret 是 exception exnaddr,则
-
设 tagaddr 为 exn_tag(store, exnaddr)。
-
设 payload 为 exn_read(store, exnaddr)。
-
设 jsTagAddr 为获取 JavaScript 异常标签的结果。
-
如果 tagaddr 等于 jsTagAddr,
-
否则,
-
设 exception 为从 exnaddr 创建的新 Exception。
-
抛出 exception。
-
-
-
设 outArity 为 ret 的大小。
-
如果 outArity 为 0,则返回 undefined。
-
否则,
-
设 values 为 « »。
-
对于 ret 中的每个 r,
-
返回 CreateArrayFromList(values)。
-
Note: 调用导出函数 会在被调用导出函数的 [[Realm]] 中执行,这符合内建函数对象的定义。
Note: 导出函数没有 [[Construct]]
方法,因此不能使用 new 运算符调用它。
-
设 [parameters] → [results] 为 functype。
-
如果 parameters 或 results 中任一类型匹配 v128 或 exnref,则抛出一个
TypeError。 -
设 jsArguments 为 « »。
-
对于 arguments 中的每个 arg,
-
设 resultsSize 为 results 的大小。
-
如果 resultsSize 为 0,则返回 « »。
-
否则,如果 resultsSize 为 1,则返回 « ? ToWebAssemblyValue(ret, results[0]) »。
-
否则,
-
设 method 为 ? GetMethod(ret,
%Symbol.iterator%)。 -
设 values 为 ? IteratorToList(? GetIteratorFromMethod(ret, method))。
-
设 wasmValues 为一个新的空列表。
-
对 values 和 results 中线性配对的每个 value 和 resultType,
-
追加 ? ToWebAssemblyValue(value, resultType) 到 wasmValues。
-
-
返回 wasmValues。
-
-
断言:IsCallable(func)。
-
设 stored settings 为现任 settings object。
-
设 hostfunc 为一个宿主函数,其在以参数 arguments 调用时执行以下步骤:
-
设 realm 为 func 的关联 Realm。
-
设 relevant settings 为 realm 的settings object。
-
使用 relevant settings 准备运行脚本。
-
使用 stored settings 准备运行一个回调。
-
设 result 为从 func、functype 和 arguments 运行一个宿主 函数的结果。
-
使用 stored settings 在运行回调后清理。
-
使用 relevant settings 在运行脚本后清理。
-
断言:result.[[Type]] 是
throw 或normal 。 -
如果 result.[[Type]] 是
throw ,则: -
否则,返回 result.[[Value]]。
-
-
设 (store, funcaddr) 为 func_alloc(store, functype, hostfunc)。
-
返回 funcaddr。
-
断言:w 的形式不是 v128.const v128。
-
断言:w 的形式不是 ref.exn exnaddr。
-
如果 w 的形式为 i64.const u64,
-
如果 w 的形式为 i32.const u32,
-
如果 w 的形式为 f32.const f32,
-
如果 w 的形式为 f64.const f64,
-
如果 w 的形式为 ref.null t,则返回 null。
-
如果 w 的形式为 ref.i31 u31,
-
如果 w 的形式为 ref.struct structaddr,则返回从 structaddr 和 "struct" 创建新的导出 GC 对象的结果。
-
如果 w 的形式为 ref.array arrayaddr,则返回从 arrayaddr 和 "array" 创建新的导出 GC 对象的结果。
-
如果 w 的形式为 ref.extern ref,则返回 ToJSValue(ref)。
Note: 等于 NaN 的 Number 值可能具有 各种可观察到的 NaN payload;详见 NumericToRawBytes。
-
断言:type 不是 v128。
-
如果 type 是 i64,
-
设 i64 为 ? ToBigInt64(v)。
-
设 u64 为无符号整数,使得 i64 是 signed_64(u64)。
-
返回 i64.const u64。
-
-
如果 type 是 i32,
-
如果 type 是 f32,
-
如果 type 是 f64,
-
如果 type 的形式为 ref null heaptype,
-
如果 v 为 null,
-
设 r 为 ref.null heaptype。
-
-
否则如果 match_valtype(type, ref null extern),
-
设 ref 为 ! ToWebAssemblyValue(v, ref any)。
-
设 r 为 ref.extern ref。
-
-
否则如果 v 是一个导出函数,并且 match_valtype(type, ref null func),
-
设 funcaddr 为 v 的 [[FunctionAddress]] 内部槽的值。
-
设 r 为 ref.func funcaddr。
-
-
否则如果 v 是一个 Number,并且 v 等于 ? ToInt32(v),且 ℝ(v) < 230 且 ℝ(v) ⩾ -230,
-
否则如果 v 是一个导出 GC 对象,
-
设 objectaddr 为 v 的 [[ObjectAddress]] 内部槽的值。
-
设 objectkind 为 v 的 [[ObjectKind]] 内部槽的值。
-
如果 objectkind 是 "array",
-
设 r 为 ref.array objectaddr。
-
-
否则如果 objectkind 是 "struct",
-
设 r 为 ref.struct objectaddr。
-
-
-
否则,
-
设 actualtype 为 ref_type(store, r)。
-
如果 match_valtype(actualtype, type) 为 false,
-
抛出一个
TypeError。
-
-
返回 r。
-
-
断言:不会到达这一步。
AddressType
为 "i32" 时,其行为类似于 [EnforceRange] unsigned
long,并通过执行以下步骤将这些语义扩展到 AddressType
"i64":
-
如果 addrtype 是 "i32",
-
设 n 为 ? ConvertToInt(v, 32, "unsigned"),其中目标类型与 [EnforceRange] 相关联。
Note: 这等价于 JS 转换规则 中对于 [EnforceRange] unsigned long 的规定。
-
-
如果 addrtype 是 "i64",
-
断言:不会到达这一步。
AddressType
的正确 AddressValue
变体,执行以下步骤:
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,执行以下步骤:
new Tag(type)
构造函数步骤如下:
5.8. 垃圾回收对象
WebAssembly 结构体或数组在 JavaScript 中以导出 GC 对象的形式提供。 导出 GC 对象是一种异质对象,它包装了一个垃圾回收的 WebAssembly 引用值。 JavaScript 对 导出 GC 对象 的大多数操作都会抛出异常或返回 undefined。
Note: 这些操作未来可能会被细化,以允许 JavaScript 与 WebAssembly 结构体和数组之间进行更丰富的交互。
导出 GC 对象 包含一个 [[ObjectAddress]] 内部槽,它保存一个相对于 外围代理关联存储的对象地址, 以及一个 [[ObjectKind]] 内部槽,它保存字符串值 "struct" 或 "array"。
导出 GC 对象的内部方法使用以下实现。
-
返回 null。
-
返回 false。
-
返回 false。
-
返回 false。
-
返回 undefined。
-
返回 false。
-
返回 false。
-
返回 undefined。
-
抛出一个
TypeError。
-
抛出一个
TypeError。
-
令 keys 为一个新的空列表。
-
返回 keys。
-
断言:objectkind 是 "array" 或 "struct" 之一。
-
设 map 为外围代理关联的 导出 GC 对象 缓存。
-
如果 map[objectaddr] 存在,
-
返回 map[objectaddr]。
-
-
设 object 为 MakeBasicObject(« [[ObjectAddress]], [[ObjectKind]] »)。
-
将 object.[[ObjectAddress]] 设为 objectaddr。
-
将 object.[[ObjectKind]] 设为 objectkind。
-
将 object.[[GetPrototypeOf]] 设为 导出 GC 对象的 [[GetPrototypeOf]] 内部方法中指定的内容。
-
将 object.[[SetPrototypeOf]] 设为 导出 GC 对象的 [[SetPrototypeOf]] 内部方法中指定的内容。
-
将 object.[[IsExtensible]] 设为 导出 GC 对象的 [[IsExtensible]] 内部方法中指定的内容。
-
将 object.[[PreventExtensions]] 设为 导出 GC 对象的 [[PreventExtensions]] 内部方法中指定的内容。
-
将 object.[[GetOwnProperty]] 设为 导出 GC 对象的 [[GetOwnProperty]] 内部方法中指定的内容。
-
将 object.[[DefineOwnProperty]] 设为 导出 GC 对象的 [[DefineOwnProperty]] 内部方法中指定的内容。
-
将 object.[[HasProperty]] 设为 导出 GC 对象的 [[HasProperty]] 内部方法中指定的内容。
-
将 object.[[Get]] 设为 导出 GC 对象的 [[Get]] 内部方法中指定的内容。
-
将 object.[[Set]] 设为 导出 GC 对象的 [[Set]] 内部方法中指定的内容。
-
将 object.[[Delete]] 设为 导出 GC 对象的 [[Delete]] 内部方法中指定的内容。
-
将 object.[[OwnPropertyKeys]] 设为 导出 GC 对象的 [[OwnPropertyKeys]] 内部方法中指定的内容。
-
设定 map[objectaddr] 为 object。
-
返回 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,执行以下 步骤:
要从一个异常地址 exnAddress 创建一个 Exception 对象,执行以下步骤:
new Exception(exceptionTag, payload, options)
构造函数步骤如下:
-
设 JSTagAddr 为获取 JavaScript 异常标签的结果。
-
如果 exceptionTag.[[Address]] 等于 JSTagAddr,
-
抛出一个
TypeError。
-
-
设 [types] → [] 为 tag_type(store, exceptionTag.[[Address]])。
-
-
抛出一个
TypeError。
-
-
设 wasmPayload 为 « »。
-
对于 payload 和 types 中按线性方式配对的每个 value 和 resultType,
-
设 (store, exceptionAddr) 为 exn_alloc(store, exceptionTag.[[Address]], wasmPayload)。
-
初始化 this,来源为 exceptionAddr。
-
如果 options["traceStack"] 为 true,
-
将 this.[[Stack]] 设为当前调用栈的
DOMString表示形式,或设为 undefined。
-
getArg(exceptionTag, index)
方法步骤如下:
-
如果 this.[[Type]] 不等于 exceptionTag.[[Address]],
-
抛出一个
TypeError。
-
-
设 tagaddr 为 exn_tag(store, this.[[Address]])。
-
设 payload 为 exn_read(store, this.[[Address]])。
-
断言:tagaddr 等于 this.[[Type]]。
-
如果 index ≥ payload 的大小,
-
抛出一个
RangeError。
-
-
设 [types] → [] 为 tag_type(store, tagaddr)。
-
如果 types[index] 匹配 v128 或 exnref,
-
抛出一个
TypeError。
-
is(exceptionTag) 方法步骤如下:
-
如果 this.[[Type]] 不等于 exceptionTag.[[Address]],
-
返回 false。
-
-
返回 true。
stack getter 步骤如下:
-
返回 this.[[Stack]]。
5.9.1. JavaScript 异常
JavaScript 异常标签是一个与 外围代理相关联的标签地址。它会在代理的关联存储中于 首次使用时分配并缓存。它始终具有标签类型 « externref » → « »。
要获取 JavaScript 异常标签,执行以下步骤:
-
如果外围代理关联的 JavaScript 异常 标签已经初始化,
-
返回外围代理关联的 JavaScript 异常标签
-
-
设 (store, tagAddress) 为 tag_alloc(store, « externref » → « »)。
-
将外围代理关联的 JavaScript 异常 标签设为 tagAddress。
-
返回 tagAddress。
5.10. 错误对象
WebAssembly 定义了以下 Error 类:CompileError、LinkError,以及 RuntimeError。
WebAssembly
命名空间创建命名空间对象时,
必须运行以下步骤:
-
设 namespaceObject 为该命名空间对象。
-
对于 « "CompileError", "LinkError", "RuntimeError" » 中的每个 error,
-
设 constructor 为一个新对象,实现 NativeError 对象结构,其中 NativeError 被设为 error。
-
! 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 的内建项集合中的 内建项,执行以下步骤:
-
返回一个 (name, funcType, steps) 的列表, 对应于本节中定义的名称为 builtinSetName 的集合。
要根据 import 和启用的内建项 builtinSetNames 查找一个内建项, 执行以下步骤:
-
断言:验证内建项集合名称 builtinSetNames 的结果为 true。
-
设 importModuleName 为 import[0]。
-
设 importName 为 import[1]。
-
对于 builtinSetNames 中的每个 builtinSetName,
-
如果 builtinSetName 未指向一个内建项集合,则 继续。
-
设 builtinSetQualifiedName 为在 builtinSetName 前加上前缀 "wasm:"。
-
如果 importModuleName 等于 builtinSetQualifiedName,
-
设 builtins 为获取一个内建项集合中的内建项 builtinSetName 的结果。
-
对于 builtins 中的每个 builtin,
-
设 builtinName 为 builtin[0]。
-
如果 importName 等于 builtinName,则返回 (builtinSetName, builtin)。
-
-
-
-
返回 null。
要根据 builtinSetNames 验证 内建项集合名称,执行以下步骤:
-
如果 builtinSetNames 包含任何重复项,则返回 false。
-
返回 true。
要根据类型 funcType 和执行步骤 steps 创建一个 内建函数,执行以下步骤:
要根据名称 builtinSetName 实例化 一个内建项集合,执行以下步骤:
-
设 builtins 为获取一个内建项集合中的内建项 builtinSetName 的结果。
-
设 exportsObject 为 ! OrdinaryObjectCreate(null)。
-
对于 builtins 中的每个 (name, funcType, steps),
-
设 funcaddr 为使用 funcType 和 steps 创建一个 内建函数 的结果。
-
设 func 为从 funcaddr 创建新的导出 函数的结果。
-
设 value 为 func。
-
设 status 为 ! CreateDataProperty(exportsObject, name, value)。
-
断言:status 为 true。
-
-
返回 exportsObject。
要根据 import 和启用的内建项 builtinSetNames 验证一个内建项导入,执行以下步骤:
-
断言:验证内建项集合名称 builtinSetNames 的结果为 true。
-
设 maybeBuiltin 为对 import 和 builtinSetNames 查找一个内建项 的结果。
-
如果 maybeBuiltin 为 null,则返回 true。
-
设 importExternType 为 import[2]。
-
设 builtinFuncType 为 maybeBuiltin[1][1]。
-
设 builtinExternType 为
func |builtinFuncType|。 -
返回 match_externtype(builtinExternType, importExternType)。
6.1. 字符串内建项
字符串内建项调整了 String 内建
对象的接口。该集合的名称是
js-string,其限定名称是 wasm:js-string。
注:本节中的算法引用了定义在 String 上的 JS 内建项。这些引用指向实际的内建项,而不会在 String 对象上执行动态查找。
6.1.1. 抽象操作
调用 UnwrapString(v) 抽象操作时, 执行以下步骤:
-
如果 v 不是字符串,
-
抛出一个
RuntimeError异常,就像执行了一个陷阱一样。
-
-
返回 v
调用 FromCharCode(v) 抽象操作时, 执行以下步骤:
-
断言:v 的类型是 i32。
-
返回 ! Call(String.fromCharCode, undefined, « ToJSValue(v) »)。
调用 CharCodeAt(string, index) 抽象 操作时,执行以下步骤:
-
断言:index 的类型是 i32。
-
返回 ! Call(String.prototype.charCodeAt, string, « ToJSValue(index) »)。
6.1.2. cast
该内建项的 funcType 是
(rec (type (func (param externref) (result (ref extern))))).0。
当使用参数 v 调用该内建项时,必须执行以下步骤:
-
返回 ? UnwrapString(v)
6.1.3. test
该内建项的 funcType 是 (rec (type (func (param externref) (result i32)))).0。
当使用参数 v 调用该内建项时,必须执行以下步骤:
-
如果 v 不是字符串,
-
返回 0。
-
-
返回 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 调用该内建项时,必须执行 以下步骤:
-
如果 array 是 null,
-
抛出一个
RuntimeError异常,就像执行了一个陷阱一样。
-
-
设 length 为 array 中元素的个数。
-
如果 start > end 或 end > length,
-
抛出一个
RuntimeError异常,就像执行了一个陷阱一样。
-
-
设 result 为空字符串。
-
设 i 为 start。
-
当 i < end 时:
-
设 charCode 为 array 中索引 i 处存储元素的值。
-
设 charCodeString 为 FromCharCode(charCode)。
-
设 result 为 result 与 charCodeString 的拼接结果。
-
将 i 设为 i + 1。
-
-
返回 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 调用该内建项时, 必须执行以下步骤:
-
如果 array 是 null,
-
抛出一个
RuntimeError异常,就像执行了一个陷阱一样。
-
-
设 string 为 ? UnwrapString(string)。
-
设 stringLength 为 string 的长度。
-
设 arrayLength 为 array 中元素的个数。
-
如果 start + stringLength > arrayLength,
-
抛出一个
RuntimeError异常,就像执行了一个陷阱一样。
-
-
设 i 为 0。
-
当 i < stringLength 时:
-
设 charCode 为 CharCodeAt(string, i)。
-
将 array 中索引 start + i 处的元素设为 ToWebAssemblyValue(charCode, i32)。
-
将 i 设为 i + 1。
-
-
返回 stringLength。
6.1.6. fromCharCode
该内建项的 funcType 是
(rec (type (func (param i32) (result (ref extern))))).0。
当使用参数 v 调用该内建项时,必须执行以下步骤:
-
返回 FromCharCode(v)。
6.1.7. fromCodePoint
该内建项的 funcType 是 (rec (type (func (param i32) (result externref)))).0。
当使用参数 v 调用该内建项时,必须执行以下步骤:
-
如果 v > 0x10ffff,
-
抛出一个
RuntimeError异常,就像执行了一个陷阱一样。
-
-
返回 ! Call(String.fromCodePoint, undefined, « ToJSValue(v) »)。
6.1.8. charCodeAt
该函数的类型是 (rec (type (func (param externref i32) (result i32)))).0。
当使用参数 string 和 index 调用该内建项时,必须执行以下步骤 :
-
设 string 为 ? UnwrapString(string)。
-
设 length 为 string 的长度。
-
如果 index >= length,
-
抛出一个
RuntimeError异常,就像执行了一个陷阱一样。
-
-
返回 CharCodeAt(string, index)。
6.1.9. codePointAt
该函数的类型是 (rec (type (func (param externref i32) (result i32)))).0。
当使用参数 string 和 index 调用该内建项时,必须执行以下步骤 :
-
设 string 为 ? UnwrapString(string)。
-
设 length 为 string 的长度。
-
如果 index >= length,
-
抛出一个
RuntimeError异常,就像执行了一个陷阱一样。
-
-
返回 ! Call(String.prototype.codePointAt, string, « ToJSValue(index) »)。
6.1.10. length
该内建项的 funcType 是 (rec (type (func (param externref) (result i32)))).0。
当使用参数 v 调用该内建项时,必须执行以下步骤:
-
设 string 为 ? UnwrapString(v)。
-
返回 string 的长度。
6.1.11. concat
该内建项的 funcType 是
(rec (type (func (param externref externref) (result (ref extern))))).0。
当使用参数 first 和 second 调用该内建项时,必须执行以下步骤 :
-
设 first 为 ? UnwrapString(first)。
-
设 second 为 ? UnwrapString(second)。
-
返回 ! 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 调用该内建项时,必须执行 以下步骤:
-
设 string 为 ? UnwrapString(string)。
-
设 length 为 string 的长度。
-
如果 start > end 或 start > length,
-
返回空字符串。
-
-
返回 ! 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 调用该内建项时,必须执行以下步骤 :
-
如果 first 不为 null,且 first 不是字符串,
-
抛出一个
RuntimeError异常,就像执行了一个陷阱一样。
-
-
如果 second 不为 null,且 second 不是字符串,
-
抛出一个
RuntimeError异常,就像执行了一个陷阱一样。
-
-
如果 ! IsStrictlyEqual(first, second) 为 true,
-
返回 1。
-
-
返回 0。
6.1.14. compare
该内建项的 funcType 是
(rec (type (func (param externref externref) (result i32)))).0。
当使用参数 first 和 second 调用该内建项时,必须执行以下步骤 :
-
设 first 为 ? UnwrapString(first)。
-
设 second 为 ? UnwrapString(second)。
-
如果 ! IsStrictlyEqual(first, second) 为 true,
-
返回 0。
-
-
如果 ! IsLessThan(first, second, true) 为 true,
-
返回 -1。
-
-
返回 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 或直接崩溃。这里两种情况都有效 。
-
一个
RangeError, 如Memory的grow()和Table的grow()操作中所规定的那样 -
像 memory.grow 指令那样返回 -1
-
本节所述的特定于 UA 的 OOM 行为。
更多讨论请参见 Issue 879。
8. 实现定义的限制
WebAssembly 核心规范允许实现对模块的语法结构定义限制。
虽然 WebAssembly 的每种嵌入都可以选择定义其自身的限制,但为了可预测性,
本文档描述的标准 WebAssembly JavaScript 接口定义了以下精确限制。
如果模块超过以下任一限制,实现必须以 CompileError
拒绝该模块。
在实践中,即使模块在这些限制之下,实现也可能因资源耗尽而失败。
- 模块的最大大小为 1,073,741,824 字节(1 GiB)。
- types 段中定义的类型最大数量为 1,000,000。
- types 段中定义的递归组最大数量为 1,000,000。
- 一个递归组中定义的类型最大数量为 1,000,000。
- 已定义子类型层级的最大深度为 63(其中没有超类型的已定义类型深度为 0)。
- 模块中定义的函数最大数量为 1,000,000。
- 模块中声明的导入最大数量为 1,000,000。
- 模块中声明的导出最大数量为 1,000,000。
- 模块中定义的全局最大数量为 1,000,000。
- 模块中定义的标签最大数量为 1,000,000。
- 模块中定义的数据段最大数量为 100,000。
- 表的最大数量(包括声明或导入的表)为 100,000。
- 表的最大大小为 10,000,000。
- 任何表初始化中的表项最大数量为 10,000,000。
- 内存的最大数量(包括已定义和导入的内存)为 100。
- 32 位内存的
min或max字段最大值为 65,536 页(4 GiB)。 - 64 位内存的
min或max字段最大值为 2^37-1 页(2^53 - 2^16 字节)。 - 任意函数或块的参数最大数量为 1,000。
- 任意函数或块的返回值最大数量为 1,000。
- 函数体的最大大小(包括局部变量声明)为 7,654,321 字节。
- 函数中声明的局部变量最大数量(包括作为参数隐式声明的)为 50,000。
- 结构体中的字段最大数量为 10,000。
array.new_fixed的操作数最大数量为 10,000。
如果运行时超出以下任一限制,实现必须抛出一个 RuntimeError
:
在实践中,即使模块在这些限制之下,实现也可能因资源耗尽而失败。
- 表的最大大小为 10,000,000。
- 32 位内存的最大大小为 65,536 页(4 GiB)。
- 64 位内存的最大大小为 262,144 页(16 GiB)。
9. 安全性和隐私注意事项
本节为非规范性内容。
本文档为 WebAssembly 定义了一个宿主环境。它允许 WebAssembly 实例从导入对象中导入 JavaScript 对象和函数,但除此之外不提供对嵌入环境的任何访问 。因此,WebAssembly 实例受到与 JavaScript 相同的约束。
10. 变更历史
本节为非规范性内容。
自 WebAssembly 规范最初的 1.0 版本发布以来, 已集成了若干扩展提案。 以下各节概述了已发生的变化。