perf: 作用域名收集六趟合一,函数体与模块体单趟填六输出

This commit is contained in:
2026-10-12 04:22:29 +00:00
parent 26441edcbc
commit f383446bd1
6 changed files with 470 additions and 44 deletions
Generated
+20 -20
View File
@@ -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",
+1 -1
View File
@@ -24,7 +24,7 @@ members = [
]
[workspace.package]
version = "0.16.4"
version = "0.16.5"
edition = "2021"
license = "MIT"
rust-version = "1.80"
+2
View File
@@ -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)绑定的名字集,作为本函数作用域的遮蔽集。
+408
View File
@@ -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<String>,
/// 当前函数作用域绑定名(参数 + 变量/函数/类/import/export 声明,含嵌套块,不含嵌套函数体)。
pub(crate) own_binding_names: HashSet<String>,
/// 块级声明名(块内 let/const/class、catch 参数、for 头 let/const;顶层直接子不纳)。
pub(crate) block_level_decl_names: HashSet<String>,
/// 直接子级词法声明名(let/const/class,入口 TDZ 占位 cell 名集)。
pub(crate) direct_lexical_names: HashSet<String>,
/// 直接子级函数声明名(无序集)。
pub(crate) top_level_function_names: HashSet<String>,
/// 直接子级函数声明名(声明序,不排序不去重)。
pub(crate) top_level_function_names_ordered: Vec<String>,
}
/// 单趟收集函数作用域六个名字输出。
///
/// 步骤:
/// 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(&param.pattern, &mut out.own_binding_names);
collect_binding_pattern_names(&param.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<String>) {
@@ -435,3 +706,140 @@ pub(crate) fn collect_decl_names_stmt(stmts: &[Statement], out: &mut HashSet<Str
}
}
}
#[cfg(test)]
mod tests {
use super::*;
/// 夹具:parse 源串(脚本口径)后,六输出逐一断言新单趟与旧六函数逐位一致。
fn assert_bitwise(src: &str, params: &[&str]) {
let alloc = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&alloc, src).unwrap_or_else(|e| panic!("parse 失败 {src:?}: {e:?}"));
let body = &program.body;
let names = collect_fn_scope_names(params, body);
assert_eq!(names.var_binding_names, collect_var_binding_names(body), "var 面漂移:{src:?}");
assert_eq!(
names.own_binding_names,
collect_own_binding_names(params, body),
"own 面漂移:{src:?}"
);
assert_eq!(
names.block_level_decl_names,
collect_block_level_decl_names(body),
"块级面漂移:{src:?}"
);
assert_eq!(
names.direct_lexical_names,
collect_direct_lexical_names(body),
"直接子词法面漂移:{src:?}"
);
assert_eq!(
names.top_level_function_names,
collect_top_level_function_names(body),
"顶层函数名面漂移:{src:?}"
);
assert_eq!(
names.top_level_function_names_ordered,
collect_top_level_function_names_ordered(body),
"顶层函数声明序漂移:{src:?}"
);
}
/// 夹具:parse 源串(模块口径)后,六输出逐一断言新单趟与旧六函数逐位一致。
fn assert_bitwise_module(src: &str, params: &[&str]) {
let alloc = oxide_parser::Allocator::default();
let program = oxide_parser::parse_module(&alloc, src)
.unwrap_or_else(|e| panic!("parse_module 失败 {src:?}: {e:?}"));
let body = &program.body;
let names = collect_fn_scope_names(params, body);
assert_eq!(names.var_binding_names, collect_var_binding_names(body), "var 面漂移:{src:?}");
assert_eq!(
names.own_binding_names,
collect_own_binding_names(params, body),
"own 面漂移:{src:?}"
);
assert_eq!(
names.block_level_decl_names,
collect_block_level_decl_names(body),
"块级面漂移:{src:?}"
);
assert_eq!(
names.direct_lexical_names,
collect_direct_lexical_names(body),
"直接子词法面漂移:{src:?}"
);
assert_eq!(
names.top_level_function_names,
collect_top_level_function_names(body),
"顶层函数名面漂移:{src:?}"
);
assert_eq!(
names.top_level_function_names_ordered,
collect_top_level_function_names_ordered(body),
"顶层函数声明序漂移:{src:?}"
);
}
/// 顶层声明面:var/let/const/函数/类声明与解构 pattern 叶名。
#[test]
fn fn_scope_names_bitwise_parity_declarations() {
assert_bitwise("var a; let b = 1; const c = 2; function f() {} class K {}", &[]);
assert_bitwise("var a = {x: 1, y: [z]}; let [p, ...q] = arr; let {m, n: o} = obj;", &[]);
assert_bitwise("function f() { var inner; } function g() {} var f2;", &[]);
assert_bitwise("var a; var a; function f() {} function f() {}", &[]);
}
/// 控制流面:if/while/do-while/for/for-in/for-of/switch/try/labeled/with 各分支。
#[test]
fn fn_scope_names_bitwise_parity_control_flow() {
assert_bitwise("if (x) { var a; let b; } else { var c; let d; }", &[]);
assert_bitwise("while (x) { var a; let b; } do { var c; } while (x);", &[]);
assert_bitwise("for (var i = 0; i < n; i++) { var a; let b; }", &[]);
assert_bitwise("for (let j of it) { var a; } for (var k in obj) { let b; }", &[]);
assert_bitwise("switch (x) { case 1: { var a; let b; } default: { var c; } }", &[]);
assert_bitwise("try { var a; } catch (e) { let b; } finally { var c; }", &[]);
assert_bitwise("try { var a; } catch { let b; }", &[]);
assert_bitwise("L: { var a; let b; }", &[]);
assert_bitwise("with (obj) { var a; let b; }", &[]);
}
/// 嵌套块面:块内 let/const/class 是块级绑定,顶层直接子不纳。
#[test]
fn fn_scope_names_bitwise_parity_nested_blocks() {
assert_bitwise("{ { var a; let b; class K {} } }", &[]);
assert_bitwise("if (x) { { let a; const b = 1; } }", &[]);
assert_bitwise("var a; { let b; } function f() { var c; }", &[]);
assert_bitwise("if (x) while (y) { let a; } for (var i;;) { const b = 1; }", &[]);
}
/// 形参注入面:param_names 进 own 面,须与旧 collect_own_binding_names 同口径。
#[test]
fn fn_scope_names_bitwise_parity_params_injection() {
assert_bitwise("var p; let q; function f() {}", &["p", "q", "r"]);
assert_bitwise("var x = 1;", &["x", "y"]);
assert_bitwise("function f() { var p; }", &["p"]);
}
/// 模块声明面:import/export 包装的声明计入各面(模块口径 parse)。
#[test]
fn fn_scope_names_bitwise_parity_module_decls() {
assert_bitwise_module("import a from 'm'; import * as ns from 'm'; import { b, c as d } from 'm';", &[]);
assert_bitwise_module("export var e = 1; export let f = 2; export const g = 3;", &[]);
assert_bitwise_module("export function h() {} export class J {}", &[]);
assert_bitwise_module("export default function named() {}", &[]);
assert_bitwise_module("export default class K {}", &[]);
assert_bitwise_module("import a from 'm'; export var b = 1; function c() {}", &[]);
assert_bitwise_module("export { x } from 'n';", &[]);
}
/// for 头面:var/let/const 头名分面归属(var 提升、let/const 块级)。
#[test]
fn fn_scope_names_bitwise_parity_for_heads() {
assert_bitwise("for (var [a, b] of it) {} for (let {x, ...y} in obj) {}", &[]);
assert_bitwise("for (var i;;) {} for (let j;;) {} for (const k = 0;;) {}", &[]);
assert_bitwise("for (var i = 0;;) { for (let j;;) { var a; } }", &[]);
}
}
+22 -14
View File
@@ -14,8 +14,8 @@ use oxide_ir::IRFunction;
use oxide_parser::{Expression, Statement, VariableDeclarationKind};
use crate::capture::{
collect_binding_pattern_names, collect_captured_bindings, collect_direct_lexical_names, collect_own_binding_names,
collect_upvalue_names, collect_var_binding_names, has_nested_function,
collect_binding_pattern_names, collect_captured_bindings, collect_fn_scope_names, collect_upvalue_names,
has_nested_function, FnScopeNames,
};
use crate::compile_ctx::{CompileCtx, FieldBuffer};
use crate::symbol_table::{Binding, ScopeKind};
@@ -434,6 +434,11 @@ impl Emitter {
// 让 next_reg 与 builtin 槽位对齐,参数在 builtin 槽之后分配。
ctx.reset_regs();
// 函数作用域六个名字面单趟收集(形参名先注入 own 面):本函数体编译链
// 各调用点(参数 prologue / builtin 排除 / 入口实例化)共用此结果。
let param_name_refs: Vec<&str> = param_specs.iter().map(|s| s.register_name()).collect();
let scope_names = collect_fn_scope_names(&param_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<u32, String> {
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(&param_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<String> = 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<String> = 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 与抑制名除外)。
+17 -9
View File
@@ -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<String> = crate::capture::collect_var_binding_names(body)
.into_iter()
let mut var_names: Vec<String> = 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<String> = crate::capture::collect_direct_lexical_names(body)
.into_iter()
let mut lex_names: Vec<String> = 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() {