# 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 访问者化重构。
相关推荐
倒头就睡的小比特2 天前
算法竞赛C++常用的STL
c++·算法
weilx12342 天前
C++笔记-文件IO-<fcntl.h>
c++
Smileyqp沛沛2 天前
前端?C++ ?较大差异基础罗列
c++·基础·前端转c++
C语言小火车3 天前
C/C++ 为什么需要编译器?
开发语言·c++
旖旎夜光3 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
吞下星星的少年·-·3 天前
C++ 萌新语法入门篇
c++·算法比赛
霍霍的袁3 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
another heaven3 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
程序猿编码3 天前
告别改源码适配模型:纯 C++ 可配置 LLM 推理引擎,全格式全结构兼容
c++·大模型·llm·推理引擎
此生决int3 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++