feat: 捕获 cell 换键 for 头按绑定身份取索引

This commit is contained in:
2026-10-05 16:21:42 +00:00
parent 34e22c5519
commit 1144b07534
7 changed files with 102 additions and 62 deletions
Generated
+18 -18
View File
@@ -1095,7 +1095,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_builtins" name = "oxide_builtins"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"chrono", "chrono",
"fast-float", "fast-float",
@@ -1120,7 +1120,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_bytecode" name = "oxide_bytecode"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxide_log", "oxide_log",
@@ -1128,7 +1128,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cfg" name = "oxide_cfg"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_emit", "oxide_emit",
@@ -1139,7 +1139,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cli" name = "oxide_cli"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"bumpalo", "bumpalo",
@@ -1159,7 +1159,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_code_cache" name = "oxide_code_cache"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"lru", "lru",
"oxide_bytecode", "oxide_bytecode",
@@ -1168,7 +1168,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_compiler" name = "oxide_compiler"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1187,7 +1187,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_dce" name = "oxide_dce"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1201,7 +1201,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_emit" name = "oxide_emit"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxc_allocator", "oxc_allocator",
@@ -1216,7 +1216,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_ir" name = "oxide_ir"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_log", "oxide_log",
@@ -1225,7 +1225,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_kernel" name = "oxide_kernel"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"dashmap", "dashmap",
@@ -1240,7 +1240,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_liveness" name = "oxide_liveness"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1252,7 +1252,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_log" name = "oxide_log"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"tracing", "tracing",
"tracing-appender", "tracing-appender",
@@ -1261,7 +1261,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_parser" name = "oxide_parser"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"oxc_allocator", "oxc_allocator",
"oxc_ast", "oxc_ast",
@@ -1276,7 +1276,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_regalloc" name = "oxide_regalloc"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1292,7 +1292,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_runtime_api" name = "oxide_runtime_api"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"num-traits", "num-traits",
@@ -1304,7 +1304,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_test262" name = "oxide_test262"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_compiler", "oxide_compiler",
@@ -1321,7 +1321,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_types" name = "oxide_types"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"hashbrown 0.14.5", "hashbrown 0.14.5",
@@ -1333,7 +1333,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_vm" name = "oxide_vm"
version = "0.8.8" version = "0.8.9"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"chrono", "chrono",
+1 -1
View File
@@ -22,7 +22,7 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "0.8.8" version = "0.8.9"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
rust-version = "1.80" rust-version = "1.80"
+7
View File
@@ -153,6 +153,12 @@ pub struct CompileCtx {
/// 拷贝的源也是寄存器,故 `emit_bind_target` 对集合内名字在 cell 写之外补写 /// 拷贝的源也是寄存器,故 `emit_bind_target` 对集合内名字在 cell 写之外补写
/// 绑定寄存器。init 发射完毕后清空。 /// 绑定寄存器。init 发射完毕后清空。
pub(crate) for_head_store_registers: HashSet<String>, pub(crate) for_head_store_registers: HashSet<String>,
/// C 风格 for 头保留集:被闭包引用或与顶层 var/函数同名的头名。这些头名保留
/// 独立 cell 贯穿循环(体/test/update 走 cell),其余头名撤出覆盖回退寄存器循环。
/// 仅 C-for 填充(for-in/for-of 全头名保留,本集为空);`emit_bind_target` 头名
/// 回填据此门控,非保留头名不置位绑定字段(否则体区读命中陈旧 cell 致死循环)。
/// begin 前按捕获集与顶层 tier 名计算,init 发射完毕后清空。
pub(crate) for_head_keep: HashSet<String>,
/// 模块编译上下文:当前模块命名空间对象寄存器(`__moduleObject` 返回值)。 /// 模块编译上下文:当前模块命名空间对象寄存器(`__moduleObject` 返回值)。
pub(crate) module_ns_reg: Option<u32>, pub(crate) module_ns_reg: Option<u32>,
/// 写穿反演表:本模块源绑定槽寄存器 → 引用它的导出名集合。仅自导入 ns 的 /// 写穿反演表:本模块源绑定槽寄存器 → 引用它的导出名集合。仅自导入 ns 的
@@ -271,6 +277,7 @@ impl CompileCtx {
completion_frames: Vec::new(), completion_frames: Vec::new(),
register_update_names: Vec::new(), register_update_names: Vec::new(),
for_head_store_registers: HashSet::new(), for_head_store_registers: HashSet::new(),
for_head_keep: HashSet::new(),
module_ns_reg: None, module_ns_reg: None,
module_local_export_regs: HashMap::new(), module_local_export_regs: HashMap::new(),
module_dep_ns_regs: HashMap::new(), module_dep_ns_regs: HashMap::new(),
+9
View File
@@ -78,6 +78,15 @@ impl Emitter {
var_reg var_reg
} }
}; };
// 头名回填:for 头绑定(字段 None)把覆盖 cell 索引写进绑定字段,解析点
// 按绑定身份取索引。保留集门控:C-for 仅保留头名置位(非保留头名走寄存器
// 循环,置位会使体区读命中陈旧 cell 致死循环);for-in/for-of 全头名保留。
// 非 for 头绑定(函数级 / 块级 / catch 参数)已由各自路径置位,不在此覆盖。
if ctx.for_head_keep.contains(name) {
if let Some(&idx) = ctx.captured_bindings.get(name) {
ctx.set_binding_cell_idx(name, idx);
}
}
if ctx.targets_readonly_builtin(name, target_reg) { if ctx.targets_readonly_builtin(name, target_reg) {
// 声明撞全局不可写内置:声明不更新既有全局绑定——sloppy 静默跳过 // 声明撞全局不可写内置:声明不更新既有全局绑定——sloppy 静默跳过
// (槽保留入口预载原值),strict 在初始化求值后抛 TypeError。 // (槽保留入口预载原值),strict 在初始化求值后抛 TypeError。
+23 -7
View File
@@ -68,6 +68,7 @@ impl Emitter {
for name in &names { for name in &names {
if ctx.captured_bindings.contains_key(name) || self.is_global_tier_name(ctx, name) { if ctx.captured_bindings.contains_key(name) || self.is_global_tier_name(ctx, name) {
head_keep.insert(name.clone()); head_keep.insert(name.clone());
ctx.for_head_keep.insert(name.clone());
} }
} }
head_env = Some(self.begin_for_head_env(names.clone(), ctx)?); head_env = Some(self.begin_for_head_env(names.clone(), ctx)?);
@@ -111,6 +112,15 @@ impl Emitter {
} }
} else { } else {
ctx.declare(bi.name.as_str(), var_reg, decl.kind, is_const)?; ctx.declare(bi.name.as_str(), var_reg, decl.kind, is_const)?;
// 头名回填:保留头名在 init 声明点建绑定后把覆盖 cell 索引
// 写进绑定字段,解析点按绑定身份取索引;非保留头名走寄存器
// 循环,不置位绑定字段(否则体区读经可见判定命中陈旧 cell,
// update 段写寄存器不覆写 cell,循环条件恒真致死循环)。
if head_keep.contains(bi.name.as_str()) {
if let Some(&idx) = ctx.captured_bindings.get(bi.name.as_str()) {
ctx.set_binding_cell_idx(bi.name.as_str(), idx);
}
}
(var_reg, false) (var_reg, false)
}; };
if !already_bound { if !already_bound {
@@ -121,10 +131,12 @@ impl Emitter {
Operand::None, Operand::None,
)); ));
} }
// 词法头无初始化声明:覆盖 cell 须置为已初始化(undefined), // 词法头无初始化声明:保留头名的覆盖 cell 须置为已初始化
// 否则后续 init 表达式内创建、捕获该头名的闭包读时误报 TDZ。 // (undefined),否则后续 init 表达式内创建、捕获该头名的
if !matches!(decl.kind, VariableDeclarationKind::Var) { // 闭包读时误报 TDZ;非保留头名走寄存器循环,不建 cell。
if let Some(&cell_idx) = ctx.captured_bindings.get(bi.name.as_str()) { // 索引按绑定实例取(`visible_cell` 已含可见性判定)。
if !matches!(decl.kind, VariableDeclarationKind::Var) && head_keep.contains(bi.name.as_str()) {
if let Some((cell_idx, _)) = ctx.visible_cell(bi.name.as_str()) {
ctx.inst(Inst::new( ctx.inst(Inst::new(
OpCode::MAKE_CELL, OpCode::MAKE_CELL,
Operand::Reg(tmp), Operand::Reg(tmp),
@@ -149,6 +161,7 @@ impl Emitter {
} }
} }
ctx.for_head_store_registers.clear(); ctx.for_head_store_registers.clear();
ctx.for_head_keep.clear();
// 撤出非保留头名的覆盖:普通 for-let 回退寄存器循环,只有被闭包引用或与顶层 // 撤出非保留头名的覆盖:普通 for-let 回退寄存器循环,只有被闭包引用或与顶层
// var/函数同名的头名保留独立 cell 贯穿循环。 // var/函数同名的头名保留独立 cell 贯穿循环。
for name in head_names.iter().flatten() { for name in head_names.iter().flatten() {
@@ -157,11 +170,14 @@ impl Emitter {
} }
} }
// 每迭代 fresh cell 的绑定:保留覆盖者(仍含 cell 下标);已撤出覆盖的头名 // 每迭代 fresh cell 的绑定:保留覆盖者(仍含 cell 下标);已撤出覆盖的头名
// 走寄存器,不含在内。 // 走寄存器,不含在内。门控用保留集而非可见性判定:头名字段对保留与非保留
// 头名都置位,可见性对全部头名返 Some,按可见性门控会误纳非保留头名。
let mut fresh_bindings: Vec<(String, u8)> = Vec::new(); let mut fresh_bindings: Vec<(String, u8)> = Vec::new();
for name in &update_names { for name in &update_names {
if let Some(&cell_idx) = ctx.captured_bindings.get(name) { if head_keep.contains(name) {
fresh_bindings.push((name.clone(), cell_idx)); if let Some((cell_idx, _)) = ctx.visible_cell(name) {
fresh_bindings.push((name.clone(), cell_idx));
}
} }
} }
ctx.labels.set_label_pos(start_label, ctx.insts.len()); ctx.labels.set_label_pos(start_label, ctx.insts.len());
+23 -22
View File
@@ -67,7 +67,7 @@ impl Emitter {
/// ///
/// # 步骤 /// # 步骤
/// 1. 逐头名:移除旧条目并记入恢复清单。 /// 1. 逐头名:移除旧条目并记入恢复清单。
/// 2. 按现有最大 cell 索引顺序分配 TDZ cell(与类 brand 合成 cell 同口径)。 /// 2. 按共享计数器顺序分配 TDZ cell(与块级追加 / 合成 cell 同口径)。
/// 3. 发射未初始化 MAKE_CELL 并覆盖映射。 /// 3. 发射未初始化 MAKE_CELL 并覆盖映射。
/// ///
/// # 副作用 /// # 副作用
@@ -76,11 +76,9 @@ impl Emitter {
/// 防头名泄漏进兄弟语句的捕获判定。 /// 防头名泄漏进兄弟语句的捕获判定。
pub(crate) fn begin_for_head_env(&self, names: Vec<String>, ctx: &mut CompileCtx) -> Result<ForHeadEnv, String> { pub(crate) fn begin_for_head_env(&self, names: Vec<String>, ctx: &mut CompileCtx) -> Result<ForHeadEnv, String> {
let mut entries = Vec::with_capacity(names.len()); let mut entries = Vec::with_capacity(names.len());
let mut next = ctx.captured_bindings.values().copied().max().map_or(0, |m| m.saturating_add(1));
for name in names { for name in names {
let saved = ctx.captured_bindings.remove(&name); let saved = ctx.captured_bindings.remove(&name);
let tdz_idx = next; let tdz_idx = ctx.alloc_cell_idx();
next = next.saturating_add(1);
ctx.captured_bindings.insert(name.clone(), tdz_idx); ctx.captured_bindings.insert(name.clone(), tdz_idx);
// 头名登记:声明点索引解析据此走映射回退,不就地追加新索引。 // 头名登记:声明点索引解析据此走映射回退,不就地追加新索引。
ctx.for_head_env_names.insert(name.clone()); ctx.for_head_env_names.insert(name.clone());
@@ -96,7 +94,6 @@ impl Emitter {
)); ));
entries.push((name, saved, tdz_idx, 0)); entries.push((name, saved, tdz_idx, 0));
} }
ctx.next_cell_idx = next;
Ok(ForHeadEnv { entries }) Ok(ForHeadEnv { entries })
} }
@@ -117,12 +114,10 @@ impl Emitter {
if env.entries.is_empty() { if env.entries.is_empty() {
return; return;
} }
let mut next = ctx.captured_bindings.values().copied().max().map_or(0, |m| m.saturating_add(1));
// 默认值窗口的 TDZ 占位:未初始化标志折入 MAKE_CELL 立即数高字节。 // 默认值窗口的 TDZ 占位:未初始化标志折入 MAKE_CELL 立即数高字节。
let undef_reg = self.emit_undefined(ctx); let undef_reg = self.emit_undefined(ctx);
for (name, _, _, body_idx) in &mut env.entries { for (name, _, _, body_idx) in &mut env.entries {
let idx = next; let idx = ctx.alloc_cell_idx();
next = next.saturating_add(1);
*body_idx = idx; *body_idx = idx;
ctx.captured_bindings.insert(name.clone(), idx); ctx.captured_bindings.insert(name.clone(), idx);
ctx.inst(Inst::new( ctx.inst(Inst::new(
@@ -132,7 +127,6 @@ impl Emitter {
Operand::None, Operand::None,
)); ));
} }
ctx.next_cell_idx = next;
} }
/// 语句收尾恢复捕获映射:旧条目放回(无旧条目则移除),头名不进入后续 /// 语句收尾恢复捕获映射:旧条目放回(无旧条目则移除),头名不进入后续
@@ -148,6 +142,7 @@ impl Emitter {
} }
} }
ctx.for_head_env_names.remove(&name); ctx.for_head_env_names.remove(&name);
ctx.for_head_keep.remove(&name);
} }
} }
@@ -162,7 +157,11 @@ impl Emitter {
// 每迭代 fresh cell,体发射后恢复捕获映射。 // 每迭代 fresh cell,体发射后恢复捕获映射。
let mut head_env = self let mut head_env = self
.collect_for_head_lexical_names(&fi.left) .collect_for_head_lexical_names(&fi.left)
.map(|names| self.begin_for_head_env(names, ctx)) .map(|names| {
// for-in 全头名保留(无撤出覆盖),保留集填全头名供头名回填门控。
ctx.for_head_keep.extend(names.iter().cloned());
self.begin_for_head_env(names, ctx)
})
.transpose()?; .transpose()?;
let obj_reg = self.emit_expression(&fi.right, ctx)?; let obj_reg = self.emit_expression(&fi.right, ctx)?;
if let Some(env) = &mut head_env { if let Some(env) = &mut head_env {
@@ -201,6 +200,12 @@ impl Emitter {
} }
} else { } else {
ctx.declare(name, var_reg, decl.kind, is_const)?; ctx.declare(name, var_reg, decl.kind, is_const)?;
// 头名回填:体区绑定点建绑定后把覆盖 cell 索引写进绑定
// 字段,解析点按绑定身份取索引(var 头绑定已回填,
// 同值覆盖幂等)。
if let Some(&idx) = ctx.captured_bindings.get(name) {
ctx.set_binding_cell_idx(name, idx);
}
var_reg var_reg
}; };
if ctx.targets_readonly_builtin(name, target_reg) { if ctx.targets_readonly_builtin(name, target_reg) {
@@ -209,7 +214,7 @@ impl Emitter {
if ctx.is_strict { if ctx.is_strict {
self.emit_throw_error("TypeError", "cannot assign to read-only property", ctx)?; self.emit_throw_error("TypeError", "cannot assign to read-only property", ctx)?;
} }
} else if let Some(&cell_idx) = ctx.captured_bindings.get(name) { } else if let Some((cell_idx, _)) = ctx.visible_cell(name) {
let op = if fresh_cell { OpCode::MAKE_CELL_FRESH } else { OpCode::MAKE_CELL }; let op = if fresh_cell { OpCode::MAKE_CELL_FRESH } else { OpCode::MAKE_CELL };
ctx.inst(Inst::new( ctx.inst(Inst::new(
op, op,
@@ -253,17 +258,13 @@ impl Emitter {
Operand::Reg(key_reg), Operand::Reg(key_reg),
Operand::Imm(uv_idx as u16), Operand::Imm(uv_idx as u16),
)); ));
} else if let Some(&cell_idx) = ctx.captured_bindings.get(name) { } else if let Some((cell_idx, _)) = ctx.visible_cell(name) {
if ctx.visible_binding_reg(name).is_some() { ctx.inst(Inst::new(
ctx.inst(Inst::new( OpCode::CELL_SET,
OpCode::CELL_SET, Operand::None,
Operand::None, Operand::Reg(key_reg),
Operand::Reg(key_reg), Operand::Imm(cell_idx as u16),
Operand::Imm(cell_idx as u16), ));
));
} else {
self.emit_for_in_assignment_target_write(name, key_reg, ctx)?;
}
} else { } else {
self.emit_for_in_assignment_target_write(name, key_reg, ctx)?; self.emit_for_in_assignment_target_write(name, key_reg, ctx)?;
} }
+21 -14
View File
@@ -30,7 +30,11 @@ impl Emitter {
// 每迭代 fresh cell,体发射后恢复捕获映射(同 for-in 覆盖)。 // 每迭代 fresh cell,体发射后恢复捕获映射(同 for-in 覆盖)。
let mut head_env = self let mut head_env = self
.collect_for_head_lexical_names(&fo.left) .collect_for_head_lexical_names(&fo.left)
.map(|names| self.begin_for_head_env(names, ctx)) .map(|names| {
// for-of 全头名保留(无撤出覆盖),保留集填全头名供头名回填门控。
ctx.for_head_keep.extend(names.iter().cloned());
self.begin_for_head_env(names, ctx)
})
.transpose()?; .transpose()?;
let iter_src_reg = self.emit_expression(&fo.right, ctx)?; let iter_src_reg = self.emit_expression(&fo.right, ctx)?;
if let Some(env) = &mut head_env { if let Some(env) = &mut head_env {
@@ -77,7 +81,11 @@ impl Emitter {
// 词法头 TDZ 环境:同同步 for-of(右值区未初始化 cell → 体区 fresh cell)。 // 词法头 TDZ 环境:同同步 for-of(右值区未初始化 cell → 体区 fresh cell)。
let mut head_env = self let mut head_env = self
.collect_for_head_lexical_names(&fo.left) .collect_for_head_lexical_names(&fo.left)
.map(|names| self.begin_for_head_env(names, ctx)) .map(|names| {
// for-await-of 全头名保留(无撤出覆盖),保留集填全头名供头名回填门控。
ctx.for_head_keep.extend(names.iter().cloned());
self.begin_for_head_env(names, ctx)
})
.transpose()?; .transpose()?;
let iter_src_reg = self.emit_expression(&fo.right, ctx)?; let iter_src_reg = self.emit_expression(&fo.right, ctx)?;
if let Some(env) = &mut head_env { if let Some(env) = &mut head_env {
@@ -153,18 +161,17 @@ impl Emitter {
)); ));
return Ok(()); return Ok(());
} }
// 目标若是被捕获 cell,走 CELL_SET;仅当名字当前可解析为真实词法绑定时才写 // 目标若是被捕获 cell,走 CELL_SET;仅当名字当前可解析为真实词法
// cell,否则落下方全局解析(未声明名不建隐式全局登记)。 // 绑定时才写 cell(`visible_cell` 已含可见性判定),否则落下方
if let Some(&cell_idx) = ctx.captured_bindings.get(name) { // 全局解析(未声明名不建隐式全局登记)。
if ctx.visible_binding_reg(name).is_some() { if let Some((cell_idx, _)) = ctx.visible_cell(name) {
ctx.inst(Inst::new( ctx.inst(Inst::new(
OpCode::CELL_SET, OpCode::CELL_SET,
Operand::None, Operand::None,
Operand::Reg(val_reg), Operand::Reg(val_reg),
Operand::Imm(cell_idx as u16), Operand::Imm(cell_idx as u16),
)); ));
return Ok(()); return Ok(());
}
} }
let var_reg = ctx.lookup_or_global(name); let var_reg = ctx.lookup_or_global(name);
if ctx.targets_readonly_builtin(name, var_reg) { if ctx.targets_readonly_builtin(name, var_reg) {