序言
出于对成为编译器工程师的向往,我开始深入挖掘各项编译技术的细节。作为一名前端工程师,我决定首先从 WebAssembly 技术开始学习。本系列文章记录了我阅读 WebAssembly 规范的重点笔记。
你可以在此链接查阅完整的 WebAssembly 规范:WebAssembly Spec 。
约定
验证阶段检查 WebAssembly 模块格式的有效性。只有有效的模块才能被实例化。
有效性是通过模块及其内容的抽象语法上的类型系统来定义的。对于每段抽象语法,都有一个类型规则来指定适用于它的约束条件。所有规则都以两种等效形式给出:
- 在描述性符号中,以直观的形式描述规则。
- 在形式化符号中,以数学形式描述规则。
描述性和形式化规则是等价的,因此阅读本规范不需要理解形式化符号。形式化符号提供了更简洁的描述,广泛用于编程语言语义学,并且很容易进行数学证明。
上下文
规则的有效性是相对于上下文决定的,上下文收集周围模块和作用域内定义的相关信息:
- <math xmlns="http://www.w3.org/1998/Math/MathML"> T y p e s Types </math>Types:当前模块中定义的类型列表。
- <math xmlns="http://www.w3.org/1998/Math/MathML"> F u n c t i o n s Functions </math>Functions:当前模块中声明的函数列表,由其函数类型表示。
- <math xmlns="http://www.w3.org/1998/Math/MathML"> T a b l e s Tables </math>Tables:当前模块中声明的表列表,由其表类型表示。
- <math xmlns="http://www.w3.org/1998/Math/MathML"> M e m o r i e s Memories </math>Memories:当前模块中声明的内存列表,由其内存类型表示。
- <math xmlns="http://www.w3.org/1998/Math/MathML"> G l o b a l s Globals </math>Globals:当前模块中声明的全局变量列表,由它们的全局类型表示。
- <math xmlns="http://www.w3.org/1998/Math/MathML"> E l e m e n t S e g e m e n t s Element Segements </math>ElementSegements:当前模块中声明的元素段列表,由其元素类型表示。
- <math xmlns="http://www.w3.org/1998/Math/MathML"> D a t a S e g e m e n t s Data Segements </math>DataSegements:当前模块中声明的数据段列表,每个段由一个 ok 条目表示。
- <math xmlns="http://www.w3.org/1998/Math/MathML"> L o c a l s Locals </math>Locals:当前函数中声明的局部变量列表(包括参数),由它们值的类型表示。
- <math xmlns="http://www.w3.org/1998/Math/MathML"> L a b e l s Labels </math>Labels:当前位置可访问的标签栈,由它们的结果类型表示。
- <math xmlns="http://www.w3.org/1998/Math/MathML"> R e t u r n Return </math>Return:当前函数的返回类型,为可选的结果类型,当不允许返回时不存在,如在独立表达式中。
- <math xmlns="http://www.w3.org/1998/Math/MathML"> R e f e r e n c e s References </math>References:模块外部函数的函数索引列表,可以通过引用使用它们。
换句话说,上下文包含每个索引空间的类型列表,描述该空间中定义的每个条目。局部变量、标签和返回类型仅用于验证函数体中的指令,在其他地方为空。标签栈是上下文中唯一随指令序列验证而更改的部分。
非形式化符号
验证由每个抽象语法相关部分的规则定义。这些规则不仅定义了短语有效性的约束条件,还将其定义为一种类型。在描述这些规则时采用以下约定。
- 当且仅当满足相应规则的所有约束时,短语 <math xmlns="http://www.w3.org/1998/Math/MathML"> A A </math>A 称为 "对类型 <math xmlns="http://www.w3.org/1998/Math/MathML"> T T </math>T 有效"。 <math xmlns="http://www.w3.org/1998/Math/MathML"> T T </math>T 的形式取决于 <math xmlns="http://www.w3.org/1998/Math/MathML"> A A </math>A 是什么。
例如,如果 <math xmlns="http://www.w3.org/1998/Math/MathML"> A A </math>A 是 function,则 <math xmlns="http://www.w3.org/1998/Math/MathML"> T T </math>T 是 function type;如果 <math xmlns="http://www.w3.org/1998/Math/MathML"> A A </math>A 是 global,则 <math xmlns="http://www.w3.org/1998/Math/MathML"> T T </math>T 是 global type。
- 规则隐式假设了一个给定的上下文 <math xmlns="http://www.w3.org/1998/Math/MathML"> C C </math>C。
- 在某些地方,这个上下文被扩展为带有额外信息的上下文 <math xmlns="http://www.w3.org/1998/Math/MathML"> C ′ C' </math>C′。采用"在上下文 <math xmlns="http://www.w3.org/1998/Math/MathML"> C ′ C' </math>C′,...语句..."这个表述,来表示以下语句必须适用于扩展上下文所体现的假设。
形式化符号
一个短语 <math xmlns="http://www.w3.org/1998/Math/MathML"> A A </math>A 有相应类型的 <math xmlns="http://www.w3.org/1998/Math/MathML"> T T </math>T,该命题写为: <math xmlns="http://www.w3.org/1998/Math/MathML"> A : T A:T </math>A:T。然而,通常情况下,类型依赖于上下文 <math xmlns="http://www.w3.org/1998/Math/MathML"> C C </math>C。为了明确表达这一点,完整形式是一个判断: <math xmlns="http://www.w3.org/1998/Math/MathML"> C ⊢ A : T C \vdash A:T </math>C⊢A:T,它表示假定上下文为 <math xmlns="http://www.w3.org/1998/Math/MathML"> C C </math>C, <math xmlns="http://www.w3.org/1998/Math/MathML"> A : T A:T </math>A:T 成立。
正式的类型规则使用标准方法来定义类型系统,使用演绎规则表示它们。每个规则都具有以下一般形式:
这样的规则被称为大含意:如果所有前提都成立,则结论成立。有些规则没有前提;它们是公理,其结论无条件成立。结论总是一个判断 <math xmlns="http://www.w3.org/1998/Math/MathML"> C ⊢ A : T C \vdash A:T </math>C⊢A:T,每个抽象语法结构都有一个相应的规则。
类型
Limit
Limit 必须具有有意义的边界,且在给定范围内。
- <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 不能大于 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k
- 如果 <math xmlns="http://www.w3.org/1998/Math/MathML"> m m </math>m 不为空,则:
- 它不能大于 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k
- 它不能小于 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n
- 则 limit 在 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k 范围内有效。
块类型(Block Types)
块类型可以用两种形式表示,这两种形式都将按照以下规则转换为普通函数类型。
<math xmlns="http://www.w3.org/1998/Math/MathML"> t y p e i d x typeidx </math>typeidx
- 类型 <math xmlns="http://www.w3.org/1998/Math/MathML"> C . t y p e s [ t y p e i d x ] C.types[typeidx] </math>C.types[typeidx] 必须在上下文中定义。
- 则块类型 <math xmlns="http://www.w3.org/1998/Math/MathML"> C . t y p e s [ t y p e i d x ] C.types[typeidx] </math>C.types[typeidx] 有效,表示函数类型。
<math xmlns="http://www.w3.org/1998/Math/MathML"> [ v a l t y p e ? ] [valtype^?] </math>[valtype?]
- 块类型有效,表示函数类型 <math xmlns="http://www.w3.org/1998/Math/MathML"> [ ] → [ v a l t y p e ? ] []\to[valtype^?] </math>[]→[valtype?]。
函数类型(Function Types)
函数类型总是有效。
表类型
内存类型
全局类型(Global Types)
外部类型(External Types)
<math xmlns="http://www.w3.org/1998/Math/MathML"> func f u n c t y p e \textsf{func}~functype </math>func functype
<math xmlns="http://www.w3.org/1998/Math/MathML"> table t a b l e t y p e \textsf{table}~tabletype </math>table tabletype
<math xmlns="http://www.w3.org/1998/Math/MathML"> mem m e m t y p e \textsf{mem}~memtype </math>mem memtype
<math xmlns="http://www.w3.org/1998/Math/MathML"> global g l o b a l t y p e \textsf{global}~globaltype </math>global globaltype
导入子类型(Import Subtyping)
指令
指令通过栈类型(stack types) <math xmlns="http://www.w3.org/1998/Math/MathML"> [ t 1 ∗ ] → [ t 2 ∗ ] [t_1^*]→[t_2^*] </math>[t1∗]→[t2∗] 进行定义,描述指令如何处理操作数栈。
<math xmlns="http://www.w3.org/1998/Math/MathML"> t 1 ∗ t_1^* </math>t1∗ 表示输入的类型,即从栈中弹出的数据。 <math xmlns="http://www.w3.org/1998/Math/MathML"> t 2 ∗ t_2^* </math>t2∗ 表示输出的类型,及推入到栈中的数据。栈类型类似于函数类型,除了它们允许将单个操作数分类为(底部),这表明该类型不受约束。作为辅助概念,操作数类型1匹配另一个操作数类型2,如果1是或等于2。这以逐点方式扩展到堆栈类型。
数值指令
模块
函数
表
内存
全局
元素段
数据段
导出
导入(Imports)
导入 <math xmlns="http://www.w3.org/1998/Math/MathML"> i m p o r t import </math>import 和导入的描述 <math xmlns="http://www.w3.org/1998/Math/MathML"> i m p o r t d e s c import~desc </math>import desc 使用外部类型定义。
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { module n a m e 1 , name n a m e 2 , desc i m p o r t d e s c } \{\textsf{module}~name_1,\textsf{name}~name_2,\textsf{desc}~importdesc\} </math>{module name1,name name2,desc importdesc}
- 导入描述 <math xmlns="http://www.w3.org/1998/Math/MathML"> i m p o r t d e s c importdesc </math>importdesc 必须是有效的 <math xmlns="http://www.w3.org/1998/Math/MathML"> e x t e r n t y p e externtype </math>externtype 。
- 然后导入是有效的,类型为 <math xmlns="http://www.w3.org/1998/Math/MathML"> e x t e r n t y p e externtype </math>externtype。
模块
模块根据导入的外部类型到导出类型的映射进行分类。
一个模块是完全封闭的,也就是说,它的组件只能引用出现在模块本身中的定义。因此,不需要初始上下文。相反,模块内容的验证上下文是从模块中的定义构建的。
- 令 <math xmlns="http://www.w3.org/1998/Math/MathML"> m o d u l e module </math>module 为被验证的模块。
- 令 <math xmlns="http://www.w3.org/1998/Math/MathML"> C C </math>C 为上下文,其中:
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C . t y p e s C.types </math>C.types 等于 <math xmlns="http://www.w3.org/1998/Math/MathML"> m o d u l e . t y p e s module.types </math>module.types,
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C . f u n c s C.funcs </math>C.funcs
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C . t a b l e s C.tables </math>C.tables
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C . m e m s C.mems </math>C.mems
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C . g l o b a l s C.globals </math>C.globals
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C . e l e m s C.elems </math>C.elems
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C . d a t a s C.datas </math>C.datas
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C . l o c a l s C.locals </math>C.locals 为空,
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C . l a b e l s C.labels </math>C.labels 为空,
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C . r e t u r n C.return </math>C.return 为空,
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C . r e f s C.refs </math>C.refs
- 令 <math xmlns="http://www.w3.org/1998/Math/MathML"> C ′ C^\prime </math>C′ 为上下文,其中:
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C ′ . g l o b a l s C^\prime .globals </math>C′.globals
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C ′ . f u n c s C^\prime .funcs </math>C′.funcs
- <math xmlns="http://www.w3.org/1998/Math/MathML"> C ′ . r e f s C^\prime .refs </math>C′.refs
- 其他字段为空。