模块
WebAssembly 程序被组织成模块,它是部署、加载和编译的单位。模块收集了对 类型、函数、表格、内存 和 全局变量 的定义。此外,它可以声明 导入 和 导出,并提供初始化形式的 数据 和 元素 段,或一个 开始函数。
\[\begin{split}\begin{array}{lllll} \def\mathdef2560#1{{}}\mathdef2560{module} & \href{../syntax/modules.html#syntax-module}{\mathit{module}} &::=& \{ & \href{../syntax/modules.html#syntax-module}{\mathsf{types}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/types.html#syntax-functype}{\mathit{functype}}), \\&&&& \href{../syntax/modules.html#syntax-module}{\mathsf{funcs}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/modules.html#syntax-func}{\mathit{func}}), \\&&&& \href{../syntax/modules.html#syntax-module}{\mathsf{tables}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/modules.html#syntax-table}{\mathit{table}}), \\&&&& \href{../syntax/modules.html#syntax-module}{\mathsf{mems}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/modules.html#syntax-mem}{\mathit{mem}}), \\&&&& \href{../syntax/modules.html#syntax-module}{\mathsf{globals}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/modules.html#syntax-global}{\mathit{global}}), \\&&&& \href{../syntax/modules.html#syntax-module}{\mathsf{elems}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/modules.html#syntax-elem}{\mathit{elem}}), \\&&&& \href{../syntax/modules.html#syntax-module}{\mathsf{datas}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/modules.html#syntax-data}{\mathit{data}}), \\&&&& \href{../syntax/modules.html#syntax-module}{\mathsf{start}}~\href{../syntax/modules.html#syntax-start}{\mathit{start}}^?, \\&&&& \href{../syntax/modules.html#syntax-module}{\mathsf{imports}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/modules.html#syntax-import}{\mathit{import}}), \\&&&& \href{../syntax/modules.html#syntax-module}{\mathsf{exports}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/modules.html#syntax-export}{\mathit{export}}) \quad\} \\ \end{array}\end{split}\]
每个向量(以及整个模块)都可能是空的。
索引
定义用以零为基准的索引来引用。每个定义类别都有自己的索引空间,由以下类别区分。
\[\begin{split}\begin{array}{llll} \def\mathdef2560#1{{}}\mathdef2560{type index} & \href{../syntax/modules.html#syntax-typeidx}{\mathit{typeidx}} &::=& \href{../syntax/values.html#syntax-int}{\mathit{u32}} \\ \def\mathdef2560#1{{}}\mathdef2560{function index} & \href{../syntax/modules.html#syntax-funcidx}{\mathit{funcidx}} &::=& \href{../syntax/values.html#syntax-int}{\mathit{u32}} \\ \def\mathdef2560#1{{}}\mathdef2560{table index} & \href{../syntax/modules.html#syntax-tableidx}{\mathit{tableidx}} &::=& \href{../syntax/values.html#syntax-int}{\mathit{u32}} \\ \def\mathdef2560#1{{}}\mathdef2560{memory index} & \href{../syntax/modules.html#syntax-memidx}{\mathit{memidx}} &::=& \href{../syntax/values.html#syntax-int}{\mathit{u32}} \\ \def\mathdef2560#1{{}}\mathdef2560{global index} & \href{../syntax/modules.html#syntax-globalidx}{\mathit{globalidx}} &::=& \href{../syntax/values.html#syntax-int}{\mathit{u32}} \\ \def\mathdef2560#1{{}}\mathdef2560{element index} & \href{../syntax/modules.html#syntax-elemidx}{\mathit{elemidx}} &::=& \href{../syntax/values.html#syntax-int}{\mathit{u32}} \\ \def\mathdef2560#1{{}}\mathdef2560{data index} & \href{../syntax/modules.html#syntax-dataidx}{\mathit{dataidx}} &::=& \href{../syntax/values.html#syntax-int}{\mathit{u32}} \\ \def\mathdef2560#1{{}}\mathdef2560{local index} & \href{../syntax/modules.html#syntax-localidx}{\mathit{localidx}} &::=& \href{../syntax/values.html#syntax-int}{\mathit{u32}} \\ \def\mathdef2560#1{{}}\mathdef2560{label index} & \href{../syntax/modules.html#syntax-labelidx}{\mathit{labelidx}} &::=& \href{../syntax/values.html#syntax-int}{\mathit{u32}} \\ \end{array}\end{split}\]
对于 函数、表格、内存 和 全局变量 的索引空间,包括在同一模块中声明的相应 导入。这些导入的索引在同一索引空间中其他定义的索引之前。
元素索引引用 元素段,而数据索引引用 数据段。
对于 局部变量 的索引空间,只能在 函数 内部访问,并包含该函数的参数,它们在局部变量之前。
标签索引引用指令序列中的 结构化控制指令。
约定
元变量 \(l\) 涵盖标签索引。
元变量 \(x, y\) 涵盖任何其他索引空间中的索引。
符号 \(\mathrm{idx}(A)\) 表示在 \(A\) 中自由出现的来自索引空间 \(\mathit{idx}\) 的索引集。有时这个集合被重新解释为其元素的 向量。
注意
例如,如果 \(\href{../syntax/instructions.html#syntax-instr}{\mathit{instr}}^\ast\) 是 \((\href{../syntax/instructions.html#syntax-instr-memory}{\mathsf{data.drop}}~x) (\href{../syntax/instructions.html#syntax-instr-memory}{\mathsf{memory.init}}~y)\),那么 \(\href{../syntax/modules.html#syntax-dataidx}{\mathrm{dataidx}}(\href{../syntax/instructions.html#syntax-instr}{\mathit{instr}}^\ast) = \{x, y\}\),或者等效地,向量 \(x~y\)。
类型
模块的 \(\href{../syntax/modules.html#syntax-module}{\mathsf{types}}\) 组件定义了一个 函数类型 向量。
模块中使用的所有函数类型都必须在此组件中定义。它们通过 类型索引 来引用。
注意
WebAssembly 的未来版本可能会添加其他形式的类型定义。
函数
模块的 \(\href{../syntax/modules.html#syntax-module}{\mathsf{funcs}}\) 组件定义了一个具有以下结构的函数向量
\[\begin{split}\begin{array}{llll} \def\mathdef2560#1{{}}\mathdef2560{function} & \href{../syntax/modules.html#syntax-func}{\mathit{func}} &::=& \{ \href{../syntax/modules.html#syntax-func}{\mathsf{type}}~\href{../syntax/modules.html#syntax-typeidx}{\mathit{typeidx}}, \href{../syntax/modules.html#syntax-func}{\mathsf{locals}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/types.html#syntax-valtype}{\mathit{valtype}}), \href{../syntax/modules.html#syntax-func}{\mathsf{body}}~\href{../syntax/instructions.html#syntax-expr}{\mathit{expr}} \} \\ \end{array}\end{split}\]
函数的 \(\href{../syntax/modules.html#syntax-func}{\mathsf{type}}\) 通过引用模块中定义的 类型 来声明其签名。函数的参数通过函数体中的以 0 为基准的 局部变量索引 来引用;它们是可变的。
The \(\href{../syntax/modules.html#syntax-func}{\mathsf{locals}}\) 声明一个可变局部变量向量及其类型。这些变量通过函数体中的 局部变量索引 来引用。第一个局部变量的索引是最小的不引用参数的索引。
The \(\href{../syntax/modules.html#syntax-func}{\mathsf{body}}\) 是一个 指令 序列,在终止时必须生成与函数类型 结果类型 匹配的堆栈。
函数通过 函数索引 来引用,从最小的不引用函数 导入 的索引开始。
表格
模块的 \(\href{../syntax/modules.html#syntax-module}{\mathsf{tables}}\) 组件定义了一个由其 表格类型 描述的表格向量
\[\begin{split}\begin{array}{llll} \def\mathdef2560#1{{}}\mathdef2560{table} & \href{../syntax/modules.html#syntax-table}{\mathit{table}} &::=& \{ \href{../syntax/modules.html#syntax-table}{\mathsf{type}}~\href{../syntax/types.html#syntax-tabletype}{\mathit{tabletype}} \} \\ \end{array}\end{split}\]
表格是特定 引用类型 的不透明值的向量。表格类型 限制 中的 \(\href{../syntax/types.html#syntax-limits}{\mathsf{min}}\) 大小指定该表格的初始大小,而其 \(\href{../syntax/types.html#syntax-limits}{\mathsf{max}}\)(如果存在)则限制其以后可以增长到的大小。
表格可以通过 元素段 来初始化。
表格通过 表格索引 来引用,从最小的不引用表格 导入 的索引开始。大多数构造隐式引用表格索引 \(0\)。
内存
模块的 \(\href{../syntax/modules.html#syntax-module}{\mathsf{mems}}\) 组件定义了一个由其 内存类型 描述的线性内存(或简称为内存)向量
\[\begin{split}\begin{array}{llll} \def\mathdef2560#1{{}}\mathdef2560{memory} & \href{../syntax/modules.html#syntax-mem}{\mathit{mem}} &::=& \{ \href{../syntax/modules.html#syntax-mem}{\mathsf{type}}~\href{../syntax/types.html#syntax-memtype}{\mathit{memtype}} \} \\ \end{array}\end{split}\]
内存是原始未解释字节的向量。内存类型 限制 中的 \(\href{../syntax/types.html#syntax-limits}{\mathsf{min}}\) 大小指定该内存的初始大小,而其 \(\href{../syntax/types.html#syntax-limits}{\mathsf{max}}\)(如果存在)则限制其以后可以增长到的大小。两者都以 页面大小 为单位。
内存可以通过 数据段 来初始化。
内存通过 内存索引 来引用,从最小的不引用内存 导入 的索引开始。大多数构造隐式引用内存索引 \(0\)。
注意
在当前版本的 WebAssembly 中,单个模块最多只能定义或导入一个内存,并且 *所有* 结构都隐式引用此内存 \(0\)。此限制可能会在未来版本中取消。
全局变量
模块的 \(\href{../syntax/modules.html#syntax-module}{\mathsf{globals}}\) 组件定义了一个全局变量(简称全局变量)的向量。
\[\begin{split}\begin{array}{llll} \def\mathdef2560#1{{}}\mathdef2560{global} & \href{../syntax/modules.html#syntax-global}{\mathit{global}} &::=& \{ \href{../syntax/modules.html#syntax-global}{\mathsf{type}}~\href{../syntax/types.html#syntax-globaltype}{\mathit{globaltype}}, \href{../syntax/modules.html#syntax-global}{\mathsf{init}}~\href{../syntax/instructions.html#syntax-expr}{\mathit{expr}} \} \\ \end{array}\end{split}\]
每个全局变量存储给定 全局类型 的单个值。它的 \(\href{../syntax/modules.html#syntax-global}{\mathsf{type}}\) 还指定全局变量是不可变还是可变。此外,每个全局变量都使用 常量 初始化器 表达式 给出的 \(\href{../syntax/modules.html#syntax-global}{\mathsf{init}}\) 值进行初始化。
全局变量通过 全局索引 引用,从不引用全局 导入 的最小索引开始。
元素段
表的初始内容未初始化。*元素段* 可用于从静态 向量 中的元素初始化表的子范围。
模块的 \(\href{../syntax/modules.html#syntax-module}{\mathsf{elems}}\) 组件定义了一个元素段向量。每个元素段都定义一个 引用类型 和一个相应的 常量 元素 表达式 列表。
元素段具有识别它们是 *被动*、*主动* 还是 *声明式* 的模式。被动元素段的元素可以使用 \(\href{../syntax/instructions.html#syntax-instr-table}{\mathsf{table.init}}\) 指令复制到表中。主动元素段在 实例化 期间将它的元素复制到表中,如 表索引 和定义表中偏移量的 常量 表达式 所指定。声明式元素段在运行时不可用,但仅用于前向声明在使用 \(\href{../syntax/instructions.html#syntax-instr-ref}{\mathsf{ref{.}func}}\) 等指令的代码中形成的引用。
\[\begin{split}\begin{array}{llll} \def\mathdef2560#1{{}}\mathdef2560{element segment} & \href{../syntax/modules.html#syntax-elem}{\mathit{elem}} &::=& \{ \href{../syntax/modules.html#syntax-elem}{\mathsf{type}}~\href{../syntax/types.html#syntax-reftype}{\mathit{reftype}}, \href{../syntax/modules.html#syntax-elem}{\mathsf{init}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/instructions.html#syntax-expr}{\mathit{expr}}), \href{../syntax/modules.html#syntax-elem}{\mathsf{mode}}~\href{../syntax/modules.html#syntax-elemmode}{\mathit{elemmode}} \} \\ \def\mathdef2560#1{{}}\mathdef2560{element segment mode} & \href{../syntax/modules.html#syntax-elemmode}{\mathit{elemmode}} &::=& \href{../syntax/modules.html#syntax-elemmode}{\mathsf{passive}} \\&&|& \href{../syntax/modules.html#syntax-elemmode}{\mathsf{active}}~\{ \href{../syntax/modules.html#syntax-elem}{\mathsf{table}}~\href{../syntax/modules.html#syntax-tableidx}{\mathit{tableidx}}, \href{../syntax/modules.html#syntax-elem}{\mathsf{offset}}~\href{../syntax/instructions.html#syntax-expr}{\mathit{expr}} \} \\&&|& \href{../syntax/modules.html#syntax-elemmode}{\mathsf{declarative}} \\ \end{array}\end{split}\]
\(\href{../syntax/modules.html#syntax-elem}{\mathsf{offset}}\) 由 常量 表达式 给出。
元素段通过 元素索引 引用。
数据段
内存 的初始内容为零字节。*数据段* 可用于从静态 向量 中的 字节 初始化内存范围。
模块的 \(\href{../syntax/modules.html#syntax-module}{\mathsf{datas}}\) 组件定义了一个数据段向量。
与元素段类似,数据段具有识别它们是 *被动* 还是 *主动* 的模式。被动数据段的内容可以使用 \(\href{../syntax/instructions.html#syntax-instr-memory}{\mathsf{memory.init}}\) 指令复制到内存中。主动数据段在 实例化 期间将它的内容复制到内存中,如 内存索引 和定义内存中偏移量的 常量 表达式 所指定。
\[\begin{split}\begin{array}{llll} \def\mathdef2560#1{{}}\mathdef2560{data segment} & \href{../syntax/modules.html#syntax-data}{\mathit{data}} &::=& \{ \href{../syntax/modules.html#syntax-data}{\mathsf{init}}~\href{../syntax/conventions.html#syntax-vec}{\mathit{vec}}(\href{../syntax/values.html#syntax-byte}{\mathit{byte}}), \href{../syntax/modules.html#syntax-data}{\mathsf{mode}}~\href{../syntax/modules.html#syntax-datamode}{\mathit{datamode}} \} \\ \def\mathdef2560#1{{}}\mathdef2560{data segment mode} & \href{../syntax/modules.html#syntax-datamode}{\mathit{datamode}} &::=& \href{../syntax/modules.html#syntax-datamode}{\mathsf{passive}} \\&&|& \href{../syntax/modules.html#syntax-datamode}{\mathsf{active}}~\{ \href{../syntax/modules.html#syntax-data}{\mathsf{memory}}~\href{../syntax/modules.html#syntax-memidx}{\mathit{memidx}}, \href{../syntax/modules.html#syntax-data}{\mathsf{offset}}~\href{../syntax/instructions.html#syntax-expr}{\mathit{expr}} \} \\ \end{array}\end{split}\]
数据段通过 数据索引 引用。
注意
在当前版本的 WebAssembly 中,模块中最多只能允许一个内存。因此,唯一有效的 \(\href{../syntax/modules.html#syntax-memidx}{\mathit{memidx}}\) 是 \(0\)。
开始函数
模块的 \(\href{../syntax/modules.html#syntax-module}{\mathsf{start}}\) 组件声明了 *开始函数* 的 函数索引,该函数在模块 实例化 时自动调用,在 表 和 内存 初始化后。
\[\begin{split}\begin{array}{llll} \def\mathdef2560#1{{}}\mathdef2560{start function} & \href{../syntax/modules.html#syntax-start}{\mathit{start}} &::=& \{ \href{../syntax/modules.html#syntax-start}{\mathsf{func}}~\href{../syntax/modules.html#syntax-funcidx}{\mathit{funcidx}} \} \\ \end{array}\end{split}\]
注意
开始函数旨在初始化模块的状态。在初始化完成之前,模块及其导出不能在外部访问。
导出
模块的 \(\href{../syntax/modules.html#syntax-module}{\mathsf{exports}}\) 组件定义了一组 *导出*,这些导出在模块 实例化 后将可供主机环境访问。
\[\begin{split}\begin{array}{llcl} \def\mathdef2560#1{{}}\mathdef2560{export} & \href{../syntax/modules.html#syntax-export}{\mathit{export}} &::=& \{ \href{../syntax/modules.html#syntax-export}{\mathsf{name}}~\href{../syntax/values.html#syntax-name}{\mathit{name}}, \href{../syntax/modules.html#syntax-export}{\mathsf{desc}}~\href{../syntax/modules.html#syntax-exportdesc}{\mathit{exportdesc}} \} \\ \def\mathdef2560#1{{}}\mathdef2560{export description} & \href{../syntax/modules.html#syntax-exportdesc}{\mathit{exportdesc}} &::=& \href{../syntax/modules.html#syntax-exportdesc}{\mathsf{func}}~\href{../syntax/modules.html#syntax-funcidx}{\mathit{funcidx}} \\&&|& \href{../syntax/modules.html#syntax-exportdesc}{\mathsf{table}}~\href{../syntax/modules.html#syntax-tableidx}{\mathit{tableidx}} \\&&|& \href{../syntax/modules.html#syntax-exportdesc}{\mathsf{mem}}~\href{../syntax/modules.html#syntax-memidx}{\mathit{memidx}} \\&&|& \href{../syntax/modules.html#syntax-exportdesc}{\mathsf{global}}~\href{../syntax/modules.html#syntax-globalidx}{\mathit{globalidx}} \\ \end{array}\end{split}\]
每个导出都用一个唯一的 名称 进行标记。可导出定义是 函数、表、内存 和 全局变量,它们通过相应的描述符引用。
约定
为导出序列定义以下辅助符号,以保持顺序,过滤掉特定类型的索引。
\(\href{../syntax/modules.html#syntax-exportdesc}{\mathrm{funcs}}(\href{../syntax/modules.html#syntax-export}{\mathit{export}}^\ast) = [\href{../syntax/modules.html#syntax-funcidx}{\mathit{funcidx}} ~|~ \href{../syntax/modules.html#syntax-exportdesc}{\mathsf{func}}~\href{../syntax/modules.html#syntax-funcidx}{\mathit{funcidx}} \in (\href{../syntax/modules.html#syntax-export}{\mathit{export}}.\href{../syntax/modules.html#syntax-export}{\mathsf{desc}})^\ast]\)
\(\href{../syntax/modules.html#syntax-exportdesc}{\mathrm{tables}}(\href{../syntax/modules.html#syntax-export}{\mathit{export}}^\ast) = [\href{../syntax/modules.html#syntax-tableidx}{\mathit{tableidx}} ~|~ \href{../syntax/modules.html#syntax-exportdesc}{\mathsf{table}}~\href{../syntax/modules.html#syntax-tableidx}{\mathit{tableidx}} \in (\href{../syntax/modules.html#syntax-export}{\mathit{export}}.\href{../syntax/modules.html#syntax-export}{\mathsf{desc}})^\ast]\)
\(\href{../syntax/modules.html#syntax-exportdesc}{\mathrm{mems}}(\href{../syntax/modules.html#syntax-export}{\mathit{export}}^\ast) = [\href{../syntax/modules.html#syntax-memidx}{\mathit{memidx}} ~|~ \href{../syntax/modules.html#syntax-exportdesc}{\mathsf{mem}}~\href{../syntax/modules.html#syntax-memidx}{\mathit{memidx}} \in (\href{../syntax/modules.html#syntax-export}{\mathit{export}}.\href{../syntax/modules.html#syntax-export}{\mathsf{desc}})^\ast]\)
\(\href{../syntax/modules.html#syntax-exportdesc}{\mathrm{globals}}(\href{../syntax/modules.html#syntax-export}{\mathit{export}}^\ast) = [\href{../syntax/modules.html#syntax-globalidx}{\mathit{globalidx}} ~|~ \href{../syntax/modules.html#syntax-exportdesc}{\mathsf{global}}~\href{../syntax/modules.html#syntax-globalidx}{\mathit{globalidx}} \in (\href{../syntax/modules.html#syntax-export}{\mathit{export}}.\href{../syntax/modules.html#syntax-export}{\mathsf{desc}})^\ast]\)
导入
模块的 \(\href{../syntax/modules.html#syntax-module}{\mathsf{imports}}\) 组件定义了一组 *导入*,这些导入是 实例化 所必需的。
\[\begin{split}\begin{array}{llll} \def\mathdef2560#1{{}}\mathdef2560{import} & \href{../syntax/modules.html#syntax-import}{\mathit{import}} &::=& \{ \href{../syntax/modules.html#syntax-import}{\mathsf{module}}~\href{../syntax/values.html#syntax-name}{\mathit{name}}, \href{../syntax/modules.html#syntax-import}{\mathsf{name}}~\href{../syntax/values.html#syntax-name}{\mathit{name}}, \href{../syntax/modules.html#syntax-import}{\mathsf{desc}}~\href{../syntax/modules.html#syntax-importdesc}{\mathit{importdesc}} \} \\ \def\mathdef2560#1{{}}\mathdef2560{import description} & \href{../syntax/modules.html#syntax-importdesc}{\mathit{importdesc}} &::=& \href{../syntax/modules.html#syntax-importdesc}{\mathsf{func}}~\href{../syntax/modules.html#syntax-typeidx}{\mathit{typeidx}} \\&&|& \href{../syntax/modules.html#syntax-importdesc}{\mathsf{table}}~\href{../syntax/types.html#syntax-tabletype}{\mathit{tabletype}} \\&&|& \href{../syntax/modules.html#syntax-importdesc}{\mathsf{mem}}~\href{../syntax/types.html#syntax-memtype}{\mathit{memtype}} \\&&|& \href{../syntax/modules.html#syntax-importdesc}{\mathsf{global}}~\href{../syntax/types.html#syntax-globaltype}{\mathit{globaltype}} \\ \end{array}\end{split}\]
每个导入都由一个两级的 名称 空间标记,包含一个 \(\href{../syntax/modules.html#syntax-import}{\mathsf{模块}}\) 名称和一个 \(\href{../syntax/modules.html#syntax-import}{\mathsf{名称}}\),用于表示该模块中的一个实体。可导入的定义包括 函数、表格、内存 和 全局变量。每个导入都由一个描述符指定,该描述符具有相应的类型,在实例化期间提供的定义必须与该类型匹配。
每个导入在相应的 索引空间 中定义一个索引。在每个索引空间中,导入的索引位于模块本身中包含的任何定义的第一个索引之前。
注意
与导出名称不同,导入名称不一定唯一。可以多次导入同一个 \(\href{../syntax/modules.html#syntax-import}{\mathsf{模块}}\)/\(\href{../syntax/modules.html#syntax-import}{\mathsf{名称}}\) 对;这些导入甚至可能具有不同的类型描述,包括不同类型的实体。具有此类导入的模块仍然可以实例化,具体取决于 嵌入器 允许解析和提供导入的方式。但是,嵌入器不需要支持这种重载,而 WebAssembly 模块本身无法实现重载名称。