From f383446bd1e801489db01bb0b4b65728c1fca293 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Mon, 12 Oct 2026 04:22:29 +0000 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BD=9C=E7=94=A8=E5=9F=9F=E5=90=8D?= =?UTF-8?q?=E6=94=B6=E9=9B=86=E5=85=AD=E8=B6=9F=E5=90=88=E4=B8=80=EF=BC=8C?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E4=BD=93=E4=B8=8E=E6=A8=A1=E5=9D=97=E4=BD=93?= =?UTF-8?q?=E5=8D=95=E8=B6=9F=E5=A1=AB=E5=85=AD=E8=BE=93=E5=87=BA?= 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/mod.rs | 2 + crates/oxide_emit/src/capture/names.rs | 408 +++++++++++++++++++++++++ crates/oxide_emit/src/function_body.rs | 36 ++- crates/oxide_emit/src/module.rs | 26 +- 6 files changed, 470 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3bf2a0a7..e5cab49f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "oxide_builtins" -version = "0.16.4" +version = "0.16.5" dependencies = [ "chrono", "fast-float", @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "oxide_bytecode" -version = "0.16.4" +version = "0.16.5" dependencies = [ "num-bigint", "oxide_log", @@ -1193,7 +1193,7 @@ dependencies = [ [[package]] name = "oxide_cfg" -version = "0.16.4" +version = "0.16.5" dependencies = [ "oxide_bytecode", "oxide_emit", @@ -1204,7 +1204,7 @@ dependencies = [ [[package]] name = "oxide_cli" -version = "0.16.4" +version = "0.16.5" dependencies = [ "ansi_term", "bumpalo", @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "oxide_code_cache" -version = "0.16.4" +version = "0.16.5" dependencies = [ "lru", "oxide_bytecode", @@ -1237,7 +1237,7 @@ dependencies = [ [[package]] name = "oxide_compiler" -version = "0.16.4" +version = "0.16.5" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1257,7 +1257,7 @@ dependencies = [ [[package]] name = "oxide_dce" -version = "0.16.4" +version = "0.16.5" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1271,7 +1271,7 @@ dependencies = [ [[package]] name = "oxide_emit" -version = "0.16.4" +version = "0.16.5" dependencies = [ "num-bigint", "oxc_allocator", @@ -1286,7 +1286,7 @@ dependencies = [ [[package]] name = "oxide_engine" -version = "0.16.4" +version = "0.16.5" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1298,7 +1298,7 @@ dependencies = [ [[package]] name = "oxide_ir" -version = "0.16.4" +version = "0.16.5" dependencies = [ "oxide_bytecode", "oxide_log", @@ -1307,7 +1307,7 @@ dependencies = [ [[package]] name = "oxide_kernel" -version = "0.16.4" +version = "0.16.5" dependencies = [ "bumpalo", "dashmap", @@ -1321,7 +1321,7 @@ dependencies = [ [[package]] name = "oxide_liveness" -version = "0.16.4" +version = "0.16.5" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1333,7 +1333,7 @@ dependencies = [ [[package]] name = "oxide_log" -version = "0.16.4" +version = "0.16.5" dependencies = [ "tracing", "tracing-appender", @@ -1342,11 +1342,11 @@ dependencies = [ [[package]] name = "oxide_net" -version = "0.16.4" +version = "0.16.5" [[package]] name = "oxide_parser" -version = "0.16.4" +version = "0.16.5" dependencies = [ "oxc_allocator", "oxc_ast", @@ -1361,7 +1361,7 @@ dependencies = [ [[package]] name = "oxide_regalloc" -version = "0.16.4" +version = "0.16.5" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1377,7 +1377,7 @@ dependencies = [ [[package]] name = "oxide_runtime_api" -version = "0.16.4" +version = "0.16.5" dependencies = [ "num-bigint", "num-traits", @@ -1390,7 +1390,7 @@ dependencies = [ [[package]] name = "oxide_test262" -version = "0.16.4" +version = "0.16.5" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1410,7 +1410,7 @@ dependencies = [ [[package]] name = "oxide_types" -version = "0.16.4" +version = "0.16.5" dependencies = [ "bumpalo", "dashmap", @@ -1423,7 +1423,7 @@ dependencies = [ [[package]] name = "oxide_vm" -version = "0.16.4" +version = "0.16.5" dependencies = [ "bumpalo", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 22fde606..603da1dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ members = [ ] [workspace.package] -version = "0.16.4" +version = "0.16.5" edition = "2021" license = "MIT" rust-version = "1.80" diff --git a/crates/oxide_emit/src/capture/mod.rs b/crates/oxide_emit/src/capture/mod.rs index fda56fdc..b2d3684f 100644 --- a/crates/oxide_emit/src/capture/mod.rs +++ b/crates/oxide_emit/src/capture/mod.rs @@ -20,10 +20,12 @@ pub(crate) use captured::collect_captured_bindings; pub(crate) use guard::has_nested_function; pub(crate) use names::collect_block_level_decl_names; pub(crate) use names::collect_direct_lexical_names; +pub(crate) use names::collect_fn_scope_names; pub(crate) use names::collect_own_binding_names; pub(crate) use names::collect_top_level_function_names; pub(crate) use names::collect_top_level_function_names_ordered; pub(crate) use names::collect_var_binding_names; +pub(crate) use names::FnScopeNames; pub(crate) use upvalues::collect_upvalue_names; /// 收集形参(含 rest)绑定的名字集,作为本函数作用域的遮蔽集。 diff --git a/crates/oxide_emit/src/capture/names.rs b/crates/oxide_emit/src/capture/names.rs index 353ab0b8..cd327da6 100644 --- a/crates/oxide_emit/src/capture/names.rs +++ b/crates/oxide_emit/src/capture/names.rs @@ -301,6 +301,277 @@ pub(crate) fn collect_own_binding_names(param_names: &[&str], stmts: &[Statement names } +/// 函数作用域名收集结果:单趟遍历同时填六个输出,与旧的六个独立收集函数逐位一致。 +/// +/// 字段含义与旧函数一一对应(var 提升名 / own 绑定名 / 块级声明名 / 直接子词法名 / +/// 顶层函数名集 / 顶层函数声明序)。调用点改经本结构取各面,旧收集器保留待删。 +pub(crate) struct FnScopeNames { + /// var 声明名(函数/程序作用域提升目标,递归进嵌套块)。 + pub(crate) var_binding_names: HashSet, + /// 当前函数作用域绑定名(参数 + 变量/函数/类/import/export 声明,含嵌套块,不含嵌套函数体)。 + pub(crate) own_binding_names: HashSet, + /// 块级声明名(块内 let/const/class、catch 参数、for 头 let/const;顶层直接子不纳)。 + pub(crate) block_level_decl_names: HashSet, + /// 直接子级词法声明名(let/const/class,入口 TDZ 占位 cell 名集)。 + pub(crate) direct_lexical_names: HashSet, + /// 直接子级函数声明名(无序集)。 + pub(crate) top_level_function_names: HashSet, + /// 直接子级函数声明名(声明序,不排序不去重)。 + pub(crate) top_level_function_names_ordered: Vec, +} + +/// 单趟收集函数作用域六个名字输出。 +/// +/// 步骤: +/// 1. 形参名注入 `own_binding_names`(须在遍历前,own 面是遮蔽集,形参须先入)。 +/// 2. 以 `top=true` 递归遍历顶层语句列表,直接子级填直接子词法/顶层函数名输出, +/// 各递归层填 var/own/块级输出。 +/// +/// 边界:`param_names` 含解构叶名与 rest 名(规范 `paramNames` 口径);顶层语句列表 +/// 不递归进嵌套函数体(嵌套函数是独立编译单元)。 +/// 副作用:无(纯收集)。 +/// 注意事项:六个字段与旧六函数逐位一致,调用点切换后发射产物不变。 +pub(crate) fn collect_fn_scope_names(param_names: &[&str], stmts: &[Statement]) -> FnScopeNames { + let mut out = FnScopeNames { + var_binding_names: HashSet::new(), + own_binding_names: HashSet::new(), + block_level_decl_names: HashSet::new(), + direct_lexical_names: HashSet::new(), + top_level_function_names: HashSet::new(), + top_level_function_names_ordered: Vec::new(), + }; + for p in param_names { + out.own_binding_names.insert(p.to_string()); + } + collect_fn_scope_names_impl(stmts, &mut out, true); + out +} + +/// 递归遍历语句树单趟填六个输出。`top` 标记当前层是否为顶层(直接子级):顶层填 +/// 直接子词法与顶层函数名输出,且顶层 let/const/class 是顶层词法绑定非块级; +/// 各递归层(块/if/循环/switch case/try/标签/with)以 `top=false` 进入。 +fn collect_fn_scope_names_impl(stmts: &[Statement], out: &mut FnScopeNames, top: bool) { + for stmt in stmts { + match stmt { + Statement::VariableDeclaration(vd) => { + let is_var = matches!(vd.kind, VariableDeclarationKind::Var); + // var 面:仅 var 名提升到函数作用域。 + if is_var { + for d in &vd.declarations { + collect_binding_pattern_names(&d.id, &mut out.var_binding_names); + } + } + // own 面:全部声明种类计入当前作用域绑定。 + for d in &vd.declarations { + collect_binding_pattern_names(&d.id, &mut out.own_binding_names); + } + // 块级面:非顶层的非 var(顶层词法是顶层绑定,非块级)。 + if !is_var && !top { + for d in &vd.declarations { + collect_binding_pattern_names(&d.id, &mut out.block_level_decl_names); + } + } + // 直接子词法面:仅顶层非 var。 + if top && !is_var { + for d in &vd.declarations { + collect_binding_pattern_names(&d.id, &mut out.direct_lexical_names); + } + } + } + Statement::FunctionDeclaration(fd) => { + if let Some(id) = &fd.id { + // own 面:函数声明是当前作用域绑定。 + out.own_binding_names.insert(id.name.to_string()); + if top { + // 顶层函数名集与声明序列表(顶层函数声明是全局 var 绑定)。 + out.top_level_function_names.insert(id.name.to_string()); + out.top_level_function_names_ordered.push(id.name.to_string()); + } + } + } + Statement::ClassDeclaration(cd) => { + if let Some(id) = &cd.id { + let name = id.name.to_string(); + // own 面:类名是本作用域 const 绑定。 + out.own_binding_names.insert(name.clone()); + if top { + // 直接子词法面:顶层类是顶层词法绑定。 + out.direct_lexical_names.insert(name); + } else { + // 块级面:块内类是块作用域绑定。 + out.block_level_decl_names.insert(name); + } + } + } + Statement::ImportDeclaration(imp) => { + // own 面:import 绑定是模块作用域 const 绑定。 + if let Some(specifiers) = &imp.specifiers { + for sp in specifiers { + match sp { + oxide_parser::ImportDeclarationSpecifier::ImportSpecifier(s) => { + out.own_binding_names.insert(s.local.name.to_string()); + } + oxide_parser::ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => { + out.own_binding_names.insert(s.local.name.to_string()); + } + oxide_parser::ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => { + out.own_binding_names.insert(s.local.name.to_string()); + } + } + } + } + } + Statement::ExportNamedDeclaration(exp) => { + if let Some(decl) = &exp.declaration { + match decl { + oxide_parser::Declaration::VariableDeclaration(vd) => { + let is_var = matches!(vd.kind, VariableDeclarationKind::Var); + if is_var { + for d in &vd.declarations { + collect_binding_pattern_names(&d.id, &mut out.var_binding_names); + } + } + for d in &vd.declarations { + collect_binding_pattern_names(&d.id, &mut out.own_binding_names); + } + if !is_var && !top { + for d in &vd.declarations { + collect_binding_pattern_names(&d.id, &mut out.block_level_decl_names); + } + } + if top && !is_var { + for d in &vd.declarations { + collect_binding_pattern_names(&d.id, &mut out.direct_lexical_names); + } + } + } + oxide_parser::Declaration::FunctionDeclaration(fd) => { + if let Some(id) = &fd.id { + out.own_binding_names.insert(id.name.to_string()); + } + } + oxide_parser::Declaration::ClassDeclaration(cd) => { + if let Some(id) = &cd.id { + let name = id.name.to_string(); + out.own_binding_names.insert(name.clone()); + if top { + out.direct_lexical_names.insert(name); + } else { + out.block_level_decl_names.insert(name); + } + } + } + _ => {} + } + } + } + Statement::ExportDefaultDeclaration(exp) => { + match &exp.declaration { + oxide_parser::ExportDefaultDeclarationKind::FunctionDeclaration(fd) => { + if let Some(id) = &fd.id { + out.own_binding_names.insert(id.name.to_string()); + } + } + oxide_parser::ExportDefaultDeclarationKind::ClassDeclaration(cd) => { + if let Some(id) = &cd.id { + let name = id.name.to_string(); + out.own_binding_names.insert(name.clone()); + // 直接子词法面仅顶层:export default class 是 lexical 绑定。 + if top { + out.direct_lexical_names.insert(name); + } + } + } + _ => {} + } + } + Statement::BlockStatement(b) => collect_fn_scope_names_impl(&b.body, out, false), + Statement::IfStatement(is) => { + collect_fn_scope_names_impl(std::slice::from_ref(&is.consequent), out, false); + if let Some(alt) = &is.alternate { + collect_fn_scope_names_impl(std::slice::from_ref(alt), out, false); + } + } + Statement::WhileStatement(w) => collect_fn_scope_names_impl(std::slice::from_ref(&w.body), out, false), + Statement::DoWhileStatement(d) => collect_fn_scope_names_impl(std::slice::from_ref(&d.body), out, false), + Statement::ForStatement(f) => { + if let Some(oxide_parser::ForStatementInit::VariableDeclaration(vd)) = &f.init { + let is_var = matches!(vd.kind, VariableDeclarationKind::Var); + if is_var { + for d in &vd.declarations { + collect_binding_pattern_names(&d.id, &mut out.var_binding_names); + } + } + // own 面:for 头声明是本函数局部绑定(仅标识符形态,与旧趟一致)。 + for d in &vd.declarations { + if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id { + out.own_binding_names.insert(bi.name.to_string()); + } + } + // 块级面:for 头 let/const 是循环作用域绑定(各层均收集)。 + if !is_var { + for d in &vd.declarations { + collect_binding_pattern_names(&d.id, &mut out.block_level_decl_names); + } + } + } + collect_fn_scope_names_impl(std::slice::from_ref(&f.body), out, false); + } + Statement::ForInStatement(fi) => { + if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fi.left { + let is_var = matches!(vd.kind, VariableDeclarationKind::Var); + if is_var { + // 仅 var 头名提升到函数作用域,let/const 头名是迭代级绑定。 + collect_for_left_decl_names(&fi.left, &mut out.var_binding_names); + } + collect_for_left_decl_names(&fi.left, &mut out.own_binding_names); + if !is_var { + collect_for_left_decl_names(&fi.left, &mut out.block_level_decl_names); + } + } + collect_fn_scope_names_impl(std::slice::from_ref(&fi.body), out, false); + } + Statement::ForOfStatement(fo) => { + if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fo.left { + let is_var = matches!(vd.kind, VariableDeclarationKind::Var); + if is_var { + collect_for_left_decl_names(&fo.left, &mut out.var_binding_names); + } + collect_for_left_decl_names(&fo.left, &mut out.own_binding_names); + if !is_var { + collect_for_left_decl_names(&fo.left, &mut out.block_level_decl_names); + } + } + collect_fn_scope_names_impl(std::slice::from_ref(&fo.body), out, false); + } + Statement::SwitchStatement(sw) => { + for case in &sw.cases { + collect_fn_scope_names_impl(&case.consequent, out, false); + } + } + Statement::TryStatement(ts) => { + // catch 参数是本作用域的词法绑定:own 与块级两面均计入。 + if let Some(h) = &ts.handler { + if let Some(param) = &h.param { + collect_binding_pattern_names(¶m.pattern, &mut out.own_binding_names); + collect_binding_pattern_names(¶m.pattern, &mut out.block_level_decl_names); + } + collect_fn_scope_names_impl(&h.body.body, out, false); + } + collect_fn_scope_names_impl(&ts.block.body, out, false); + if let Some(f) = &ts.finalizer { + collect_fn_scope_names_impl(&f.body, out, false); + } + } + Statement::LabeledStatement(ls) => { + collect_fn_scope_names_impl(std::slice::from_ref(&ls.body), out, false) + } + Statement::WithStatement(ws) => collect_fn_scope_names_impl(std::slice::from_ref(&ws.body), out, false), + _ => {} + } + } +} + /// 递归遍历语句树收集当前函数作用域声明的绑定名(变量/函数/类/import/export, /// 含嵌套块,不进嵌套函数体)。 pub(crate) fn collect_decl_names_stmt(stmts: &[Statement], out: &mut HashSet) { @@ -435,3 +706,140 @@ pub(crate) fn collect_decl_names_stmt(stmts: &[Statement], out: &mut HashSet = param_specs.iter().map(|s| s.register_name()).collect(); + let scope_names = collect_fn_scope_names(¶m_name_refs, body_stmts); + let param_base = self.emit_params_prologue( param_specs, body_stmts, @@ -443,6 +448,7 @@ impl Emitter { extra_capture_exprs, extra_upvalue_names, name, + &scope_names, )?; // 实例字段 computed key 数组所在 upvalue 下标,供字段初始化 emit 定位。 ctx.field_keys_uv = ctx @@ -456,7 +462,7 @@ impl Emitter { // 预注册 builtin 引用(先于任何临时寄存器),builtin 槽不与被复用的临时值冲突。 // 函数体直接子级词法声明名排除登记(顶层词法遮蔽同口径,见 program.rs)。 - let lexical_excluded = collect_direct_lexical_names(body_stmts); + let lexical_excluded = scope_names.direct_lexical_names.clone(); self.pre_register_builtin_references(body_stmts, &lexical_excluded, &mut ctx); // 预声明 `var` 名,使首个 sub-pass 中提升的函数声明能解析其闭包引用的外层 var。 @@ -488,7 +494,7 @@ impl Emitter { // 不发射定义指令,声明点对已绑定名又跳过 undefined 写,缺失入口写会让首次 // 写入前的读取取到调用方遗留的寄存器值。捕获名已由参数 prologue 的 // MAKE_CELL(undefined) 实例化,此处只补未捕获名。 - self.instantiate_var_bindings(body_stmts, &mut ctx); + self.instantiate_var_bindings(body_stmts, &mut ctx, &scope_names); // 被捕获的函数名绑定同样建 cell(MAKE_CELL):值源是帧槽写入已置位的 // 名槽寄存器(函数对象),非 undefined。名槽寄存器此时已知(非抑制面 @@ -655,7 +661,7 @@ impl Emitter { fn emit_params_prologue<'a>( &self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, ctx: &mut CompileCtx, body_context: FunctionBodyContext, extra_capture_exprs: &[&'a Expression<'a>], - extra_upvalue_names: &[(String, u8)], name: Option<&str>, + extra_upvalue_names: &[(String, u8)], name: Option<&str>, scope_names: &FnScopeNames, ) -> Result { ctx.push_scope_with_kind(ScopeKind::FunctionScope); let param_base = ctx.next_reg; @@ -696,7 +702,7 @@ impl Emitter { 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 = collect_own_binding_names(¶m_names, body_stmts); + ctx.own_bindings = scope_names.own_binding_names.clone(); for spec in param_specs { if let ParamSpec::Pattern { pattern, .. } = spec { collect_binding_pattern_names(pattern, &mut ctx.own_bindings); @@ -723,7 +729,7 @@ impl Emitter { // 名登记须先于 set_captured_bindings:嵌套函数捕获名分析依赖 own_bindings // 完整(名被捕获时须识别为本函数绑定并建 cell)。 if let Some(fn_name) = name { - let var_names = collect_var_binding_names(body_stmts); + let var_names = &scope_names.var_binding_names; let suppressed = ctx.param_names.contains(fn_name) || var_names.contains(fn_name) || (fn_name == "arguments" && arguments_reg.is_some()); @@ -1005,7 +1011,7 @@ impl Emitter { // 则取调用方寄存器残留。参数与 arguments 已在上方初始化(跳过以免覆盖参数 // 值);let/const/class 保持 TDZ 语义不动。声明语句的 MAKE_CELL 按占位更新 // 语义覆盖此初值。 - let mut captured_entry_names = collect_var_binding_names(body_stmts); + let mut captured_entry_names = scope_names.var_binding_names.clone(); // 块级函数外层 var 名与 instantiate_var_bindings 同源并入;抑制名(形参/ // 词法声明同名)无外层绑定,不并入。抑制集在此独立计算:本循环早于函数体 // 的 block_fn_suppressed 构建。 @@ -1046,10 +1052,12 @@ impl Emitter { // 运行时抛真 TDZ;声明语句的 MAKE_CELL 按占位更新语义原位翻转。名集只取 // 直接子级(块级名不提升到函数作用域,与块内重执行 cell 族零交集), // 排序保证发射序跨进程稳定。 - let mut lex_names: Vec = collect_direct_lexical_names(body_stmts) - .into_iter() - .filter(|n| !param_names.contains(&n.as_str()) && n != "arguments") - .filter(|n| ctx.captured_bindings.contains_key(n)) + let mut lex_names: Vec = scope_names + .direct_lexical_names + .iter() + .filter(|n| !param_names.contains(&n.as_str()) && n != &"arguments") + .filter(|n| ctx.captured_bindings.contains_key(n.as_str())) + .cloned() .collect(); lex_names.sort(); if !lex_names.is_empty() { @@ -1085,8 +1093,8 @@ impl Emitter { /// var;被形参/词法同名抑制的名字无外层绑定,不并入。直接子标签函数声明由 /// 函数入口单独物化闭包,不并入。 /// - 符号表查不到的名字(如解构 pattern 叶名未被预声明)跳过,不报错。 - fn instantiate_var_bindings(&self, body_stmts: &[Statement], ctx: &mut CompileCtx) { - let mut name_set = collect_var_binding_names(body_stmts); + fn instantiate_var_bindings(&self, body_stmts: &[Statement], ctx: &mut CompileCtx, scope_names: &FnScopeNames) { + let mut name_set = scope_names.var_binding_names.clone(); // 块级函数外层 var 绑定同样只预声明不发射定义指令,缺失入口写会让块前读取 // 取到调用方残留;入口写须并入(strict 与抑制名除外)。 diff --git a/crates/oxide_emit/src/module.rs b/crates/oxide_emit/src/module.rs index 6214cab8..510c1ace 100644 --- a/crates/oxide_emit/src/module.rs +++ b/crates/oxide_emit/src/module.rs @@ -13,7 +13,7 @@ use std::collections::{HashMap, HashSet}; use std::path::Path; -use crate::capture::{collect_captured_bindings, collect_direct_lexical_names, collect_own_binding_names}; +use crate::capture::{collect_captured_bindings, collect_fn_scope_names}; use crate::expr::call::pack_arg_regs; use crate::{CompileCtx, Emitter}; use oxc_allocator::Box; @@ -451,17 +451,21 @@ impl Emitter { ) -> Result<(), String> { let body = &program.body; + // 模块作用域六个名字面单趟收集(模块顶层无形参,param_names 传空): + // builtin 排除 / own 绑定 / 入口 var 与词法实例化各调用点共用此结果。 + let scope_names = collect_fn_scope_names(&[], body); + // —— 预声明(镜像 emit_program;import/export 包装的声明也计入 hoisting)—— self.predeclare_function_declarations(body, ctx); // 模块顶层词法声明名排除镜像登记(词法绑定遮蔽同名全局属性,同 program.rs)。 - let lexical_excluded = collect_direct_lexical_names(body); + let lexical_excluded = scope_names.direct_lexical_names.clone(); self.pre_register_builtin_references(body, &lexical_excluded, ctx); self.predeclare_var_declarations(body, ctx); // 模块 lexical 声明入模块环境(非全局对象),不做受限全局名检查。 let _ = self.predeclare_lexical_declarations(body, ctx); // 闭包捕获分析(import 绑定名纳入 own_bindings,供嵌套函数 cell 捕获)。 - ctx.own_bindings = collect_own_binding_names(&[], body); + ctx.own_bindings = scope_names.own_binding_names.clone(); ctx.set_captured_bindings(collect_captured_bindings(body, &[], &ctx.own_bindings)); // 模块顶层函数级绑定 cell 索引回填:预声明已完成,绑定已齐。 ctx.backfill_captured_cell_idxs(); @@ -834,10 +838,12 @@ impl Emitter { // var 名在模块入口统一 MAKE_CELL(undefined),与脚本顶层实例化同语义。—— self.reconcile_alias_captures(ctx); { - let mut var_names: Vec = crate::capture::collect_var_binding_names(body) - .into_iter() + let mut var_names: Vec = scope_names + .var_binding_names + .iter() .filter(|n| !ctx.param_names.contains(n.as_str())) - .filter(|n| ctx.captured_bindings.contains_key(n)) + .filter(|n| ctx.captured_bindings.contains_key(n.as_str())) + .cloned() .collect(); var_names.sort(); if !var_names.is_empty() { @@ -857,10 +863,12 @@ impl Emitter { // 既有预注册保持未初始化 TDZ(命名空间对象面,按导出名),入口 cell // 只覆盖被嵌套函数捕获的名(按捕获名),两面名集独立。声明语句的 // MAKE_CELL 按占位更新语义原位翻转;直接子级 only,块级名不提升。 - let mut lex_names: Vec = crate::capture::collect_direct_lexical_names(body) - .into_iter() + let mut lex_names: Vec = scope_names + .direct_lexical_names + .iter() .filter(|n| !ctx.param_names.contains(n.as_str())) - .filter(|n| ctx.captured_bindings.contains_key(n)) + .filter(|n| ctx.captured_bindings.contains_key(n.as_str())) + .cloned() .collect(); lex_names.sort(); if !lex_names.is_empty() {