章节目录

验收:120 个程序走同一条流水线

本节阅读量:

第十一章继承第十章 92 个示例,并新增 28 个 coroutine 专项示例:

1
2
3
cd code/11_coroutines
make
find examples -name '*.lang' | wc -l

应看到 120。新增部分由 19 个正常示例、7 个静态 validation 错误和 2 个动态错误组成。全目录中有 112 个程序能够完成 compile 并分别生成 Linux/macOS 汇编;另外 8 个必须在 compile 阶段被拒绝:继承的 set_undefined_error.lang,以及本章 7 个 yield validation 错误。

19 个正常示例

示例 主要检查 结果
coroutine_lazy.lang 创建不执行 body 42
coroutine_no_yield.lang 首次 resume 完成 42
coroutine_one_yield.lang 一次暂停 42
coroutine_protocol.lang paused/done record 42
coroutine_begin.lang 多次 yield 42
coroutine_if.lang condition/branch yield 42
coroutine_if_unselected.lang 未选分支不执行 42
coroutine_capture.lang 外层捕获 42
coroutine_state.lang cell 跨暂停共享 42
coroutine_yield_order.lang yield 副作用顺序 42
coroutine_resume_operand_order.lang resume operand 顺序 42
coroutine_yield_record.lang yield 堆对象 42
coroutine_done_repeat.lang 同一完成 record 42
coroutine_done_no_restart.lang body 不重跑 42
coroutine_interleaved.lang 交错推进 42
coroutine_nested.lang 嵌套边界 42
coroutine_name_hygiene.lang 内部名字卫生 42
coroutine_gc_capture_record.lang 捕获 record 与完成态跨 GC 42
coroutine_gc_saved_next.lang next closure 跨 GC 42

可运行全部正常专项:

1
2
3
4
5
6
for f in examples/coroutine_*.lang; do
  case "$f" in
    *coroutine_reentry_error.lang) continue ;;
  esac
  ./mini run "$f" || exit 1
done

每行应打印 42。

检查 surface/core 边界

1
2
3
./mini ast examples/coroutine_protocol.lang
./mini core examples/coroutine_protocol.lang
./mini ir examples/coroutine_protocol.lang

验收点:

  • ast 保留 Coroutine、Yield、Resume;
  • core 不再出现三个 surface 节点;
  • core 出现用户无法写出的 $coro.*;
  • ir 只含第十章已有 op;
  • ir 能看到 state cell、store、continuation closure、普通 call 和协议 record。
1
./mini run examples/coroutine_name_hygiene.lang

源码故意使用 coroutine、resume、yield、state、next 和 done 作为普通变量名,仍应输出 42。

协议和顺序回归

1
2
3
4
5
./mini run examples/coroutine_protocol.lang
./mini run examples/coroutine_yield_order.lang
./mini run examples/coroutine_resume_operand_order.lang
./mini run examples/coroutine_if_unselected.lang
./mini run examples/coroutine_done_repeat.lang

都应输出 42。它们分别防止协议 tag 错误、yield value 顺序错误、resume operand 顺序错误、提前执行未选分支,以及每次完成都重新分配 record。coroutine_done_repeat.lang 连续 resume 四次并逐次检查身份,还能防止 dispatcher 清空 state 后丢失 done closure。

七个静态错误

1
2
3
4
5
6
7
./mini run examples/yield_outside_error.lang
./mini run examples/yield_add_error.lang
./mini run examples/yield_record_error.lang
./mini run examples/yield_call_error.lang
./mini run examples/yield_lambda_error.lang
./mini run examples/yield_letrec_error.lang
./mini run examples/yield_nested_error.lang

每项打印 error: 并返回 1。换成 core、ir、alloc 或 compile 也必须由同一个 validation pass 拒绝;ast 只展示语法树,是唯一例外。

两个动态错误

1
2
3
4
./mini run examples/resume_integer_error.lang
echo $?
./mini run examples/coroutine_reentry_error.lang
echo $?

两项都包含:

1
2
error: function call expected a function
1

它们能生成汇编,链接本章的 gc_runtime.o 后进入已有语言错误出口。Linux、WSL 或 Intel Mac:

1
2
3
4
./mini compile examples/resume_integer_error.lang -o out.s
c++ out.s gc_runtime.o -o out
./out
echo $?

Apple Silicon Mac:

1
2
3
4
./mini compile examples/resume_integer_error.lang -o out.s --target macos
c++ -arch x86_64 out.s gc_runtime.o -o out
./out
echo $?

状态均为 70;coroutine_reentry_error.lang 同样验收。

GC 与分配验收

1
2
3
./mini run examples/coroutine_gc_capture_record.lang
./mini run examples/coroutine_gc_saved_next.lang
./mini alloc examples/coroutine_gc_saved_next.lang

前两项输出 42。alloc 应显示 dispatcher、state、continuation 和 captured cell 都是 root,并拥有 %r15 相对槽;恢复后 (+ value 2) 的确定整数结果仍可进入寄存器。

两个示例累计分配超过一个半区。若 continuation 或 captured record 没有进入 root,搬移后恢复会读取旧地址。coroutine_gc_capture_record.lang 还会在完成后再次制造 GC 压力,再连续恢复两次并比较 record 身份;这会同时检查自引用 done closure 与 completed record 已被 collector 正确更新。

两种目标与旧能力回归

1
2
./mini compile examples/coroutine_protocol.lang -o linux.s --target linux
./mini compile examples/coroutine_protocol.lang -o macos.s --target macos

两份都应是完整 AT&T x86-64 汇编,不含 fallback。最终 Value 若是 record,main 按既有规则返回 0,所以编译验收程序应像本例一样最终取出整数。

全量双目标检查只对 112 个可编译程序生成汇编。不要为了凑数量绕过另外 8 个静态错误;它们在 mini compile 返回状态 1,正是验收成功。两个动态错误属于这 112 个可编译程序,生成的可执行文件运行后状态为 70。

再抽查继承能力:

1
2
3
4
5
6
7
./mini run examples/add.lang
./mini run examples/recursive_sum.lang
./mini run examples/counter.lang
./mini run examples/nested_record.lang
./mini run examples/gc_stress.lang
./mini run examples/register_call_live.lang
./mini alloc examples/register_spill.lang

前六项依次为 42、42、2、42、42、42;最后一项仍出现 ordinary spill。正式发布回归应覆盖全部 92 个继承示例。

最终必须同时满足:surface 语义正确、core 无泄漏、静态边界统一、动态错误一致、GC 保存 continuation、统一后端不回退。只看到一个 yield 示例输出 42,还不足以说明本章完成。


11.7 语义边界:这不是通用协程系统

上一节

11.9 常见错误、练习与全书收束

下一节