feat: 七类作用域出口正常释放 using 资源,for-of 每迭代

This commit is contained in:
2026-10-09 18:40:24 +00:00
parent b5ff2c132a
commit 48ffb54c4f
19 changed files with 473 additions and 46 deletions
+11
View File
@@ -11,6 +11,13 @@ impl Emitter {
return Ok(None);
};
ctx.push_scope();
// 块是释放作用域:仅当块含 using 声明时入口登记水位、块尾正常完成逆序
// 释放本块声明的资源(无 using 的块不发 mark/pop,防早退跳过 POP 留
// 未配对水位)。
let has_using = Self::scope_contains_using(&block.body);
if has_using {
ctx.emit_dispose_mark();
}
// 函数预声明先于 lexical:`{ let g; function g(){} }` 时 lexical 的预声明
// 命中已存在的函数绑定自然报重复声明错,不被静默覆盖破坏 TDZ。
self.predeclare_block_function_declarations(&block.body, ctx, false);
@@ -35,6 +42,10 @@ impl Emitter {
}
ctx.pop_completion_list();
ctx.block_fn_entry_mats.pop();
// 块尾正常完成:逆序释放本块声明的资源(异常/return 穿越跳过本点)。
if has_using {
ctx.emit_dispose_pop();
}
ctx.pop_scope();
Ok(r)
}
+89 -11
View File
@@ -5,7 +5,10 @@ use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{BindingPattern, Statement, VariableDeclaration, VariableDeclarationKind};
use oxide_parser::{
BindingPattern, ForStatementInit, ForStatementLeft, Statement, VariableDeclaration,
VariableDeclarationKind,
};
impl Emitter {
pub(crate) fn emit_variable_declaration_statement(
@@ -44,16 +47,8 @@ impl Emitter {
}
}
// using/await using 声明登记:把资源值压入 VM 释放栈(释放时机由
// 作用域出口点决定,本指令只登记)。a 槽为释放提示:0 = 同步、1 = 异步。
if matches!(decl.kind, VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing) {
let hint = u16::from(matches!(decl.kind, VariableDeclarationKind::AwaitUsing));
ctx.inst(Inst::new(
OpCode::DISPOSE_REGISTER,
Operand::Reg(val_reg),
Operand::Imm(hint),
Operand::None,
));
}
// 作用域出口点决定,本指令只登记)。
self.emit_dispose_register(val_reg, decl.kind, ctx);
} else {
let BindingPattern::BindingIdentifier(bi) = &d.id else {
return Err("destructuring declaration requires an initializer".into());
@@ -97,4 +92,87 @@ impl Emitter {
}
Ok(None)
}
/// 递归扫描语句列表是否含 using/await using 声明(含嵌套复合语句,不进入
/// 函数/类体——那是独立作用域,其 using 声明不属本作用域)。释放作用域的
/// mark/pop 仅在有资源声明时发射:无 using 的作用域若发 mark/pop,其早退
/// (return/break/continue/throw)跳过 POP 会留下未配对水位,错乱外层作用域
/// 的 mark/pop 对齐。
pub(crate) fn scope_contains_using(stmts: &[Statement]) -> bool {
stmts.iter().any(Self::statement_contains_using)
}
pub(crate) fn statement_contains_using(stmt: &Statement) -> bool {
match stmt {
Statement::VariableDeclaration(decl) => {
matches!(decl.kind, VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing)
}
Statement::BlockStatement(block) => Self::scope_contains_using(&block.body),
Statement::IfStatement(if_) => {
Self::statement_contains_using(&if_.consequent)
|| if_.alternate.as_ref().is_some_and(|s| Self::statement_contains_using(s))
}
Statement::WhileStatement(while_) => Self::statement_contains_using(&while_.body),
Statement::DoWhileStatement(do_) => Self::statement_contains_using(&do_.body),
Statement::ForStatement(for_) => Self::statement_contains_using(&for_.body),
Statement::ForOfStatement(for_) => Self::statement_contains_using(&for_.body),
Statement::ForInStatement(for_) => Self::statement_contains_using(&for_.body),
Statement::LabeledStatement(labeled) => Self::statement_contains_using(&labeled.body),
Statement::WithStatement(with_) => Self::statement_contains_using(&with_.body),
Statement::SwitchStatement(switch_) => {
switch_.cases.iter().any(|case| Self::scope_contains_using(&case.consequent))
}
Statement::TryStatement(try_) => {
Self::scope_contains_using(&try_.block.body)
|| try_
.handler
.as_deref()
.is_some_and(|h| Self::scope_contains_using(&h.body.body))
|| try_.finalizer.as_deref().is_some_and(|f| Self::scope_contains_using(&f.body))
}
// 函数/类声明是独立作用域,其 using 声明不属本作用域;其余语句无嵌套。
_ => false,
}
}
/// using/await using 声明登记释放栈:把资源值(val_reg)压入释放栈。非
/// using/await using 声明不登记。a 槽为释放提示(0 = 同步、1 = 异步)。
pub(crate) fn emit_dispose_register(
&self, val_reg: u32, kind: VariableDeclarationKind, ctx: &mut CompileCtx,
) {
if !matches!(kind, VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing) {
return;
}
let hint = u16::from(matches!(kind, VariableDeclarationKind::AwaitUsing));
ctx.inst(Inst::new(
OpCode::DISPOSE_REGISTER,
Operand::Reg(val_reg),
Operand::Imm(hint),
Operand::None,
));
}
/// C 风格 for 头是否含 using 声明(init 为 using/await using 变量声明)。
pub(crate) fn for_init_contains_using(init: &Option<ForStatementInit>) -> bool {
matches!(
init,
Some(ForStatementInit::VariableDeclaration(decl))
if matches!(
decl.kind,
VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing
)
)
}
/// for-of/for-in 左侧是否含 using 声明(头为 using/await using 变量声明)。
pub(crate) fn for_left_contains_using(left: &ForStatementLeft) -> bool {
matches!(
left,
ForStatementLeft::VariableDeclaration(decl)
if matches!(
decl.kind,
VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing
)
)
}
}
@@ -38,6 +38,12 @@ impl Emitter {
// try block 是独立块作用域:lexical 声明(let/const/class)限定于 try 内,
// 与外层同名绑定互不干扰;块级预声明使声明点前读取编译为 TDZ 抛错。
ctx.push_scope();
// try 体是独立释放环境:仅当体含 using 声明时入口登记水位、体尾正常
// 完成逆序释放(异常穿越跳过本点,归穿越面)。
let try_has_using = Self::scope_contains_using(&ts.block.body);
if try_has_using {
ctx.emit_dispose_mark();
}
// 函数预声明先于 lexical:同名 let 命中已有函数绑定报重复声明错。
self.predeclare_block_function_declarations(&ts.block.body, ctx, false);
// try 块 lexical 声明是局部绑定:不做受限全局名检查(重复声明错在 emit 期报)。
@@ -58,6 +64,10 @@ impl Emitter {
}
ctx.pop_completion_list();
ctx.block_fn_entry_mats.pop();
// try 体正常完成出口:逆序释放本体声明的资源。
if try_has_using {
ctx.emit_dispose_pop();
}
ctx.pop_scope();
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
@@ -77,6 +87,12 @@ impl Emitter {
ctx.labels.set_label_pos(catch_label, ctx.insts.len());
if let Some(catch) = &ts.handler {
ctx.push_scope();
// catch 体是独立释放环境:仅当体含 using 声明时入口登记水位、体尾
// 正常完成逆序释放。
let catch_has_using = Self::scope_contains_using(&catch.body.body);
if catch_has_using {
ctx.emit_dispose_mark();
}
if let Some(param) = &catch.param {
let src_reg = ctx.alloc_reg();
// 异常值在 VM 物理 regs[0](unwind 展开处写入),STORE_VAR a=None 读回。
@@ -111,6 +127,10 @@ impl Emitter {
Operand::Reg(last_catch_result.unwrap_or(result_reg)),
Operand::None,
));
// catch 体正常完成出口:逆序释放本体声明的资源。
if catch_has_using {
ctx.emit_dispose_pop();
}
ctx.pop_scope();
}
if has_finally {
@@ -124,6 +144,12 @@ impl Emitter {
// try/catch 收敛值保持 try 体或 catch 体值,finally 值不渗入。
// finally block 同为独立块作用域,lexical 声明互不泄漏。
ctx.push_scope();
// finally 体是独立释放环境:仅当体含 using 声明时入口登记水位、
// 体尾正常完成逆序释放。
let finally_has_using = Self::scope_contains_using(&ts.finalizer.as_ref().unwrap().body);
if finally_has_using {
ctx.emit_dispose_mark();
}
// finally 块函数预声明先于 lexical,块入口物化与 try/普通块同口径。
self.predeclare_block_function_declarations(&ts.finalizer.as_ref().unwrap().body, ctx, false);
// finally 块 lexical 声明同为局部绑定:不做受限全局名检查。
@@ -142,6 +168,10 @@ impl Emitter {
}
ctx.pop_completion_list();
ctx.block_fn_entry_mats.pop();
// finally 体正常完成出口:逆序释放本体声明的资源。
if finally_has_using {
ctx.emit_dispose_pop();
}
ctx.pop_scope();
ctx.inst(Inst::new(OpCode::TRY_FINALLY_END, Operand::None, Operand::None, Operand::None));
ctx.pop_open_try_handler();
@@ -44,6 +44,12 @@ impl Emitter {
return Ok(None);
};
ctx.push_scope();
// C 风格 for 是整语句单一释放环境(非每迭代):仅当头/体含 using 声明
// 时入口登记水位、出口(end_label 后)逆序释放。
let has_using = Self::for_init_contains_using(&fr.init) || Self::statement_contains_using(&fr.body);
if has_using {
ctx.emit_dispose_mark();
}
let start_label = ctx.next_label_id();
let update_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
@@ -98,6 +104,8 @@ impl Emitter {
// 捕获头名的寄存器补写在 `emit_bind_target` 经
// `for_head_store_registers` 完成(解构叶用各自的叶值,不用整头 RHS)。
self.emit_binding_pattern(&d.id, val_reg, decl.kind, is_const, false, ctx)?;
// using/await using 头声明登记释放栈(资源值即 init 表达式结果)。
self.emit_dispose_register(val_reg, decl.kind, ctx);
} else if let BindingPattern::BindingIdentifier(bi) = &d.id {
let idx = ctx.add_constant(Constant::Undefined);
let tmp = ctx.alloc_reg();
@@ -222,6 +230,10 @@ impl Emitter {
}
ctx.inst(Inst::jmp(start_label));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
// 循环正常完成出口:逆序释放本 for 语句声明的资源。
if has_using {
ctx.emit_dispose_pop();
}
ctx.pop_label_scopes(n_labeled);
ctx.pop_loop();
ctx.pop_scope();
@@ -189,6 +189,12 @@ impl Emitter {
ctx.labels.set_label_pos(continue_label, ctx.insts.len());
let key_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::FOR_IN_NEXT, Operand::Reg(key_reg), Operand::None, Operand::None));
// for-in 每迭代独立环境(规范 iterationEnv):仅当头/体含 using 声明时
// 本迭代 mark/pop。
let has_using = Self::for_left_contains_using(&fi.left) || Self::statement_contains_using(&fi.body);
if has_using {
ctx.emit_dispose_mark();
}
match &fi.left {
ForStatementLeft::VariableDeclaration(decl) => {
// let/const 声明对被捕获绑定用 fresh cell(每迭代新 cell);var 单绑定。
@@ -253,6 +259,8 @@ impl Emitter {
_ => self.emit_binding_pattern(&d.id, key_reg, decl.kind, is_const, fresh_cell, ctx)?,
}
}
// using/await using 头声明登记释放栈(资源值即本迭代键)。
self.emit_dispose_register(key_reg, decl.kind, ctx);
}
ForStatementLeft::AssignmentTargetIdentifier(id_ref) => {
let name = id_ref.name.as_str();
@@ -284,6 +292,10 @@ impl Emitter {
if let Some(env) = head_env {
self.restore_for_head_env(env, ctx);
}
// 本迭代正常完成:逆序释放本迭代声明的资源。
if has_using {
ctx.emit_dispose_pop();
}
ctx.inst(Inst::jmp(start_label));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
ctx.inst(Inst::new(OpCode::FOR_IN_CLEANUP, Operand::None, Operand::None, Operand::None));
@@ -49,11 +49,21 @@ impl Emitter {
ctx.inst(Inst::jmp_if_false(has_reg, end_label));
let val_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::FOR_OF_NEXT, Operand::Reg(val_reg), Operand::None, Operand::None));
// for-of 每迭代独立环境(规范 iterationEnv):仅当头/体含 using 声明时
// 本迭代 mark/pop,迭代器关闭(FOR_OF_CLOSE)与释放互不干扰。
let has_using = Self::for_left_contains_using(&fo.left) || Self::statement_contains_using(&fo.body);
if has_using {
ctx.emit_dispose_mark();
}
self.emit_for_of_left_assignment(&fo.left, val_reg, ctx)?;
let body_result = self.emit_statement(&fo.body, ctx)?;
if let Some(env) = head_env {
self.restore_for_head_env(env, ctx);
}
// 本迭代正常完成:逆序释放本迭代声明的资源。
if has_using {
ctx.emit_dispose_pop();
}
ctx.inst(Inst::jmp(start_label));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
ctx.inst(Inst::new(OpCode::FOR_OF_CLOSE, Operand::None, Operand::None, Operand::None));
@@ -115,11 +125,21 @@ impl Emitter {
ctx.inst(Inst::jmp_if_false(has_reg, end_label));
let val_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::FOR_OF_NEXT, Operand::Reg(val_reg), Operand::None, Operand::None));
// for-await-of 同同步 for-of:每迭代独立环境,仅当头/体含 using 声明时
// 本迭代 mark/pop。
let has_using = Self::for_left_contains_using(&fo.left) || Self::statement_contains_using(&fo.body);
if has_using {
ctx.emit_dispose_mark();
}
self.emit_for_of_left_assignment(&fo.left, val_reg, ctx)?;
let body_result = self.emit_statement(&fo.body, ctx)?;
if let Some(env) = head_env {
self.restore_for_head_env(env, ctx);
}
// 本迭代正常完成:逆序释放本迭代声明的资源。
if has_using {
ctx.emit_dispose_pop();
}
ctx.inst(Inst::jmp(start_label));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
ctx.inst(Inst::new(OpCode::FOR_AWAIT_OF_CLOSE, Operand::None, Operand::None, Operand::None));
@@ -147,6 +167,8 @@ impl Emitter {
for d in &decl.declarations {
self.emit_binding_pattern(&d.id, val_reg, decl.kind, false, fresh_cell, ctx)?;
}
// using/await using 头声明登记释放栈(资源值即本迭代值)。
self.emit_dispose_register(val_reg, decl.kind, ctx);
}
ForStatementLeft::AssignmentTargetIdentifier(id_ref) => {
let name = id_ref.name.as_str();
+10
View File
@@ -32,6 +32,12 @@ impl Emitter {
// 块函数预声明先于 lexical,使 `case 0: let g; function g(){}` 的 lexical
// 占位命中已存在的函数绑定,报重复声明错。
ctx.push_scope();
// CaseBlock 是单一释放环境(非逐 case):穿落不跨环境,仅当 case 体含
// using 声明时入口登记水位、出口逆序释放。
let has_using = cases.iter().any(|case| Self::scope_contains_using(&case.consequent));
if has_using {
ctx.emit_dispose_mark();
}
for case in cases.iter() {
self.predeclare_block_function_declarations(&case.consequent, ctx, false);
self.predeclare_lexical_declarations(&case.consequent, ctx)?;
@@ -84,6 +90,10 @@ impl Emitter {
}
ctx.block_fn_entry_mats.pop();
ctx.labels.set_label_pos(end_label, ctx.insts.len());
// CaseBlock 正常完成出口:逆序释放本块声明的资源。
if has_using {
ctx.emit_dispose_pop();
}
ctx.pop_scope();
ctx.pop_completion_target();
ctx.pop_switch();