From b9ff4226b7e7738180de43adcad43562404cd1df Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Mon, 12 Oct 2026 05:33:01 +0000 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=8D=95=E8=8E=B7=E5=88=A4=E5=AE=9A?= =?UTF-8?q?=E4=B8=8Eupvalue=E6=94=B6=E9=9B=86=E5=90=88=E5=B9=B6=E5=8D=95?= =?UTF-8?q?=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 40 +- Cargo.toml | 2 +- crates/oxide_emit/src/capture/captured.rs | 507 ---------------------- crates/oxide_emit/src/capture/guard.rs | 246 ----------- crates/oxide_emit/src/capture/mod.rs | 9 +- crates/oxide_emit/src/capture/scanner.rs | 126 ++++-- crates/oxide_emit/src/capture/upvalues.rs | 73 +++- crates/oxide_emit/src/function_body.rs | 68 +-- 8 files changed, 191 insertions(+), 880 deletions(-) delete mode 100644 crates/oxide_emit/src/capture/captured.rs delete mode 100644 crates/oxide_emit/src/capture/guard.rs diff --git a/Cargo.lock b/Cargo.lock index d29e7dd2..b8f4e2ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "oxide_builtins" -version = "0.16.7" +version = "0.16.8" dependencies = [ "chrono", "fast-float", @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "oxide_bytecode" -version = "0.16.7" +version = "0.16.8" dependencies = [ "num-bigint", "oxide_log", @@ -1193,7 +1193,7 @@ dependencies = [ [[package]] name = "oxide_cfg" -version = "0.16.7" +version = "0.16.8" dependencies = [ "oxide_bytecode", "oxide_emit", @@ -1204,7 +1204,7 @@ dependencies = [ [[package]] name = "oxide_cli" -version = "0.16.7" +version = "0.16.8" dependencies = [ "ansi_term", "bumpalo", @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "oxide_code_cache" -version = "0.16.7" +version = "0.16.8" dependencies = [ "lru", "oxide_bytecode", @@ -1237,7 +1237,7 @@ dependencies = [ [[package]] name = "oxide_compiler" -version = "0.16.7" +version = "0.16.8" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1257,7 +1257,7 @@ dependencies = [ [[package]] name = "oxide_dce" -version = "0.16.7" +version = "0.16.8" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1271,7 +1271,7 @@ dependencies = [ [[package]] name = "oxide_emit" -version = "0.16.7" +version = "0.16.8" dependencies = [ "num-bigint", "oxc_allocator", @@ -1286,7 +1286,7 @@ dependencies = [ [[package]] name = "oxide_engine" -version = "0.16.7" +version = "0.16.8" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1298,7 +1298,7 @@ dependencies = [ [[package]] name = "oxide_ir" -version = "0.16.7" +version = "0.16.8" dependencies = [ "oxide_bytecode", "oxide_log", @@ -1307,7 +1307,7 @@ dependencies = [ [[package]] name = "oxide_kernel" -version = "0.16.7" +version = "0.16.8" dependencies = [ "bumpalo", "dashmap", @@ -1321,7 +1321,7 @@ dependencies = [ [[package]] name = "oxide_liveness" -version = "0.16.7" +version = "0.16.8" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1333,7 +1333,7 @@ dependencies = [ [[package]] name = "oxide_log" -version = "0.16.7" +version = "0.16.8" dependencies = [ "tracing", "tracing-appender", @@ -1342,11 +1342,11 @@ dependencies = [ [[package]] name = "oxide_net" -version = "0.16.7" +version = "0.16.8" [[package]] name = "oxide_parser" -version = "0.16.7" +version = "0.16.8" dependencies = [ "oxc_allocator", "oxc_ast", @@ -1361,7 +1361,7 @@ dependencies = [ [[package]] name = "oxide_regalloc" -version = "0.16.7" +version = "0.16.8" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1377,7 +1377,7 @@ dependencies = [ [[package]] name = "oxide_runtime_api" -version = "0.16.7" +version = "0.16.8" dependencies = [ "num-bigint", "num-traits", @@ -1390,7 +1390,7 @@ dependencies = [ [[package]] name = "oxide_test262" -version = "0.16.7" +version = "0.16.8" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1410,7 +1410,7 @@ dependencies = [ [[package]] name = "oxide_types" -version = "0.16.7" +version = "0.16.8" dependencies = [ "bumpalo", "dashmap", @@ -1423,7 +1423,7 @@ dependencies = [ [[package]] name = "oxide_vm" -version = "0.16.7" +version = "0.16.8" dependencies = [ "bumpalo", "chrono", diff --git a/Cargo.toml b/Cargo.toml index f940591a..e6516677 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ members = [ ] [workspace.package] -version = "0.16.7" +version = "0.16.8" edition = "2021" license = "MIT" rust-version = "1.80" diff --git a/crates/oxide_emit/src/capture/captured.rs b/crates/oxide_emit/src/capture/captured.rs deleted file mode 100644 index b19fcf50..00000000 --- a/crates/oxide_emit/src/capture/captured.rs +++ /dev/null @@ -1,507 +0,0 @@ -//! 闭包捕获分析,父层捕获分析:本函数哪些绑定被任意深度嵌套函数捕获 -//! → BTreeMap(cell_idx 按名字排序分配,同一程序重编译得到相同索引, -//! 父 MAKE_CELL 与子函数 upvalue 引用同一 cell)。 - -use std::collections::{BTreeMap, HashSet}; - -use oxide_parser::{Declaration, ExportDefaultDeclarationKind, Expression, Statement}; - -use super::collect_fn_param_names; -use super::names::collect_own_binding_names; -use super::scanner::{ - collect_capture_names_expr, collect_capture_names_for_left, collect_capture_names_shadowed, - collect_class_capture_names, CaptureEngine, -}; - -/// 分析本函数:哪些绑定被任意深度嵌套函数捕获 → captured_bindings。 -/// -/// 本族以本函数 own 绑定集为过滤条件做捕获集的最终判定;`scanner.rs` 的 -/// `collect_capture_names_*` 族带显式 `ref_set`/`shadow`,按过滤条件收集引用名。 -pub(crate) fn collect_captured_bindings( - stmts: &[Statement], extra_exprs: &[&oxide_parser::Expression], own: &HashSet, -) -> BTreeMap { - let mut names = HashSet::new(); - for stmt in stmts { - collect_captured_stmt(stmt, own, &mut names); - } - // 参数默认值表达式里的引用同样纳入捕获分析:默认值位于函数体之外,其中的 - // 嵌套函数引用全局或外层变量时,若未登记进捕获集,发射期会走 LOAD_VAR 读到 - // 寄存器残留值。 - for expr in extra_exprs { - collect_captured_expr(expr, own, &mut names); - } - // 名字排序分配 cell_idx(稳定跨 run,父 MAKE_CELL 与子 upvalue 统一引用) - let mut sorted: Vec = names.into_iter().collect(); - sorted.sort(); - sorted.into_iter().enumerate().map(|(i, n)| (n, i as u8)).collect() -} - -/// 收集函数参数默认值表达式里的嵌套函数引用(父层 captured/子层 upvalue 判定)。 -pub(crate) fn collect_fn_default_captured( - params: &oxide_parser::FormalParameters, own: &HashSet, out: &mut HashSet, -) { - for p in ¶ms.items { - if let Some(init) = &p.initializer { - let mut eng = CaptureEngine::new(own, HashSet::new(), out); - collect_capture_names_expr(init, &mut eng); - } - // 形参模式的运行时求值表达式(计算键/内嵌默认值)在子作用域求值, - // 其标识符引用须纳入父层 MAKE_CELL 判定。 - collect_captured_pattern_runtime_exprs(&p.pattern, own, out); - } -} - -/// 遍历绑定 pattern 内全部运行时求值表达式(计算键与 AssignmentPattern 默认值): -/// 这些表达式在子作用域(嵌套函数形参绑定时)求值,引用的父层绑定须建 cell 供 -/// 子函数 upvalue 读取——与 `collect_capture_names_expr` 同口径(标识符比对)。 -pub(crate) fn collect_captured_pattern_runtime_exprs( - pattern: &oxide_parser::BindingPattern, own: &HashSet, out: &mut HashSet, -) { - match pattern { - oxide_parser::BindingPattern::BindingIdentifier(_) => {} - oxide_parser::BindingPattern::ArrayPattern(ap) => { - for p in ap.elements.iter().flatten() { - collect_captured_pattern_runtime_exprs(p, own, out); - } - if let Some(rest) = &ap.rest { - collect_captured_pattern_runtime_exprs(&rest.argument, own, out); - } - } - oxide_parser::BindingPattern::ObjectPattern(op) => { - for prop in &op.properties { - if prop.computed { - let mut eng = CaptureEngine::new(own, HashSet::new(), out); - collect_capture_names_expr(prop.key.to_expression(), &mut eng); - } - collect_captured_pattern_runtime_exprs(&prop.value, own, out); - } - if let Some(rest) = &op.rest { - collect_captured_pattern_runtime_exprs(&rest.argument, own, out); - } - } - oxide_parser::BindingPattern::AssignmentPattern(ap) => { - let mut eng = CaptureEngine::new(own, HashSet::new(), out); - collect_capture_names_expr(&ap.right, &mut eng); - collect_captured_pattern_runtime_exprs(&ap.left, own, out); - } - } -} - -/// 只从嵌套函数节点进入扫描(本函数直接引用不算捕获)。 -pub(crate) fn collect_captured_stmt(stmt: &Statement, own: &HashSet, out: &mut HashSet) { - match stmt { - Statement::FunctionDeclaration(fd) => { - let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); - collect_fn_default_captured(&fd.params, own, out); - // 函数参数与体内部声明遮蔽父级绑定:体内对这些名字的引用不算捕获父级。 - let mut fn_shadow = HashSet::new(); - fn_shadow.extend(collect_fn_param_names(&fd.params)); - fn_shadow.extend(collect_own_binding_names(&[], body)); - let mut eng = CaptureEngine::new(own, fn_shadow, out); - collect_capture_names_shadowed(body, &mut eng); - } - Statement::ClassDeclaration(cd) => { - // 类构造器/方法体与字段表达式引用的父级绑定须建 cell,供子模块 upvalue 捕获。 - let mut class_shadow = HashSet::new(); - if let Some(id) = &cd.id { - class_shadow.insert(id.name.as_str().to_string()); - } - let mut eng = CaptureEngine::new(own, class_shadow, out); - collect_class_capture_names(&cd.body, &mut eng); - } - // export 包裹的变量/函数/类声明:捕获分析须下探声明体,否则被导出函数体内 - // 引用模块绑定(含自引用)不会被识别为捕获,闭包内读写退化为隐式全局。 - Statement::ExportNamedDeclaration(exp) => { - if let Some(decl) = &exp.declaration { - match decl { - Declaration::VariableDeclaration(vd) => { - for d in &vd.declarations { - collect_captured_binding_keys(&d.id, own, out); - if let Some(init) = &d.init { - collect_captured_expr(init, own, out); - } - } - } - Declaration::FunctionDeclaration(fd) => { - let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); - collect_fn_default_captured(&fd.params, own, out); - let mut fn_shadow = HashSet::new(); - fn_shadow.extend(collect_fn_param_names(&fd.params)); - fn_shadow.extend(collect_own_binding_names(&[], body)); - let mut eng = CaptureEngine::new(own, fn_shadow, out); - collect_capture_names_shadowed(body, &mut eng); - } - Declaration::ClassDeclaration(cd) => { - let mut class_shadow = HashSet::new(); - if let Some(id) = &cd.id { - class_shadow.insert(id.name.as_str().to_string()); - } - let mut eng = CaptureEngine::new(own, class_shadow, out); - collect_class_capture_names(&cd.body, &mut eng); - } - _ => {} - } - } - } - Statement::ExportDefaultDeclaration(exp) => match &exp.declaration { - ExportDefaultDeclarationKind::FunctionDeclaration(fd) => { - let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); - collect_fn_default_captured(&fd.params, own, out); - let mut fn_shadow = HashSet::new(); - fn_shadow.extend(collect_fn_param_names(&fd.params)); - fn_shadow.extend(collect_own_binding_names(&[], body)); - let mut eng = CaptureEngine::new(own, fn_shadow, out); - collect_capture_names_shadowed(body, &mut eng); - } - ExportDefaultDeclarationKind::ClassDeclaration(cd) => { - let mut class_shadow = HashSet::new(); - if let Some(id) = &cd.id { - class_shadow.insert(id.name.as_str().to_string()); - } - let mut eng = CaptureEngine::new(own, class_shadow, out); - collect_class_capture_names(&cd.body, &mut eng); - } - other => { - if let Some(e) = other.as_expression() { - collect_captured_expr(e, own, out); - } - } - }, - Statement::ExpressionStatement(es) => collect_captured_expr(&es.expression, own, out), - Statement::ReturnStatement(rs) => { - if let Some(a) = &rs.argument { - collect_captured_expr(a, own, out); - } - } - Statement::VariableDeclaration(vd) => { - for d in &vd.declarations { - // 绑定 pattern 的计算键是运行时求值表达式,其引用须纳入捕获判定。 - collect_captured_binding_keys(&d.id, own, out); - if let Some(init) = &d.init { - collect_captured_expr(init, own, out); - } - } - } - Statement::IfStatement(is) => { - collect_captured_expr(&is.test, own, out); - collect_captured_stmt(&is.consequent, own, out); - if let Some(alt) = &is.alternate { - collect_captured_stmt(alt, own, out); - } - } - Statement::ForStatement(fs) => { - if let Some(init) = &fs.init { - if let Some(e) = init.as_expression() { - collect_captured_expr(e, own, out); - } - if let oxide_parser::ForStatementInit::VariableDeclaration(vd) = init { - for d in &vd.declarations { - collect_captured_binding_keys(&d.id, own, out); - if let Some(i) = &d.init { - collect_captured_expr(i, own, out); - } - } - } - } - if let Some(t) = &fs.test { - collect_captured_expr(t, own, out); - } - if let Some(u) = &fs.update { - collect_captured_expr(u, own, out); - } - collect_captured_stmt(&fs.body, own, out); - } - Statement::WhileStatement(w) => { - collect_captured_expr(&w.test, own, out); - collect_captured_stmt(&w.body, own, out); - } - Statement::DoWhileStatement(d) => { - collect_captured_stmt(&d.body, own, out); - collect_captured_expr(&d.test, own, out); - } - Statement::ForInStatement(fi) => { - collect_captured_expr(&fi.right, own, out); - if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fi.left { - for d in &vd.declarations { - collect_captured_binding_keys(&d.id, own, out); - } - } else { - // 赋值头是既有绑定引用:头名与默认值表达式须纳入捕获判定。 - let mut eng = CaptureEngine::new(own, HashSet::new(), out); - collect_capture_names_for_left(&fi.left, &mut eng); - } - collect_captured_stmt(&fi.body, own, out); - } - Statement::ForOfStatement(fo) => { - collect_captured_expr(&fo.right, own, out); - if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fo.left { - for d in &vd.declarations { - collect_captured_binding_keys(&d.id, own, out); - } - } else { - let mut eng = CaptureEngine::new(own, HashSet::new(), out); - collect_capture_names_for_left(&fo.left, &mut eng); - } - collect_captured_stmt(&fo.body, own, out); - } - Statement::BlockStatement(b) => { - for s in &b.body { - collect_captured_stmt(s, own, out); - } - } - Statement::TryStatement(ts) => { - for s in &ts.block.body { - collect_captured_stmt(s, own, out); - } - if let Some(h) = &ts.handler { - if let Some(param) = &h.param { - collect_captured_binding_pattern(¶m.pattern, own, out); - } - for s in &h.body.body { - collect_captured_stmt(s, own, out); - } - } - if let Some(f) = &ts.finalizer { - for s in &f.body { - collect_captured_stmt(s, own, out); - } - } - } - Statement::ThrowStatement(ts) => collect_captured_expr(&ts.argument, own, out), - Statement::SwitchStatement(sw) => { - collect_captured_expr(&sw.discriminant, own, out); - for case in &sw.cases { - for s in &case.consequent { - collect_captured_stmt(s, own, out); - } - } - } - Statement::LabeledStatement(ls) => collect_captured_stmt(&ls.body, own, out), - Statement::WithStatement(ws) => { - collect_captured_expr(&ws.object, own, out); - collect_captured_stmt(&ws.body, own, out); - } - _ => {} - } -} - -/// 遍历 catch 参数解构模式内表达式引用(默认值等),供父层 MAKE_CELL 判定。 -pub(crate) fn collect_captured_binding_pattern( - pattern: &oxide_parser::BindingPattern, own: &HashSet, out: &mut HashSet, -) { - match pattern { - oxide_parser::BindingPattern::BindingIdentifier(_) => {} - oxide_parser::BindingPattern::ArrayPattern(ap) => { - for p in ap.elements.iter().flatten() { - collect_captured_binding_pattern(p, own, out); - } - if let Some(rest) = &ap.rest { - collect_captured_binding_pattern(&rest.argument, own, out); - } - } - oxide_parser::BindingPattern::ObjectPattern(op) => { - for prop in &op.properties { - // 计算键表达式(本作用域 catch 参数求值,含 IIFE 等嵌套函数)引用 - // 本函数绑定走寄存器,只须扫描键内嵌套函数表达式。 - if prop.computed { - collect_captured_expr(prop.key.to_expression(), own, out); - } - collect_captured_binding_pattern(&prop.value, own, out); - } - if let Some(rest) = &op.rest { - collect_captured_binding_pattern(&rest.argument, own, out); - } - } - oxide_parser::BindingPattern::AssignmentPattern(ap) => { - collect_captured_expr(&ap.right, own, out); - collect_captured_binding_pattern(&ap.left, own, out); - } - } -} - -/// 遍历绑定 pattern 的运行时求值表达式引用:计算键(`{[k]: a}` 的键)与内嵌 -/// 默认值(`{a = x}` 的 x),供父层捕获判定(声明语句/for 头的模式与 catch/ -/// 默认值路径同口径)。 -pub(crate) fn collect_captured_binding_keys( - pattern: &oxide_parser::BindingPattern, own: &HashSet, out: &mut HashSet, -) { - match pattern { - oxide_parser::BindingPattern::BindingIdentifier(_) => {} - oxide_parser::BindingPattern::ArrayPattern(ap) => { - for p in ap.elements.iter().flatten() { - collect_captured_binding_keys(p, own, out); - } - if let Some(rest) = &ap.rest { - collect_captured_binding_keys(&rest.argument, own, out); - } - } - oxide_parser::BindingPattern::ObjectPattern(op) => { - for prop in &op.properties { - if prop.computed { - collect_captured_expr(prop.key.to_expression(), own, out); - } - collect_captured_binding_keys(&prop.value, own, out); - } - if let Some(rest) = &op.rest { - collect_captured_binding_keys(&rest.argument, own, out); - } - } - oxide_parser::BindingPattern::AssignmentPattern(ap) => { - // 内嵌默认值表达式引用外层绑定须建 cell(与 captured_binding_pattern - // 同口径);left 继续递归模式键。 - collect_captured_expr(&ap.right, own, out); - collect_captured_binding_keys(&ap.left, own, out); - } - } -} - -/// 以本函数 own 绑定集为过滤条件,判定表达式内嵌套函数捕获了哪些父绑定。与 -/// `scanner.rs` 的 `collect_capture_names_expr` 相比,本函数以 own 为过滤条件做 -/// 捕获最终判定,不接收显式 `ref_set`/`shadow`。 -pub(crate) fn collect_captured_expr(expr: &Expression, own: &HashSet, out: &mut HashSet) { - match expr { - Expression::FunctionExpression(fe) => { - let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); - let mut inner = collect_fn_param_names(&fe.params); - inner.extend(collect_own_binding_names(&[], body)); - collect_fn_default_captured(&fe.params, own, out); - let mut eng = CaptureEngine::new(own, inner, out); - collect_capture_names_shadowed(body, &mut eng); - } - Expression::ArrowFunctionExpression(ae) => { - let mut inner = collect_fn_param_names(&ae.params); - inner.extend(collect_own_binding_names(&[], &ae.body.statements)); - collect_fn_default_captured(&ae.params, own, out); - let mut eng = CaptureEngine::new(own, inner, out); - collect_capture_names_shadowed(&ae.body.statements, &mut eng); - } - Expression::ClassExpression(class) => { - // 类表达式:构造器/方法体与字段表达式引用的父级绑定须建 cell。 - let mut class_shadow = HashSet::new(); - if let Some(id) = &class.id { - class_shadow.insert(id.name.as_str().to_string()); - } - let mut eng = CaptureEngine::new(own, class_shadow, out); - collect_class_capture_names(&class.body, &mut eng); - } - Expression::CallExpression(ce) => { - collect_captured_expr(&ce.callee, own, out); - for a in &ce.arguments { - collect_captured_arg(a, own, out); - } - } - Expression::BinaryExpression(be) => { - collect_captured_expr(&be.left, own, out); - collect_captured_expr(&be.right, own, out); - } - Expression::UnaryExpression(ue) => collect_captured_expr(&ue.argument, own, out), - Expression::LogicalExpression(le) => { - collect_captured_expr(&le.left, own, out); - collect_captured_expr(&le.right, own, out); - } - Expression::ConditionalExpression(ce) => { - collect_captured_expr(&ce.test, own, out); - collect_captured_expr(&ce.consequent, own, out); - collect_captured_expr(&ce.alternate, own, out); - } - Expression::SequenceExpression(se) => { - for e in &se.expressions { - collect_captured_expr(e, own, out); - } - } - Expression::AssignmentExpression(ae) => { - // 只扫右侧:左侧赋值目标是本函数绑定,不引用嵌套函数; - // 若目标含嵌套函数表达式(如 `[f()] = ...`),由其自身递归处理。 - collect_captured_expr(&ae.right, own, out); - } - Expression::UpdateExpression(_ue) => {} // 一元更新目标不引用嵌套函数,无需捕获 - Expression::ArrayExpression(ae) => { - for e in &ae.elements { - if let Some(e) = e.as_expression() { - collect_captured_expr(e, own, out); - } - } - } - Expression::ObjectExpression(o) => { - for prop in &o.properties { - match prop { - oxide_parser::ObjectPropertyKind::ObjectProperty(p) => { - if p.computed { - collect_captured_expr(p.key.to_expression(), own, out); - } - collect_captured_expr(&p.value, own, out); - } - oxide_parser::ObjectPropertyKind::SpreadProperty(spread) => { - collect_captured_expr(&spread.argument, own, out); - } - } - } - } - Expression::NewExpression(ne) => { - collect_captured_expr(&ne.callee, own, out); - for a in &ne.arguments { - collect_captured_arg(a, own, out); - } - } - Expression::ComputedMemberExpression(m) => { - collect_captured_expr(&m.object, own, out); - collect_captured_expr(&m.expression, own, out); - } - Expression::StaticMemberExpression(m) => collect_captured_expr(&m.object, own, out), - Expression::PrivateFieldExpression(m) => collect_captured_expr(&m.object, own, out), - Expression::TemplateLiteral(tl) => { - for e in &tl.expressions { - collect_captured_expr(e, own, out); - } - } - Expression::TaggedTemplateExpression(tt) => { - collect_captured_expr(&tt.tag, own, out); - for e in &tt.quasi.expressions { - collect_captured_expr(e, own, out); - } - } - Expression::ParenthesizedExpression(p) => collect_captured_expr(&p.expression, own, out), - Expression::YieldExpression(ye) => { - if let Some(a) = &ye.argument { - collect_captured_expr(a, own, out); - } - } - Expression::AwaitExpression(ae) => collect_captured_expr(&ae.argument, own, out), - Expression::ChainExpression(c) => collect_captured_chain(&c.expression, own, out), - _ => {} - } -} - -/// 遍历可选链元素,判定链上表达式对父绑定的捕获。 -pub(crate) fn collect_captured_chain( - element: &oxide_parser::ChainElement, own: &HashSet, out: &mut HashSet, -) { - match element { - oxide_parser::ChainElement::StaticMemberExpression(m) => { - collect_captured_expr(&m.object, own, out); - } - oxide_parser::ChainElement::ComputedMemberExpression(m) => { - collect_captured_expr(&m.object, own, out); - collect_captured_expr(&m.expression, own, out); - } - oxide_parser::ChainElement::PrivateFieldExpression(m) => { - collect_captured_expr(&m.object, own, out); - } - oxide_parser::ChainElement::CallExpression(c) => { - collect_captured_expr(&c.callee, own, out); - for a in &c.arguments { - collect_captured_arg(a, own, out); - } - } - _ => {} - } -} - -/// 遍历调用实参:静态实参与 spread 内部表达式都纳入捕获判定。 -pub(crate) fn collect_captured_arg(arg: &oxide_parser::Argument, own: &HashSet, out: &mut HashSet) { - if let Some(e) = arg.as_expression() { - collect_captured_expr(e, own, out); - } else if let oxide_parser::Argument::SpreadElement(sp) = arg { - collect_captured_expr(&sp.argument, own, out); - } -} diff --git a/crates/oxide_emit/src/capture/guard.rs b/crates/oxide_emit/src/capture/guard.rs deleted file mode 100644 index 26a365b8..00000000 --- a/crates/oxide_emit/src/capture/guard.rs +++ /dev/null @@ -1,246 +0,0 @@ -//! 闭包捕获分析早退守卫:扫描语句树与附加表达式,判定是否存在嵌套函数/类节点, -//! 无嵌套时使捕获集收集(collect_captured_bindings,仅从嵌套函数/类节点产出名字) -//! 整体跳过。 -//! -//! 关键约定:守卫臂集须与 `captured.rs` / `scanner.rs` 两收集器同步——新增 parser -//! 臂引入函数/类节点入口时三处同改;守卫漏任一入口臂即假阴,跳过捕获集收集导致 -//! 嵌套函数 upvalue 捕获丢失。 - -use oxide_parser::{ - Argument, AssignmentTarget, AssignmentTargetMaybeDefault, BindingPattern, ChainElement, Declaration, - ExportDefaultDeclarationKind, Expression, ForStatementLeft, SimpleAssignmentTarget, Statement, -}; - -/// 扫描语句树与附加表达式,判定是否存在嵌套函数/类节点(早退)。 -/// -/// 命中首个函数/类节点(函数声明/表达式、箭头函数、类声明/表达式)立即返回真, -/// 不分配任何集合、不克隆遮蔽集,单趟只读遍历显著轻于捕获集收集(每层嵌套函数 -/// 克隆遮蔽集并再遍历)。 -/// -/// # 边界与前提 -/// - `extra_exprs` 为参数默认值与类字段值表达式(位于函数体之外),与体同臂扫描。 -/// - 臂集与 `captured.rs` / `scanner.rs` 两收集器逐臂对齐(含 pattern 计算键、 -/// for 赋值头、catch 参数、export 包裹臂);新增 parser 臂引入函数/类节点入口 -/// 时三处同改。 -/// -/// # 注意事项 -/// - 守卫是跳过捕获集收集的必要条件:假阴(漏扫)丢 upvalue 捕获、读错 cell; -/// 假阳(多扫)仅使捕获集收集照跑,安全。 -pub(crate) fn has_nested_function(stmts: &[Statement], extra_exprs: &[&Expression]) -> bool { - for stmt in stmts { - if scan_stmt(stmt) { - return true; - } - } - for expr in extra_exprs { - if scan_expr(expr) { - return true; - } - } - false -} - -/// 扫描语句树:函数/类声明节点立即返回真,其余臂递归其表达式子节点,臂集与 -/// 两收集器一致。 -fn scan_stmt(stmt: &Statement) -> bool { - match stmt { - Statement::FunctionDeclaration(_) | Statement::ClassDeclaration(_) => true, - // export 包裹的声明:变量/函数/类声明体须下探。 - Statement::ExportNamedDeclaration(exp) => match &exp.declaration { - Some(Declaration::VariableDeclaration(vd)) => scan_var_decl(vd), - Some(Declaration::FunctionDeclaration(_)) | Some(Declaration::ClassDeclaration(_)) => true, - _ => false, - }, - Statement::ExportDefaultDeclaration(exp) => match &exp.declaration { - ExportDefaultDeclarationKind::FunctionDeclaration(_) - | ExportDefaultDeclarationKind::ClassDeclaration(_) => true, - other => other.as_expression().is_some_and(scan_expr), - }, - Statement::ExpressionStatement(es) => scan_expr(&es.expression), - Statement::ReturnStatement(rs) => rs.argument.as_ref().is_some_and(scan_expr), - Statement::VariableDeclaration(vd) => scan_var_decl(vd), - Statement::IfStatement(is) => { - scan_expr(&is.test) || scan_stmt(&is.consequent) || is.alternate.as_ref().is_some_and(scan_stmt) - } - Statement::ForStatement(fs) => { - let init = fs.init.as_ref().is_some_and(|init| { - if let Some(e) = init.as_expression() { - scan_expr(e) - } else if let oxide_parser::ForStatementInit::VariableDeclaration(vd) = init { - scan_var_decl(vd) - } else { - false - } - }); - init || fs.test.as_ref().is_some_and(scan_expr) - || fs.update.as_ref().is_some_and(scan_expr) - || scan_stmt(&fs.body) - } - Statement::WhileStatement(w) => scan_expr(&w.test) || scan_stmt(&w.body), - Statement::DoWhileStatement(d) => scan_stmt(&d.body) || scan_expr(&d.test), - Statement::ForInStatement(fi) => scan_expr(&fi.right) || scan_for_left(&fi.left) || scan_stmt(&fi.body), - Statement::ForOfStatement(fo) => scan_expr(&fo.right) || scan_for_left(&fo.left) || scan_stmt(&fo.body), - Statement::BlockStatement(b) => b.body.iter().any(scan_stmt), - Statement::TryStatement(ts) => { - ts.block.body.iter().any(scan_stmt) - || ts.handler.as_ref().is_some_and(|h| { - // catch 参数 pattern 的内嵌默认值可含嵌套函数。 - h.param.as_ref().is_some_and(|p| scan_binding_keys(&p.pattern)) || h.body.body.iter().any(scan_stmt) - }) - || ts.finalizer.as_ref().is_some_and(|f| f.body.iter().any(scan_stmt)) - } - Statement::ThrowStatement(ts) => scan_expr(&ts.argument), - Statement::SwitchStatement(sw) => { - scan_expr(&sw.discriminant) || sw.cases.iter().any(|c| c.consequent.iter().any(scan_stmt)) - } - Statement::LabeledStatement(ls) => scan_stmt(&ls.body), - Statement::WithStatement(ws) => scan_expr(&ws.object) || scan_stmt(&ws.body), - _ => false, - } -} - -/// 变量声明:绑定 pattern 的计算键与内嵌默认值是运行时求值表达式,与初始化式 -/// 同臂扫描。 -fn scan_var_decl(vd: &oxide_parser::VariableDeclaration) -> bool { - vd.declarations - .iter() - .any(|d| scan_binding_keys(&d.id) || d.init.as_ref().is_some_and(scan_expr)) -} - -/// 遍历绑定 pattern 内运行时求值表达式:计算键(`{[k]: a}` 的键)与内嵌默认值 -/// (`[x = expr]`),与 catch 参数 pattern 同形。 -fn scan_binding_keys(pattern: &BindingPattern) -> bool { - match pattern { - BindingPattern::BindingIdentifier(_) => false, - BindingPattern::ArrayPattern(ap) => { - ap.elements.iter().flatten().any(scan_binding_keys) - || ap.rest.as_ref().is_some_and(|rest| scan_binding_keys(&rest.argument)) - } - BindingPattern::ObjectPattern(op) => { - op.properties - .iter() - .any(|prop| (prop.computed && scan_expr(prop.key.to_expression())) || scan_binding_keys(&prop.value)) - || op.rest.as_ref().is_some_and(|rest| scan_binding_keys(&rest.argument)) - } - BindingPattern::AssignmentPattern(ap) => scan_expr(&ap.right) || scan_binding_keys(&ap.left), - } -} - -/// for-in/for-of 头:声明头扫 pattern 键,赋值头扫解构目标元素(含默认值)。 -fn scan_for_left(left: &ForStatementLeft) -> bool { - match left { - ForStatementLeft::VariableDeclaration(vd) => scan_var_decl(vd), - ForStatementLeft::ArrayAssignmentTarget(a) => scan_array_target(a), - ForStatementLeft::ObjectAssignmentTarget(o) => scan_object_target(o), - _ => false, - } -} - -/// 赋值目标:成员目标扫对象/键,解构目标扫元素(含默认值)。 -fn scan_assign_target(target: &AssignmentTarget) -> bool { - match target { - AssignmentTarget::StaticMemberExpression(m) => scan_expr(&m.object), - AssignmentTarget::ComputedMemberExpression(m) => scan_expr(&m.object) || scan_expr(&m.expression), - AssignmentTarget::ArrayAssignmentTarget(a) => scan_array_target(a), - AssignmentTarget::ObjectAssignmentTarget(o) => scan_object_target(o), - _ => false, - } -} - -/// 数组赋值目标:元素(含默认值)与 rest 目标。 -fn scan_array_target(a: &oxide_parser::ArrayAssignmentTarget) -> bool { - a.elements.iter().flatten().any(scan_maybe_default_target) - || a.rest.as_ref().is_some_and(|rest| scan_assign_target(&rest.target)) -} - -/// 对象赋值目标:属性标识符默认值、属性名表达式、绑定目标与 rest。 -fn scan_object_target(o: &oxide_parser::ObjectAssignmentTarget) -> bool { - o.properties.iter().any(|prop| match prop { - oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(id) => { - id.init.as_ref().is_some_and(scan_expr) - } - oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyProperty(p) => { - p.name.as_expression().is_some_and(scan_expr) || scan_maybe_default_target(&p.binding) - } - }) || o.rest.as_ref().is_some_and(|rest| scan_assign_target(&rest.target)) -} - -/// 解构赋值元素:带默认值的元素多一层(默认值表达式加绑定目标)。 -fn scan_maybe_default_target(target: &AssignmentTargetMaybeDefault) -> bool { - match target { - AssignmentTargetMaybeDefault::AssignmentTargetWithDefault(d) => { - scan_expr(&d.init) || scan_assign_target(&d.binding) - } - AssignmentTargetMaybeDefault::StaticMemberExpression(m) => scan_expr(&m.object), - AssignmentTargetMaybeDefault::ComputedMemberExpression(m) => scan_expr(&m.object) || scan_expr(&m.expression), - AssignmentTargetMaybeDefault::ArrayAssignmentTarget(a) => scan_array_target(a), - AssignmentTargetMaybeDefault::ObjectAssignmentTarget(o) => scan_object_target(o), - _ => false, - } -} - -/// 一元更新目标:成员目标扫对象/键。 -fn scan_simple_target(target: &SimpleAssignmentTarget) -> bool { - match target { - SimpleAssignmentTarget::StaticMemberExpression(m) => scan_expr(&m.object), - SimpleAssignmentTarget::ComputedMemberExpression(m) => scan_expr(&m.object) || scan_expr(&m.expression), - _ => false, - } -} - -/// 扫描表达式树:函数/类表达式节点立即返回真,其余臂递归,臂集与两收集器一致。 -fn scan_expr(expr: &Expression) -> bool { - match expr { - Expression::FunctionExpression(_) | Expression::ArrowFunctionExpression(_) | Expression::ClassExpression(_) => { - true - } - Expression::CallExpression(ce) => scan_expr(&ce.callee) || ce.arguments.iter().any(scan_arg), - Expression::NewExpression(ne) => scan_expr(&ne.callee) || ne.arguments.iter().any(scan_arg), - Expression::BinaryExpression(be) => scan_expr(&be.left) || scan_expr(&be.right), - Expression::UnaryExpression(ue) => scan_expr(&ue.argument), - Expression::LogicalExpression(le) => scan_expr(&le.left) || scan_expr(&le.right), - Expression::ConditionalExpression(ce) => { - scan_expr(&ce.test) || scan_expr(&ce.consequent) || scan_expr(&ce.alternate) - } - Expression::SequenceExpression(se) => se.expressions.iter().any(scan_expr), - // 赋值目标侧也可含嵌套函数(解构目标默认值),左右同扫。 - Expression::AssignmentExpression(ae) => scan_assign_target(&ae.left) || scan_expr(&ae.right), - Expression::UpdateExpression(ue) => scan_simple_target(&ue.argument), - Expression::ArrayExpression(ae) => ae.elements.iter().any(|e| e.as_expression().is_some_and(scan_expr)), - Expression::ObjectExpression(o) => o.properties.iter().any(|prop| match prop { - oxide_parser::ObjectPropertyKind::ObjectProperty(p) => { - (p.computed && scan_expr(p.key.to_expression())) || scan_expr(&p.value) - } - oxide_parser::ObjectPropertyKind::SpreadProperty(spread) => scan_expr(&spread.argument), - }), - Expression::ComputedMemberExpression(m) => scan_expr(&m.object) || scan_expr(&m.expression), - Expression::StaticMemberExpression(m) => scan_expr(&m.object), - Expression::PrivateFieldExpression(m) => scan_expr(&m.object), - Expression::TemplateLiteral(tl) => tl.expressions.iter().any(scan_expr), - Expression::TaggedTemplateExpression(tt) => scan_expr(&tt.tag) || tt.quasi.expressions.iter().any(scan_expr), - Expression::ParenthesizedExpression(p) => scan_expr(&p.expression), - Expression::YieldExpression(ye) => ye.argument.as_ref().is_some_and(scan_expr), - Expression::AwaitExpression(ae) => scan_expr(&ae.argument), - Expression::ChainExpression(c) => scan_chain(&c.expression), - _ => false, - } -} - -/// 遍历可选链元素:成员访问、调用与实参。 -fn scan_chain(element: &ChainElement) -> bool { - match element { - ChainElement::StaticMemberExpression(m) => scan_expr(&m.object), - ChainElement::ComputedMemberExpression(m) => scan_expr(&m.object) || scan_expr(&m.expression), - ChainElement::PrivateFieldExpression(m) => scan_expr(&m.object), - ChainElement::CallExpression(c) => scan_expr(&c.callee) || c.arguments.iter().any(scan_arg), - _ => false, - } -} - -/// 调用实参:静态实参与 spread 内部表达式。 -fn scan_arg(arg: &Argument) -> bool { - match arg { - Argument::SpreadElement(sp) => scan_expr(&sp.argument), - _ => arg.as_expression().is_some_and(scan_expr), - } -} diff --git a/crates/oxide_emit/src/capture/mod.rs b/crates/oxide_emit/src/capture/mod.rs index 595d337b..0d7bf760 100644 --- a/crates/oxide_emit/src/capture/mod.rs +++ b/crates/oxide_emit/src/capture/mod.rs @@ -5,22 +5,19 @@ //! 相同索引,保证父 MAKE_CELL 与子函数 upvalue 引用同一 cell),为 MAKE_CELL / //! CELL_GET / CELL_SET 与子函数 upvalue cell_idx 提供统一依据。 //! -//! 五区严格单向分层(本文件 ← names ← scanner ← captured ← upvalues): +//! 四区严格单向分层(本文件 ← names ← scanner ← upvalues): //! 跨区调用单向、无共享局部状态、无接收者状态。 -mod captured; -mod guard; mod names; mod scanner; mod upvalues; use std::collections::HashSet; -pub(crate) use captured::collect_captured_bindings; -pub(crate) use guard::has_nested_function; pub(crate) use names::collect_fn_scope_names; pub(crate) use names::FnScopeNames; -pub(crate) use upvalues::collect_upvalue_names; +pub(crate) use upvalues::collect_captured_bindings; +pub(crate) use upvalues::collect_captures_and_upvalues; /// 收集形参(含 rest)绑定的名字集,作为本函数作用域的遮蔽集。 pub(crate) fn collect_fn_param_names(params: &oxide_parser::FormalParameters) -> HashSet { diff --git a/crates/oxide_emit/src/capture/scanner.rs b/crates/oxide_emit/src/capture/scanner.rs index 2b6a18e3..140deacd 100644 --- a/crates/oxide_emit/src/capture/scanner.rs +++ b/crates/oxide_emit/src/capture/scanner.rs @@ -1,6 +1,7 @@ -//! 闭包捕获分析,遮蔽感知引用收集:`CaptureEngine` 捆绑 ref_set(关注名集)× -//! shadow(遮蔽名集)× out(输出累加器)三集,遍历语句/表达式/赋值目标/类体 -//! AST,嵌套函数/类/for 头/catch 参数逐层遮蔽,收集任意深度嵌套函数引用的名字。 +//! 闭包捕获分析,遮蔽感知引用收集:`CaptureEngine` 捆绑双引用集(own × +//! parent_names)× shadow(遮蔽名集)× 双输出累加器(captured_out × +//! upvalue_out)× depth(嵌套深度),遍历语句/表达式/赋值目标/类体 AST,嵌套 +//! 函数/类/for 头/catch 参数逐层遮蔽,按深度分区写两输出。 use std::collections::HashSet; @@ -9,22 +10,60 @@ use oxide_parser::{ClassBody, ClassElement, Expression, Statement}; use super::names::collect_own_binding_names; use super::{collect_fn_param_names, collect_for_left_decl_names}; -/// 双引用集引擎:捆绑 ref_set(关注名集)、shadow(遮蔽名集)与 out(输出累加器) -/// 三集,本族十五个收集函数共享单一 `&mut CaptureEngine` 参数。作用域边界(嵌套 -/// 函数/类/for 头/catch 参数)对 shadow 集做保存/恢复,逐层遮蔽外层绑定。 +/// 双引用集引擎:捆绑 own(深度 ≥ 1 引用集)、parent_names(全深度引用集)、 +/// sub_own(upvalue 显式排除集)、shadow(遮蔽名集)、depth(嵌套深度)与双输出 +/// 累加器,本族十五个收集函数共享单一 `&mut CaptureEngine` 参数。作用域边界(嵌套 +/// 函数/类/for 头/catch 参数)对 shadow 集做保存/恢复,逐层遮蔽外层绑定;函数/类 +/// 边界对 depth 做增减,区分本函数体层与嵌套层。 pub(crate) struct CaptureEngine<'a> { - /// 关注名集:本次收集哪些名字(不可变)。 - ref_set: &'a HashSet, + /// 深度 ≥ 1 的引用集:本函数 own 绑定集(父层捕获判定)。 + own: &'a HashSet, + /// 全深度引用集:父捕获名 ∪ 父 upvalue 名(子层 upvalue 判定)。 + parent_names: &'a HashSet, + /// upvalue 判定的显式排除集:本函数 own 绑定集。 + sub_own: &'a HashSet, /// 遮蔽名集:当前作用域内被遮蔽、须排除的名字;作用域边界保存/恢复。 shadow: HashSet, - /// 输出累加器:本次收集到的名字。 - out: &'a mut HashSet, + /// 嵌套深度:0 = 本函数体层,≥ 1 = 嵌套函数/类内。 + depth: u32, + /// 输出累加器:被嵌套函数捕获的名字(父层捕获判定)。 + captured_out: &'a mut HashSet, + /// 输出累加器:子函数引用父被捕获绑定的名字(子层 upvalue 判定)。 + upvalue_out: &'a mut HashSet, } impl<'a> CaptureEngine<'a> { - /// 构造引擎:`ref_set` 为关注名集,`shadow` 为初始遮蔽名集,`out` 为输出累加器。 - pub(crate) fn new(ref_set: &'a HashSet, shadow: HashSet, out: &'a mut HashSet) -> Self { - CaptureEngine { ref_set, shadow, out } + /// 构造引擎:`own` 为深度 ≥ 1 引用集,`parent_names` 为全深度引用集, + /// `sub_own` 为 upvalue 显式排除集,`captured_out` 与 `upvalue_out` 为双输出 + /// 累加器。shadow 初始空,depth 初始 0。 + pub(crate) fn new( + own: &'a HashSet, + parent_names: &'a HashSet, + sub_own: &'a HashSet, + captured_out: &'a mut HashSet, + upvalue_out: &'a mut HashSet, + ) -> Self { + CaptureEngine { + own, + parent_names, + sub_own, + shadow: HashSet::new(), + depth: 0, + captured_out, + upvalue_out, + } + } + + /// 单一标识符检查点:按深度分区写两输出。 + /// 深度 ≥ 1 且名字在 own 且不在 shadow → captured_out; + /// 名字在 parent_names 且不在 shadow 且不在 sub_own → upvalue_out。 + fn check_identifier(&mut self, name: &str) { + if self.depth >= 1 && self.own.contains(name) && !self.shadow.contains(name) { + self.captured_out.insert(name.to_string()); + } + if self.parent_names.contains(name) && !self.shadow.contains(name) && !self.sub_own.contains(name) { + self.upvalue_out.insert(name.to_string()); + } } } @@ -58,21 +97,25 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi Statement::FunctionDeclaration(fd) => { let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); collect_fn_default_names(&fd.params, eng); - // 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复。 + // 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复,深度增一。 let saved = std::mem::take(&mut eng.shadow); eng.shadow.extend(collect_fn_param_names(&fd.params)); eng.shadow.extend(collect_own_binding_names(&[], body)); + eng.depth += 1; collect_capture_names_shadowed(body, eng); + eng.depth -= 1; eng.shadow = saved; } Statement::ClassDeclaration(cd) => { // 类体(构造器/方法体、字段键与值、静态块)是嵌套作用域: - // 类名遮蔽外层绑定,方法形参与方法体局部进一步遮蔽。 + // 类名遮蔽外层绑定,方法形参与方法体局部进一步遮蔽。深度增一。 let saved = std::mem::take(&mut eng.shadow); if let Some(id) = &cd.id { eng.shadow.insert(id.name.as_str().to_string()); } + eng.depth += 1; collect_class_capture_names(&cd.body, eng); + eng.depth -= 1; eng.shadow = saved; } Statement::IfStatement(is) => { @@ -181,7 +224,9 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi let saved = std::mem::take(&mut eng.shadow); eng.shadow.extend(collect_fn_param_names(&fd.params)); eng.shadow.extend(collect_own_binding_names(&[], body)); + eng.depth += 1; collect_capture_names_shadowed(body, eng); + eng.depth -= 1; eng.shadow = saved; } oxide_parser::Declaration::ClassDeclaration(cd) => { @@ -189,7 +234,9 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi if let Some(id) = &cd.id { eng.shadow.insert(id.name.as_str().to_string()); } + eng.depth += 1; collect_class_capture_names(&cd.body, eng); + eng.depth -= 1; eng.shadow = saved; } _ => {} @@ -203,7 +250,9 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi let saved = std::mem::take(&mut eng.shadow); eng.shadow.extend(collect_fn_param_names(&fd.params)); eng.shadow.extend(collect_own_binding_names(&[], body)); + eng.depth += 1; collect_capture_names_shadowed(body, eng); + eng.depth -= 1; eng.shadow = saved; } oxide_parser::ExportDefaultDeclarationKind::ClassDeclaration(cd) => { @@ -211,7 +260,9 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi if let Some(id) = &cd.id { eng.shadow.insert(id.name.as_str().to_string()); } + eng.depth += 1; collect_class_capture_names(&cd.body, eng); + eng.depth -= 1; eng.shadow = saved; } other => { @@ -367,10 +418,7 @@ pub(crate) fn collect_capture_names_binding_keys(pattern: &oxide_parser::Binding pub(crate) fn collect_capture_names_assign_target(target: &oxide_parser::AssignmentTarget, eng: &mut CaptureEngine) { match target { oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(ati) => { - let name = ati.name.as_str(); - if eng.ref_set.contains(name) && !eng.shadow.contains(name) { - eng.out.insert(ati.name.to_string()); - } + eng.check_identifier(ati.name.as_str()); } oxide_parser::AssignmentTarget::StaticMemberExpression(m) => { collect_capture_names_expr(&m.object, eng); @@ -408,9 +456,7 @@ fn collect_capture_names_array_target(a: &oxide_parser::ArrayAssignmentTarget, e fn collect_capture_names_object_target(o: &oxide_parser::ObjectAssignmentTarget, eng: &mut CaptureEngine) { for prop in &o.properties { if let oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(id) = prop { - if eng.ref_set.contains(id.binding.name.as_str()) && !eng.shadow.contains(id.binding.name.as_str()) { - eng.out.insert(id.binding.name.to_string()); - } + eng.check_identifier(id.binding.name.as_str()); if let Some(init) = &id.init { collect_capture_names_expr(init, eng); } @@ -431,10 +477,7 @@ fn collect_capture_names_object_target(o: &oxide_parser::ObjectAssignmentTarget, pub(crate) fn collect_capture_names_for_left(left: &oxide_parser::ForStatementLeft, eng: &mut CaptureEngine) { match left { oxide_parser::ForStatementLeft::AssignmentTargetIdentifier(id) => { - let name = id.name.as_str(); - if eng.ref_set.contains(name) && !eng.shadow.contains(name) { - eng.out.insert(name.to_string()); - } + eng.check_identifier(id.name.as_str()); } oxide_parser::ForStatementLeft::ArrayAssignmentTarget(a) => { collect_capture_names_array_target(a, eng); @@ -465,10 +508,7 @@ pub(crate) fn collect_capture_names_maybe_default_target( collect_capture_names_assign_target(&d.binding, eng); } MaybeDefault::AssignmentTargetIdentifier(ati) => { - let name = ati.name.as_str(); - if eng.ref_set.contains(name) && !eng.shadow.contains(name) { - eng.out.insert(ati.name.to_string()); - } + eng.check_identifier(ati.name.as_str()); } MaybeDefault::StaticMemberExpression(m) => { collect_capture_names_expr(&m.object, eng); @@ -485,10 +525,7 @@ pub(crate) fn collect_capture_names_maybe_default_target( MaybeDefault::ObjectAssignmentTarget(o) => { for prop in &o.properties { if let oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(id) = prop { - if eng.ref_set.contains(id.binding.name.as_str()) && !eng.shadow.contains(id.binding.name.as_str()) - { - eng.out.insert(id.binding.name.to_string()); - } + eng.check_identifier(id.binding.name.as_str()); if let Some(init) = &id.init { collect_capture_names_expr(init, eng); } @@ -515,10 +552,7 @@ pub(crate) fn collect_capture_names_simple_target( ) { match target { oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(ati) => { - let name = ati.name.as_str(); - if eng.ref_set.contains(name) && !eng.shadow.contains(name) { - eng.out.insert(ati.name.to_string()); - } + eng.check_identifier(ati.name.as_str()); } oxide_parser::SimpleAssignmentTarget::StaticMemberExpression(m) => { collect_capture_names_expr(&m.object, eng); @@ -555,10 +589,7 @@ pub(crate) fn collect_fn_default_names(params: &oxide_parser::FormalParameters, pub(crate) fn collect_capture_names_expr(expr: &Expression, eng: &mut CaptureEngine) { match expr { Expression::Identifier(id) => { - let name = id.name.as_str(); - if eng.ref_set.contains(name) && !eng.shadow.contains(name) { - eng.out.insert(id.name.to_string()); - } + eng.check_identifier(id.name.as_str()); } Expression::AssignmentExpression(ae) => { // 赋值目标里的引用也须捕获:标识符目标写名,成员/解构目标扫描其对象/元素。 @@ -571,28 +602,35 @@ pub(crate) fn collect_capture_names_expr(expr: &Expression, eng: &mut CaptureEng Expression::FunctionExpression(fe) => { let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); collect_fn_default_names(&fe.params, eng); - // 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复。 + // 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复,深度增一。 let saved = std::mem::take(&mut eng.shadow); eng.shadow.extend(collect_fn_param_names(&fe.params)); eng.shadow.extend(collect_own_binding_names(&[], body)); + eng.depth += 1; collect_capture_names_shadowed(body, eng); + eng.depth -= 1; eng.shadow = saved; } Expression::ArrowFunctionExpression(ae) => { collect_fn_default_names(&ae.params, eng); + // 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复,深度增一。 let saved = std::mem::take(&mut eng.shadow); eng.shadow.extend(collect_fn_param_names(&ae.params)); eng.shadow.extend(collect_own_binding_names(&[], &ae.body.statements)); + eng.depth += 1; collect_capture_names_shadowed(&ae.body.statements, eng); + eng.depth -= 1; eng.shadow = saved; } Expression::ClassExpression(class) => { - // 类表达式:方法/构造器体与字段表达式是嵌套作用域,引用须捕获。 + // 类表达式:方法/构造器体与字段表达式是嵌套作用域,引用须捕获。深度增一。 let saved = std::mem::take(&mut eng.shadow); if let Some(id) = &class.id { eng.shadow.insert(id.name.as_str().to_string()); } + eng.depth += 1; collect_class_capture_names(&class.body, eng); + eng.depth -= 1; eng.shadow = saved; } Expression::BinaryExpression(be) => { diff --git a/crates/oxide_emit/src/capture/upvalues.rs b/crates/oxide_emit/src/capture/upvalues.rs index cf85b2cb..8d13c55a 100644 --- a/crates/oxide_emit/src/capture/upvalues.rs +++ b/crates/oxide_emit/src/capture/upvalues.rs @@ -1,39 +1,55 @@ -//! 闭包捕获分析,子函数 upvalue 分析:子函数体对父被捕获绑定的引用 -//! → Vec(排序对齐 cell_idx,enclosing_reg 留 0 待 -//! assemble_ir 填充)。 +//! 闭包捕获分析,单入口收集:对同一 AST(body_stmts + extra_exprs)单趟产出 +//! 两个输出(captured_bindings 的 BTreeMap 与 upvalue_captures 的 Vec)。 +//! 顶层两个薄包装 `collect_captured_bindings` / `collect_upvalue_names` 签名不变, +//! 调用点不动。 use std::collections::{BTreeMap, HashSet}; use oxide_bytecode::module::UpvalueCapture; -use oxide_parser::Statement; +use oxide_parser::{Expression, Statement}; use super::scanner::{collect_capture_names_expr, collect_capture_names_shadowed, CaptureEngine}; -/// 分析子函数 body:引用父级被捕获绑定的名字 → upvalue_captures。 -/// 名字若在父 `captured_bindings`(父 own cell)则 `cell_idx` 索引定义方表; -/// 若在父 `upvalue_captures`(父自身从更外层捕获)则链式标记 `parent_uv_idx`, -/// 运行时从父闭包 upvalues 取 cell。enclosing_reg 由父 emit 完成后填充。 -pub(crate) fn collect_upvalue_names( - body_stmts: &[Statement], extra_exprs: &[&oxide_parser::Expression], parent_captured: &BTreeMap, - parent_upvalues: &[UpvalueCapture], sub_own: &HashSet, -) -> Vec { +/// 单入口:对同一 AST 单趟产出两个输出(captured_bindings 的 BTreeMap 与 +/// upvalue_captures 的 Vec)。`own` 为父层捕获判定引用集(深度 ≥ 1 生效), +/// `parent_captured` 与 `parent_upvalues` 为父层两映射(构建全深度引用集), +/// `sub_own` 为 upvalue 判定的显式排除集。 +pub(crate) fn collect_captures_and_upvalues( + body_stmts: &[Statement], + extra_exprs: &[&Expression], + own: &HashSet, + parent_captured: &BTreeMap, + parent_upvalues: &[UpvalueCapture], + sub_own: &HashSet, +) -> (BTreeMap, Vec) { + // 构建全深度引用集:父捕获名 ∪ 父 upvalue 名。 let mut parent_names: HashSet = parent_captured.keys().cloned().collect(); for u in parent_upvalues { parent_names.insert(u.name.clone()); } - let mut names = HashSet::new(); - let mut eng = CaptureEngine::new(&parent_names, sub_own.clone(), &mut names); + + // 双输出累加器。 + let mut captured_out: HashSet = HashSet::new(); + let mut upvalue_out: HashSet = HashSet::new(); + + // 构造引擎并扫描。 + let mut eng = CaptureEngine::new(own, &parent_names, sub_own, &mut captured_out, &mut upvalue_out); collect_capture_names_shadowed(body_stmts, &mut eng); - // 参数默认值表达式(不在 body_stmts)里的嵌套函数引用也会捕获父变量。 for expr in extra_exprs { collect_capture_names_expr(expr, &mut eng); } - // HashSet 迭代序带随机种子(进程级非确定),必须排序使 upvalue_captures 的顺序与 - // 父 captured_bindings 的 cell_idx(BTreeMap 名字序)对齐——否则 LOAD_UPVALUE 的 - // a 槽 uv_idx 编码与 cell_idx 错位,读错 upvalue。 - let mut names: Vec = names.into_iter().collect(); - names.sort(); - names + + // 输出整形:captured_out 排序后按枚举序分配 cell_idx 成 BTreeMap。 + let mut captured_sorted: Vec = captured_out.into_iter().collect(); + captured_sorted.sort(); + let captured_map: BTreeMap = + captured_sorted.into_iter().enumerate().map(|(i, n)| (n, i as u8)).collect(); + + // 输出整形:upvalue_out 排序后逐名取 cell_idx(父捕获映射)与 parent_uv_idx + // (父 upvalue 向量位置)成 Vec。 + let mut upvalue_sorted: Vec = upvalue_out.into_iter().collect(); + upvalue_sorted.sort(); + let upvalue_vec: Vec = upvalue_sorted .into_iter() .map(|name| { let parent_uv_idx = parent_upvalues.iter().position(|u| u.name == name).map(|i| i as u8); @@ -45,5 +61,18 @@ pub(crate) fn collect_upvalue_names( parent_uv_idx, } }) - .collect() + .collect(); + + (captured_map, upvalue_vec) +} + +/// 薄包装:父层捕获判定。`collect_captured_bindings(stmts, extra, own)` = +/// 入口(own, 空父映射).0。签名不变,调用点不动。 +pub(crate) fn collect_captured_bindings( + stmts: &[Statement], extra_exprs: &[&Expression], own: &HashSet, +) -> BTreeMap { + let empty_map: BTreeMap = BTreeMap::new(); + let empty_vec: Vec = Vec::new(); + let empty_set: HashSet = HashSet::new(); + collect_captures_and_upvalues(stmts, extra_exprs, own, &empty_map, &empty_vec, &empty_set).0 } diff --git a/crates/oxide_emit/src/function_body.rs b/crates/oxide_emit/src/function_body.rs index db14f974..b12dd7fb 100644 --- a/crates/oxide_emit/src/function_body.rs +++ b/crates/oxide_emit/src/function_body.rs @@ -14,8 +14,7 @@ use oxide_ir::IRFunction; use oxide_parser::{Expression, Statement, VariableDeclarationKind}; use crate::capture::{ - collect_binding_pattern_names, collect_captured_bindings, collect_fn_scope_names, collect_upvalue_names, - has_nested_function, FnScopeNames, + collect_binding_pattern_names, collect_captures_and_upvalues, collect_fn_scope_names, FnScopeNames, }; use crate::compile_ctx::{CompileCtx, FieldBuffer}; use crate::symbol_table::{Binding, ScopeKind}; @@ -703,13 +702,8 @@ impl Emitter { ParamSpec::Rest { .. } => {} } } - // 早退守卫:体与附加表达式无嵌套函数/类节点时,捕获集 - // (collect_captured_bindings,仅从嵌套函数/类节点产出名字)必为空,跳过该 - // 趟;own_bindings 是 upvalue 分析的遮蔽集、upvalue 捕获是本体对父的捕获, - // 二者独立于嵌套函数,不得跳过。 let mut capture_exprs: Vec<&oxide_parser::Expression> = param_defaults.clone(); capture_exprs.extend_from_slice(extra_capture_exprs); - let has_nested = has_nested_function(body_stmts, &capture_exprs); ctx.own_bindings = scope_names.own_binding_names.clone(); for spec in param_specs { if let ParamSpec::Pattern { pattern, .. } = spec { @@ -766,27 +760,25 @@ impl Emitter { } } - if has_nested { - ctx.set_captured_bindings(collect_captured_bindings(body_stmts, &capture_exprs, &ctx.own_bindings)); - } - // 自由变量分析:收集 upvalue 捕获(类方法也是普通函数,可捕获外层变量)。 - if matches!( + // 单入口:对同一 AST 单趟产出两个输出(captured_bindings 与 upvalue_captures)。 + let is_closure_context = matches!( body_context, FunctionBodyContext::Ordinary | FunctionBodyContext::Arrow | FunctionBodyContext::ClassElement - ) { - // 只有创建点父作用域链内可解析的父捕获名才可能成为子函数 upvalue: - // 捕获集是函数级名字并集,块级 let/const 在块退出后 cell 仍存留但名字 - // 已不可解析,块外嵌套函数按名命中会错误读取已失效的 cell。父自身 - // upvalue 代表的祖父绑定在父函数体内恒可见,不参与过滤。 - // C 风格 for 头 let/const 名在 init 内尚未 declare,但同头声明会为其 - // 建 cell,前向捕获须按父捕获集保留(见 `pending_for_head_names`)。 - // 索引按父可见绑定实例取(块级遮蔽绑定持追加索引);词法循环头名 - // (for-in/for-of 头绑定在右值区编译时未进符号表,按名回查会误命中 - // 外层同名绑定)与 for 头前向名无条件取捕获映射值(ForHeadEnv 覆盖 - // 索引或名字排序索引);绑定未分配索引的其余名(命名空间导入等) - // 回退映射值。顶层 tier 名(顶层 var/函数)已在捕获集剔除阶段出集, - // 不在此列。 - let visible_parent_captured: BTreeMap = parent_ctx + ); + // 只有创建点父作用域链内可解析的父捕获名才可能成为子函数 upvalue: + // 捕获集是函数级名字并集,块级 let/const 在块退出后 cell 仍存留但名字 + // 已不可解析,块外嵌套函数按名命中会错误读取已失效的 cell。父自身 + // upvalue 代表的祖父绑定在父函数体内恒可见,不参与过滤。 + // C 风格 for 头 let/const 名在 init 内尚未 declare,但同头声明会为其 + // 建 cell,前向捕获须按父捕获集保留(见 `pending_for_head_names`)。 + // 索引按父可见绑定实例取(块级遮蔽绑定持追加索引);词法循环头名 + // (for-in/for-of 头绑定在右值区编译时未进符号表,按名回查会误命中 + // 外层同名绑定)与 for 头前向名无条件取捕获映射值(ForHeadEnv 覆盖 + // 索引或名字排序索引);绑定未分配索引的其余名(命名空间导入等) + // 回退映射值。顶层 tier 名(顶层 var/函数)已在捕获集剔除阶段出集, + // 不在此列。 + let visible_parent_captured: BTreeMap = if is_closure_context { + parent_ctx .captured_bindings .iter() .filter(|(n, _)| { @@ -830,14 +822,22 @@ impl Emitter { }; (n.clone(), idx) }) - .collect(); - ctx.current_upvalue_captures = collect_upvalue_names( - body_stmts, - &capture_exprs, - &visible_parent_captured, - &parent_ctx.current_upvalue_captures, - &ctx.own_bindings, - ); + .collect() + } else { + BTreeMap::new() + }; + let (captured_map, upvalue_vec) = collect_captures_and_upvalues( + body_stmts, + &capture_exprs, + &ctx.own_bindings, + &visible_parent_captured, + &parent_ctx.current_upvalue_captures, + &ctx.own_bindings, + ); + ctx.set_captured_bindings(captured_map); + // 自由变量分析:收集 upvalue 捕获(类方法也是普通函数,可捕获外层变量)。 + if is_closure_context { + ctx.current_upvalue_captures = upvalue_vec; // 捕获 const 信息快照:父作用域符号表此时完整(预声明已完成), // 直接查绑定 is_const(不依赖初始化状态,TDZ 中 const 也须拦截)。 ctx.upvalue_const_flags = ctx