perf: 程序模块入口名字收集切单趟,删旧收集器

This commit is contained in:
2026-10-12 04:52:56 +00:00
parent 3e4f923ee2
commit 15c6e1db6c
9 changed files with 783 additions and 654 deletions
Generated
+20 -20
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]]
name = "oxide_builtins"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"chrono",
"fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]]
name = "oxide_bytecode"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"num-bigint",
"oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]]
name = "oxide_cfg"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"oxide_bytecode",
"oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]]
name = "oxide_cli"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"ansi_term",
"bumpalo",
@@ -1228,7 +1228,7 @@ dependencies = [
[[package]]
name = "oxide_code_cache"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"lru",
"oxide_bytecode",
@@ -1237,7 +1237,7 @@ dependencies = [
[[package]]
name = "oxide_compiler"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1257,7 +1257,7 @@ dependencies = [
[[package]]
name = "oxide_dce"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1271,7 +1271,7 @@ dependencies = [
[[package]]
name = "oxide_emit"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"num-bigint",
"oxc_allocator",
@@ -1286,7 +1286,7 @@ dependencies = [
[[package]]
name = "oxide_engine"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1298,7 +1298,7 @@ dependencies = [
[[package]]
name = "oxide_ir"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"oxide_bytecode",
"oxide_log",
@@ -1307,7 +1307,7 @@ dependencies = [
[[package]]
name = "oxide_kernel"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"bumpalo",
"dashmap",
@@ -1321,7 +1321,7 @@ dependencies = [
[[package]]
name = "oxide_liveness"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1333,7 +1333,7 @@ dependencies = [
[[package]]
name = "oxide_log"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"tracing",
"tracing-appender",
@@ -1342,11 +1342,11 @@ dependencies = [
[[package]]
name = "oxide_net"
version = "0.16.5"
version = "0.16.6"
[[package]]
name = "oxide_parser"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"oxc_allocator",
"oxc_ast",
@@ -1361,7 +1361,7 @@ dependencies = [
[[package]]
name = "oxide_regalloc"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1377,7 +1377,7 @@ dependencies = [
[[package]]
name = "oxide_runtime_api"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"num-bigint",
"num-traits",
@@ -1390,7 +1390,7 @@ dependencies = [
[[package]]
name = "oxide_test262"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1410,7 +1410,7 @@ dependencies = [
[[package]]
name = "oxide_types"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"bumpalo",
"dashmap",
@@ -1423,7 +1423,7 @@ dependencies = [
[[package]]
name = "oxide_vm"
version = "0.16.5"
version = "0.16.6"
dependencies = [
"bumpalo",
"chrono",
+1 -1
View File
@@ -24,7 +24,7 @@ members = [
]
[workspace.package]
version = "0.16.5"
version = "0.16.6"
edition = "2021"
license = "MIT"
rust-version = "1.80"
-6
View File
@@ -18,13 +18,7 @@ use std::collections::HashSet;
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;
File diff suppressed because it is too large Load Diff
+23 -16
View File
@@ -434,10 +434,18 @@ impl Emitter {
// 让 next_reg 与 builtin 槽位对齐,参数在 builtin 槽之后分配。
ctx.reset_regs();
// 函数作用域六个名字面单趟收集(形参名先注入 own 面):本函数体编译链
// 各调用点(参数 prologue / builtin 排除 / 入口实例化)共用此结果。
// 函数作用域八个名字面单趟收集(形参名先注入 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 mut scope_names = collect_fn_scope_names(&param_name_refs, body_stmts);
// 抑制集口径是规范 paramNames(含解构叶名),合并趟形参注入按登记名,
// 叶名在此补入(登记名已入集,重复插入无副作用)。
for name in ctx.param_names.iter() {
if !param_name_refs.contains(&name.as_str()) {
scope_names.block_fn_suppressed.insert(name.clone());
}
}
let param_base = self.emit_params_prologue(
param_specs,
@@ -478,10 +486,10 @@ impl Emitter {
// (形参/词法声明同名,该形退化为纯块作用域)则不建。求值期声明点把
// 函数对象写回此绑定(见函数声明 emit)。
if !ctx.is_strict {
ctx.block_fn_suppressed = self.collect_block_fn_suppressed_names(body_stmts, &ctx.param_names);
for name in self.collect_block_function_names(body_stmts) {
if !ctx.block_fn_suppressed.contains(&name) {
self.predeclare_var_name(&name, &mut ctx);
ctx.block_fn_suppressed = scope_names.block_fn_suppressed.clone();
for name in &scope_names.block_function_names {
if !ctx.block_fn_suppressed.contains(name) {
self.predeclare_var_name(name, &mut ctx);
}
}
}
@@ -1013,13 +1021,12 @@ impl Emitter {
// 语义覆盖此初值。
let mut captured_entry_names = scope_names.var_binding_names.clone();
// 块级函数外层 var 名与 instantiate_var_bindings 同源并入;抑制名(形参/
// 词法声明同名)无外层绑定,不并入。抑制集在此独立计算:本循环早于函数体
// 的 block_fn_suppressed 构建。
// 词法声明同名)无外层绑定,不并入。
if !ctx.is_strict {
let suppressed = self.collect_block_fn_suppressed_names(body_stmts, &ctx.param_names);
for name in self.collect_block_function_names(body_stmts) {
if !suppressed.contains(&name) {
captured_entry_names.insert(name);
let suppressed = &scope_names.block_fn_suppressed;
for name in &scope_names.block_function_names {
if !suppressed.contains(name) {
captured_entry_names.insert(name.clone());
}
}
}
@@ -1107,9 +1114,9 @@ impl Emitter {
.filter_map(|fd| fd.id.as_ref())
.map(|id| id.name.as_str())
.collect();
for name in self.collect_block_function_names(body_stmts) {
if !ctx.block_fn_suppressed.contains(&name) && !labeled_hoisted.contains(name.as_str()) {
name_set.insert(name);
for name in &scope_names.block_function_names {
if !ctx.block_fn_suppressed.contains(name) && !labeled_hoisted.contains(name.as_str()) {
name_set.insert(name.clone());
}
}
}
-205
View File
@@ -1,205 +0,0 @@
//! emit 前置 pass,块级函数名收集:web-compat 外层 var 绑定实例化支撑——
//! 语句树内块级普通函数声明名源序去重收集、词法声明名抑制集(块函数名与词法名
//! 同名时退化为纯块作用域)、形参名 ∪ 词法名抑制集构建。
use std::collections::HashSet;
use crate::capture::collect_binding_pattern_names;
use crate::Emitter;
use oxide_parser::{Declaration, Statement, VariableDeclarationKind};
impl Emitter {
/// 递归收集语句树内块级普通函数声明名(源序去重),供 sloppy 模式浏览器兼容
/// 行为(Annex B.3.3 为块级普通函数声明建外层 var 绑定)下的外层 var 绑定实例化。
///
/// # 边界与前提
/// - 只收普通 `FunctionDeclaration`:Annex B.3.3 的 web-compat 仅改写普通函数
/// 声明,async 函数、生成器与 async 生成器是各自独立的块级词法绑定,块外
/// 不可见,不入名集。
/// - 调用点直接子级(函数体/程序顶层直接子句)是提升 var 声明,非块级
/// 函数,不收集;进入嵌套语句(块/if/循环/switch case/try 各区)后的
/// 函数声明才是块级。
/// - 不递归进嵌套函数体:那是独立编译单元,其内部块函数名由该单元自身收集。
/// - switch 不推作用域(case 内函数声明随外层块),收集须进入 case 才能到达
/// case 内的 for/块等块级形。
pub(crate) fn collect_block_function_names(&self, statements: &[Statement]) -> Vec<String> {
let mut names = Vec::new();
self.collect_block_function_names_into(statements, &mut names, false);
names
}
fn collect_block_function_names_into(&self, statements: &[Statement], names: &mut Vec<String>, block_level: bool) {
for statement in statements {
match statement {
Statement::FunctionDeclaration(f) => {
if block_level && !f.generator && !f.r#async {
if let Some(id) = &f.id {
let name = id.name.to_string();
if !names.contains(&name) {
names.push(name);
}
}
}
}
Statement::BlockStatement(bs) => self.collect_block_function_names_into(&bs.body, names, true),
Statement::IfStatement(is) => {
self.collect_block_function_names_into(std::slice::from_ref(&is.consequent), names, true);
if let Some(alt) = &is.alternate {
self.collect_block_function_names_into(std::slice::from_ref(alt), names, true);
}
}
Statement::WhileStatement(wh) => {
self.collect_block_function_names_into(std::slice::from_ref(&wh.body), names, true)
}
Statement::DoWhileStatement(dw) => {
self.collect_block_function_names_into(std::slice::from_ref(&dw.body), names, true)
}
Statement::ForStatement(fs) => {
self.collect_block_function_names_into(std::slice::from_ref(&fs.body), names, true)
}
Statement::ForInStatement(fi) => {
self.collect_block_function_names_into(std::slice::from_ref(&fi.body), names, true)
}
Statement::ForOfStatement(fo) => {
self.collect_block_function_names_into(std::slice::from_ref(&fo.body), names, true)
}
Statement::SwitchStatement(sw) => {
for case in &sw.cases {
self.collect_block_function_names_into(&case.consequent, names, true);
}
}
Statement::TryStatement(ts) => {
self.collect_block_function_names_into(&ts.block.body, names, true);
if let Some(handler) = &ts.handler {
self.collect_block_function_names_into(&handler.body.body, names, true);
}
if let Some(finalizer) = &ts.finalizer {
self.collect_block_function_names_into(&finalizer.body, names, true);
}
}
Statement::LabeledStatement(ls) => {
self.collect_block_function_names_into(std::slice::from_ref(&ls.body), names, true)
}
Statement::WithStatement(ws) => {
self.collect_block_function_names_into(std::slice::from_ref(&ws.body), names, true)
}
_ => {}
}
}
}
/// 收集语句树内的词法声明名(let/const/class 含解构叶、for 头词法名、catch
/// 参数):块级函数名与树内任意词法声明同名时退化为纯块作用域(无外层
/// 绑定、无求值写回)。
///
/// # 边界与前提
/// - 不递归进嵌套函数体/class 元素体:独立编译单元,其词法名不撞本单元的
/// 块函数名。
/// - var 声明是 var 绑定,不撞词法环境,不入集。
fn collect_lexical_name_suppressions(&self, statements: &[Statement], names: &mut HashSet<String>) {
for statement in statements {
match statement {
Statement::VariableDeclaration(vd) => {
if !matches!(vd.kind, VariableDeclarationKind::Var) {
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, names);
}
}
}
Statement::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
names.insert(id.name.to_string());
}
}
Statement::ForStatement(fs) => {
if let Some(oxide_parser::ForStatementInit::VariableDeclaration(decl)) = &fs.init {
if !matches!(decl.kind, VariableDeclarationKind::Var) {
for d in &decl.declarations {
collect_binding_pattern_names(&d.id, names);
}
}
}
self.collect_lexical_name_suppressions(std::slice::from_ref(&fs.body), names);
}
Statement::ForInStatement(fi) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(decl) = &fi.left {
if !matches!(decl.kind, VariableDeclarationKind::Var) {
for d in &decl.declarations {
collect_binding_pattern_names(&d.id, names);
}
}
}
self.collect_lexical_name_suppressions(std::slice::from_ref(&fi.body), names);
}
Statement::ForOfStatement(fo) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(decl) = &fo.left {
if !matches!(decl.kind, VariableDeclarationKind::Var) {
for d in &decl.declarations {
collect_binding_pattern_names(&d.id, names);
}
}
}
self.collect_lexical_name_suppressions(std::slice::from_ref(&fo.body), names);
}
Statement::TryStatement(ts) => {
// catch 参数是 handler 环境的词法绑定。
if let Some(handler) = &ts.handler {
if let Some(param) = &handler.param {
collect_binding_pattern_names(&param.pattern, names);
}
self.collect_lexical_name_suppressions(&handler.body.body, names);
}
self.collect_lexical_name_suppressions(&ts.block.body, names);
if let Some(finalizer) = &ts.finalizer {
self.collect_lexical_name_suppressions(&finalizer.body, names);
}
}
Statement::BlockStatement(bs) => self.collect_lexical_name_suppressions(&bs.body, names),
Statement::IfStatement(is) => {
self.collect_lexical_name_suppressions(std::slice::from_ref(&is.consequent), names);
if let Some(alt) = &is.alternate {
self.collect_lexical_name_suppressions(std::slice::from_ref(alt), names);
}
}
Statement::WhileStatement(wh) => {
self.collect_lexical_name_suppressions(std::slice::from_ref(&wh.body), names)
}
Statement::DoWhileStatement(dw) => {
self.collect_lexical_name_suppressions(std::slice::from_ref(&dw.body), names)
}
Statement::SwitchStatement(sw) => {
for case in &sw.cases {
self.collect_lexical_name_suppressions(&case.consequent, names);
}
}
Statement::LabeledStatement(ls) => {
self.collect_lexical_name_suppressions(std::slice::from_ref(&ls.body), names)
}
Statement::WithStatement(ws) => {
self.collect_lexical_name_suppressions(std::slice::from_ref(&ws.body), names)
}
Statement::ExportNamedDeclaration(exp) => {
if let Some(Declaration::VariableDeclaration(vd)) = &exp.declaration {
if !matches!(vd.kind, VariableDeclarationKind::Var) {
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, names);
}
}
}
}
_ => {}
}
}
}
/// 块级函数名的外层 var 绑定抑制集(sloppy 模式浏览器兼容行为):形参名
/// (含解构叶/rest)∪ 语句树内词法声明名。命中抑制的名字不建外层 var 绑定、
/// 不求值写回。
pub(crate) fn collect_block_fn_suppressed_names(
&self, statements: &[Statement], param_names: &HashSet<String>,
) -> HashSet<String> {
let mut names = param_names.clone();
self.collect_lexical_name_suppressions(statements, &mut names);
names
}
}
-1
View File
@@ -4,6 +4,5 @@
//! (builtin_reg_map),避免与临时寄存器池冲突;同时预声明函数/var 声明,
//! 支持提升语义。
mod block_fn;
mod builtin_scan;
mod declare;
+25 -21
View File
@@ -16,10 +16,7 @@ use oxide_ir::operand::Operand;
use oxide_ir::IRFunction;
use oxide_parser::Statement;
use crate::capture::{
collect_block_level_decl_names, collect_captured_bindings, collect_direct_lexical_names, collect_own_binding_names,
collect_top_level_function_names, collect_top_level_function_names_ordered, collect_var_binding_names,
};
use crate::capture::{collect_captured_bindings, collect_fn_scope_names};
use crate::compile_ctx::CompileCtx;
use crate::Emitter;
@@ -231,10 +228,10 @@ impl Emitter {
/// # 边界与前提
/// - 仅普通脚本调用(`is_eval_script` 面由调用点按条件判定排除);eval 动态
/// 路径与 eval 三常量编译期条件开关零触碰。
/// - 仅遍历语句列表直接子级具名函数声明(生成器/异步声明同节点类型,天然
/// 覆盖);块内函数声明与 `export default function` 不入全局检查面。
pub(crate) fn emit_gdi_func_decl_checks(&self, stmts: &[Statement], ctx: &mut CompileCtx) {
let names = collect_top_level_function_names_ordered(stmts);
/// - `names` 为顶层函数声明名列表(声明序,由调用点经合并单趟收集):仅
/// 直接子级具名函数声明(生成器/异步声明同节点类型,天然覆盖);块内函数
/// 声明与 `export default function` 不入全局检查面。
pub(crate) fn emit_gdi_func_decl_checks(&self, names: &[String], ctx: &mut CompileCtx) {
let mut seen = HashSet::new();
for name in names.iter().rev() {
// 逆序首见即源序最后声明者(规范去重口径),重名只查一次。
@@ -272,6 +269,11 @@ impl Emitter {
// 脚本顶层严格模式由源码 "use strict" directive 决定(嵌套函数经父 ctx 继承)。
ctx.is_strict = program.has_use_strict_directive();
// 程序作用域八个名字面单趟收集(程序无形参,param_names 传空):
// GDI 检查 / eval 门禁 / builtin 排除 / 块函数 / own 绑定 / tier 名集 /
// 入口实例化各调用点共用此结果。
let scope_names = collect_fn_scope_names(&[], &program.body);
// eval 代码顶层函数声明撞不可写全局内置(三常量的全局绑定在任何符合规范的
// 实现中均不可配置,声明实例化无法建立全局绑定):规范在建立全局 var 绑定
// 之前抛 TypeError(step 8 的 abrupt 先于绑定实例化),故 throw 发为程序首
@@ -279,7 +281,7 @@ impl Emitter {
// 严格 eval 代码函数声明绑定 eval 自身 lexical 环境、不触全局、不抛,门禁
// 随 !is_strict 关闭,其写点抑制在声明发射处。
if ctx.is_eval_script && !ctx.is_strict {
for name in collect_top_level_function_names_ordered(&program.body) {
for name in &scope_names.top_level_function_names_ordered {
if NON_WRITABLE_GLOBAL_BUILTINS.contains(&name.as_str()) {
let _ = self.emit_throw_error(
"TypeError",
@@ -295,7 +297,7 @@ impl Emitter {
// 顶层函数声明撞既有不可配置全局属性抛 TypeError,sloppy/strict 同形。
// eval 面零触碰:静态三常量面由上方 eval 三常量编译期门禁拦,动态臂另归口。
if !ctx.is_eval_script {
self.emit_gdi_func_decl_checks(&program.body, &mut ctx);
self.emit_gdi_func_decl_checks(&scope_names.top_level_function_names_ordered, &mut ctx);
}
self.predeclare_function_declarations(&program.body, &mut ctx);
@@ -303,7 +305,7 @@ impl Emitter {
// 预注册 builtin 引用(先于任何临时寄存器),builtin 槽不进入临时寄存器池。
// 顶层词法声明名(let/const/class)排除登记:词法绑定遮蔽同名全局属性,
// 镜像占位先建会与词法预声明撞 scope 0 致合法遮蔽形被编译期误拒。
let lexical_excluded = collect_direct_lexical_names(&program.body);
let lexical_excluded = scope_names.direct_lexical_names.clone();
self.pre_register_builtin_references(&program.body, &lexical_excluded, &mut ctx);
// 预声明顶层 `var` 名,使首个 sub-pass 中提升的函数声明能解析外层 var。
@@ -320,8 +322,8 @@ impl Emitter {
// (define-if-absent,既有属性不改动值)。strict 代码不建。
let mut block_fn_names: Vec<String> = Vec::new();
if !ctx.is_strict {
ctx.block_fn_suppressed = self.collect_block_fn_suppressed_names(&program.body, &ctx.param_names);
block_fn_names = self.collect_block_function_names(&program.body);
ctx.block_fn_suppressed = scope_names.block_fn_suppressed.clone();
block_fn_names = scope_names.block_function_names.clone();
for name in &block_fn_names {
if !ctx.block_fn_suppressed.contains(name) && !CompileCtx::is_non_writable_global_builtin(name) {
self.predeclare_var_name(name, &mut ctx);
@@ -330,7 +332,7 @@ impl Emitter {
}
// 闭包捕获分析(AST 级,emit 前确定)
ctx.own_bindings = collect_own_binding_names(&[], &program.body);
ctx.own_bindings = scope_names.own_binding_names.clone();
// 顶层已声明名(全局对象属性为唯一存储):裸读走全局对象属性、裸写走感知
// 全局对象属性描述符的写,不落引擎侧镜像副本——从捕获集剔除,使嵌套函数经
// 继承 scope 0 直连全局。
@@ -338,9 +340,9 @@ impl Emitter {
// 其全局对象属性值由首个 sub-pass(`emit_program` 顶层的内部阶段划分:先
// 声明实例化、后用户代码发射)以真闭包建立,先于任何用户代码。
// 仅在此顶层调用点过滤:嵌套函数的局部同名遮蔽是独立绑定,其调用点不过滤。
let var_names = collect_var_binding_names(&program.body);
let var_names = scope_names.var_binding_names.clone();
let mut tier_names = var_names.clone();
tier_names.extend(collect_top_level_function_names(&program.body));
tier_names.extend(scope_names.top_level_function_names.iter().cloned());
// 块级函数泄漏名并入:求值期写回与块入口头写同走全局对象属性(全局对象
// 属性为唯一存储)。
for name in &block_fn_names {
@@ -353,7 +355,7 @@ impl Emitter {
// 顶层 tier 名(顶层 var/函数)的全局对象属性是唯一存储,从捕获集剔除;
// 被同名块级绑定(catch 参数 / 块级 let/const)遮蔽时保留,使块级绑定能
// 追加新索引供闭包捕获(顶层 var 本身不建 cell,回填与解析点均跳过)。
let block_level_names = collect_block_level_decl_names(&program.body);
let block_level_names = scope_names.block_level_decl_names.clone();
ctx.captured_bindings
.retain(|n, _| !ctx.global_tier_names.contains(n) || block_level_names.contains(n));
// 顶层函数级绑定 cell 索引回填:预声明已完成,绑定已齐。
@@ -388,9 +390,11 @@ impl Emitter {
// 创建的闭包指向此未初始化 cell,声明前读写经运行时抛真 TDZ;声明语句
// 的 MAKE_CELL 按占位更新语义原位翻转为已初始化。名集取捕获集交集
// (直接子级词法名,块级名不提升到顶层),排序保证发射序跨进程稳定。
let mut lex_names: Vec<String> = collect_direct_lexical_names(&program.body)
.into_iter()
.filter(|n| ctx.captured_bindings.contains_key(n))
let mut lex_names: Vec<String> = scope_names
.direct_lexical_names
.iter()
.filter(|n| ctx.captured_bindings.contains_key(*n))
.cloned()
.collect();
lex_names.sort();
if !lex_names.is_empty() {
@@ -420,7 +424,7 @@ impl Emitter {
// 把全局属性值预载进固定寄存器槽),既有属性不改动值,值幂等保留。
// 序言名集 = 顶层 var 名 ∪ 顶层块级函数泄漏名(sloppy 模式浏览器兼容行为的
// 外层绑定同样在求值前实例化,同走 define-if-absent)。
let mut gdi_var_names: Vec<String> = collect_var_binding_names(&program.body).into_iter().collect();
let mut gdi_var_names: Vec<String> = scope_names.var_binding_names.iter().cloned().collect();
gdi_var_names.extend(
block_fn_names
.iter()
+24
View File
@@ -375,3 +375,27 @@ fn source_encoded_regex_pool_key() {
assert!(!enc.contains("\\ud800"));
assert!(pool_strings(&static_ir).contains("\\ud800"), "静态源池键为明文转义文本");
}
/// 面 12:块函数抑制集含解构形参叶名——块函数名撞叶名时不建外层 var 绑定、
/// 声明点不写回(STORE_VAR 少一条写回);非抑制名块函数有入口 undefined 写
/// 与声明点写回。
#[test]
fn block_fn_suppressed_by_destructured_param_leaf() {
// 撞解构叶名:叶名绑定(1)+ 块函数物化自写(1)= 2,无外层 var 写回。
let suppressed = emit_ir("function f({x}) { { function x() { return 1; } } return 2; }");
let f = &suppressed.nested[0];
assert_eq!(
count_op(&f.insts, OpCode::STORE_VAR),
2,
"撞解构叶名的块函数被抑制:无外层 var 写回"
);
// 非抑制对照:入口 undefined 写(1)+ 块函数物化自写(1)+ 外层 var 写回(1)= 3。
let control = emit_ir("function f() { { function y() { return 1; } } return 2; }");
let fc = &control.nested[0];
assert_eq!(
count_op(&fc.insts, OpCode::STORE_VAR),
3,
"非抑制块函数应有入口 undefined 写与外层 var 写回"
);
}