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 标准。[INFRA]
WebAssembly 的 sequence 类型等价于该标准中定义的 list 类型;二者的值可直接转换,无需特殊处理。
4. 内部存储
4.1. WebAssembly Store 与 JavaScript 的交互
注: WebAssembly 语义是基于抽象的store定义的,store 表示 WebAssembly 抽象机的状态。 WebAssembly 操作接受 store 并返回更新后的 store。
每个 agent 都有一个 关联 store。当新 agent 创建时,其关联 store 初始化为 store_init() 的结果。
注: 本规范下,任何 WebAssembly 相关对象、内存或地址都不能在同一个agent cluster中的 agent 之间共享。未来版本的 WebAssembly 可能会改变这一点。
WebAssembly store 的各元素可通过 JavaScript 值标识。特别是,有对应 Memory 对象的 WebAssembly
memory instance 会被标识为一个 JavaScript Data Block;对该 Data Block 的修改等价于将 agent 的 store 更新为反映这些变化的新 store,反之亦然。
4.2. WebAssembly JS 对象缓存
注: 某些 WebAssembly 对象可能有对应的 JavaScript 对象。这种对应关系保存在每个 agent 的 WebAssembly 地址到 JavaScript 对象的映射中。 该映射用于确保针对同一 agent,同一个 WebAssembly 地址至多对应一个 JavaScript 对象。但该属性对共享对象不成立。
-
内存对象缓存:把memory address 映射为
Memory对象。 -
表对象缓存:把table address 映射为
Table对象。 -
导出函数缓存:把function address 映射为 导出函数对象。
-
导出 GC 对象缓存:把struct address 和 array address 映射为 导出 GC 对象。
-
全局对象缓存:把global address 映射为
Global对象。 -
标签对象缓存:把tag address 映射为
Tag对象。 -
异常对象缓存:把exception address 映射为
Exception对象。 -
宿主值缓存:把host address 映射为相应值。
5. WebAssembly 命名空间
dictionary {WebAssemblyInstantiatedSource required Module ;module required Instance ; };instance dictionary {WebAssemblyCompileOptions USVString ?;importedStringConstants sequence <USVString >; }; [Exposed=*]builtins namespace {WebAssembly boolean validate (BufferSource ,bytes optional WebAssemblyCompileOptions = {});options Promise <Module >compile (BufferSource ,bytes optional WebAssemblyCompileOptions = {});options Promise <WebAssemblyInstantiatedSource >instantiate (BufferSource ,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 验证 import 是否为内建导入结果为 false,则返回 false。
-
-
-
返回 true。
validate(bytes, options) 方法时,
执行如下步骤:
-
令 stableBytes 为 buffer 所持有字节的副本 bytes。
-
将 stableBytes 编译 为一个 WebAssembly 模块,并将结果存为 module。
-
如果 module 为 error,则返回 false。
-
令 builtinSetNames 为 options["builtins"]。
-
令 importedStringModule 为 options["importedStringConstants"]。
-
如果对 module 以 builtinSetNames 和 importedStringModule 验证内建与导入字符串 的结果为 false,则返回 false。
-
返回 true。
Module 对象表示单个
WebAssembly 模块。每个
Module 对象具有以下内部槽:
-
[[Module]]:一个 WebAssembly module
-
[[Bytes]]:[[Module]] 的源字节。
-
[[BuiltinSets]]:builtin sets 的名称有序集合。
-
[[ImportedStringModule]]:一个可选的模块指示符字符串,字符串常量可自其中导入。
-
令 moduleObject 为一个新的
Module对象。 -
将 moduleObject.[[Module]] 设为 module。
-
将 moduleObject.[[Bytes]] 设为 bytes。
-
将 moduleObject.[[BuiltinSets]] 设为 builtinSetNames。
-
将 moduleObject.[[ImportedStringModule]] 设为 importedStringModule。
-
返回 moduleObject。
WebAssemblyCompileOptions
options 异步编译一个 WebAssembly 模块,并使用可选的 task
source taskSource,执行以下步骤:
-
令 promise 为 一个新的 promise。
-
并行执行以下步骤:
-
编译 WebAssembly 模块 bytes 并将结果存为 module。
-
排队一个任务(Queue a task) 以执行以下步骤。若提供了 taskSource,则在该 task source 上排队该任务。
-
如果 module 为 error,则以
CompileError异常拒绝 promise。 -
令 builtinSetNames 为 options["builtins"]。
-
令 importedStringModule 为 options["importedStringConstants"]。
-
如果对 module 以 builtinSetNames 和 importedStringModule 验证内建与导入字符串 的结果为 false,则以
CompileError异常拒绝 promise。 -
否则,
-
从 module、bytes、builtinSetNames、 importedStringModule 构造一个 WebAssembly 模块对象,并令 moduleObject 为结果。
-
Resolve promise,其值为 moduleObject。
-
-
-
-
返回 promise。
compile(bytes, options) 方法时,
执行如下步骤:
-
令 stableBytes 为 buffer 所持有字节的副本 bytes。
-
使用 options 从 stableBytes 异步编译一个 WebAssembly 模块 并返回结果。
要用模块 module 和 importedStringModule 实例化导入的字符串,执行以下步骤:
-
断言:importedStringModule 不为 null。
-
令 exportsObject 为 ! OrdinaryObjectCreate(null)。
-
对于每个
(moduleName, componentName, externtype)属于 module_imports(module),-
如果 moduleName 不等于 importedStringModule,则继续。
-
令 stringConstant 为 componentName。
-
令 status 为 ! CreateDataProperty(exportsObject, stringConstant, stringConstant)。
-
断言:status 为 true。
-
-
返回 exportsObject。
-
如果 module.imports 非空 且 importObject 为 undefined,则抛出
TypeError异常。 -
令 builtinOrStringImports 为有序映射 « »。
-
对于每个 builtinSetName 属于 builtinSetNames,
-
断言:builtinOrStringImports 不包含 builtinSetName
-
如果 builtinSetName 不指代一个 builtin set,则继续。
-
令 exportsObject 为使用 builtinSetName 实例化一个 builtin set 的结果。
-
令 builtinSetQualifiedName 为以 "wasm:" 作为前缀的 builtinSetName。
-
将 builtinOrStringImports[builtinSetQualifiedName] 设为 exportsObject
-
-
如果 importedStringModule 不为 null,
-
令 imports 为 « »。
-
对于每个
(moduleName, componentName, externtype)属于 module_imports(module),-
如果 builtinOrStringImports 包含 moduleName,
-
否则,
-
若 externtype 形式为 func functype,
-
若 IsCallable(v) 为 false,则抛出
LinkError异常。 -
若 v 具有 [[FunctionAddress]] 内部槽,因此是一个 导出函数(Exported Function),
-
令 funcaddr 为 v 的 [[FunctionAddress]] 内部槽的值。
-
-
否则,
-
从 v 与 functype 创建一个宿主函数,并令 funcaddr 为结果。
-
令 index 为 imports 中外部函数的数量。该值 index 即 宿主函数的索引 funcaddr。
-
-
令 externfunc 为 external value func funcaddr。
-
将 externfunc 追加到 imports。
-
-
若 externtype 形式为 global mut valtype,
-
如果 v 实现(implements)了
Global,-
令 globaladdr 为 v.[[Global]]。
-
-
否则,
-
令 externglobal 为 global globaladdr。
-
将 externglobal 追加到 imports。
-
-
若 externtype 形式为 mem memtype,
-
若 externtype 形式为 table tabletype,
-
若 externtype 形式为 tag attribute functype,
-
-
返回 imports。
注: 此算法只验证传入的 JavaScript 值类型是否正确。 对 WebAssembly 类型需求的验证被推迟到 “实例化 WebAssembly 模块核心” 算法。
-
令 exportsObject 为 ! OrdinaryObjectCreate(null)。
-
对于每个 (name, externtype) 属于 module_exports(module),
-
令 externval 为 instance_export(instance, name)。
-
断言:externval 不是 error。
-
若 externtype 形式为 func functype,
-
断言:externval 形式为 func funcaddr。
-
令 func funcaddr 为 externval。
-
令 func 为从 funcaddr 创建的新导出函数(Exported Function)。
-
令 value 为 func。
-
-
若 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 创建一个 exports 对象,并令 exportsObject 为结果。
-
将 instanceObject.[[Instance]] 设为 instance。
-
将 instanceObject.[[Exports]] 设为 exportsObject。
-
令 result 为 module_instantiate(store, module,imports)。
-
如果 result 为 error,则抛出适当的异常类型:
-
大多数链接时发生的错误,抛出
LinkError异常。 -
若错误来自运行 start 函数,则对于多数由 WebAssembly 产生的错误抛出
RuntimeError, 或抛出从内部 ECMAScript 代码传播的错误对象。 -
如适用,抛出其它错误类型,例如内存耗尽异常,详见 WebAssembly 错误映射。
-
-
令 (store, instance) 为 result。
-
返回 instance。
Module
moduleObject 与导入 importObject 异步实例化一个 WebAssembly 模块,执行以下步骤:
-
令 promise 为 一个新的 promise。
-
令 module 为 moduleObject.[[Module]]。
-
令 builtinSetNames 为 moduleObject.[[BuiltinSets]]。
-
令 importedStringModule 为 moduleObject.[[ImportedStringModule]]。
-
读取导入(read the imports) module 的导入,使用 importObject、builtinSetNames 和 importedStringModule,并令 imports 为结果。 如果此操作抛出异常,则捕获之,以该异常拒绝 promise,并返回 promise。
-
并行执行以下步骤:
-
排队一个任务(Queue a task) 以执行以下步骤: 注:此处可执行与实现相关的工作。
-
-
返回 promise。
-
令 promise 为 一个新的 promise。
-
对 promiseOfModule 作出响应(React):
-
如果 promiseOfModule 以值 module 得到兑现:
-
实例化 WebAssembly 模块 module,导入 importObject,并令 innerPromise 为结果。
-
对 innerPromise 作出响应(React):
-
如果 innerPromise 以值 instance 得到兑现。
-
令 result 为
WebAssemblyInstantiatedSource值 «[ "module" → module, "instance" → instance ]»。 -
Resolve promise,其值为 result。
-
-
如果 innerPromise 因原因 reason 被拒绝:
-
以 reason 拒绝 promise。
-
-
-
-
如果 promiseOfModule 因原因 reason 被拒绝:
-
以 reason 拒绝 promise。
-
-
-
返回 promise。
instantiate(bytes, importObject, options)
方法时,执行如下步骤:
-
令 stableBytes 为 buffer 所持有字节的副本 bytes。
-
使用 options 从 stableBytes 异步编译一个 WebAssembly 模块,并令 promiseOfModule 为结果。
-
实例化 promiseOfModule,使用导入 importObject,并返回结果。
instantiate(moduleObject, importObject)
方法时,执行如下步骤:
-
异步实例化 WebAssembly 模块 moduleObject,导入 importObject,并返回结果。
注: 后续的流式 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 (BufferSource ,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) 方法时,执行如下步骤:
-
令 module 为 moduleObject.[[Module]]。
-
令 exports 为 « »。
-
对于每个 属于 module_exports(module) 的 (name, type),
-
令 kind 为 extern 类型的字符串值 type。
-
将 obj 追加到 exports。
-
-
返回 exports。
imports(moduleObject) 方法时,执行如下步骤:
-
令 module 为 moduleObject.[[Module]]。
-
令 builtinSetNames 为 moduleObject.[[BuiltinSets]]。
-
令 importedStringModule 为 moduleObject.[[ImportedStringModule]]。
-
令 imports 为 « »。
-
对于每个 属于 module_imports(module) 的 (moduleName, name, type),
-
如果对 (moduleName, name, type) 和 builtinSetNames 查找内建(find a builtin) 的结果不为 null,则继续。
-
如果 importedStringModule 不为 null 且 moduleName 等于 importedStringModule,则继续。
-
令 kind 为 extern 类型的字符串值 type。
-
令 obj 为 «[ "
module" → moduleName, "name" → name, "kind" → kind ]»。 -
将 obj 追加到 imports。
-
-
返回 imports。
customSections(moduleObject, sectionName)
方法时,执行如下步骤:
-
令 bytes 为 moduleObject.[[Bytes]]。
-
令 customSections 为 « »。
-
对于每个 custom section customSection 属于 bytes, 按照 module 语法 进行解释,
-
令 name 为 customSection 的
name,按 UTF-8 解码。 -
断言:name 非失败(moduleObject.[[Module]] 有效)。
-
若 name 作为字符串等于 sectionName,
-
将 一个新的
ArrayBuffer(其包含 bytes 中由该 customsec 产生式匹配范围的字节副本)追加到 customSections。
-
-
-
返回 customSections。
Module(bytes, options) 构造函数时,执行如下步骤:
-
令 stableBytes 为 buffer 所持有字节的副本 bytes。
-
编译 WebAssembly 模块 stableBytes 并将结果存为 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(module, importObject)
构造函数时,执行如下步骤:
-
令 module 为 module.[[Module]]。
-
令 builtinSetNames 为 module.[[BuiltinSets]]。
-
令 importedStringModule 为 module.[[ImportedStringModule]]。
-
读取导入(read the imports) module 的导入,使用 importObject、 builtinSetNames 和 importedStringModule,并令 imports 为结果。
-
实例化 WebAssembly 模块核心 module,使用 imports,并令 instance 为结果。
-
初始化 this,来自 module 与 instance。
注: 不推荐使用该同步 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 对象表示一个 memory instance,
可被多个 Instance
对象同时引用。每个
Memory 对象具有以下内部槽:
-
[[Memory]]:一个 memory address
-
[[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 为 外围 agent 关联的 Memory object cache。
-
断言: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 为 memory type addrtype { min initial, max maximum }。
-
若 memtype 非 有效,抛出
RangeError异常。 -
令 (store, memaddr) 为 mem_alloc(store, memtype)。若分配失败,抛出
RangeError异常。 -
初始化 this,来自 memaddr。
-
令 map 为 外围 agent 关联的 Memory object cache。
-
断言: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 的长度。
-
-
令 ret 为 mem_size(store, memaddr)。
-
令 store 为 mem_grow(store, memaddr, delta)。
-
若 store 为 error,抛出
RangeError异常。 -
刷新 Memory 缓冲区 memaddr。
-
返回 ret。
grow(delta) 方法时,执行如下步骤:
-
令 memaddr 为 this.[[Memory]]。
-
令 addrtype 为 address type,来自 mem_type(store, memaddr)。
-
令 delta64 为 ? AddressValueToU64(delta, addrtype)。
-
令 ret 为 扩展内存缓冲区(与 memaddr 关联)delta64 的结果。
-
返回 U64ToAddressValue(ret, addrtype)。
在 WebAssembly memory.grow 指令执行后立即,执行如下步骤:
-
如果栈顶不是 i32.const (−1),
-
令 frame 为 当前帧(current frame)。
-
刷新 Memory 缓冲区 memaddr。
-
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 page
size(常量 65536)的整数倍大小。因此 HostResizeArrayBuffer 重新定义如下。
抽象操作 HostResizeArrayBuffer 接受参数
buffer(一个 ArrayBuffer)
和 newLength。调用时执行以下步骤。
-
若 buffer.[[ArrayBufferDetachKey]] 为 "WebAssembly.Memory",
-
令 map 为 外围 agent 关联的 Memory object cache。
-
断言:buffer 是 map 中恰好一个值的 [[BufferObject]]。
-
对于每个 memaddr → mem 属于 map,
-
若 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" , // Note: More values may be added in future iterations, // e.g., typed function references, typed GC references };"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 对象表示一个 table 实例,可同时被多个
Instance 对象引用。
每个 Table 对象都有一个
[[Table]] 内部槽,其值为一个 table address。
-
令 map 为 外围 agent 关联的 Table object cache。
-
断言: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 为 table 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异常。注: 上述异常可能由内存不足或无效的尺寸参数导致。
-
返回 initialSize。
Table 的 length 属性的 getter 时,执行如下步骤:
-
令 tableaddr 为 this.[[Table]]。
-
令 addrtype 为 address type,来自 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 对象表示一个 global 实例,
可同时被多个 Instance
对象引用。
每个
Global 对象有一个内部槽:
-
[[Global]]:一个 global address
-
令 map 为 外围 agent 关联的 Global object cache。
-
断言: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"])。
-
-
抛出
TypeError异常。
-
-
若 v 缺失,
-
令 value 为 DefaultValue(valuetype)。
-
断言:value 非 error。
-
-
否则,
-
令 value 为 ToWebAssemblyValue(v, valuetype)。
-
-
若 mutable 为 true,令 globaltype 为 var valuetype;否则令 globaltype 为 const valuetype。
-
令 store 为当前 agent 的 关联 store。
-
令 (store, globaladdr) 为 global_alloc(store, globaltype, value)。
-
将当前 agent 的 关联 store 设为 store。
-
初始化 this,来自 globaladdr。
Global
global) 执行以下步骤:
-
令 store 为当前 agent 的 关联 store。
-
令 globaladdr 为 global.[[Global]]。
-
令 globaltype 为 global_type(store, globaladdr)。
-
若 globaltype 形式为 mut valuetype 且 valuetype 匹配 v128 或 exnref,抛出
TypeError。 -
令 value 为 global_read(store, globaladdr)。
-
返回 ToJSValue(value)。
Global 的 value 属性的 getter 时,执行如下步骤:
-
返回 GetGlobalValue(this)。
当设置 Global 的
value 属性时,执行如下步骤:
-
令 store 为当前 agent 的 关联 store。
-
令 globaladdr 为 this.[[Global]]。
-
令 mut valuetype 为 global_type(store, globaladdr)。
-
令 value 为 ToWebAssemblyValue(the given value, valuetype)。
-
令 store 为 global_write(store, globaladdr, value)。
-
若 store 为 error,抛出
RangeError异常。 -
将当前 agent 的 关联 store 设为 store。
valueOf() 方法时,执行如下步骤:
-
返回 GetGlobalValue(this)。
5.6. 导出函数
WebAssembly 函数以 导出函数(Exported Function) 的形式在 JavaScript 中可用。 导出函数是内建函数对象(Built-in Function Objects),不是构造函数,且具有 [[FunctionAddress]] 内部槽。 该内部槽保存一个相对于外围 agent的关联 store的函数地址。
-
令 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 为 外围 agent 关联的 导出函数缓存(Exported Function cache)。
-
若 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。注: 上述错误会在每次调用 [[Call]] 方法时抛出。
-
令 args 为 « »。
-
令 i 为 0。
-
对于每个 t 属于 parameters,
-
若 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 为 THROW ref.exn exnaddr,则
-
令 tagaddr 为 exn_tag(store, exnaddr)。
-
令 payload 为 exn_read(store, exnaddr)。
-
令 jsTagAddr 为获取 JavaScript 异常标签的结果。
-
若 tagaddr 等于 jsTagAddr,
-
抛出从 payload[0] 检索宿主值 的结果。
-
-
否则,
-
令 exception 为从 exnaddr 创建的新 Exception。
-
抛出 exception。
-
-
-
令 outArity 为 大小为 ret 的值。
-
若 outArity 为 0,返回 undefined。
-
否则,若 outArity 为 1,返回 ToJSValue(ret[0])。
-
否则,
-
令 values 为 « »。
-
对于每个 r 属于 ret,
-
返回 CreateArrayFromList(values)。
-
注: 调用导出函数 按 内建函数对象 的定义,在被调用的导出函数的 [[Realm]] 中执行。
注: 导出函数没有 [[Construct]] 方法,因此无法使用 new
运算符调用。
-
令 [parameters] → [results] 为 functype。
-
令 jsArguments 为 « »。
-
对于每个 arg 属于 arguments,
-
令 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 为在任设置对象(incumbent settings object)。
-
令 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 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)。
注: 值为 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 heaptype。
-
-
否则若 match_valtype(type, ref null extern),
-
令 ref 为 ToWebAssemblyValue(v, ref any)。
-
令 r 为 ref.extern ref。
-
-
否则若 v 是一个 导出函数(Exported Function) 且 match_valtype(type, ref null func),
-
令 funcaddr 为 v 的 [[FunctionAddress]] 内部槽的值。
-
令 r 为 ref.func funcaddr。
-
-
否则若 v 是 Number 且 v 等于 ? ToInt32(v) 且 ℝ(v) < 230 且 ℝ(v) ⩾ -230,
-
否则若 v 是 导出 GC 对象(Exported GC Object),
-
令 objectaddr 为 v 的 [[ObjectAddress]] 内部槽。
-
令 objectkind 为 v 的 [[ObjectKind]] 内部槽。
-
若 objectkind 为 "array",
-
令 r 为 ref.array objectaddr。
-
-
若 objectkind 为 "struct",
-
令 r 为 ref.struct objectaddr。
-
-
-
否则,
-
令 store 为当前 agent 的 关联 store。
-
令 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]。
注: 这等价于 JS 转换规则 中的 [EnforceRange] unsigned long。
-
-
若 addrtype 为 "i64",
-
断言:不会到达此步骤。
5.7. 标签
tag_alloc(store, parameters) 算法在 store 中为 parameters 创建一个新的标签地址,并返回更新后的 store 与该标签地址。
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 的 struct 或 array 在 JavaScript 中以 导出 GC 对象(Exported GC Object) 的形式提供。 导出 GC 对象 是一种封装了垃圾回收的 WebAssembly 引用值的异质对象。 对 导出 GC 对象 的大多数 JavaScript 操作将抛出异常或返回 undefined。
注: 这些操作未来可能进一步细化,以允许在 JavaScript 中与 WebAssembly 的 struct 与 array 进行更丰富的交互。
导出 GC 对象 包含 [[ObjectAddress]] 内部槽,其中保存相对于外围 agent的关联 store的object address, 以及 [[ObjectKind]] 内部槽,保存字符串 "struct" 或 "array"。
导出 GC 对象 的内部方法如下实现。
-
返回 null。
-
返回 false。
-
返回 false。
-
返回 false。
-
返回 undefined。
-
返回 false。
-
返回 false。
-
返回 undefined。
-
抛出
TypeError。
-
抛出
TypeError。
-
令 keys 为一个新的空列表。
-
返回 keys。
-
断言:objectkind 为 "array" 或 "struct"。
-
令 map 为 外围 agent 关联的 导出 GC 对象缓存。
-
若 map[objectaddr] 存在,
-
返回 map[objectaddr]。
-
-
令 object 为 MakeBasicObject(« [[ObjectAddress]] »)。
-
将 object.[[ObjectAddress]] 设为 objectaddr。
-
将 object.[[ObjectKind]] 设为 objectkind。
-
按 导出 GC 对象的 [[GetPrototypeOf]] 内部方法 指定设置 object.[[GetPrototypeOf]]。
-
按 导出 GC 对象的 [[SetPrototypeOf]] 内部方法 指定设置 object.[[SetPrototypeOf]]。
-
按 导出 GC 对象的 [[IsExtensible]] 内部方法 指定设置 object.[[IsExtensible]]。
-
按 导出 GC 对象的 [[PreventExtensions]] 内部方法 指定设置 object.[[PreventExtensions]]。
-
按 导出 GC 对象的 [[GetOwnProperty]] 内部方法 指定设置 object.[[GetOwnProperty]]。
-
按 导出 GC 对象的 [[DefineOwnProperty]] 内部方法 指定设置 object.[[DefineOwnProperty]]。
-
按 导出 GC 对象的 [[HasProperty]] 内部方法 指定设置 object.[[HasProperty]]。
-
按 导出 GC 对象的 [[Get]] 内部方法 指定设置 object.[[Get]]。
-
按 导出 GC 对象的 [[Set]] 内部方法 指定设置 object.[[Set]]。
-
按 导出 GC 对象的 [[Delete]] 内部方法 指定设置 object.[[Delete]]。
-
按 导出 GC 对象的 [[OwnPropertyKeys]] 内部方法 指定设置 object.[[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 ([EnforceRange ]unsigned long );index boolean is (Tag );exceptionTag readonly attribute (DOMString or undefined )stack ; };
Exception
值表示一个异常。
要从 Exception address exnAddress 初始化一个 Exception 对象 exn,执行以下步骤:
要从 exception address exnAddress 创建一个 Exception 对象,执行以下步骤:
new Exception(exceptionTag, payload, options)
构造函数步骤为:
-
令 JSTagAddr 为 获取 JavaScript 异常标签 的结果。
-
若 exceptionTag.[[Address]] 等于 JSTagAddr,
-
抛出
TypeError。
-
-
令 [types] → [] 为 tag_type(store, exceptionTag.[[Address]])。
-
-
抛出
TypeError。
-
-
令 wasmPayload 为 « »。
-
对于每个 value 与 resultType(来自 payload 与 types,按顺序配对),
-
令 (store, exceptionAddr) 为 exn_alloc(store, exceptionTag.[[Address]], wasmPayload)
-
初始化 this,来自 exceptionAddr。
-
若 options["traceStack"] 为 true,
-
将 this.[[Stack]] 设为当前调用栈的
DOMString表示,或设为 undefined。
-
getArg(index) 方法的步骤为:
is(exceptionTag) 方法的步骤为:
-
若 this.[[Type]] 不等于 exceptionTag.[[Address]],
-
返回 false。
-
-
返回 true。
stack 的 getter 步骤为:
-
返回 this.[[Stack]]。
5.9.1. JavaScript 异常
JavaScript 异常标签是一个与外围 agent 关联的 标签地址。它会在该 agent 的 关联 store 中首次使用时分配并被缓存。它始终具有 标签类型 « externref » → « »。
要获取 JavaScript 异常标签,执行以下步骤:
-
如果 外围 agent 关联的 JavaScript 异常标签 已初始化,
-
返回该 外围 agent 关联的 JavaScript 异常标签
-
-
令 (store, tagAddress) 为 tag_alloc(store, « externref » → « »)。
-
将当前 agent 的 关联 store 设为 store。
-
将当前 agent 关联的 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)。
-
注: 这会在 CompileError、
LinkError
与 RuntimeError
类在 WebAssembly
命名空间上进行定义,这些类由本规范定义的 API 产生。它们公开的接口与原生 JavaScript 错误(如 TypeError
和 RangeError)一致。
注: 目前无法使用 Web IDL 来定义此行为。
6. 内建函数
JS-API 定义了一组可在编译模块时通过 options
导入的内建函数集合。WebAssembly 的内建函数反映现有的 JavaScript 内建函数,但将其适配为可以直接作为 WebAssembly 函数使用,且开销最小。
所有内建函数被分组为若干集合。每个内建集合都有一个在 WebAssemblyCompileOptions
中使用的 name,以及一个带有 wasm: 前缀、在导入查找期间使用的 qualified name。
要获取某个内建集合的内建函数,给定 builtinSetName,执行以下步骤:
-
返回该名称为 builtinSetName 的集合(在本节中定义)的 (name, funcType, steps) 列表。
要用 import 与已启用的内建集合 builtinSetNames 查找内建函数,执行以下步骤:
-
断言:验证内建集合名称 builtinSetNames 的结果为 true。
-
令 importModuleName 为 import[0]。
-
令 importName 为 import[1]。
-
对于每个 builtinSetName 属于 builtinSetNames,
-
若 builtinSetName 不指向一个内建集合,则继续。
-
令 builtinSetQualifiedName 为在 builtinSetName 前加前缀 "wasm:" 的结果。
-
若 importModuleName 等于 builtinSetQualifiedName,
-
令 builtins 为 获取某个内建集合的内建函数 builtinSetName 的结果。
-
对于每个 builtin 属于 builtins,
-
令 builtinName 为 builtin[0]。
-
若 importName 等于 builtinName,返回 (builtinSetName, builtin)。
-
-
-
-
返回 null。
要对 builtinSetNames 验证内建集合名称,执行以下步骤:
-
若 builtinSetNames 包含任何重复项,返回 false。
-
返回 true。
要从类型 funcType 和执行步骤 steps 创建一个内建函数,执行以下步骤:
-
令 hostfunc 为一个 宿主函数,当被调用时执行 steps。
-
令 (store, funcaddr) 为 func_alloc(store, functype, hostfunc)。
-
返回 funcaddr。
要用名称 builtinSetName 实例化一个内建集合,执行以下步骤:
-
令 builtins 为 获取某个内建集合的内建函数 builtinSetName 的结果。
-
令 exportsObject 为 ! OrdinaryObjectCreate(null)。
-
对于每个 (name, funcType, steps) 属于 builtins,
-
令 funcaddr 为用 funcType 与 steps 创建一个内建函数 的结果。
-
令 func 为从 funcaddr 创建 新的导出函数(Exported Function) 的结果。
-
令 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[0][1]。
-
令 builtinExternType 为
func |builtinFuncType|。 -
返回 match_externtype(builtinExternType, importExternType)。
6.1. 字符串内建
字符串内建适配了 String
内建对象的接口。该集合的 name
为 js-string,其 qualified name 为 wasm:js-string。
注: 本节中的算法引用定义在 String 上的 JS 内建函数。这里指的是实际的内建函数,不会对 String 对象进行动态查找。
6.1.1. 抽象操作
UnwrapString(v) 抽象操作被调用时,执行以下步骤:
-
若 v 不是 String,
-
抛出
RuntimeError异常,就像执行了一个 trap 一样。
-
-
返回 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 externref)))).0。
当以参数 v 调用该内建时,必须运行以下步骤:
-
返回 ? UnwrapString(v)
6.1.3. test
此内建的 funcType 为 (rec (type (func (param externref) (result i32)))).0。
当以参数 v 调用该内建时,必须运行以下步骤:
-
若 v 不是 String,
-
返回 0。
-
-
返回 1。
6.1.4. fromCharCodeArray
令 arrayType 为 (rec (type (array (mut i16)))).0。
此内建的 funcType 为
(rec (type (func (param (ref null arrayType) i32 i32) (result externref)))).0。
当以参数 array、start 与 end 调用该内建时,必须运行以下步骤:
-
若 array 为 null,
-
抛出
RuntimeError异常,就像执行了一个 trap 一样。
-
-
令 length 为 array 中元素的数量。
-
若 start > end 或 end > length,
-
抛出
RuntimeError异常,就像执行了一个 trap 一样。
-
-
令 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异常,就像执行了一个 trap 一样。
-
-
令 string 为 ? UnwrapString(string) 的结果。
-
令 stringLength 为 string 的长度。
-
令 arrayLength 为 array 中元素的数量。
-
若 start + stringLength > arrayLength,
-
抛出
RuntimeError异常,就像执行了一个 trap 一样。
-
-
令 i 为 0。
-
当 i < stringLength 时:
-
令 charCode 为 CharCodeAt(string, i)。
-
将 array 中索引 start + i 处的元素设为 ToWebAssemblyValue(charCode)。
-
将 i 设为 i + 1。
-
-
返回 stringLength。
6.1.6. fromCharCode
此内建的 funcType 为 (rec (type (func (param i32) (result externref)))).0。
当以参数 v 调用该内建时,必须运行以下步骤:
-
返回 FromCharCode(v)。
6.1.7. fromCodePoint
此内建的 funcType 为 (rec (type (func (param i32) (result externref)))).0。
当以参数 v 调用该内建时,必须运行以下步骤:
-
若 v > 0x10ffff,
-
抛出
RuntimeError异常,就像执行了一个 trap 一样。
-
-
返回 ! 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异常,就像执行了一个 trap 一样。
-
-
返回 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异常,就像执行了一个 trap 一样。
-
-
返回 ! 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 externref)))).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 externref)))).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异常,就像执行了一个 trap 一样。
-
-
若 second 非 null 且 second 不是 String,
-
抛出
RuntimeError异常,就像执行了一个 trap 一样。
-
-
若 ! 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 通过 import 调用 JavaScript,而 JavaScript 抛出了异常,则该异常会通过 WebAssembly 的激活帧传播到 外层调用方。
由于 JavaScript 异常是可处理的,且在 trap 被处理后 JavaScript 仍可继续调用 WebAssembly 的导出函数,一般而言, trap 并不会阻止后续执行。
7.1. 栈溢出
每当 WebAssembly 代码发生栈溢出时,将抛出与 JavaScript 栈溢出相同类别的异常。具体抛出的异常在两种情况下均为实现定义。
注: ECMAScript 并未规定栈溢出的具体行为;已有实现会抛出 RangeError、
InternalError 或 Error。以上任一行为在此均视为有效。
7.2. 内存不足
当验证、编译或实例化出现内存不足时,将抛出与 JavaScript 中内存不足情况相同类别的异常。 具体抛出的异常在两种情况下均为实现定义。
注: ECMAScript 并未规定内存不足的具体行为;已有实现会抛出 OOMError 或直接崩溃。两者在此均视为有效。
-
RangeError, 如在Memory的grow()和Table的grow()操作中所规定的那样 -
返回 -1,正如 memory.grow 指令所规定的那样
-
如本节所述的特定 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。
- 一个 struct 的字段数量上限为 10,000。
array.new_fixed的操作数数量上限为 10,000。
在运行时若超过以下任一限制,实现必须抛出 RuntimeError:
实际上,实现也可能在低于这些限制的有效模块上耗尽资源。
- 表的最大大小为 10,000,000。
- 32 位内存的最大大小为 65,536 页(4 GiB)。
- 64 位内存的最大大小为 262,144 页(16 GiB)。
9. 安全与隐私注意事项
本节为非规范性内容。
本文档为 WebAssembly 定义了宿主环境。它使 WebAssembly 实例能够从一个 import 的 JavaScript 对象与函数(来自一个导入对象)中进行导入,但除此之外不提供对嵌入环境的访问。 因此,一个 WebAssembly 实例受与 JavaScript 相同的约束。
10. 变更历史
本节为非规范性内容。
自 WebAssembly 规范 1.0 最初发布以来,已有若干扩展提案被集成。 下列小节概述了发生的变更。