This repository has been archived on 2026-09-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
OxideJS/crates/oxide_regalloc/tests/nested_parent_slot_regress.rs
T
爱特每羊队 d8aa902ff0 fix(regalloc): nested 子模块引用父槽无预着色保护致读错物理槽(B014)
子模块 alloc 时引用父槽的 LOAD_VAR.a/STORE_VAR.rd 被当作自身 vreg 染色移走,
父侧 collect_escaped 只保护父不移动槽,子侧无对称保护。以 param_layout.base
(inherited_reg_start 分界)识别父槽引用并预着色恒等,spill 自由色排除。

新增 nested_parent_slot_regress 回归测试(field/method + 高压力变量),
workspace 全绿 + clippy 干净。
2026-08-06 20:34:55 +08:00

90 lines
3.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! B013 延伸回归:nested 子模块直接槽引用父槽,RegAlloc on/off 运行时等价。
//!
//! 父侧 collect_escaped 保证父不移动槽;但子模块自身 alloc 时引用父槽的
//! LOAD_VAR.a / STORE_VAR.rd 曾被当作子模块自己的 vreg 染色移走(→ 读错物理槽,
//! on={object} vs off=42)。修复:graph.rs/rewrite.rs 对称 collect_own_escaped。
//! 槽号 ≥ inherited_reg_start(param_layout.base)时触发,故用高压力变量推高槽号。
use oxide_vm::vm::Vm;
fn run_source(src: &str, regalloc: bool) -> (bool, String) {
let allocator = oxide_parser::Allocator::default();
let program = match oxide_parser::parse(&allocator, src) {
Ok(p) => p,
Err(e) => return (false, format!("parse error: {}", e[0].message)),
};
let mut ir = match oxide_emit::Emitter::new().emit_program(&program) {
Ok(i) => i,
Err(e) => return (false, format!("emit error: {e}")),
};
oxide_dce::dce(&mut ir);
if regalloc {
let cfg = oxide_cfg::build_cfg(&ir);
let live = oxide_liveness::liveness(&ir, &cfg);
oxide_dce::dce_precise(&mut ir, &live);
let cfg2 = oxide_cfg::build_cfg(&ir);
let live2 = oxide_liveness::liveness(&ir, &cfg2);
if let Err(e) = oxide_regalloc::alloc(&mut ir, &live2) {
return (false, format!("alloc error: {e}"));
}
}
let module = match oxide_ir::lower::lower(&ir) {
Ok(m) => m,
Err(e) => return (false, format!("lower error: {e}")),
};
let mut vm = Vm::new();
match vm.run(&module) {
Ok(v) => (true, v.to_string()),
Err(e) => (false, e),
}
}
fn pressure(n: usize) -> String {
let mut src = String::new();
for i in 0..n {
src.push_str(&format!("var v{i} = {i}; "));
}
src
}
#[test]
fn field_reads_outer_40_pressure() {
let src = format!("{}var a = 42; class C {{ p = a; }} new C().p;", pressure(40));
let off = run_source(&src, false);
let on = run_source(&src, true);
assert_eq!(on, off, "field 读外层 40 压力: off={off:?} on={on:?}");
}
#[test]
fn method_reads_outer_40_pressure() {
let src = format!("{}var a = 42; class C {{ m() {{ return a; }} }} new C().m();", pressure(40));
let off = run_source(&src, false);
let on = run_source(&src, true);
assert_eq!(on, off, "method 读外层 40 压力: off={off:?} on={on:?}");
}
#[test]
fn field_reads_outer_30_pressure() {
let src = format!("{}var a = 42; class C {{ p = a; }} new C().p;", pressure(30));
let off = run_source(&src, false);
let on = run_source(&src, true);
assert_eq!(on, off, "field 读外层 30 压力: off={off:?} on={on:?}");
}
#[test]
fn field_reads_outer_25_pressure() {
let src = format!("{}var a = 42; class C {{ p = a; }} new C().p;", pressure(25));
let off = run_source(&src, false);
let on = run_source(&src, true);
assert_eq!(on, off, "field 读外层 25 压力: off={off:?} on={on:?}");
}
#[test]
fn field_reads_outer_hi_last_40_pressure() {
let mut src = pressure(40);
src.push_str("var a_hi = 777; class C { p = a_hi; } new C().p;");
let off = run_source(&src, false);
let on = run_source(&src, true);
assert_eq!(on, off, "field 读外层末位 40 压力: off={off:?} on={on:?}");
}