mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
feat: 异常与 return 穿越释放资源,dispose_count 门控
This commit is contained in:
@@ -316,7 +316,7 @@ impl Emitter {
|
||||
module.insts.extend(field_ctx.insts);
|
||||
module.constants = field_ctx.constants;
|
||||
module.n_registers = field_ctx.max_regs.max(1);
|
||||
module.insts.push(Inst::ret(Operand::Reg(undef_reg), 0, 0));
|
||||
module.insts.push(Inst::ret(Operand::Reg(undef_reg), 0, 0, 0));
|
||||
}
|
||||
module
|
||||
};
|
||||
|
||||
@@ -50,7 +50,6 @@ pub(crate) struct LoopEntry {
|
||||
pub(crate) v_reg: u32,
|
||||
/// 循环打开时已打开的释放作用域数(break/continue/return 逃出时据此
|
||||
/// 计算需穿越释放的作用域层数)。
|
||||
#[allow(dead_code)]
|
||||
pub(crate) dispose_depth_at_open: usize,
|
||||
}
|
||||
|
||||
@@ -88,7 +87,6 @@ pub struct LabelScope {
|
||||
/// 标签打开时已打开的 for-in 循环数。
|
||||
pub(crate) for_in_depth_at_open: usize,
|
||||
/// 标签打开时已打开的释放作用域数(break 逃出时据此计算需穿越释放的层数)。
|
||||
#[allow(dead_code)]
|
||||
pub(crate) dispose_depth_at_open: usize,
|
||||
/// 标签目标出口结果寄存器:迭代标签取所包裹循环的 `v_reg`;非迭代标签仅当
|
||||
/// 体含指向本标签的 break 时分配(体正常完成回写、break 携值写入)。
|
||||
@@ -104,7 +102,6 @@ pub(crate) struct SwitchEntry {
|
||||
pub(crate) for_of_depth_at_open: usize,
|
||||
pub(crate) for_in_depth_at_open: usize,
|
||||
/// switch 打开时已打开的释放作用域数(switch 内 break 逃出时据此计算穿越层数)。
|
||||
#[allow(dead_code)]
|
||||
pub(crate) dispose_depth_at_open: usize,
|
||||
pub(crate) result_reg: u32,
|
||||
}
|
||||
|
||||
@@ -509,18 +509,18 @@ impl Emitter {
|
||||
}
|
||||
if is_expression_body {
|
||||
if let Some(reg) = last_result_reg {
|
||||
ctx.inst(Inst::ret(Operand::Reg(reg), 0, 0));
|
||||
ctx.inst(Inst::ret(Operand::Reg(reg), 0, 0, 0));
|
||||
} else {
|
||||
let undef_idx = ctx.add_constant(Constant::Undefined);
|
||||
let undef_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(undef_reg), undef_idx));
|
||||
ctx.inst(Inst::ret(Operand::Reg(undef_reg), 0, 0));
|
||||
ctx.inst(Inst::ret(Operand::Reg(undef_reg), 0, 0, 0));
|
||||
}
|
||||
} else {
|
||||
let undef_idx = ctx.add_constant(Constant::Undefined);
|
||||
let undef_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(undef_reg), undef_idx));
|
||||
ctx.inst(Inst::ret(Operand::Reg(undef_reg), 0, 0));
|
||||
ctx.inst(Inst::ret(Operand::Reg(undef_reg), 0, 0, 0));
|
||||
}
|
||||
|
||||
// 调用契约参数段只含固定形参:rest 是函数体内普通变量,不在 VM 实参传递区。
|
||||
|
||||
@@ -938,9 +938,9 @@ impl Emitter {
|
||||
let undef_idx = ctx.add_constant(Constant::Undefined);
|
||||
let r = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(r), undef_idx));
|
||||
ctx.inst(Inst::ret(Operand::Reg(r), 0, 0));
|
||||
ctx.inst(Inst::ret(Operand::Reg(r), 0, 0, 0));
|
||||
} else {
|
||||
ctx.inst(Inst::ret(Operand::Reg(ns_reg), 0, 0));
|
||||
ctx.inst(Inst::ret(Operand::Reg(ns_reg), 0, 0, 0));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1003,7 +1003,7 @@ impl Emitter {
|
||||
let kind_reg = self.load_string_const(kind, &mut ctx);
|
||||
let content_reg = self.load_string_const(content, &mut ctx);
|
||||
let val_reg = self.emit_module_call(&mut ctx, "__moduleData", &[kind_reg, content_reg])?;
|
||||
ctx.inst(Inst::ret(Operand::Reg(val_reg), 0, 0));
|
||||
ctx.inst(Inst::ret(Operand::Reg(val_reg), 0, 0, 0));
|
||||
Ok(ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None))
|
||||
}
|
||||
|
||||
|
||||
@@ -33,46 +33,51 @@ impl Emitter {
|
||||
pub(crate) fn emit_break_statement(
|
||||
&self, stmt: &oxide_parser::BreakStatement, ctx: &mut CompileCtx,
|
||||
) -> Result<Option<u32>, String> {
|
||||
let (break_label, fd_at_open, fod_at_open, fid_at_open, target_v_reg) = if let Some(label) = &stmt.label {
|
||||
let name = label.name.as_str();
|
||||
let scope = ctx
|
||||
.find_label(name)
|
||||
.ok_or_else(|| format!("SyntaxError: Undefined label '{name}'"))?;
|
||||
(
|
||||
scope.break_label,
|
||||
scope.finally_depth_at_open,
|
||||
scope.for_of_depth_at_open,
|
||||
scope.for_in_depth_at_open,
|
||||
scope.completion_reg,
|
||||
)
|
||||
} else if let Some(sw) = ctx.current_switch() {
|
||||
// switch 内 break:目标为 switch 出口。逃出计数以 switch 打开时的
|
||||
// 深度快照为基准——switch 之前已打开的循环不属于本次逃出,仅当
|
||||
// case 内新打开了迭代循环(并逃出)时才需关闭。
|
||||
(
|
||||
sw.break_label,
|
||||
sw.finally_depth_at_open,
|
||||
sw.for_of_depth_at_open,
|
||||
sw.for_in_depth_at_open,
|
||||
Some(sw.result_reg),
|
||||
)
|
||||
} else {
|
||||
let entry = ctx.current_loop().ok_or("break outside switch or loop".to_string())?;
|
||||
(
|
||||
entry.break_label,
|
||||
entry.finally_depth_at_open,
|
||||
entry.for_of_depth_at_open,
|
||||
entry.for_in_depth_at_open,
|
||||
Some(entry.v_reg),
|
||||
)
|
||||
};
|
||||
let (break_label, fd_at_open, fod_at_open, fid_at_open, dd_at_open, target_v_reg) =
|
||||
if let Some(label) = &stmt.label {
|
||||
let name = label.name.as_str();
|
||||
let scope = ctx
|
||||
.find_label(name)
|
||||
.ok_or_else(|| format!("SyntaxError: Undefined label '{name}'"))?;
|
||||
(
|
||||
scope.break_label,
|
||||
scope.finally_depth_at_open,
|
||||
scope.for_of_depth_at_open,
|
||||
scope.for_in_depth_at_open,
|
||||
scope.dispose_depth_at_open,
|
||||
scope.completion_reg,
|
||||
)
|
||||
} else if let Some(sw) = ctx.current_switch() {
|
||||
// switch 内 break:目标为 switch 出口。逃出计数以 switch 打开时的
|
||||
// 深度快照为基准——switch 之前已打开的循环不属于本次逃出,仅当
|
||||
// case 内新打开了迭代循环(并逃出)时才需关闭。
|
||||
(
|
||||
sw.break_label,
|
||||
sw.finally_depth_at_open,
|
||||
sw.for_of_depth_at_open,
|
||||
sw.for_in_depth_at_open,
|
||||
sw.dispose_depth_at_open,
|
||||
Some(sw.result_reg),
|
||||
)
|
||||
} else {
|
||||
let entry = ctx.current_loop().ok_or("break outside switch or loop".to_string())?;
|
||||
(
|
||||
entry.break_label,
|
||||
entry.finally_depth_at_open,
|
||||
entry.for_of_depth_at_open,
|
||||
entry.for_in_depth_at_open,
|
||||
entry.dispose_depth_at_open,
|
||||
Some(entry.v_reg),
|
||||
)
|
||||
};
|
||||
if let Some(target_v_reg) = target_v_reg {
|
||||
self.emit_completion_carry(ctx, target_v_reg);
|
||||
}
|
||||
let crossed = ctx.labels.finally_depth.saturating_sub(fd_at_open) as u16;
|
||||
let (for_of_count, for_in_count) = escape_iter_counts(ctx, fod_at_open, fid_at_open);
|
||||
if crossed > 0 || for_of_count > 0 || for_in_count > 0 {
|
||||
ctx.inst(Inst::brk(break_label, crossed, for_of_count, for_in_count));
|
||||
let dispose_count = ctx.labels.dispose_depth.saturating_sub(dd_at_open);
|
||||
if crossed > 0 || for_of_count > 0 || for_in_count > 0 || dispose_count > 0 {
|
||||
ctx.inst(Inst::brk(break_label, crossed, for_of_count, for_in_count, dispose_count));
|
||||
} else {
|
||||
ctx.inst(Inst::jmp(break_label));
|
||||
}
|
||||
@@ -82,37 +87,41 @@ impl Emitter {
|
||||
pub(crate) fn emit_continue_statement(
|
||||
&self, stmt: &oxide_parser::ContinueStatement, ctx: &mut CompileCtx,
|
||||
) -> Result<Option<u32>, String> {
|
||||
let (continue_label, fd_at_open, fod_at_open, fid_at_open, target_v_reg) = if let Some(label) = &stmt.label {
|
||||
let name = label.name.as_str();
|
||||
let scope = ctx
|
||||
.find_label(name)
|
||||
.ok_or_else(|| format!("SyntaxError: Undefined label '{name}'"))?;
|
||||
(
|
||||
scope.continue_label.ok_or_else(|| {
|
||||
format!("SyntaxError: Illegal continue statement: '{name}' does not denote an iteration statement")
|
||||
})?,
|
||||
scope.finally_depth_at_open,
|
||||
scope.for_of_depth_at_open,
|
||||
scope.for_in_depth_at_open,
|
||||
scope.completion_reg,
|
||||
)
|
||||
} else {
|
||||
let entry = ctx.current_loop().ok_or("continue outside loop".to_string())?;
|
||||
(
|
||||
entry.continue_label,
|
||||
entry.finally_depth_at_open,
|
||||
entry.for_of_depth_at_open,
|
||||
entry.for_in_depth_at_open,
|
||||
Some(entry.v_reg),
|
||||
)
|
||||
};
|
||||
let (continue_label, fd_at_open, fod_at_open, fid_at_open, dd_at_open, target_v_reg) =
|
||||
if let Some(label) = &stmt.label {
|
||||
let name = label.name.as_str();
|
||||
let scope = ctx
|
||||
.find_label(name)
|
||||
.ok_or_else(|| format!("SyntaxError: Undefined label '{name}'"))?;
|
||||
(
|
||||
scope.continue_label.ok_or_else(|| {
|
||||
format!("SyntaxError: Illegal continue statement: '{name}' does not denote an iteration statement")
|
||||
})?,
|
||||
scope.finally_depth_at_open,
|
||||
scope.for_of_depth_at_open,
|
||||
scope.for_in_depth_at_open,
|
||||
scope.dispose_depth_at_open,
|
||||
scope.completion_reg,
|
||||
)
|
||||
} else {
|
||||
let entry = ctx.current_loop().ok_or("continue outside loop".to_string())?;
|
||||
(
|
||||
entry.continue_label,
|
||||
entry.finally_depth_at_open,
|
||||
entry.for_of_depth_at_open,
|
||||
entry.for_in_depth_at_open,
|
||||
entry.dispose_depth_at_open,
|
||||
Some(entry.v_reg),
|
||||
)
|
||||
};
|
||||
if let Some(target_v_reg) = target_v_reg {
|
||||
self.emit_completion_carry(ctx, target_v_reg);
|
||||
}
|
||||
let crossed = ctx.labels.finally_depth.saturating_sub(fd_at_open) as u16;
|
||||
let (for_of_count, for_in_count) = escape_iter_counts(ctx, fod_at_open, fid_at_open);
|
||||
if crossed > 0 || for_of_count > 0 || for_in_count > 0 {
|
||||
ctx.inst(Inst::cont(continue_label, crossed, for_of_count, for_in_count));
|
||||
let dispose_count = ctx.labels.dispose_depth.saturating_sub(dd_at_open);
|
||||
if crossed > 0 || for_of_count > 0 || for_in_count > 0 || dispose_count > 0 {
|
||||
ctx.inst(Inst::cont(continue_label, crossed, for_of_count, for_in_count, dispose_count));
|
||||
} else {
|
||||
ctx.inst(Inst::jmp(continue_label));
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@ impl Emitter {
|
||||
let Statement::ReturnStatement(ret) = stmt else {
|
||||
return Ok(None);
|
||||
};
|
||||
// return 逃出全部打开的迭代循环:for-of 需 IteratorClose,for-in 弹出迭代器。
|
||||
// return 逃出全部打开的迭代循环与释放作用域:for-of 需 IteratorClose,
|
||||
// for-in 弹出迭代器,释放栈顶部资源需 DisposeResources。
|
||||
let for_of_count = ctx.labels.for_of_depth;
|
||||
let for_in_count = ctx.labels.for_in_depth;
|
||||
let dispose_count = ctx.labels.dispose_depth;
|
||||
match &ret.argument {
|
||||
Some(expr) => {
|
||||
let r = self.emit_expression(expr, ctx)?;
|
||||
@@ -22,15 +24,15 @@ impl Emitter {
|
||||
// 弹出连续纯 catch handler(finally handler 走运行时完成穿越逐个
|
||||
// 执行)。否则 return 跳过 TRY_END 会让 handler 残留在 try_stack,
|
||||
// 后续异常 unwind 会跳回已返回函数的 catch 形成死循环。
|
||||
// 逃出迭代器时(close_count>0)保留 handler:return() 抛错须经
|
||||
// unwind 被外围 catch 捕获(新错误替代完成值),弹出后无法展开。
|
||||
if for_of_count == 0 && for_in_count == 0 {
|
||||
// 逃出迭代器或资源时(close_count>0)保留 handler:return() 抛错
|
||||
// 须经 unwind 被外围 catch 捕获(新错误替代完成值),弹出后无法展开。
|
||||
if for_of_count == 0 && for_in_count == 0 && dispose_count == 0 {
|
||||
self.emit_return_try_cleanup(ctx);
|
||||
}
|
||||
ctx.inst(Inst::ret(Operand::Reg(r), for_of_count, for_in_count));
|
||||
ctx.inst(Inst::ret(Operand::Reg(r), for_of_count, for_in_count, dispose_count));
|
||||
}
|
||||
None => {
|
||||
if for_of_count == 0 && for_in_count == 0 {
|
||||
if for_of_count == 0 && for_in_count == 0 && dispose_count == 0 {
|
||||
self.emit_return_try_cleanup(ctx);
|
||||
}
|
||||
// 裸 return 须显式物化 undefined 为完成值:RETURN 从 rd 槽读值,
|
||||
@@ -38,7 +40,7 @@ impl Emitter {
|
||||
let undef_idx = ctx.add_constant(Constant::Undefined);
|
||||
let undef_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(undef_reg), undef_idx));
|
||||
ctx.inst(Inst::ret(Operand::Reg(undef_reg), for_of_count, for_in_count));
|
||||
ctx.inst(Inst::ret(Operand::Reg(undef_reg), for_of_count, for_in_count, dispose_count));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
|
||||
Reference in New Issue
Block a user