docs: 补充注释与格式化

This commit is contained in:
2026-08-06 23:10:27 +08:00
parent e36a69976e
commit 31e28a03a6
156 changed files with 2393 additions and 1687 deletions
+49 -32
View File
@@ -1,11 +1,11 @@
//! Pass B:全函数 use 计数迭代删除到不动点(D-02 连锁语义)。
//! Pass B:全函数 use 计数迭代删除到不动点(连锁删上游写者)。
//!
//! 只对可达存活指令聚合 use 计数(逐条 `inst.use_regs()` 累加)→ 收集 `def_reg` 为
//! Some(r) 且 use_count[r]==0 且 `is_pure(f)` 的指令 → 删除并减去其 use_regs → 迭代。
//! CALL 隐式 def reg0 不参与死删(CALL 本身 is_pure=false 永不删,Pitfall 1),但 CALL
//! CALL 隐式 def reg0 不参与死删(CALL 本身 is_pure=false 永不删),但 CALL
//! 的 use 计数正常聚合——喂活上游写其参数的纯指令。
//! **label 目标指令强制保留**:块头是控制流汇合点,即使 def 无 use 也删除会使存活
//! JMP 的 label 引用悬空(lowering "Label not found")——保守保留(D-01 少删不错删)。
//! **label 目标指令强制保留**:块头是控制流汇合点,删除会使存活 JMP 的 label 引用
//! 悬空(lowering "Label not found")——保守保留,少删不错删。
use oxide_bytecode::opcode::OpCode;
use oxide_ir::operand::Operand;
@@ -41,11 +41,11 @@ pub(super) fn pass_b_dead_code(f: &IRFunction, keep: &mut [bool]) {
}
}
// nested 树引用的变量槽位图:闭包可跨函数读外层变量槽(LOAD_VAR.a 读槽 / STORE_VAR.rd 写槽
// 以寄存器号编码)。D-03 不递归删除 nested,但跨函数引用必须保活当前函数内写该槽的
// 以寄存器号编码)。不递归删除 nested,但跨函数引用必须保活当前函数内写该槽的
// STORE_VAR——否则死 `var k='x'` + 构造器内 `[k]` computed key 读槽被误删(回归锚)。
let mut escaped_slot = vec![false; max_reg as usize + 1];
collect_escaped_slots(&f.nested, &mut escaped_slot);
// 迭代删除至不动点:删一条纯指令 → 减其 use_regs → 上游写者可能连锁变死(D-02)
// 迭代删除至不动点:删一条纯指令 → 减其 use_regs → 上游写者可能连锁变死
loop {
let mut deleted = false;
for (i, k) in keep.iter_mut().enumerate() {
@@ -53,12 +53,12 @@ pub(super) fn pass_b_dead_code(f: &IRFunction, keep: &mut [bool]) {
continue;
}
let inst = &f.insts[i];
// CALL 系隐式 def reg0 是注册写入不参与死删收集;is_pure=false 已保证永不删(Pitfall 1)
// CALL 系隐式 def reg0 是注册写入不参与死删收集;is_pure=false 已保证永不删
if let Some(r) = inst.def_reg() {
// STORE_VAR 写变量槽可被 nested 闭包跨函数读取(computed class field key 等
// 场景:构造函数 submodule 内 LOAD_VAR a 槽引外层变量槽)。D-03 不递归 nested,
// 场景:构造函数 submodule 内 LOAD_VAR a 槽引外层变量槽)。DCE 不递归 nested,
// 顶层 use 计数看不到跨函数读——凡 nested 树引用的变量槽,其顶层写者保活
//(保守"少删不错删",D-01)。
//(保守"少删不错删")。
let slot_escapes = inst.op == OpCode::STORE_VAR
&& matches!(inst.rd, Operand::Reg(_))
&& escaped_slot.get(r as usize).copied().unwrap_or(false);
@@ -78,8 +78,9 @@ pub(super) fn pass_b_dead_code(f: &IRFunction, keep: &mut [bool]) {
}
/// 递归收集 nested 树中全部变量槽引用(LOAD_VAR.a 读槽、STORE_VAR.rd 写槽)。
///
/// 槽号 = 寄存器号编码的变量槽;其余操作数(局部寄存器/Imm/This)不构成跨函数引用。
/// precise_sweep 复用(B012 约束同一来源)。
/// precise_sweep 复用此函数,保证跨函数保活判定同一来源。
pub(crate) fn collect_escaped_slots(nested: &[IRFunction], out: &mut Vec<bool>) {
for sub in nested {
for inst in &sub.insts {
@@ -111,8 +112,10 @@ mod tests {
fn linear_dead_chain_deleted() {
let mut f = IRFunction::new();
f.insts.push(Inst::load_const(Operand::Reg(0), 0)); // 0: r0 = const
f.insts.push(Inst::new(OpCode::ADD, Operand::Reg(1), Operand::Reg(0), Operand::Reg(0))); // 1: r1 = r0 + r0
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(2), Operand::None, Operand::None)); // 2: return r2
f.insts
.push(Inst::new(OpCode::ADD, Operand::Reg(1), Operand::Reg(0), Operand::Reg(0))); // 1: r1 = r0 + r0
f.insts
.push(Inst::new(OpCode::RETURN, Operand::Reg(2), Operand::None, Operand::None)); // 2: return r2
let mut keep = vec![true; f.insts.len()];
pass_b_dead_code(&f, &mut keep);
@@ -127,24 +130,30 @@ mod tests {
f.insts.push(Inst::call(Operand::Reg(0), Operand::Reg(0), Operand::Reg(0), 0)); // 1: CALL
f.insts.push(Inst::load_const(Operand::Reg(1), 1)); // 2
f.insts.push(Inst::load_const(Operand::Reg(2), 2)); // 3
f.insts.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(1), Operand::Reg(2), Operand::Imm(1))); // 4
f.insts.push(Inst::new(OpCode::GET_PROP, Operand::Reg(3), Operand::Reg(1), Operand::Reg(2))); // 5
f.insts.push(Inst::new(OpCode::SET_PROP, Operand::Reg(3), Operand::Reg(1), Operand::Reg(2))); // 6
f.insts.push(Inst::new(OpCode::INC_POST, Operand::Reg(4), Operand::Reg(5), Operand::None)); // 7
f.insts
.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(1), Operand::Reg(2), Operand::Imm(1))); // 4
f.insts
.push(Inst::new(OpCode::GET_PROP, Operand::Reg(3), Operand::Reg(1), Operand::Reg(2))); // 5
f.insts
.push(Inst::new(OpCode::SET_PROP, Operand::Reg(3), Operand::Reg(1), Operand::Reg(2))); // 6
f.insts
.push(Inst::new(OpCode::INC_POST, Operand::Reg(4), Operand::Reg(5), Operand::None)); // 7
let mut keep = vec![true; f.insts.len()];
pass_b_dead_code(&f, &mut keep);
assert!(keep.iter().all(|k| *k), "有副作用指令一律保留");
}
/// STORE_VAR 一律保留(Pitfall 6):写变量槽可能被外部观察(脚本顶层/模块作用域变量、
/// STORE_VAR 一律保留:写变量槽可能被外部观察(脚本顶层/模块作用域变量、
/// nested 闭包跨函数读槽),即使本函数内无 use 也不删。
#[test]
fn store_var_never_deleted() {
let mut f = IRFunction::new();
f.insts.push(Inst::load_const(Operand::Reg(1), 1)); // 0
f.insts.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(0), Operand::Reg(1), Operand::None)); // 1
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 2
f.insts
.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(0), Operand::Reg(1), Operand::None)); // 1
f.insts
.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 2
let mut keep = vec![true; f.insts.len()];
pass_b_dead_code(&f, &mut keep);
@@ -152,12 +161,13 @@ mod tests {
assert!(keep[0] && keep[2], "源与 RETURN 保留");
}
/// 死闭包:CREATE_CLOSURE 结果未用 → 删除;nested 槽位不动(D-03 不递归不回收)。
/// 死闭包:CREATE_CLOSURE 结果未用 → 删除;nested 不递归不回收。
#[test]
fn dead_create_closure_deleted_nested_untouched() {
let mut f = IRFunction::new();
f.insts.push(Inst::create_closure(Operand::Reg(1), 0)); // 0: r1 = nested[0]
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 1
f.insts
.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 1
f.nested.push(IRFunction::new());
let mut keep = vec![true; f.insts.len()];
@@ -165,14 +175,16 @@ mod tests {
assert_eq!(keep, vec![false, true], "死 CREATE_CLOSURE 删,RETURN 保留");
}
/// 连锁迭代(D-02):写链 LOAD_CONST→ADD→LOAD_CONST 全死,逐轮删除至不动点。
/// 连锁迭代:写链 LOAD_CONST→ADD→LOAD_CONST 全死,逐轮删除至不动点。
#[test]
fn chained_dead_writes_deleted_iteratively() {
let mut f = IRFunction::new();
f.insts.push(Inst::load_const(Operand::Reg(0), 0)); // 0: r0(ADD 读,轮 2 删)
f.insts.push(Inst::new(OpCode::ADD, Operand::Reg(1), Operand::Reg(0), Operand::Reg(0))); // 1: r1(轮 1 删)
f.insts
.push(Inst::new(OpCode::ADD, Operand::Reg(1), Operand::Reg(0), Operand::Reg(0))); // 1: r1(轮 1 删)
f.insts.push(Inst::load_const(Operand::Reg(2), 2)); // 2: r2 无人读(轮 1 删)
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 3
f.insts
.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 3
let mut keep = vec![true; f.insts.len()];
pass_b_dead_code(&f, &mut keep);
@@ -181,14 +193,15 @@ mod tests {
/// label 目标指令强制保留(回归:do-while 形态)。`LOAD_CONST r0` 是 label 0 的目标,
/// 虽然 def 无 use 属死值,但删除会使存活 JMP_IF_TRUE 的 label 引用悬空
/// (lowering 报 "Label not found")——保守保留(D-01 少删不错删)。
/// (lowering 报 "Label not found")——保守保留,少删不错删。
#[test]
fn label_target_inst_never_deleted() {
let mut f = IRFunction::new();
f.insts.push(Inst::load_const(Operand::Reg(0), 1)); // 0: body 头,label 0 目标(死值)
f.insts.push(Inst::load_const(Operand::Reg(1), 1)); // 1: 条件 true
f.insts.push(Inst::jmp_if_true(1, 0)); // 2: 回跳 label 0
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 3
f.insts
.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 3
f.label_pos = vec![Some(0)];
f.label_count = 1;
let mut keep = vec![true; f.insts.len()];
@@ -199,18 +212,22 @@ mod tests {
/// STORE_VAR 跨函数逃逸(回归:computed class field key)。顶层写变量槽 Reg(1) 的
/// STORE_VAR 在本函数无 use,但 nested 构造器内 LOAD_VAR a=Reg(1) 跨函数读该槽——
/// DCE 只统计当前函数(D-03 不递归),nested 引用槽保活顶层写者。
/// DCE 只统计当前函数(不递归 nested),nested 引用槽保活顶层写者。
#[test]
fn store_var_slot_read_by_nested_kept() {
let mut f = IRFunction::new();
f.insts.push(Inst::load_const(Operand::Reg(2), 0)); // 0: 'x'
f.insts.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(1), Operand::Reg(2), Operand::Imm(0))); // 1: k = 'x'(槽 1)
f.insts
.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(1), Operand::Reg(2), Operand::Imm(0))); // 1: k = 'x'(槽 1)
f.insts.push(Inst::create_closure(Operand::Reg(4), 0)); // 2
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 3
// nested 构造器:LOAD_VAR a=Reg(1) 跨函数读外层变量槽 1(computed key)
f.insts
.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 3
// nested 构造器:LOAD_VAR a=Reg(1) 跨函数读外层变量槽 1(computed key)
let mut sub = IRFunction::new();
sub.insts.push(Inst::new(OpCode::LOAD_VAR, Operand::Reg(5), Operand::Reg(1), Operand::None));
sub.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(7), Operand::None, Operand::None));
sub.insts
.push(Inst::new(OpCode::LOAD_VAR, Operand::Reg(5), Operand::Reg(1), Operand::None));
sub.insts
.push(Inst::new(OpCode::RETURN, Operand::Reg(7), Operand::None, Operand::None));
f.nested.push(sub);
let mut keep = vec![true; f.insts.len()];