fix: CFG 异常边覆盖 try 体全部块,补全干涉图 keep 与 callee 边

This commit is contained in:
2026-10-05 22:00:50 +00:00
parent 3ceadcf8c9
commit 013c0eb3cf
9 changed files with 136 additions and 61 deletions
Generated
+18 -18
View File
@@ -1095,7 +1095,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_builtins" name = "oxide_builtins"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"chrono", "chrono",
"fast-float", "fast-float",
@@ -1120,7 +1120,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_bytecode" name = "oxide_bytecode"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxide_log", "oxide_log",
@@ -1128,7 +1128,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cfg" name = "oxide_cfg"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_emit", "oxide_emit",
@@ -1139,7 +1139,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cli" name = "oxide_cli"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"bumpalo", "bumpalo",
@@ -1159,7 +1159,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_code_cache" name = "oxide_code_cache"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"lru", "lru",
"oxide_bytecode", "oxide_bytecode",
@@ -1168,7 +1168,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_compiler" name = "oxide_compiler"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1187,7 +1187,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_dce" name = "oxide_dce"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1201,7 +1201,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_emit" name = "oxide_emit"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxc_allocator", "oxc_allocator",
@@ -1216,7 +1216,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_ir" name = "oxide_ir"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_log", "oxide_log",
@@ -1225,7 +1225,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_kernel" name = "oxide_kernel"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"dashmap", "dashmap",
@@ -1240,7 +1240,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_liveness" name = "oxide_liveness"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1252,7 +1252,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_log" name = "oxide_log"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"tracing", "tracing",
"tracing-appender", "tracing-appender",
@@ -1261,7 +1261,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_parser" name = "oxide_parser"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"oxc_allocator", "oxc_allocator",
"oxc_ast", "oxc_ast",
@@ -1276,7 +1276,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_regalloc" name = "oxide_regalloc"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1292,7 +1292,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_runtime_api" name = "oxide_runtime_api"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"num-traits", "num-traits",
@@ -1304,7 +1304,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_test262" name = "oxide_test262"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_compiler", "oxide_compiler",
@@ -1321,7 +1321,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_types" name = "oxide_types"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"hashbrown 0.14.5", "hashbrown 0.14.5",
@@ -1333,7 +1333,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_vm" name = "oxide_vm"
version = "0.8.13" version = "0.8.14"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"chrono", "chrono",
+1 -1
View File
@@ -22,7 +22,7 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "0.8.13" version = "0.8.14"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
rust-version = "1.80" rust-version = "1.80"
+102 -26
View File
@@ -1,7 +1,10 @@
//! Pass 3:异常边。 //! Pass 3:异常边。
//! //!
//! 块内扫 TRY_BEGIN / TRY_FINALLY_BEGIN(块内标记,非 terminator), //! TRY_BEGIN:匹配 TRY_BEGIN/TRY_END 对(栈匹配,处理嵌套),从 try 体
//! 从所在 BB 连 Exception 边到处理入口(仅起始 BB,不扩散)。 //! [p_begin, p_end) 内所有重叠块连 Exception 边到 catch 入口。try 体内任意点
//! 可抛异常,catch 须读到的活变量在整段 try 体保持存活,故异常边须覆盖整段。
//!
//! TRY_FINALLY_BEGIN:从所在 BB 连 Exception 边到 finally 入口(仅起始 BB)。
use oxide_bytecode::opcode::OpCode; use oxide_bytecode::opcode::OpCode;
use oxide_ir::operand::Operand; use oxide_ir::operand::Operand;
@@ -9,29 +12,62 @@ use oxide_ir::IRFunction;
use crate::{BasicBlock, EdgeKind}; use crate::{BasicBlock, EdgeKind};
/// 补异常边:从 TRY 标记所在 BB 出发,指向处理入口块。 /// 补异常边:TRY_BEGIN 从 try 体全部重叠块出发,TRY_FINALLY_BEGIN 从所在块出发。
pub(super) fn add_exception_edges(f: &IRFunction, blocks: &mut [BasicBlock]) { pub(super) fn add_exception_edges(f: &IRFunction, blocks: &mut [BasicBlock]) {
for i in 0..blocks.len() { // TRY_BEGIN/TRY_END 栈匹配(处理嵌套),收集 (p_begin, p_end, catch_label)。
let range = blocks[i].inst_range.clone(); let mut try_spans: Vec<(usize, usize, u32)> = Vec::new();
let mut stack: Vec<(usize, u32)> = Vec::new();
for (idx, inst) in f.insts.iter().enumerate() {
match inst.op {
OpCode::TRY_BEGIN => {
if let Operand::Label(l) = inst.b {
stack.push((idx, l));
}
}
OpCode::TRY_END => {
if let Some((p_begin, catch_label)) = stack.pop() {
try_spans.push((p_begin, idx, catch_label));
}
}
_ => {}
}
}
// 每个 try 体:从 [p_begin, p_end) 内所有重叠块连 Exception 边到 catch 入口。
for (p_begin, p_end, catch_label) in try_spans {
if let Some(p) = f.label_pos.get(catch_label as usize).and_then(|p| *p) {
let target = crate::split::block_id_of(p, blocks);
for block in blocks.iter_mut() {
if block.inst_range.start < p_end
&& block.inst_range.end > p_begin
&& !block.succs.contains(&(target, EdgeKind::Exception))
{
block.succs.push((target, EdgeKind::Exception));
}
}
}
}
// TRY_FINALLY_BEGIN:从所在块连 Exception 边到 finally 入口(仅起始块)。
// 先收集 (block_index, target) 对,再统一加边(避免 iter_mut 与 block_id_of 借用冲突)。
let mut finally_edges: Vec<(usize, usize)> = Vec::new();
for (i, block) in blocks.iter().enumerate() {
let range = block.inst_range.clone();
for inst_idx in range.start..range.end { for inst_idx in range.start..range.end {
let inst = &f.insts[inst_idx]; if f.insts[inst_idx].op != OpCode::TRY_FINALLY_BEGIN {
if !matches!(inst.op, OpCode::TRY_BEGIN | OpCode::TRY_FINALLY_BEGIN) {
continue; continue;
} }
if let Operand::Label(l) = inst.b { if let Operand::Label(l) = f.insts[inst_idx].b {
match f.label_pos.get(l as usize).and_then(|p| *p) { match f.label_pos.get(l as usize).and_then(|p| *p) {
Some(p) => { Some(p) => finally_edges.push((i, crate::split::block_id_of(p, blocks))),
let target = crate::split::block_id_of(p, blocks);
// push 前去重:块内多个 TRY 标记可指向同一目标,只保留一条边。
if !blocks[i].succs.contains(&(target, EdgeKind::Exception)) {
blocks[i].succs.push((target, EdgeKind::Exception));
}
}
None => debug_assert!(false, "unresolved label {l}"), None => debug_assert!(false, "unresolved label {l}"),
} }
} }
} }
} }
for (i, target) in finally_edges {
if !blocks[i].succs.contains(&(target, EdgeKind::Exception)) {
blocks[i].succs.push((target, EdgeKind::Exception));
}
}
} }
#[cfg(test)] #[cfg(test)]
@@ -40,32 +76,34 @@ mod tests {
use crate::BasicBlock; use crate::BasicBlock;
use oxide_ir::inst::Inst; use oxide_ir::inst::Inst;
/// TRY_BEGIN 所在 BB 出发 Exception 边 → catch 入口块(仅起始 BB)。 /// TRY_BEGIN 从 try 体全部重叠块出发 Exception 边 → catch 入口块。
#[test] #[test]
fn try_begin_emits_exception_edge_to_handler() { fn try_begin_emits_exception_edge_to_handler() {
let mut f = IRFunction::new(); let mut f = IRFunction::new();
f.insts.push(Inst::try_begin(0)); // 0: TRY_BEGIN → catch(label 0 → inst 2) f.insts.push(Inst::try_begin(0)); // 0: TRY_BEGIN → catch(label 0 → inst 3)
f.insts f.insts
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 1 .push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 1
f.insts f.insts
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 2: catch 入口 .push(Inst::new(OpCode::TRY_END, Operand::None, Operand::None, Operand::None)); // 2
f.label_pos = vec![Some(2)]; f.insts
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 3: catch 入口
f.label_pos = vec![Some(3)];
f.label_count = 1; f.label_count = 1;
let mut blocks = vec![ let mut blocks = vec![
BasicBlock { BasicBlock {
inst_range: 0..2, inst_range: 0..3,
preds: Vec::new(), preds: Vec::new(),
succs: Vec::new(), succs: Vec::new(),
}, },
BasicBlock { BasicBlock {
inst_range: 2..3, inst_range: 3..4,
preds: Vec::new(), preds: Vec::new(),
succs: Vec::new(), succs: Vec::new(),
}, },
]; ];
add_exception_edges(&f, &mut blocks); add_exception_edges(&f, &mut blocks);
assert_eq!(blocks[0].succs, vec![(1, EdgeKind::Exception)], "TRY_BEGIN 所在 BB 出 Exception 边"); assert_eq!(blocks[0].succs, vec![(1, EdgeKind::Exception)], "try 体块出 Exception 边到 catch 入口");
assert!(blocks[1].succs.is_empty(), "catch 入口块无出边"); assert!(blocks[1].succs.is_empty(), "catch 入口块无出边");
} }
@@ -76,18 +114,20 @@ mod tests {
f.insts.push(Inst::try_begin(0)); // 0: TRY_BEGIN → L0 f.insts.push(Inst::try_begin(0)); // 0: TRY_BEGIN → L0
f.insts.push(Inst::try_finally_begin(0)); // 1: TRY_FINALLY_BEGIN → 同一 L0 f.insts.push(Inst::try_finally_begin(0)); // 1: TRY_FINALLY_BEGIN → 同一 L0
f.insts f.insts
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 2: L0 目标 .push(Inst::new(OpCode::TRY_END, Operand::None, Operand::None, Operand::None)); // 2
f.label_pos = vec![Some(2)]; f.insts
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 3: L0 目标
f.label_pos = vec![Some(3)];
f.label_count = 1; f.label_count = 1;
let mut blocks = vec![ let mut blocks = vec![
BasicBlock { BasicBlock {
inst_range: 0..2, inst_range: 0..3,
preds: Vec::new(), preds: Vec::new(),
succs: Vec::new(), succs: Vec::new(),
}, },
BasicBlock { BasicBlock {
inst_range: 2..3, inst_range: 3..4,
preds: Vec::new(), preds: Vec::new(),
succs: Vec::new(), succs: Vec::new(),
}, },
@@ -99,4 +139,40 @@ mod tests {
"两个 TRY 标记指向同一目标只保留一条 Exception 边" "两个 TRY 标记指向同一目标只保留一条 Exception 边"
); );
} }
/// try 体跨多块时,每块都出 Exception 边到 catch 入口(非仅 TRY_BEGIN 所在块)。
#[test]
fn exception_edges_from_all_try_body_blocks() {
let mut f = IRFunction::new();
f.insts.push(Inst::try_begin(0)); // 0: TRY_BEGIN → catch(label 0 → inst 6)
f.insts.push(Inst::jmp_if_false(1, 3)); // 1: 条件分支
f.insts.push(Inst::call(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 0)); // 2: CALL(then)
f.insts
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 3: false 分支
f.insts
.push(Inst::new(OpCode::TRY_END, Operand::None, Operand::None, Operand::None)); // 4
f.insts
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 5: 汇合
f.insts
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 6: catch 入口
f.label_pos = vec![Some(6), None, None, Some(3)];
f.label_count = 4;
let cfg = crate::build_cfg(&f);
// 块:[0..2) TRY_BEGIN+JMP_IF_FALSE, [2..3) CALL, [3..6) false+TRY_END+NOP,
// [6..7) catch, [0..0) exit
let catch_block = cfg.blocks.iter().position(|b| b.inst_range == (6..7)).unwrap();
// CALL 块(then 分支)须有 Exception 边到 catch 入口
let call_block = cfg.blocks.iter().position(|b| b.inst_range == (2..3)).unwrap();
assert!(
cfg.blocks[call_block].succs.contains(&(catch_block, EdgeKind::Exception)),
"CALL 块(try 体深处)应有 Exception 边到 catch 入口"
);
// false 分支块也须有 Exception 边到 catch 入口
let false_block = cfg.blocks.iter().position(|b| b.inst_range == (3..6)).unwrap();
assert!(
cfg.blocks[false_block].succs.contains(&(catch_block, EdgeKind::Exception)),
"false 分支块(try 体深处)应有 Exception 边到 catch 入口"
);
}
} }
+4 -4
View File
@@ -79,7 +79,7 @@ fn if_else_conditional_jump_splits_block_with_dual_edges() {
assert_eq!(succs_total(&cfg), preds_total(&cfg)); assert_eq!(succs_total(&cfg), preds_total(&cfg));
} }
/// try/catch:TRY_BEGIN 是块内标记不切块,所在 BB 出 Exception 边到 catch 入口。 /// try/catch:TRY_BEGIN 是块内标记不切块,try 体块出 Exception 边到 catch 入口。
#[test] #[test]
fn try_begin_does_not_split_block_and_emits_exception_edge() { fn try_begin_does_not_split_block_and_emits_exception_edge() {
let mut f = IRFunction::new(); let mut f = IRFunction::new();
@@ -87,7 +87,7 @@ fn try_begin_does_not_split_block_and_emits_exception_edge() {
f.insts f.insts
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 1 .push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 1
f.insts f.insts
.push(Inst::new(OpCode::RETURN, Operand::None, Operand::None, Operand::None)); // 2 .push(Inst::new(OpCode::TRY_END, Operand::None, Operand::None, Operand::None)); // 2
f.insts f.insts
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 3: catch 入口 .push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 3: catch 入口
f.insts f.insts
@@ -98,10 +98,10 @@ fn try_begin_does_not_split_block_and_emits_exception_edge() {
let cfg = build_cfg(&f); let cfg = build_cfg(&f);
assert_eq!(cfg.blocks.len(), 3); // 2 实块 + exit 哨兵(TRY_BEGIN 不切块) assert_eq!(cfg.blocks.len(), 3); // 2 实块 + exit 哨兵(TRY_BEGIN 不切块)
assert_eq!(cfg.blocks[0].inst_range, 0..3); // try 体未被切块 assert_eq!(cfg.blocks[0].inst_range, 0..3); // try 体未被切块
// Exception 边从 TRY_BEGIN 所在 BB 出发指向 catch 入口块。 // Exception 边从 try 体块出发指向 catch 入口块。
assert!(cfg.blocks[0].succs.contains(&(1, EdgeKind::Exception))); assert!(cfg.blocks[0].succs.contains(&(1, EdgeKind::Exception)));
assert_eq!(cfg.blocks[1].succs, vec![(2, EdgeKind::Fallthrough)]); assert_eq!(cfg.blocks[1].succs, vec![(2, EdgeKind::Fallthrough)]);
assert_eq!(cfg.blocks[2].preds, vec![0, 1]); assert_eq!(cfg.blocks[2].preds, vec![1]);
assert_eq!(succs_total(&cfg), preds_total(&cfg)); assert_eq!(succs_total(&cfg), preds_total(&cfg));
} }
+1 -1
View File
@@ -76,7 +76,7 @@ mod tests {
f.insts.push(Inst::try_begin(0)); // 0: TRY_BEGIN → catch 入口(label 0 → inst 3) f.insts.push(Inst::try_begin(0)); // 0: TRY_BEGIN → catch 入口(label 0 → inst 3)
f.insts.push(Inst::load_const(Operand::Reg(5), 1)); // 1 f.insts.push(Inst::load_const(Operand::Reg(5), 1)); // 1
f.insts f.insts
.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 2 .push(Inst::new(OpCode::TRY_END, Operand::None, Operand::None, Operand::None)); // 2
f.insts.push(Inst::load_const(Operand::Reg(6), 2)); // 3: catch 入口 f.insts.push(Inst::load_const(Operand::Reg(6), 2)); // 3: catch 入口
f.insts f.insts
.push(Inst::new(OpCode::RETURN, Operand::Reg(6), Operand::None, Operand::None)); // 4 .push(Inst::new(OpCode::RETURN, Operand::Reg(6), Operand::None, Operand::None)); // 4
+2 -2
View File
@@ -236,7 +236,7 @@ mod tests {
fn try_catch_reg0_not_polluting_entry() { fn try_catch_reg0_not_polluting_entry() {
// 0: try_begin(L_catch) // 0: try_begin(L_catch)
// 1: ADD r3=r3+r2 // 1: ADD r3=r3+r2
// 2: RETURN Reg(3) // 2: TRY_END
// 3: STORE_VAR(Reg(5), None, None) catch 入口:a=None→0 读 reg 0 // 3: STORE_VAR(Reg(5), None, None) catch 入口:a=None→0 读 reg 0
// 4: RETURN Reg(5) // 4: RETURN Reg(5)
let mut f = empty_function(); let mut f = empty_function();
@@ -244,7 +244,7 @@ mod tests {
f.insts f.insts
.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2))); .push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
f.insts f.insts
.push(Inst::new(OpCode::RETURN, Operand::Reg(3), Operand::None, Operand::None)); .push(Inst::new(OpCode::TRY_END, Operand::None, Operand::None, Operand::None));
f.insts f.insts
.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(5), Operand::None, Operand::None)); .push(Inst::new(OpCode::STORE_VAR, Operand::Reg(5), Operand::None, Operand::None));
f.insts f.insts
+2 -2
View File
@@ -118,14 +118,14 @@ mod tests {
#[test] #[test]
fn catch_entry_reg0_not_live_before_block() { fn catch_entry_reg0_not_live_before_block() {
// 0: try_begin(3) 1: ADD r3=r3+r2 2: RETURN r3 // 0: try_begin(3) 1: ADD r3=r3+r2 2: TRY_END
// 3: STORE_VAR(r5, None, None) 4: RETURN r5 // 3: STORE_VAR(r5, None, None) 4: RETURN r5
let mut f = empty_function(); let mut f = empty_function();
f.insts.push(Inst::try_begin(3)); f.insts.push(Inst::try_begin(3));
f.insts f.insts
.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2))); .push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
f.insts f.insts
.push(Inst::new(OpCode::RETURN, Operand::Reg(3), Operand::None, Operand::None)); .push(Inst::new(OpCode::TRY_END, Operand::None, Operand::None, Operand::None));
f.insts f.insts
.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(5), Operand::None, Operand::None)); .push(Inst::new(OpCode::STORE_VAR, Operand::Reg(5), Operand::None, Operand::None));
f.insts f.insts
+5 -5
View File
@@ -5,8 +5,8 @@
//! (运行时回退到调用方 `active_reg_limit` 全量窗口)。`regs[254]/[255]` //! (运行时回退到调用方 `active_reg_limit` 全量窗口)。`regs[254]/[255]`
//! (this/new.target)由帧单独保存不占窗口,计算时排除。生成器 / 异步函数体 //! (this/new.target)由帧单独保存不占窗口,计算时排除。生成器 / 异步函数体
//! 内部调用点不编码——挂起恢复按全量寄存器快照搬移,保持保守语义。含 TRY //! 内部调用点不编码——挂起恢复按全量寄存器快照搬移,保持保守语义。含 TRY
//! 指令的函数同样不编码——异常 handler 的存活集不经分支/循环内调用点传播, //! 指令的函数同样不编码——保守回退全量窗口(异常 handler 存活集经 try 体全部
//! 截断窗口会丢仅 handler 存活的槽(见 `encode_call_window` 内 has_try 说明)。 //! 块传播,但 keep 全量窗口避免截断边界风险,见 `encode_call_window` 内 has_try)。
use std::borrow::Cow; use std::borrow::Cow;
@@ -25,9 +25,9 @@ pub fn encode_call_window(f: &mut IRFunction, live: &LiveInfo) {
if f.insts.is_empty() && f.nested.is_empty() { if f.insts.is_empty() && f.nested.is_empty() {
return; return;
} }
// 含 try/catch/finally 的函数跳过编码:异常边只从 TRY 标记所在 BB 发出, // 含 try/catch/finally 的函数跳过编码:保守回退全量窗口。异常边现从 try 体
// 分支/循环 BB 内调用点的 liveness 不含仅 catch/finally 存活的寄存器, // 全部块发出,handler 存活集已传播到 try 体内调用点,但 keep 全量窗口避免
// 截断窗口会丢槽(unwind 恢复后 handler 读到 callee 残留)。整体回退全量窗口。 // 截断边界风险(unwind 恢复后 handler 读到 callee 残留)。
let has_try = f let has_try = f
.insts .insts
.iter() .iter()
+1 -2
View File
@@ -92,8 +92,7 @@ fn call_window_stale_live_reruns() {
#[test] #[test]
fn call_window_skips_function_with_try() { fn call_window_skips_function_with_try() {
// 含 TRY_BEGIN 的函数整体跳过编码(全量窗口):异常边只从 TRY 所在 BB 出发, // 含 TRY_BEGIN 的函数整体跳过编码(全量窗口):保守回退,避免截断边界风险。
// 分支/循环内调用点的 liveness 不含仅 handler 存活的寄存器,截断窗口会丢槽。
let mut f = IRFunction::new(); let mut f = IRFunction::new();
f.insts.push(Inst::try_begin(0)); // 0: TRY_BEGIN → L0 f.insts.push(Inst::try_begin(0)); // 0: TRY_BEGIN → L0
f.insts.push(Inst::call(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 1)); f.insts.push(Inst::call(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 1));