# cilly-vm-cpp 重构复盘(第 1 阶段:SRP)

1. 目标与范围

这次重构只做一件事:围绕 SRP(单一职责原则) ,把 VM 里的"执行职责"和"统计职责"拆开。

重构范围如下:

  1. 栈组件从"带统计"改为"纯数据结构"。
  2. VM 通过观察者发布事件,不再内置统计接口。
  3. 同步修复测试与构建系统(Bazel 目标、依赖、测试名)。

2. 改造前的问题

改造前,VM 与 StackStats 的职责边界不清晰:

  1. StackStats 同时负责 栈存储 和 统计计数。
  2. VM 对外暴露了 PushCount/PopCount/Depth/MaxDepth 等统计接口。
  3. 统计逻辑和执行逻辑耦合,改一处会牵动核心路径。

问题本质是:功能可用,但长期维护和扩展成本会持续升高。


3. 本次改动清单

3.1 栈组件更名与瘦身

  1. 文件重命名:
    • src/stack_stats.h -> src/vm_stack.h
    • src/stack_stats.cc -> src/vm_stack.cc
    • tests/stack_stats_test.cc -> tests/vm_stack_test.cc
  2. 类型更名:
    • StackStats -> VmStack
  3. 功能调整:
    • 删除统计职责,仅保留 Push/Pop/Top/At/Clear/Empty 等栈行为。
    • 保留 values() 只读接口供 GC root 扫描使用。

3.2 观察者机制落地(栈统计)

新增 IVmObserver / VmStackObserver:

  1. IVmObserver 提供:
    • OnStackPush()
    • OnStackPop()
    • OnTestEmit(const Value&)
  2. VmStackObserver 专门负责统计:
    • push_count_
    • pop_count_
    • max_depth_

3.3 test hook 迁移到观察者

  1. VM 增加并打通测试事件路径:
    • TestEmit(const Value&)
    • NotifyTestEmit(const Value&)
  2. __test_emit(x) builtin 仍保持脚本语义不变,但内部统一走 VM 事件广播。
  3. 新增 VmHookObserver(基于 OnTestEmit),用于测试侧采集 emit 值。
  4. 测试代码从旧接口迁移为 observer 方式:
    • 旧:vm.SetTestEmitSink(...)
    • 新:VmHookObserver hook; vm.AddObserver(&hook);

3.4 VM 迁移

  1. VM 内部栈类型切换为 VmStack。
  2. VM 增加 AddObserver(IVmObserver*)。
  3. VM::Push/Pop 中增加事件通知:
    • Push 后广播 OnStackPush
    • Pop 后广播 OnStackPop

3.5 Bazel 构建修复

本次重构中,构建系统发生了两类问题并已修复:

  1. 测试目标名未同步
    • stack_stats_test 已改为 vm_stack_test 并更新到 test_suite(all)。
  2. frontend 子包依赖冲突
    • 移除 //src/frontend:frontend 残留依赖。
    • //src:cilly_core 统一收口源码。
    • 修复 src/BUILD.bazel 与 tests/BUILD.bazel 的依赖关系。

4. 验证结果

执行命令:

bash 复制代码
bazelisk test //tests:"all" --test_output=errors

结果:38/38 测试全部通过 。

说明这次 SRP 重构没有破坏现有行为。


5. 改造收益

  1. 职责更清晰
    VmStack 只管数据,统计逻辑归 VmStackObserver,VM 只负责执行与事件广播。

  2. 扩展更简单

    后续加 profiler/debugger,只需新增 observer,不必反复改 VM 核心执行路径。

  3. 构建更稳定

    Bazel 依赖图更干净,减少跨包引用造成的隐式构建错误。


6. 阶段结论

第 1 阶段(SRP)目标达成:

"将统计职责从核心执行路径剥离"已经完成,且测试全绿。

下一阶段可以按计划推进:

  1. DIP:GC 接口抽象化。
  2. OCP:Generator/AST 访问者化重构。
相关推荐
choumin8 小时前
C++中万能引用与std::forward的作用和用法
c++·万能引用·std forward
下一站春风里9 小时前
位运算完整学习笔记:按位与(&)+ 异或(^)
开发语言·c++·算法
努力努力再努力wz11 小时前
【C++高阶系列】C++20 协程底层原理:函数为什么能暂停?从状态机到 Task,彻底串起挂起、恢复与协程调度
开发语言·c++·c++20·1024程序员节
划破黑暗的第一缕曙光12 小时前
[C++]:4.模板
c++·template·模板·函数模版·类模版
十五年专注C++开发12 小时前
pybind11:一个跨C++和Python平台的编程库
开发语言·c++·python·pybind11
CodeYp201912 小时前
第11讲:stack 和 queue
开发语言·c++·queue·stack
沫璃染墨12 小时前
《Qt从零入门系列(十五):Qt线程安全与锁机制详解——从QMutex到RAII与读写锁实战》
开发语言·c++·qt·安全·交互·线程·qt6.3
hetao173383712 小时前
2026-10-25 hetao1733837 的刷题记录
c++·算法
fqbqrr13 小时前
2610C++,UI复合技术在窗口中绘画字体图标
c++·ui
见叶之秋13 小时前
【C++】红与黑的边界:红黑树从插入到自检
数据结构·c++·算法·面试