docs/current/01-定位与路线/架构设计.md
GitHub ↗
当前有效

Vitro 设计文档(后端引擎)

4962 字·约 13 分钟 阅读 2026-10-10 17:07

最后核对:2026-10-05(S9 工序④删区对齐——头部现状横幅改写为退役态、架构图切换单轨新版;前一沿革 2026-10-04 S8 收官 + 0.8.0 发版件对齐)

定位:教学 C 子集参考执行引擎(白箱;迁移 v1 = C only,C++ 已裁砍随 oracle 退役)。类比 quickjs 之于 JS——小、白箱、可嵌入、行为与标准对照诚实。 范围:本仓库只做后端(MIT 许可),提供核心引擎与出口(wasm-gc 单出口多宿主 + serve/vitro CLI);前端由社区基于出口协议实现。 定位转型的完整决策依据见 后端定位与白箱计划.md。

⚠️ 现状(2026-10-05,S9 工序④删区):本文主体描述的是迁移前 Rust 实现(native/)的架构——该实现已物理删除(档案 = tag rust-oracle-freeze + git 历史)。现役唯一实现是 MoonBit(vitro/engine,包切分与逐片进度见 MoonBit迁移总计划.md,操作手册见 moonbit/AGENTS.md)。本文的语义章节(内存模型 / 时间旅行帧语义 / 协议 / 诊断七元组)仍作 MoonBit 侧同语义实现的参照有效;文中一切 native/src/*.rs、crates/* 实现锚均为历史锚(对应删区前终态),MoonBit 侧对应物见各章内 MoonBit 注记与 S8时间旅行与教学智能总览。全文按 MoonBit 目标架构重写已列入待办。


目录


1. 设计目标

Vitro 为教学场景提供一台白箱的 C/C++ 子集执行引擎:

  • 行为可对照:以 Clang / Clang++ 为唯一 Golden 来源,任何差异如实记录(*_FAILURES.md),不粉饰;
  • 执行可观察:指令级单步、变量快照、内存与指针状态、算法步骤语义,全部通过协议暴露;
  • 过程可回放:统一模式(时间旅行)支持回退到任意历史步并正向重放;
  • 错误可教学:中文诊断 + 错误码 + 修复建议 + 知识卡片 + 根因推断;
  • 安全可保证:1MB 线性内存内的指令级边界检查与教学安全检测(越界 / UAF / Double-Free / 无效 free / 递归深度 / 步数熔断);
  • 可嵌入:C ABI / wasm32 / JSON-lines 三个出口,任意语言可消费。

明确不做:不是通用 C 编译器、不是生产级工具链、不是 Clang 替代品;不追求完整 C17/C++20 语义。


2. 三出口一核心架构

                        ┌──────────────────────────────────────────┐
                        │  vitro 引擎核心(Rust workspace)          │
                        │  编译器管线 + VitroVM + 统一模式 + 诊断     │
                        │  ── 禁止平台 API 耦合 ──                  │
                        └───────────────┬──────────────────────────┘
                                        │  native/src/session_api.rs
                                        │  (会话语义中立层:三出口共用同一套入口语义)
        ┌───────────────────────────────┼───────────────────────────────┐
        │                               │                               │
┌───────▼────────┐            ┌─────────▼─────────┐          ┌──────────▼──────────┐
│ 出口 1          │            │ 出口 2             │          │ 出口 3               │
│ C ABI (capi)    │            │ wasm32            │          │ vitro_cli serve       │
│ cdylib/staticlib│            │ .wasm + JS 绑定    │          │ JSON-lines (NDJSON)  │
│ vitro_abi_version│            │ 浏览器 / 在线教学   │          │ headless 脚本化消费   │
└─────────────────┘            └───────────────────┘          └──────────────────────┘
  消费者:vitro_cli                消费者:社区 Web 前端            消费者:IDE 后端 /
  scripts/shadow_verify.go(已退役)(capi 直调)     移动浏览器"看"场景                判分服务 / 自动化
  第三方 IDE(P/Invoke 等)

架构图(由 go run ./scripts/gen_svg 生成):2026-10-05 删区后为单轨格局(MoonBit 现役引擎 + Go 防线层 + Clang 真值源;下节 Rust 历史架构已随删区退役):

vitro 架构总览:MoonBit 现役单轨 × Go 防线层 × Clang 真值源

架构纪律(写进 AGENTS.md 编码约定):

  1. 新能力一律先落语言中立的 Rust 层,三个出口只做薄包装;
  2. 复杂结构(StepPayload、内存区域、事件流)过边界统一走 JSON 字符串——性能换稳定性与版本容忍度;
  3. capi 是公共 API,承诺即契约:vitro_abi_version() 版本化(当前 2.1.0),加函数 = minor,改签名/语义 = major;
  4. 状态码约定:0 = 成功 / 负数 = 入参错误 / 正数 = 领域状态(1 = trap,2 = 等待输入);Session 指针句柄非线程安全;输入输出为 UTF-8。

MoonBit 目标架构对齐:迁移完成后的出口形态收敛为 wasm-gc 单出口多宿主(浏览器主交付 / Node 22+ CI 主力 / Wasmtime 显式开 -W gc;宿主接口 4 函数 + 21 方法表,总计划 F-5)——capi 45 导出中 28 无消费者(亲证),capi 后续批次已裁不做。wasm-gc 单出口已于 2026-09-29 落地(S7 批五号:gateway library + gateway/wasm foreign_library 薄壳 + Node 宿主 host.js;零功能性 imports)。冻结期内本文第 2 节三出口仍为现役形态,两侧架构纪律同源(MoonBit 侧等价物:依赖严格单向无环 + .mbti 三面收敛,见总计划 §4)。


3. 编译器管线

源代码字符串(可多文件)
    │
    ▼
Lexer::tokenize()            vitro_lexer         → Vec<Token>
    │
    ▼
Parser::parse()              vitro_parser        → AST(Box<Program>)
    │
    ▼
TypeChecker                  vitro_typeck        → 类型标注 + 教学诊断(E3xxx / W3xxx)
    │
    ▼
BytecodeGen                  vitro_codegen       → Vec<Instruction>(VitroVM 扁平字节码)
    │
    ▼
SourceMap + 字符串数据段 + 符号表(含 decl_line、变量归属函数)

设计要点:

  • AST 用 Rust enum 而非多态类层次(Expr / Stmt + Box<Expr>),类型系统为完全递归的 vitro_ast::Type;
  • 零进度保护:Parser 在位置未推进时强制 advance(),杜绝死循环(历史事故见 docs/archive/INCIDENT_2026_04_27_PARSER_INFINITE_LOOP.md);
  • 错误处理不 panic:诊断收集进 Vec<Error> 后统一返回,跨出口边界处 catch_unwind 兜底;
  • 多文件:vitro_compile_unit 逐文件编译,vitro_compile_all 链接;file_ranges 维护"全局行号 ↔ 文件内行号"映射(多文件语义标签与诊断定位依赖它)。

子集规范(行为契约,修改实现必须同步):

MoonBit 侧对应管线(逐片重建中,包切分见总计划 §4):vitro/engine/{source, opcode}(L0)→ diag(L1)→ ast(L2)→ lexer + parser(L4,含独立预处理 pass)→ names + typeck + libc(L5)→ codegen + bytecode(L6)→ memory + host + vm(L7,✅ 2026-09-26 收官)→ protocol(L8,✅ 批一号+段二 2026-09-27)→ session(L8,✅ 批二号 2026-09-28)→ gateway + gateway/wasm(L8,✅ 批五号 2026-09-29——wasm-gc 单出口落地)+ time_travel + teaching + steps + diagnostics(L8,✅ S8 四域 2026-10-04 收官——时间旅行/教学智能/诊断,见S8 总览)+ cmd/serve(✅ 批三号 2026-09-28,native stdio 壳)+ cmd/vitro 总入口(✅ 2026-10-04 CLI 出口总账 #37:run/compile/step/api 四子命令);0.8.0 = S8 收官版已发布(2026-10-05,tag vitro-engine-0.8.0,线上验收三件全绿)。已收官片与 Rust oracle 的对拍口径:lexer 6002 TSV 逐字节一致、parser 601 语料 AST+诊断逐字节一致、codegen A 级 598/598(含 code 段逐指令)、执行链 cmd/run + vm_diff/clang_direct 双防线全绿(DIFF 0)、teaching 311/311 标注 golden 逐条一致。


4. VitroVM 执行模型

VitroVM 是栈式虚拟机,核心循环逐条解释执行 Instruction,每条指令携带 SourceLoc 供错误映射。

// 示意(实际定义见 crates/vitro_runtime 与 crates/vitro_vm)
struct Instruction {
    op: OpCode,        // 常量/局部变量/内存/算术/比较/跳转/调用/单步事件……
    operand: i32,
    loc: SourceLoc,    // 源码位置
}

为什么自研 VM 而不是复用现成解释器(历史决策,Phase 2 起):项目初期用 wasm3 作为执行引擎,Phase 3 深入后确认它在教学场景存在结构性瓶颈——

能力 通用 WASM 解释器 VitroVM
单步调试 无法暂停/恢复,只能阻塞宿主函数 每条指令后可检查暂停标志,同步单步
运行时中文诊断 只能翻译英文 trap 字符串 在除零/越界现场直接读取变量值与声明行
内存可视化 读原始字节,不知道变量名 自带符号表,知道某地址是 arr[2]
零侵入可视化 需注入 host call VM 层直接发射教学事件
执行步数限制 需 patch 运行时 原生支持(会话级保险丝)
安全隔离 依赖宿主内存模型 自带边界检查,同等安全

核心优势:局部变量也存放在线性内存中,因此 &x、scanf("%d", &x)、指针/数组/结构体语义与真实 C 一致;单步在主线程同步执行(零线程,无线程泄漏风险)。


5. 内存模型

VitroVM 使用 1MB 线性内存,按用途分段(NULL 陷阱区 / 字符串字面量 + 全局区 / 堆 / 栈),具体布局常量与运行时不变量由 vitro_runtime 统一定义。

关键设计:局部变量在内存中

// Call 指令:在线性内存中分配栈帧(向下增长),参数从表达式栈搬入
// LoadLocal / StoreLocal:按 frame.locals_base + index * 4 读写内存

好处:&x 是真实地址;scanf 可直接写入;数组/指针语义与真实 C 一致。

堆:2026-09-11 决议改为 bump 分配 + 有界隔离(quarantine),把 churn 与 leak 分离,配合"三道墙"(1MB 堆墙 / 步数保险丝 / region 表封顶,决议 §6 口径)保证教学场景下的内存行为有界且可解释——见 堆有界隔离决议.md。

教学安全检测(运行时,指令级):

检测 说明
E3070 栈缓冲区溢出 越界写入/读取的栈数组访问
E3060 / E3061 Use-After-Free / Double-Free(freed_logs 指令层检查)
无效 free 三场景 非堆指针 / 已释放 / 未对齐等
E3072 头文件循环包含
NULL 陷阱区 解引用 NULL 立即 trap 并给出中文诊断
步数 / 调用深度熔断 会话级保险丝,可控地撞上限并给出教学 trap

6. 统一模式 / 时间旅行

学生点"运行"后,引擎自动逐条推进并收集每一步状态;消费者可随时暂停、单步、拖到任意历史步。

后端组成:

组件 位置 职责
VM 全量快照 vitro_vm::snapshot 1MB 内存 + 运行时状态 + 内存管理状态
检查点管理器 vitro_vm::snapshot::CheckpointManager 按固定间隔保存快照(按语义标签决定密度)
统一执行引擎 native/src/unified/engine.rs 批量自动执行 run_batch + seek_to + Trap 自动回退
每步收集器 native/src/unified/collector.rs 变量快照、调用栈、可视化事件、语义标签、热力图
帧缓存 / 流 native/src/unified/{stream,types}.rs 窗口 2000 帧、差分编码 StepPayloadDelta
根因推断 native/src/unified/{root_cause,trace_analyzer}.rs 轨迹切片 + Trap 根因提示
算法步骤标注 crates/vitro_algorithm_steps/ 预定义算法步骤模板 → 教学描述

语义契约(消费者必须遵守,schema 见 STEP_PAYLOAD_SCHEMA_V0_1.md):

  • 回退到第 N 步时,文件状态、变量历史、输出窗口必须一致;
  • 越窗 seek = 检查点恢复 + 正向重放;
  • 输出按 OutputKind(Stdout / Stderr / Note)分通道,消费方不得对文本做正则清洗。

设计细节与消费方契约见 统一模式设计.md; 为什么这套体验本身是竞争力见 VM教学体验优势.md。


7. 诊断与修复系统

7.1 三级信息架构

级别 内容 载体
L1 感知 表情 + 一句话 + 修复按钮 诊断条目(含位置与 error code)
L2 理解 通俗解释 + 代码片段 + 对比 诊断 detail + 结构化修复建议
L3 原理 概念详解 + 内存动画描述 + 练习 知识卡片(JSON,由前端渲染)

7.2 运行时诊断优势(利用符号表读取真实值)

错误 静态分析只能说 Vitro 运行时能说
数组越界 "索引可能越界" "当 i=10 时越界了,数组大小是 5"
空指针 "p 可能未初始化" "p 的值是 0x00000000,声明于第 3 行,之后无赋值"
无限循环 "循环条件可能恒真" "已执行 100000 步,i 始终是 1(你可能注释掉了 i++)"

7.3 结构化自动修复

诊断在语言中立层(native/src/diagnostics/)生成结构化修复数据(fixKind + 精确替换区间 + 替换文本),三个出口原样透出,不各自实现修复逻辑:

级别 类型 示例 自动?
L1 语法 缺 ; } ) ]、` →
L2 语义 <=→<、补初始化 精确替换 ✅ 全自动
L3 逻辑 = vs ==、死代码 预览确认 需确认
L4 教学 递归边界、排序逻辑 仅建议 否

前端切割时(2026-09-11)自动修复应用器本体从 FRB 出口层下沉到 native/src/diagnostics/auto_fix.rs,三出口共用 (见 CHANGELOG.md [Unreleased] Removed 段)。

7.4 认知推理

能力 位置
轨迹切片 + Trap 根因推断(RootCauseHint) native/src/unified/trace_analyzer/
认知误区模式(MisconceptionPattern)+ 学习路径推荐 native/src/diagnostics/
知识图谱(概念节点 + 关系边) native/src/diagnostics/
代码意图推断(CFG + 数据流 + IntentInference) native/src/compiler/{cfg,data_flow,intent}

路线与设计见 认知推理系统设计.md、算法与数据结构教学设计.md。


8. 算法与数据结构支持

8.1 零侵入可视化

学生写纯 C,编译器/VM 自动识别算法并发射教学事件——不需要 vis_array() 之类的额外代码。

for (int i = 0; i < n - 1; i++)
    for (int j = 0; j < n - i - 1; j++)
        if (arr[j] > arr[j + 1]) { int t = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = t; }

引擎侧产出:算法识别结果(置信度)、每步语义标签、vis_events(compare / swap / update)、数组快照、指针快照、热力图。 这些字段通过 StepPayload 协议暴露,渲染完全交给消费方。

设计见 ARCHIVE_零侵入可视化设计.md。

8.2 数据结构支持

当前子集(数组 / 指针 / struct / union / malloc;C++ 模板类容器随砍 C++ 裁定冻结于 oracle,MoonBit 侧零迁移)已可表达并可观察:

结构 表达方式
数组 / 动态数组 int[] / malloc
单链表 / 双链表 struct Node { int val; Node* next; }
栈 / 队列 数组 + 索引,或链表
二叉树 struct TreeNode { int val; TreeNode *left, *right; }
C++ 容器(已裁砍 2026-09-20) vitro_vec<T> / vitro_list<T> 等内置容器(仅 Rust 冻结区现役;MoonBit 侧由 C# 批 BCL 数据驱动承接,见 CSharp前端引入计划)

模板源与教材算法清单见 模板维护指南.md、ARCHIVE_数据结构模板路线图.md。


9. 协议层与出口 API

协议先行:StepPayload schema v0.1 是公共承诺(STEP_PAYLOAD_SCHEMA_V0_1.md),字段只增不改语义,废弃走双写过渡期。协议与引擎内部表示解耦,引擎侧优化(CoW、脏页恢复等)可独立推进。

出口 形态 主要入口
C ABI native/include/vitro_capi.h vitro_abi_version / vitro_compile_json / vitro_run_json / vitro_get_program_output* / vitro_step_next_json / vitro_get_step_payloads_json / vitro_set_breakpoints / vitro_free_string 等
wasm32 .wasm;TS 类型生成链 @vitro/protocol 已接线(2026-09-22) 与 capi 同一套 C ABI 符号;MoonBit 侧 wasm-gc 单出口已落地(S7 批五号 2026-09-29:gateway.invoke 单口 21 方法表 + Node 宿主 host.js)
serve JSON-lines(NDJSON) compile / run / output.delta / step.begin / step.next / seek / payload.get / breakpoints.set / memory.regions / config.* / session.* + dump 族(ast/typeck/symbols/diagnostics_probe);MoonBit 侧 cmd/serve 已落同构方法族(S7 批三号起,serve_smoke 双宿主对拍锁定;step 族 S8 已接 2026-10-01,dump 族 S8 已接 2026-10-01~02)

capi 分批落地进度与签名评审依据见 CAPI评审回复与实现状态.md(已归档——后续批次经 U2 拍板裁不做); serve 方法与协议契约见 CLI使用手册.md §6。

输出通道(E-P1-5):引擎把程序 stdout / stderr 与引擎附注分别打标,绝不再混流后由消费方正则清洗 (历史教训:十余处清洗规则语义不一致,且程序自己打印同类文本时误删真实输出)。


10. 仓库结构

见 README.md(项目结构)与 AGENTS.md(关键目录)——MoonBit 迁移期与 moonbit/ workspace 并行保持同步。 文档索引见 docs/README.md。


11. 关键设计决策

决策点 选择 理由
执行引擎 自研 VitroVM(替代 wasm3) 教学专用:完全可控的单步/诊断/内存可视化;局部变量入线性内存以支持 &x
编译目标 自定义扁平字节码(替代 WASM) 只实现教学子集需要的指令;简化编译器与 VM 耦合
出口形态 三出口共用一套语义层 防"typeck 与 codegen 双轨语义"的漂移覆辙
边界数据 JSON 字符串 稳定、可版本化、任意语言可消费;ctypes 生产验证已证明够用
对外契约 协议先行(schema v0.1) 协议是公共承诺;与引擎内部表示解耦后各自演进
可视化 零侵入自动识别 初学者写纯 C,系统自动给出教学事件
诊断风格 运行时值注入 + 三级信息 L1 感知 / L2 理解 / L3 原理
算法修复 诊断 + 引导,不代写代码 保护学习过程
内存安全 1MB 线性内存 + 指令级检查 + 有界堆隔离 教学场景需要"可控地失败并解释"
许可证 MIT 对教育产品集成最友好(无 copyleft 顾虑)
前端 切割给社区(2026-09-11) 前端 30 条审查发现几乎全是架构级;移动端取舍持续拖累桌面端
原生移动端 放弃 软键盘/IME/触控目标是自研编辑器在移动端的固有硬伤;"看"由 wasm + 浏览器覆盖
引擎语言 MoonBit 绞杀者迁移(2026-09-18 定稿,同仓双区) LLM 效率 / VM 吞吐 / Wasmtime / 快照往返四道证伪门实测全过;Rust 版冻结为差分对照 oracle 逐包对拍,"每搬一包趁 Rust 版仍在做差分扫描"是唯一不重踩坑路径;C++ 随裁砍零迁移(2026-09-20),依据见 MoonBit迁移总计划.md §1

历史设计(wasm3 时代、Flutter 前端时代)保留在 ../archive/,仅供追溯。