WebAssembly规范精读(第三篇)——验证

序言

出于对成为编译器工程师的向往,我开始深入挖掘各项编译技术的细节。作为一名前端工程师,我决定首先从 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
    • 其他字段为空。
相关推荐
萧大侠jdeps7 分钟前
图片生成视频-右进
前端·javascript·音视频
Domain-zhuo29 分钟前
JS对于数组去重都有哪些方法?
开发语言·前端·javascript
明月清风徐徐1 小时前
Vue实训---2-路由搭建
前端·javascript·vue.js
王解1 小时前
速度革命:esbuild如何改变前端构建游戏 (1)
前端·vite·esbuild
葡萄城技术团队1 小时前
使用 前端技术 创建 QR 码生成器 API1
前端
DN金猿1 小时前
Vue移动端网页(H5)预览pdf文件(pdfh5和vue-pdf)(很详细)
前端·vue.js·pdf
鸽鸽程序猿1 小时前
【前端】javaScript
开发语言·前端·javascript
秦时明月之君临天下2 小时前
React和Next.js的相关内容
前端·javascript·react.js
上官花雨2 小时前
什么是axios?怎么使用axios封装Ajax?
前端·ajax·okhttp
米奇妙妙wuu2 小时前
React中 setState 是同步的还是异步的?调和阶段 setState 干了什么?
前端·javascript·react.js