mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: CFG 异常边覆盖 try 体全部块,补全干涉图 keep 与 callee 边
This commit is contained in:
Generated
+18
-18
@@ -1095,7 +1095,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1120,7 +1120,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1128,7 +1128,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1139,7 +1139,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1159,7 +1159,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1168,7 +1168,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1187,7 +1187,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1201,7 +1201,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1216,7 +1216,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1225,7 +1225,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1240,7 +1240,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1252,7 +1252,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1261,7 +1261,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1276,7 +1276,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1292,7 +1292,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1304,7 +1304,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"hashbrown 0.14.5",
|
||||
@@ -1333,7 +1333,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.8.13"
|
||||
version = "0.8.14"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
//! Pass 3:异常边。
|
||||
//!
|
||||
//! 块内扫 TRY_BEGIN / TRY_FINALLY_BEGIN(块内标记,非 terminator),
|
||||
//! 从所在 BB 连 Exception 边到处理入口(仅起始 BB,不扩散)。
|
||||
//! TRY_BEGIN:匹配 TRY_BEGIN/TRY_END 对(栈匹配,处理嵌套),从 try 体
|
||||
//! [p_begin, p_end) 内所有重叠块连 Exception 边到 catch 入口。try 体内任意点
|
||||
//! 可抛异常,catch 须读到的活变量在整段 try 体保持存活,故异常边须覆盖整段。
|
||||
//!
|
||||
//! TRY_FINALLY_BEGIN:从所在 BB 连 Exception 边到 finally 入口(仅起始 BB)。
|
||||
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::operand::Operand;
|
||||
@@ -9,29 +12,62 @@ use oxide_ir::IRFunction;
|
||||
|
||||
use crate::{BasicBlock, EdgeKind};
|
||||
|
||||
/// 补异常边:从 TRY 标记所在 BB 出发,指向处理入口块。
|
||||
/// 补异常边:TRY_BEGIN 从 try 体全部重叠块出发,TRY_FINALLY_BEGIN 从所在块出发。
|
||||
pub(super) fn add_exception_edges(f: &IRFunction, blocks: &mut [BasicBlock]) {
|
||||
for i in 0..blocks.len() {
|
||||
let range = blocks[i].inst_range.clone();
|
||||
// TRY_BEGIN/TRY_END 栈匹配(处理嵌套),收集 (p_begin, p_end, catch_label)。
|
||||
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 {
|
||||
let inst = &f.insts[inst_idx];
|
||||
if !matches!(inst.op, OpCode::TRY_BEGIN | OpCode::TRY_FINALLY_BEGIN) {
|
||||
if f.insts[inst_idx].op != OpCode::TRY_FINALLY_BEGIN {
|
||||
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) {
|
||||
Some(p) => {
|
||||
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));
|
||||
}
|
||||
}
|
||||
Some(p) => finally_edges.push((i, crate::split::block_id_of(p, blocks))),
|
||||
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)]
|
||||
@@ -40,32 +76,34 @@ mod tests {
|
||||
use crate::BasicBlock;
|
||||
use oxide_ir::inst::Inst;
|
||||
|
||||
/// TRY_BEGIN 所在 BB 出发 Exception 边 → catch 入口块(仅起始 BB)。
|
||||
/// TRY_BEGIN 从 try 体全部重叠块出发 Exception 边 → catch 入口块。
|
||||
#[test]
|
||||
fn try_begin_emits_exception_edge_to_handler() {
|
||||
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
|
||||
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 1
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 2: catch 入口
|
||||
f.label_pos = vec![Some(2)];
|
||||
.push(Inst::new(OpCode::TRY_END, Operand::None, Operand::None, Operand::None)); // 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;
|
||||
|
||||
let mut blocks = vec![
|
||||
BasicBlock {
|
||||
inst_range: 0..2,
|
||||
inst_range: 0..3,
|
||||
preds: Vec::new(),
|
||||
succs: Vec::new(),
|
||||
},
|
||||
BasicBlock {
|
||||
inst_range: 2..3,
|
||||
inst_range: 3..4,
|
||||
preds: Vec::new(),
|
||||
succs: Vec::new(),
|
||||
},
|
||||
];
|
||||
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 入口块无出边");
|
||||
}
|
||||
|
||||
@@ -76,18 +114,20 @@ mod tests {
|
||||
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::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 2: L0 目标
|
||||
f.label_pos = vec![Some(2)];
|
||||
.push(Inst::new(OpCode::TRY_END, Operand::None, Operand::None, Operand::None)); // 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;
|
||||
|
||||
let mut blocks = vec![
|
||||
BasicBlock {
|
||||
inst_range: 0..2,
|
||||
inst_range: 0..3,
|
||||
preds: Vec::new(),
|
||||
succs: Vec::new(),
|
||||
},
|
||||
BasicBlock {
|
||||
inst_range: 2..3,
|
||||
inst_range: 3..4,
|
||||
preds: Vec::new(),
|
||||
succs: Vec::new(),
|
||||
},
|
||||
@@ -99,4 +139,40 @@ mod tests {
|
||||
"两个 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 入口"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ fn if_else_conditional_jump_splits_block_with_dual_edges() {
|
||||
assert_eq!(succs_total(&cfg), preds_total(&cfg));
|
||||
}
|
||||
|
||||
/// try/catch:TRY_BEGIN 是块内标记不切块,所在 BB 出 Exception 边到 catch 入口。
|
||||
/// try/catch:TRY_BEGIN 是块内标记不切块,try 体块出 Exception 边到 catch 入口。
|
||||
#[test]
|
||||
fn try_begin_does_not_split_block_and_emits_exception_edge() {
|
||||
let mut f = IRFunction::new();
|
||||
@@ -87,7 +87,7 @@ fn try_begin_does_not_split_block_and_emits_exception_edge() {
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 1
|
||||
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
|
||||
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None)); // 3: catch 入口
|
||||
f.insts
|
||||
@@ -98,10 +98,10 @@ fn try_begin_does_not_split_block_and_emits_exception_edge() {
|
||||
let cfg = build_cfg(&f);
|
||||
assert_eq!(cfg.blocks.len(), 3); // 2 实块 + exit 哨兵(TRY_BEGIN 不切块)
|
||||
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_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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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::load_const(Operand::Reg(5), 1)); // 1
|
||||
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::new(OpCode::RETURN, Operand::Reg(6), Operand::None, Operand::None)); // 4
|
||||
|
||||
@@ -236,7 +236,7 @@ mod tests {
|
||||
fn try_catch_reg0_not_polluting_entry() {
|
||||
// 0: try_begin(L_catch)
|
||||
// 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
|
||||
// 4: RETURN Reg(5)
|
||||
let mut f = empty_function();
|
||||
@@ -244,7 +244,7 @@ mod tests {
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
|
||||
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
|
||||
.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.insts
|
||||
|
||||
@@ -118,14 +118,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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
|
||||
let mut f = empty_function();
|
||||
f.insts.push(Inst::try_begin(3));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
|
||||
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
|
||||
.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.insts
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
//! (运行时回退到调用方 `active_reg_limit` 全量窗口)。`regs[254]/[255]`
|
||||
//! (this/new.target)由帧单独保存不占窗口,计算时排除。生成器 / 异步函数体
|
||||
//! 内部调用点不编码——挂起恢复按全量寄存器快照搬移,保持保守语义。含 TRY
|
||||
//! 指令的函数同样不编码——异常 handler 的存活集不经分支/循环内调用点传播,
|
||||
//! 截断窗口会丢仅 handler 存活的槽(见 `encode_call_window` 内 has_try 说明)。
|
||||
//! 指令的函数同样不编码——保守回退全量窗口(异常 handler 存活集经 try 体全部
|
||||
//! 块传播,但 keep 全量窗口避免截断边界风险,见 `encode_call_window` 内 has_try)。
|
||||
|
||||
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() {
|
||||
return;
|
||||
}
|
||||
// 含 try/catch/finally 的函数跳过编码:异常边只从 TRY 标记所在 BB 发出,
|
||||
// 分支/循环 BB 内调用点的 liveness 不含仅 catch/finally 存活的寄存器,
|
||||
// 截断窗口会丢槽(unwind 恢复后 handler 读到 callee 残留)。整体回退全量窗口。
|
||||
// 含 try/catch/finally 的函数跳过编码:保守回退全量窗口。异常边现从 try 体
|
||||
// 全部块发出,handler 存活集已传播到 try 体内调用点,但 keep 全量窗口避免
|
||||
// 截断边界风险(unwind 恢复后 handler 读到 callee 残留)。
|
||||
let has_try = f
|
||||
.insts
|
||||
.iter()
|
||||
|
||||
@@ -92,8 +92,7 @@ fn call_window_stale_live_reruns() {
|
||||
|
||||
#[test]
|
||||
fn call_window_skips_function_with_try() {
|
||||
// 含 TRY_BEGIN 的函数整体跳过编码(全量窗口):异常边只从 TRY 所在 BB 出发,
|
||||
// 分支/循环内调用点的 liveness 不含仅 handler 存活的寄存器,截断窗口会丢槽。
|
||||
// 含 TRY_BEGIN 的函数整体跳过编码(全量窗口):保守回退,避免截断边界风险。
|
||||
let mut f = IRFunction::new();
|
||||
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));
|
||||
|
||||
Reference in New Issue
Block a user