WABT 上游提案测试目录 test/spec-new 解析:以 wide-arithmetic 测试集为例
【免费下载链接】wabtThe WebAssembly Binary Toolkit项目地址: https://gitcode.com/GitHub_Trending/wa/wabt
导读
test/spec-new/是 WABT(WebAssembly Binary Toolkit)仓库中一个专门承接「尚未纳入官方 testsuite 的上游提案测试」的目录。本篇文章以其中的 wide-arithmetic.wast 为核心案例,剖析该目录的存在意义、测试文件的结构与断言手法(包括 overlong 二进制编码与类型检查),并结合 opcode.def、lexer-keywords.txt 与 interp.cc 等源码,讲清 WABT 对i64.add128、i64.sub128、i64.mul_wide_s、i64.mul_wide_u四个 128 位宽算术操作码的词法、二进制解析与解释器支持现状。读完本文,你将掌握 WABT 提案测试的接入机制、测试文件写作范式以及如何定位源码中的对应实现。
test/spec-new 目录:上游提案测试的过渡缓冲区
test/spec-new/README.md 用寥寥数行说明了该目录的全部设计意图:
本目录包含来自上游提案的测试,这些测试要么尚未进入 testsuite 仓库,要么位于我们(WABT)尚未支持/导入的 testsuite 版本中。
这句话概括了目录的两种典型用途:
- 提案仍在演进中:对应的 WebAssembly 提案(proposal)测试已经写好,但官方 [testsuite] 仓库尚未合并;
- testsuite 版本滞后:测试已进入 testsuite,但当前 WABT 依赖的 testsuite 子模块版本还未包含它,无法直接通过常规路径导入。
README 明确给出了本目录唯一一个测试文件的出处:
wide-arithmetic.wast来自 WebAssembly/testsuite 仓库的proposals/wide-arithmetic目录。
并注明了一个重要的生命周期约定:一旦 WABT 导入了包含该测试的最新版 testsuite 仓库,本目录中的该文件即可删除。也就是说,test/spec-new是介于「上游提案诞生」与「正式并入官方测试集」之间的过渡缓冲区,避免 WABT 在等待 testsuite 更新的空窗期内丢失对这些提案的回归覆盖。
这种「先落地、后转正」的测试接入策略,保证了 WABT 的工具链(wat2wasm、wasm2wat、wast2json等)始终与正在演进中的 WebAssembly 提案保持同步验证,而不是被动等待官方测试集的一次性大更新。
wide-arithmetic.wast:128 位宽算术提案测试全解
wide-arithmetic.wast 共 470 行,是一个结构相当完整的提案测试文件,覆盖了功能正确性、二进制编码兼容性与类型检查三个维度。
模块定义:四个导出函数
测试文件开头定义一个 WAT 模块,导出了 4 个包装函数,分别对应 wide-arithmetic 提案的 4 个操作码:
(module (func (export "i64.add128") (param i64 i64 i64 i64) (result i64 i64) local.get 0 local.get 1 local.get 2 local.get 3 i64.add128) (func (export "i64.sub128") (param i64 i64 i64 i64) (result i64 i64) local.get 0 local.get 1 local.get 2 local.get 3 i64.sub128) (func (export "i64.mul_wide_s") (param i64 i64) (result i64 i64) local.get 0 local.get 1 i64.mul_wide_s) (func (export "i64.mul_wide_u") (param i64 i64) (result i64 i64) local.get 0 local.get 1 i64.mul_wide_u) )从中可以提炼出这 4 个操作码的类型签名:
| 操作码 | 参数 | 结果 | 语义 |
|---|---|---|---|
i64.add128 | 4 × i64(低 64 位、高 64 位各两个操作数) | 2 × i64(和 的低 64 位、高 64 位) | 128 位加法 |
i64.sub128 | 4 × i64 | 2 × i64 | 128 位减法 |
i64.mul_wide_s | 2 × i64 | 2 × i64 | 带符号 128 位宽乘法 |
i64.mul_wide_u | 2 × i64 | 2 × i64 | 无符号 128 位宽乘法 |
这些签名与 opcode.def 中的操作码定义一一对应:
WABT_OPCODE(I64, I64, I64, I64, I64, 0, 0xfc, 0x13, I64Add128, "i64.add128", "") WABT_OPCODE(I64, I64, I64, I64, I64, 0, 0xfc, 0x14, I64Sub128, "i64.sub128", "") WABT_OPCODE(I64, I64, I64, I64, ___, 0, 0xfc, 0x15, I64MulWideS, "i64.mul_wide_s", "") WABT_OPCODE(I64, I64, I64, I64, ___, 0, 0xfc, 0x16, I64MulWideU, "i64.mul_wide_u", "")可以看到:四个操作码都属于0xfc前缀段,子码依次为0x13–0x16;类型位中___表示「无」,与mul_wide_*只有 2 个参数的事实吻合。
功能断言:简单用例 + 随机生成用例
测试的主体部分是assert_return断言,分为两类:
简单用例覆盖了最容易出错的边界情况,例如 128 位加法的进位传播:
(assert_return (invoke "i64.add128" (i64.const 1) (i64.const 0) (i64.const -1) (i64.const 0)) (i64.const 0) (i64.const 1))这里低 64 位1 + (-1) = 0产生向高 64 位的进位,高 64 位0 + 0 + 进位 = 1,结果应为(0, 1)。类似地,减法用例覆盖借位传播:
(assert_return (invoke "i64.sub128" (i64.const 0) (i64.const 0) (i64.const 1) (i64.const 1)) (i64.const -1) (i64.const -2))mul_wide的简单用例则验证符号处理:i64.mul_wide_s (-1) × (-1) → (1, 0);而无符号版本中i64.mul_wide_u (-1) × 1 → (-1, 0),即0xFFFFFFFFFFFFFFFF × 1的低 64 位仍为全 1。
随机生成用例数量庞大且分布全面:文件随后给出了各 20 个随机生成的i64.add128、i64.sub128、i64.mul_wide_s、i64.mul_wide_u用例(共 80 个),覆盖大量跨符号、跨进位边界的随机 64 位操作数组合,例如:
(assert_return (invoke "i64.add128" (i64.const 1) (i64.const -5381447440966559717) (i64.const 1020031372481336745) (i64.const 1)) (i64.const 1020031372481336746) (i64.const -5381447440966559716))这类随机用例由提案作者离线生成、固化到测试文件中,用于对实现做统计意义上的正确性检验,比手工边界用例更能暴露进位/借位链路中的隐蔽缺陷。
overlong 二进制编码测试:对 LEB128 的宽松性验证
测试中段插入了一个完整的module binary模块,其用意非常明确:验证二进制读取器接受每个操作码的 overlong(过长)LEB128 编码。WABT 中这些操作码的二进制编码由前缀0xfc+ LEB128 编码的子码构成,例如i64.add128的标准编码为fc 13,而测试给出的是:
"\fc\93\80\00" ;; i64.add128 (overlong) "\fc\94\00" ;; i64.sub128 (overlong) "\fc\95\80\80\80\00" ;; i64.mul_wide_s (overlong) "\fc\96\80\80\00" ;; i64.mul_wide_u (overlong)LEB128 是允许「加长表示」的变长整数编码:0x93 0x80 0x00的低 7 位依次为0x13、0x00、0x00,解码结果仍是0x13,只是本可 1 字节完成的值被写成了 3 字节。这类 overlong 编码通常被规范视为可接受(canonical 之外)的形式,读取器应当宽容处理。这段测试因此专门验证 WABT 的 binary-reader.cc 在解析0xfc前缀段时能正确容忍并解码这些非规范编码——文件中的assert_return断言确认了这些模块不仅可被解析,其函数调用结果也完全符合预期。
assert_invalid:类型检查的负向测试
测试文件的最后一部分针对 4 个操作码各给出两组assert_invalid用例,验证验证器(validator)能够拒绝签名不匹配的模块。例如:
(assert_invalid (module (func (param i64 i64 i64 i64) (result i64) local.get 0 local.get 1 local.get 2 local.get 3 i64.add128) ) "type mismatch")以及参数个数不足(3 个参数而非 4 个)的用例。这确认了 WABT 的共享验证器对宽算术操作码实施了严格的栈类型与结果数量检查,错误消息统一为"type mismatch"。
源码视角:WABT 对这 4 个操作码的支持现状
词法层:关键字注册
src/lexer-keywords.txt 中为四个操作码注册了词法关键字及其运算元类别:
i64.add128, TokenType::Quaternary, Opcode::I64Add128 i64.mul_wide_s, TokenType::Binary, Opcode::I64MulWideS i64.mul_wide_u, TokenType::Binary, Opcode::I64MulWideUQuaternary(四元)对应 4 参数操作码,Binary(二元)对应 2 参数操作码,与提案签名完全对应。该文件经生成流程产出 src/prebuilt/lexer-keywords.cc,供wat2wasm、wast2json等工具在文本解析阶段识别这些助记符——这也是wide-arithmetic.wast能被正确解析的前提。
解释器层:尚未实现
在 src/interp/interp.cc 中,这 4 个操作码被显式标记为未实现:
case O::I64Add128: case O::I64Sub128: case O::I64MulWideS: case O::I64MulWideU: return TRAP("not implemented");从源码结构可以推断:WABT 的解释器(wasm-interp、spectest-interp)目前对这四个宽算术操作码一律返回"not implemented"陷阱,尚未给出真正的执行语义。这也从侧面解释了为什么这些测试仍停留在test/spec-new的「过渡区」——工具链的解析、验证链路已就绪,但运行时语义支持还在推进中。
如何运行这些测试
WABT 的测试由 test/run-tests.py 驱动,每个.wast测试文件通常伴随一个描述测试方式的.txt元数据文件。本目录的 wide-arithmetic.txt 内容如下:
;;; TOOL: wast2json ;;; STDIN_FILE: test/spec-new/wide-arithmetic.wast它声明了两个关键信息:
- TOOL: wast2json:本次测试使用
wast2json工具(src/tools/wast2json.cc)处理测试文件,负责将.wast中的模块、断言逐一转换,验证文本解析、二进制编码与验证器的正确性; - STDIN_FILE:测试文件通过标准输入喂给工具,这是 WABT 测试框架对「零长度文件」「stdin 输入」等场景的通用支持方式。
运行全部测试只需执行python3 test/run-tests.py;单独验证本目录时,可将其作为run-tests.py的过滤参数传入。测试通过的标准是:wast2json能无错误地完成解析与类型检查,且所有assert_return、assert_invalid断言得到预期结果。
小结
test/spec-new/是 WABT 与上游 WebAssembly 提案演进保持同步的窗口:它承接尚未进入官方 testsuite 的提案测试,并在 testsuite 更新后随时可被清空转正。以wide-arithmetic.wast为例可以看到,一份合格的提案测试需要同时覆盖功能正确性(简单边界 + 大规模随机用例)、二进制编码兼容性(overlong LEB128 的宽容解析)与类型安全(assert_invalid负向用例)。而在 WABT 源码侧,这四个 128 位宽算术操作码已具备完整的词法关键字、0xfc前缀段二进制定义与验证支持,唯独解释器运行时不支持——这正是它们仍停留在test/spec-new、尚未并入主线测试目录的直接原因。关注 test/spec-new 目录的增删变化,即可追踪 WABT 对 wide-arithmetic 等新提案的跟进进度。
【免费下载链接】wabtThe WebAssembly Binary Toolkit项目地址: https://gitcode.com/GitHub_Trending/wa/wabt
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考