1. 引言
按照设计,WebAssembly 核心规范 [WEBASSEMBLY] 的 范围 不包括描述 WebAssembly 程序如何与其周围执行环境交互。 相反,它定义了 WebAssembly 与其环境之间的抽象嵌入接口, (称为 嵌入器)。 只有通过这个接口,嵌入器才能与 WebAssembly 的语义交互,而 嵌入器负责实现其宿主环境与嵌入 API 之间的连接。 本文档描述了 WebAssembly 嵌入到 JavaScript [ECMASCRIPT] 环境中的方式, 包括如何构造和实例化 WebAssembly 模块、如何调用导入和导出函数、 如何交换数据,以及如何处理错误。 当 JavaScript 环境本身被嵌入到 Web 浏览器中时,Web API 规范 [WASMWEB] 描述了与 Web 环境相关的附加行为。
2. API 用法示例
本节非规范性内容。
给定 demo.wat(编码为 demo.wasm):
( module ( import"js" "import1" ( func $i1 )) ( import"js" "import2" ( func $i2 )) ( func $main ( call $i1 )) ( start $main ) ( func ( export"f" ) ( call $i2 )) )
以及下面这段在浏览器中运行的 JavaScript:
var importObj= { js: { import1: () => console. log( "hello," ), import2: () => console. log( "world!" ) }}; fetch( 'demo.wasm' ). then( response=> response. arrayBuffer() ). then( buffer=> WebAssembly. instantiate( buffer, importObj) ). then(({ module, instance}) => instance. exports. f() );
3. 记法
本规范依赖于 Infra Standard。[INFRA]
WebAssembly 的 序列 类型等同于其中定义的 列表 类型;两者的值 可以透明地相互视为对方的值。
4. 内部存储
4.1. WebAssembly 存储与 JavaScript 的交互
注:WebAssembly 语义是根据一个 抽象的存储来定义的, 它表示 WebAssembly 抽象机器的状态。 WebAssembly 操作接收一个存储并返回一个更新后的存储。
每个 代理 都有一个关联存储。当创建一个新代理时,其关联存储被设为 store_init() 的结果。
注:在本规范中,没有任何与 WebAssembly 相关的 对象、内存或地址可以在一个 代理集群 中的多个代理之间共享。在未来版本的 WebAssembly 中,这一点可能会改变。
WebAssembly 存储中的元素可以与 JavaScript 值对应标识。特别地,每个具有对应 Memory 对象的 WebAssembly
内存实例
都与一个 JavaScript 数据块对应标识;对该数据块的修改等同于将
代理的存储更新为反映这些变更的存储,反之亦然。
4.2. WebAssembly JS 对象缓存
注:有若干 WebAssembly 对象 可能具有对应的 JavaScript 对象。这种对应关系存储在每个代理单独维护的映射中,用于将 WebAssembly 地址映射到 JavaScript 对象。 该映射用于确保,对于给定的 代理,某个特定 WebAssembly 地址至多只存在一个 JavaScript 对象。不过,共享对象不具备这一性质。
-
宿主值 缓存,将 宿主地址映射到值。
5. WebAssembly 命名空间
dictionary {WebAssemblyInstantiatedSource required Module ;module required Instance ; };instance dictionary {WebAssemblyCompileOptions USVString ?=importedStringConstants null ;sequence <USVString >= []; }; [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。
要验证 WebAssembly 模块的内置功能和导入的 字符串,给定模块 module、已启用的内置功能 builtinSetNames 和 importedStringModule,执行以下步骤:
-
如果对 内置功能集名称的验证针对 builtinSetNames 的结果为 false,则返回 false。
-
对于每个 import,其来自 module_imports(module),
-
如果 importedStringModule 不为 null,且 import[0] 等于 importedStringModule,
-
令 importExternType 为 import[2]。
-
如果 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 是错误,则使用
CompileError异常拒绝 promise,并返回。 -
令 builtinSetNames 为 options["builtins"]。
-
令 importedStringModule 为 options["importedStringConstants"]。
-
如果使用 builtinSetNames 和 importedStringModule 对 module 验证 内置项和导入字符串的结果为 false,则使用
CompileError异常拒绝 promise。 -
否则,
-
根据 module、 bytes、builtinSetNames、 importedStringModule 构造一个 WebAssembly 模块对象,并令 moduleObject 为 结果。
-
使用 moduleObject 解决 promise。
-
-
-
-
返回 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(module) 非空,且缺少 importObject,则抛出一个
TypeError异常。 -
令 builtinOrStringImports 为有序映射 «[ ]»。
-
对于每个 builtinSetName,其来自 builtinSetNames,
-
如果 importedStringModule 不为 null,
-
令 imports 为 « »。
-
对于每个 (moduleName, componentName, externtype),其来自 module_imports(module),
-
如果 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, valtype, value)。
-
-
令 externglobal 为 global globaladdr。
-
将 externglobal 追加到 imports。
-
-
如果 externtype 的形式为 mem memtype,
-
如果 externtype 的形式为 table tabletype,
-
如果 externtype 的形式为 tag functype,
-
-
返回 imports。
注:此算法仅验证传入的 JavaScript 值是否属于正确的 类型。 WebAssembly 类型要求的验证则推迟到 “实例化 WebAssembly 模块的核心 部分”算法中进行。
-
令 exportsObject 为 OrdinaryObjectCreate(null)。
-
对于每个 (name, externtype),其来自 module_exports(module),
-
令 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 functype,
-
断言: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。
-
令(store,result)为 module_instantiate(store, module, imports)。
-
如果 result 为 error,则抛出适当的异常类型:
-
对于链接期间发生的大多数情况,抛出
LinkError异常。 -
如果错误发生在运行启动函数时,对于源自 WebAssembly 的大多数错误,抛出
RuntimeError; 或者抛出从内部 ECMAScript 代码传播出来的错误对象。 -
如果适用,则抛出其他错误类型,例如内存不足异常,如 WebAssembly 错误映射中所述。
-
-
返回 result。
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 兑现:
-
使用导入 importObject 实例化 WebAssembly 模块 module, 并令 innerPromise 为结果。
-
对 innerPromise 作出反应:
-
如果 innerPromise 已以值 instance 兑现。
-
令 result 为
WebAssemblyInstantiatedSource值 «[ "module" → module, "instance" → instance ]»。 -
使用 result 解决 promise。
-
-
如果 innerPromise 已以原因 reason 被拒绝:
-
使用 reason 拒绝 promise。
-
-
-
-
如果 promiseOfModule 已以原因 reason 被拒绝:
-
使用 reason 拒绝 promise。
-
-
-
返回 promise。
instantiate(bytes, importObject, options)
方法在调用时执行以下步骤:
-
令 stableBytes 为缓冲区 bytes 所保存字节的副本。
-
使用 options 根据 stableBytes 异步编译 WebAssembly 模块,并令 promiseOfModule 为结果。
-
使用导入 importObject 实例化 promiseOfModule 并返回结果。
instantiate(moduleObject, importObject)
方法在调用时执行以下步骤:
-
使用导入 importObject 异步实例化 WebAssembly 模块 moduleObject,并返回 结果。
注意:后续的流式 API 记录在 WebAssembly Web API 中。
WebAssembly
Namespace 的 JSTag 属性的 getter
在调用时执行以下步骤:
-
令 JSTagAddr 为获取 JavaScript 异常 tag的结果。
-
令 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 为 ToValueType(descriptor["address"]);否则,令 addrtype 为 i32。
-
令 initial 为 ? AddressValueToU64(descriptor["initial"], addrtype)。
-
如果 descriptor["maximum"] 存在,则令 maximum 为 ? AddressValueToU64(descriptor["maximum"], addrtype);否则,令 maximum 为空。
-
令 memtype 为内存类型 addrtype [initial .. maximum] page。
-
如果 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。
-
-
否则,
grow(delta) 方法时,执行
以下步骤:
-
令 memaddr 为 this.[[Memory]]。
-
令 (addrtype, limits) 为 mem_type(store, memaddr)。
-
令 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。
由 Memory 对象返回的 ArrayBuffer
对象的大小必须是 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 为 ToValueType(descriptor["address"]);否则,令 addrtype 为 i32。
-
令 initial 为 ? AddressValueToU64(descriptor["initial"], addrtype)。
-
如果 descriptor["maximum"] 存在,则令 maximum 为 ? AddressValueToU64(descriptor["maximum"], addrtype);否则,令 maximum 为空。
-
令 type 为表类型 addrtype [initial .. maximum] elementtype。
-
如果 type 无效,则抛出一个
RangeError异常。 -
如果缺少 value,
-
令 ref 为 DefaultValue(elementtype)。
-
断言:ref 不是 error。
-
-
否则,
-
令 ref 为 ? ToWebAssemblyValue(value, elementtype)。
-
-
令 (store, tableaddr) 为 table_alloc(store, type, ref)。如果分配失败,则抛出一个
RangeError异常。 -
使用 tableaddr 初始化 this 。
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 属性的获取器时,
执行以下步骤:
-
令 tableaddr 为 this.[[Table]]。
-
令 (addrtype, limits, elementtype) 为 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异常。 -
返回 ToJSValue(result)。
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 为 mut valuetype;否则,令 globaltype 为 valuetype。
-
令 (store, globaladdr) 为 global_alloc(store, globaltype, value)。
-
使用 globaladdr 初始化 this 。
Global
global) 执行以下步骤:
-
令 globaladdr 为 global.[[Global]]。
-
令 globaltype 为 global_type(store, globaladdr)。
-
如果 globaltype 的形式为 mut valuetype,其中 valuetype 匹配 v128 或 exnref,则抛出一个
TypeError。 -
令 value 为 global_read(store, globaladdr)。
-
返回 ToJSValue(value)。
Global 的 value
属性的设置器时,
执行以下步骤:
-
令 globaladdr 为 this.[[Global]]。
-
令 mut valuetype 为 global_type(store, globaladdr)。
-
如果 mut 为空,则抛出一个
TypeError。 -
令 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.funcs 中。
-
令 index 为在 moduleinst.funcs 中找到 funcaddr 的索引。
-
-
如果 map[funcaddr] 存在,
-
返回 map[funcaddr]。
-
-
令 steps 为“调用导出函数 funcaddr 并传入参数。”
-
令 realm 为当前 Realm。
-
令 functype 为 func_type(store, funcaddr)。
-
令 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 中的任何类型匹配 v128 或 exnref,则抛出一个
TypeError。注:每次 调用 [[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
RuntimeError异常,除非WebAssembly 错误映射另有规定。 -
如果 ret 的形式为 exception exnaddr,则
-
令 tagaddr 为 exn_tag(store, exnaddr)。
-
令 payload 为 exn_read(store, exnaddr)。
-
令 jsTagAddr 为获取 JavaScript 异常 标签的结果。
-
如果 tagaddr 等于 jsTagAddr,
-
抛出 ToJSValue(payload[0])。
-
-
否则,
-
令 exception 为根据 exnaddr 创建的一个 新的 Exception 对象。
-
抛出 exception。
-
-
-
令 outArity 为 ret 的大小。
-
如果 outArity 为 0,则返回 undefined。
-
否则,如果 outArity 为 1,则返回 ToJSValue(ret[0])。
-
否则,
-
令 values 为 « »。
-
对于每个 ret 中的 r,
-
返回 CreateArrayFromList(values)。
-
注:调用导出 函数会在被调用的导出函数的 [[Realm]] 中执行,这符合内置函数对象的定义。
注:导出函数不具有 [[Construct]]
方法,因此无法使用 new 运算符调用它。
-
如果 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 为现任设置对象。
-
令 hostfunc 为一个宿主函数,当使用参数 arguments 调用时,执行以下步骤:
-
令 realm 为 func 的关联 Realm。
-
令 relevant settings 为 realm 的设置对象。
-
使用 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,则返回 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)。
注:等于 NaN 的 Number 值可能具有 各种可观察的 NaN 载荷;有关详细信息,请参阅 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。
-
-
否则,如果 match_valtype(type, ref null extern) 为 true,
-
令 ref 为 ! ToWebAssemblyValue(v, ref any)。
-
令 r 为 ref.extern ref。
-
-
否则,如果 v 是一个导出函数,且 match_valtype(type, ref null func) 为 true,
-
令 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" 下的行为,并将这些语义扩展到 AddressType
"i64",具体执行以下步骤:
-
令 jsValue 为已转换为 JavaScript 值的 v。
注:IDL
any类型是一个 可辨识联合类型,而不是 JavaScript 值的透明包装器。 -
如果 addrtype 为 i32,
-
令 n 为 ? ConvertToInt(jsValue, 32, "unsigned"),其中目标类型关联了 [EnforceRange]。
注:这等效于 JS 转换规则,适用于 [EnforceRange] unsigned long。
-
-
如果 addrtype 为 i64,
-
断言:不会执行到此步骤。
AddressValue
的正确变体,以对应 AddressType,
具体执行以下步骤:
5.7. 标签
5.7.1. 标签类型
dictionary {TagType required sequence <ValueType >; }; [parameters LegacyNamespace =WebAssembly , Exposed=*]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。
-
返回 « »。
-
断言: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=*]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。
-
-
令 func types → « » 为展开结果,其来自 tag_type(store, exceptionTag.[[Address]])。
-
-
抛出一个
TypeError。
-
-
令 wasmPayload 为 « »。
-
对于每个 value 和 resultType,分别来自 payload 和 types,并按顺序一一配对,
-
令 (store, exceptionAddr) 为 exn_alloc(store, exceptionTag.[[Address]], wasmPayload)。
-
使用 exceptionAddr 初始化 this。
-
如果 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[index] 匹配 v128 或 exnref,
-
抛出一个
TypeError。
-
-
返回 ToJSValue(payload[index])。
调用 is(exceptionTag) 方法时,执行以下步骤:
-
如果 this.[[Type]] 不等于 exceptionTag.[[Address]],
-
返回 false。
-
-
返回 true。
调用 stack 获取器时,执行以下步骤:
-
返回 this.[[Stack]]。
5.9.1. JavaScript 异常
JavaScript 异常标签 是一个与标签地址,关联于 周围代理。它在该代理的关联存储中于 首次使用时分配并缓存。它始终具有标签类型 « externref » → « »。
要获取 JavaScript 异常标签,执行以下步骤:
-
如果周围代理关联的JavaScript 异常 标签已初始化,
-
返回周围代理关联的JavaScript 异常标签
-
-
令 tagtype 为一个定义类型,使得 func « externref » → « » 是 展开结果,由 tagtype 得到。
-
令 (store, tagAddress) 为 tag_alloc(store, tagtype)。
-
将周围代理关联的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 不是 String,
-
抛出
RuntimeError异常,如同执行了陷阱一样。
-
-
如果 second 不为 null 且 second 不是 String,
-
抛出
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 版本发布以来, 已集成了若干扩展提案。 以下各节概述了已发生的变化。