fix(vm): 链式 upvalue 捕获支持多层嵌套函数引用深层变量

This commit is contained in:
爱特每羊队
2026-08-07 14:56:51 +08:00
parent 543f88ce86
commit f4d95f373e
6 changed files with 53 additions and 20 deletions
+6 -2
View File
@@ -23,13 +23,17 @@ pub enum Constant {
/// 闭包对上层作用域一个变量的捕获描述。
///
/// `enclosing_reg` 是外层函数中该变量的寄存器位;若外层变量本身就是 upvalue
/// (多级闭包),`cell_idx` 指向链式捕获的 cell。
/// `enclosing_reg` 是外层函数中该变量的寄存器位;`cell_idx` 是父函数 own cell
/// 表下标(`parent_uv_idx` 为 None 时)。多级闭包(外层变量本身就是父函数从更
/// 外层捕获的 upvalue)时 `parent_uv_idx` 给出父闭包 `upvalues` 数组下标。
#[derive(Debug, Clone)]
pub struct UpvalueCapture {
pub name: String,
pub enclosing_reg: u32,
pub cell_idx: u8,
/// 链式捕获:None = 父 own cell(cell_idx 索引定义方 cell 表);
/// Some = 父函数自身 upvalue(运行时从父闭包 upvalues[parent_uv_idx] 取 cell)。
pub parent_uv_idx: Option<u8>,
}
/// 一个函数单元(或顶层脚本)的编译产物。
+11 -4
View File
@@ -556,12 +556,17 @@ impl Emitter {
}
/// 分析子函数 body:引用父级被捕获绑定的名字 → upvalue_captures。
/// cell_idx 直接取父 captured_bindings 映射(父 emit 前已确定,索引一致);
/// enclosing_reg 由父 emit 完成后填充(assemble_ir)。
/// 名字若在父 `captured_bindings`(父 own cell)则 `cell_idx` 索引定义方表;
/// 若在父 `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>, sub_own: &HashSet<String>,
&self, body_stmts: &[Statement], parent_captured: &BTreeMap<String, u8>,
parent_upvalues: &[UpvalueCapture], sub_own: &HashSet<String>,
) -> Vec<UpvalueCapture> {
let parent_names: HashSet<String> = parent_captured.keys().cloned().collect();
let mut parent_names: HashSet<String> = parent_captured.keys().cloned().collect();
for u in parent_upvalues {
parent_names.insert(u.name.clone());
}
let mut names = HashSet::new();
self.collect_capture_names_shadowed(body_stmts, &parent_names, sub_own, &mut names);
// HashSet 迭代序带随机种子(进程级非确定),必须排序使 upvalue_captures 的顺序与
@@ -572,11 +577,13 @@ impl Emitter {
names
.into_iter()
.map(|name| {
let parent_uv_idx = parent_upvalues.iter().position(|u| u.name == name).map(|i| i as u8);
let cell_idx = parent_captured.get(&name).copied().unwrap_or(0);
UpvalueCapture {
name,
enclosing_reg: 0, // assemble_ir 时从父符号表填充
cell_idx,
parent_uv_idx,
}
})
.collect()
+7 -2
View File
@@ -473,6 +473,7 @@ impl CompileCtx {
name: u.name.clone(),
enclosing_reg,
cell_idx: u.cell_idx,
parent_uv_idx: u.parent_uv_idx,
}
})
.collect();
@@ -757,8 +758,12 @@ impl Emitter {
// 自由变量分析(仅普通/箭头函数):收集 upvalue 捕获。
if matches!(body_context, FunctionBodyContext::Ordinary | FunctionBodyContext::Arrow) {
ctx.current_upvalue_captures =
self.collect_upvalue_names(body_stmts, &parent_ctx.captured_bindings, &ctx.own_bindings);
ctx.current_upvalue_captures = self.collect_upvalue_names(
body_stmts,
&parent_ctx.captured_bindings,
&parent_ctx.current_upvalue_captures,
&ctx.own_bindings,
);
}
Ok(param_base)
+3
View File
@@ -184,6 +184,7 @@ fn module_fields_are_copied_through() {
name: "x".to_string(),
enclosing_reg: 5,
cell_idx: 0,
parent_uv_idx: None,
});
f.cells_needed = 1;
let m = lower_ok(&f);
@@ -274,6 +275,7 @@ fn ir_function_domain_assemble_default_clone() {
name: "x".to_string(),
enclosing_reg: 0,
cell_idx: 0,
parent_uv_idx: None,
});
f.cells_needed = 1;
f.function_name = Some("f".to_string());
@@ -305,3 +307,4 @@ fn operand_this_is_semantic_not_physical_index() {
assert_eq!(Operand::This, Operand::This);
assert_eq!(Operand::NewTarget, Operand::NewTarget);
}
+1
View File
@@ -118,6 +118,7 @@ mod tests {
name: "x".to_string(),
enclosing_reg: 7,
cell_idx: 0,
parent_uv_idx: None,
});
let map = AllocMap::new();
run(&mut f, &map);
+25 -12
View File
@@ -133,21 +133,34 @@ impl Vm {
let name_val = function_name.as_deref().map(|n| self.new_string(n)).unwrap_or_else(|| self.new_string(""));
self.set_or_create_prop_value(func_obj, name_si, name_val);
if !upvalue_captures.is_empty() {
// 链式捕获(parent_uv_idx):从父闭包(创建者)的 upvalues 取 cell。
let parent_upvalues: Vec<*mut Cell> = match self.current_callee() {
Some(callee) if callee.is_object() => {
unsafe { &*callee.as_js_object_ptr() }.upvalues_slice().to_vec()
}
_ => Vec::new(),
};
if let Some(current_cells) = self.cell_stack.last_mut() {
let mut upvals = Box::new(Vec::with_capacity(upvalue_captures.len()));
for capture in &upvalue_captures {
let cell_idx = capture.cell_idx as usize;
if cell_idx >= current_cells.len() {
current_cells.resize(cell_idx + 1, std::ptr::null_mut());
}
// cell 可能尚未 MAKE_CELL(hoisting 顺序:CREATE_CLOSURE 先于
// MAKE_CELL)——建占位 Cell,后续 MAKE_CELL 更新同一 Cell 的值,
// 保证 upvalue 始终指向定义方表里的稳定 cell(而非调用方表)。
if current_cells[cell_idx].is_null() {
let cell = self.gc_state.session_epoch.alloc(Cell::new(JsValue::undefined(), true));
current_cells[cell_idx] = cell as *mut Cell;
}
upvals.push(current_cells[cell_idx]);
let cell_ptr = if let Some(puv) = capture.parent_uv_idx {
parent_upvalues.get(puv as usize).copied().unwrap_or(std::ptr::null_mut())
} else {
let cell_idx = capture.cell_idx as usize;
if cell_idx >= current_cells.len() {
current_cells.resize(cell_idx + 1, std::ptr::null_mut());
}
// cell 可能尚未 MAKE_CELL(hoisting 顺序:CREATE_CLOSURE 先于
// MAKE_CELL)——建占位 Cell,后续 MAKE_CELL 更新同一 Cell 的值,
// 保证 upvalue 始终指向定义方表里的稳定 cell(而非调用方表)。
if current_cells[cell_idx].is_null() {
let cell =
self.gc_state.session_epoch.alloc(Cell::new(JsValue::undefined(), true));
current_cells[cell_idx] = cell as *mut Cell;
}
current_cells[cell_idx]
};
upvals.push(cell_ptr);
}
let func_obj = unsafe { &mut *result.as_js_object_ptr() };
func_obj.set_upvalues(upvals);