约定

实例化模块或调用结果模块实例上的导出函数时,WebAssembly 代码会被执行

执行行为是根据一个模拟程序状态抽象机来定义的。它包括一个堆栈,用于记录操作数的值和控制结构,以及一个包含全局状态的抽象存储

对于每条指令,都有一个规则指定其执行对程序状态的影响。此外,还有一些规则描述了模块的实例化。与验证一样,所有规则都以两种等效的形式给出

  1. 散文形式,以直观的形式描述执行。

  2. 形式符号形式,以数学形式描述规则。 [1]

注意

与验证一样,散文和形式规则是等效的,因此不需要理解形式符号就可以阅读本规范。形式主义以在编程语言语义中广泛使用的符号提供了更简洁的描述,并且很容易进行数学证明。

散文符号

执行是通过对指令的每条抽象语法的风格化、逐步规则来指定的。在陈述这些规则时采用了以下约定。

  • 执行规则隐式地假定给定的存储 S

  • 执行规则还假设存在一个隐式堆栈,该堆栈通过推入弹出标签来修改。

  • 某些规则要求堆栈至少包含一个帧。最新的帧称为当前帧。

  • 存储和当前帧都通过替换它们的某些组件来进行变异。假定这种替换是全局应用的。

  • 指令的执行可能会陷阱,在这种情况下,整个计算会被中止,并且不会对其进行任何进一步的存储修改。(之后仍然可以启动其他计算。)

  • 指令的执行也可能以跳转到指定的目标而结束,该目标定义了要执行的下一条指令。

  • 执行可以进入退出形成指令序列

  • 指令序列隐式地按顺序执行,除非发生陷阱或跳转。

  • 在各种地方,规则包含表达程序状态的关键不变式的断言

形式符号

注意

本节简要说明了正式指定执行的符号。对于感兴趣的读者,可以在相应的教科书中找到更详细的介绍。 [2]

正式执行规则使用一种标准方法来指定操作语义,将其呈现为归约规则。每个规则都具有以下一般形式

配置是程序状态的句法描述。每个规则指定执行的一。只要最多只有一个归约规则适用于给定的配置,归约(以及由此产生的执行)就是确定性的。WebAssembly 只有很少的例外,在本规范中明确指出了这些例外。

对于 WebAssembly,配置通常是一个元组 (S;F;instr),它由当前存储 S、当前函数的调用帧 F 以及要执行的指令序列组成。(更精确的定义在后面给出。)

为了避免不必要的混乱,存储 S 和帧 F 从不触及它们的归约规则中省略。

没有堆栈的单独表示。相反,它可以方便地表示为配置的指令序列的一部分。特别是, 被定义为与 const 指令一致,并且const 指令的序列可以解释为向右增长的操作数“堆栈”。

注意

例如,i32.add 指令的归约规则 可以给出如下

(i32.const n1) (i32.const n2) i32.add(i32.const (n1+n2)mod232)

根据此规则,两个 const 指令和add 指令本身从指令流中删除,并替换为一个新的const 指令。这可以解释为从堆栈中弹出两个值并推入结果。

当没有产生结果时,指令归约为空序列

nopϵ

标签 类似地定义 为指令序列的一部分。

归约的顺序由适当评估上下文的定义决定。

当不再适用任何归约规则时,归约终止。 WebAssembly 的健全性类型系统保证只有当原始指令序列被归约为 const 指令的序列时,才会发生这种情况,该序列可以解释为结果操作数堆栈的,或者如果发生了陷阱

注意

例如,以下指令序列,

(f64.const x1) (f64.const x2) f64.neg (f64.const x3) f64.add f64.mul

在三个步骤后终止

(f64.const x1) (f64.const x2) f64.neg (f64.const x3) f64.add f64.mul(f64.const x1) (f64.const x4) (f64.const x3) f64.add f64.mul(f64.const x1) (f64.const x5) f64.mul(f64.const x6)

其中 x4=x2 并且 x5=x2+x3 并且 x6=x1(x2+x3)