fix: 闭包捕获/upvalue 分析纳入参数默认值表达式(含嵌套函数声明)

This commit is contained in:
2026-08-07 19:04:25 +08:00
parent 9981086424
commit e3d8092088
2 changed files with 99 additions and 4 deletions
+45 -2
View File
@@ -123,6 +123,7 @@ impl Emitter {
let mut inner = shadow.clone();
inner.extend(self.collect_fn_param_names(&fd.params));
inner.extend(self.collect_own_binding_names(&[], body));
self.collect_fn_default_names(&fd.params, ref_set, shadow, out);
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
}
Statement::IfStatement(is) => {
@@ -240,6 +241,20 @@ impl Emitter {
}
}
/// 收集函数参数默认值表达式里的引用(子层 upvalue 判定;参数名遮蔽)。
fn collect_fn_default_names(
&self, params: &oxide_parser::FormalParameters, ref_set: &HashSet<String>, shadow: &HashSet<String>,
out: &mut HashSet<String>,
) {
for p in &params.items {
if let Some(init) = &p.initializer {
self.collect_capture_names_expr(init, ref_set, shadow, out);
}
let mut param_shadow = shadow.clone();
self.collect_capture_names_binding_pattern(&p.pattern, ref_set, shadow, out, &mut param_shadow);
}
}
fn collect_capture_names_expr(
&self, expr: &Expression, ref_set: &HashSet<String>, shadow: &HashSet<String>, out: &mut HashSet<String>,
) {
@@ -272,12 +287,14 @@ impl Emitter {
let mut inner = shadow.clone();
inner.extend(self.collect_fn_param_names(&fe.params));
inner.extend(self.collect_own_binding_names(&[], body));
self.collect_fn_default_names(&fe.params, ref_set, shadow, out);
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
}
Expression::ArrowFunctionExpression(ae) => {
let mut inner = shadow.clone();
inner.extend(self.collect_fn_param_names(&ae.params));
inner.extend(self.collect_own_binding_names(&[], &ae.body.statements));
self.collect_fn_default_names(&ae.params, ref_set, shadow, out);
self.collect_capture_names_shadowed(&ae.body.statements, ref_set, &inner, out);
}
Expression::BinaryExpression(be) => {
@@ -382,21 +399,41 @@ impl Emitter {
}
/// 分析本函数:哪些绑定被任意深度嵌套函数捕获 → captured_bindings。
pub(crate) fn collect_captured_bindings(&self, stmts: &[Statement], own: &HashSet<String>) -> BTreeMap<String, u8> {
pub(crate) fn collect_captured_bindings(
&self, stmts: &[Statement], extra_exprs: &[&oxide_parser::Expression], own: &HashSet<String>,
) -> BTreeMap<String, u8> {
let mut names = HashSet::new();
for stmt in stmts {
self.collect_captured_stmt(stmt, own, &mut names);
}
// 参数默认值表达式(不在 body_stmts 内)里的嵌套函数引用也要纳入捕获,
// 否则默认值内 IIFE 引用全局/外层变量走 LOAD_VAR 读寄存器残留(B022 扩展)。
for expr in extra_exprs {
self.collect_captured_expr(expr, own, &mut names);
}
// 名字排序分配 cell_idx(稳定跨 run,父 MAKE_CELL 与子 upvalue 统一引用)
let mut sorted: Vec<String> = names.into_iter().collect();
sorted.sort();
sorted.into_iter().enumerate().map(|(i, n)| (n, i as u8)).collect()
}
/// 收集函数参数默认值表达式里的嵌套函数引用(父层 captured/子层 upvalue 判定)。
fn collect_fn_default_captured(
&self, params: &oxide_parser::FormalParameters, own: &HashSet<String>, out: &mut HashSet<String>,
) {
for p in &params.items {
if let Some(init) = &p.initializer {
self.collect_captured_expr(init, own, out);
}
self.collect_captured_binding_pattern(&p.pattern, own, out);
}
}
/// 只从嵌套函数节点进入扫描(本函数直接引用不算捕获)。
fn collect_captured_stmt(&self, stmt: &Statement, own: &HashSet<String>, out: &mut HashSet<String>) { match stmt {
Statement::FunctionDeclaration(fd) => {
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
self.collect_fn_default_captured(&fd.params, own, out);
self.collect_capture_names(body, own, out);
}
Statement::ExpressionStatement(es) => self.collect_captured_expr(&es.expression, own, out),
@@ -523,11 +560,13 @@ impl Emitter {
let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
let mut inner = self.collect_fn_param_names(&fe.params);
inner.extend(self.collect_own_binding_names(&[], body));
self.collect_fn_default_captured(&fe.params, own, out);
self.collect_capture_names_shadowed(body, own, &inner, out);
}
Expression::ArrowFunctionExpression(ae) => {
let mut inner = self.collect_fn_param_names(&ae.params);
inner.extend(self.collect_own_binding_names(&[], &ae.body.statements));
self.collect_fn_default_captured(&ae.params, own, out);
self.collect_capture_names_shadowed(&ae.body.statements, own, &inner, out);
}
Expression::CallExpression(ce) => {
@@ -634,7 +673,7 @@ impl Emitter {
/// 若在父 `upvalue_captures`(父自身从更外层捕获)则链式标记 `parent_uv_idx`,
/// 运行时从父闭包 upvalues 取 cell。enclosing_reg 由父 emit 完成后填充。
pub(crate) fn collect_upvalue_names(
&self, body_stmts: &[Statement], parent_captured: &BTreeMap<String, u8>,
&self, body_stmts: &[Statement], extra_exprs: &[&oxide_parser::Expression], parent_captured: &BTreeMap<String, u8>,
parent_upvalues: &[UpvalueCapture], sub_own: &HashSet<String>,
) -> Vec<UpvalueCapture> {
let mut parent_names: HashSet<String> = parent_captured.keys().cloned().collect();
@@ -643,6 +682,10 @@ impl Emitter {
}
let mut names = HashSet::new();
self.collect_capture_names_shadowed(body_stmts, &parent_names, sub_own, &mut names);
// 参数默认值表达式(不在 body_stmts)里的嵌套函数引用也会捕获父变量。
for expr in extra_exprs {
self.collect_capture_names_expr(expr, &parent_names, sub_own, &mut names);
}
// HashSet 迭代序带随机种子(进程级非确定),必须排序使 upvalue_captures 的顺序与
// 父 captured_bindings 的 cell_idx(BTreeMap 名字序)对齐——否则 LOAD_UPVALUE 的
// a 槽 uv_idx 编码与 cell_idx 错位,读错 upvalue。
+54 -2
View File
@@ -523,6 +523,39 @@ impl Emitter {
Self
}
/// 遍历解构 pattern 收集内嵌默认值表达式(AssignmentPattern.right)。
fn collect_pattern_default_exprs<'a>(
&self, pattern: &'a oxide_parser::BindingPattern<'a>, out: &mut Vec<&'a oxide_parser::Expression<'a>>,
) {
use oxide_parser::BindingPattern;
match pattern {
BindingPattern::AssignmentPattern(ap) => {
out.push(&ap.right);
self.collect_pattern_default_exprs(&ap.left, out);
}
BindingPattern::ArrayPattern(ap) => {
for elem in &ap.elements {
if let Some(p) = elem {
self.collect_pattern_default_exprs(p, out);
}
}
if let Some(rest) = &ap.rest {
self.collect_pattern_default_exprs(&rest.argument, out);
}
}
BindingPattern::ObjectPattern(op) => {
for prop in &op.properties {
self.collect_pattern_default_exprs(&prop.value, out);
}
if let Some(rest) = &op.rest {
self.collect_pattern_default_exprs(&rest.argument, out);
}
}
_ => {}
}
}
// ── 闭包捕获分析(AST 级,时序无关)──
/// 收集函数参数的绑定名(BindingIdentifier 形态)。
@@ -759,8 +792,26 @@ impl Emitter {
// 闭包捕获分析(AST 级,emit 前确定,时序无关)
let param_names: Vec<&str> = param_specs.iter().map(|s| s.register_name()).collect();
let mut param_defaults: Vec<&oxide_parser::Expression> = Vec::new();
for spec in param_specs {
match spec {
ParamSpec::Identifier { initializer, .. } => {
if let Some(init) = initializer {
param_defaults.push(init);
}
}
ParamSpec::Pattern { pattern, initializer, .. } => {
if let Some(init) = initializer {
param_defaults.push(init);
}
// 模式内嵌默认值(`[x = expr]` 的 AssignmentPattern.right)也会被
// 内部闭包引用,需纳入捕获分析。
self.collect_pattern_default_exprs(pattern, &mut param_defaults);
}
}
}
ctx.own_bindings = self.collect_own_binding_names(&param_names, body_stmts);
ctx.captured_bindings = self.collect_captured_bindings(body_stmts, &ctx.own_bindings);
ctx.captured_bindings = self.collect_captured_bindings(body_stmts, &param_defaults, &ctx.own_bindings);
// 被捕获的参数也必须建 cell(MAKE_CELL):否则子函数经 lazy upvalue 路径读
// 自身寄存器(依赖调用者寄存器残留),vreg 化/RegAlloc 移动寄存器后读到垃圾。
@@ -782,6 +833,7 @@ impl Emitter {
if matches!(body_context, FunctionBodyContext::Ordinary | FunctionBodyContext::Arrow) {
ctx.current_upvalue_captures = self.collect_upvalue_names(
body_stmts,
&param_defaults,
&parent_ctx.captured_bindings,
&parent_ctx.current_upvalue_captures,
&ctx.own_bindings,
@@ -888,7 +940,7 @@ impl Emitter {
// 闭包捕获分析(AST 级,emit 前确定)
ctx.own_bindings = self.collect_own_binding_names(&[], &program.body);
ctx.captured_bindings = self.collect_captured_bindings(&program.body, &ctx.own_bindings);
ctx.captured_bindings = self.collect_captured_bindings(&program.body, &[], &ctx.own_bindings);
// 首个 sub-pass:发函数声明(hoisting),保证任何代码运行前函数对象已就绪。
for stmt in &program.body {