mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 03:01:12 +08:00
feat: 模块命名空间枚举读活值并支持写穿
This commit is contained in:
@@ -137,6 +137,10 @@ pub struct CompileCtx {
|
||||
pub(crate) for_head_store_registers: HashSet<String>,
|
||||
/// 模块编译上下文:当前模块命名空间对象寄存器(`__moduleObject` 返回值)。
|
||||
pub(crate) module_ns_reg: Option<u32>,
|
||||
/// 写穿反演表:本模块源绑定名 → 引用它的导出名集合。仅自导入 ns 的 live 模块
|
||||
/// 填充;顶层对该源绑定的赋值据此同步命名空间条目。嵌套函数 ctx 为新建,
|
||||
/// 不继承本字段,写穿天然只作用于模块顶层。
|
||||
pub(crate) module_local_exports: HashMap<String, Vec<String>>,
|
||||
/// 已求值依赖模块的命名空间对象寄存器(按 import/export source 字符串索引)。
|
||||
pub(crate) module_dep_ns_regs: HashMap<String, u32>,
|
||||
/// 自导入(import from 自身)的 source 字符串集合:绑定走别名语义,不能链接期快照。
|
||||
@@ -226,6 +230,7 @@ impl CompileCtx {
|
||||
register_update_names: Vec::new(),
|
||||
for_head_store_registers: HashSet::new(),
|
||||
module_ns_reg: None,
|
||||
module_local_exports: HashMap::new(),
|
||||
module_dep_ns_regs: HashMap::new(),
|
||||
module_self_import_specs: HashSet::new(),
|
||||
module_self_aliases: HashMap::new(),
|
||||
|
||||
@@ -66,6 +66,7 @@ impl Emitter {
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(uv as u16),
|
||||
));
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
Ok(val_reg)
|
||||
} else if let Some(cell_idx) = captured_cell {
|
||||
let val_reg = ctx.alloc_reg();
|
||||
@@ -86,6 +87,7 @@ impl Emitter {
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
Ok(val_reg)
|
||||
} else {
|
||||
let var_reg = ctx.lookup_or_global(name);
|
||||
@@ -128,6 +130,8 @@ impl Emitter {
|
||||
// 可写内置名:RMW 新值同步落全局对象属性。
|
||||
self.emit_global_put_write(name, var_reg, ctx);
|
||||
}
|
||||
// live 模块顶层复合赋值同样写穿命名空间条目。
|
||||
self.emit_module_write_through(name, var_reg, ctx)?;
|
||||
Ok(var_reg)
|
||||
}
|
||||
}
|
||||
@@ -586,12 +590,12 @@ impl Emitter {
|
||||
if with_dynamic {
|
||||
let is_const = ctx.lookup_const_flag(name);
|
||||
let const_flag: u16 = if is_const { 1 } else { 0 };
|
||||
self.emit_with_dynamic_write(name, val_reg, const_flag, ctx);
|
||||
self.emit_with_dynamic_write(name, val_reg, const_flag, ctx)?;
|
||||
return Ok(val_reg);
|
||||
}
|
||||
let is_const = ctx.lookup_const_flag(name);
|
||||
let const_flag: u16 = if is_const { 1 } else { 0 };
|
||||
self.emit_identifier_store(name, val_reg, const_flag, ctx);
|
||||
self.emit_identifier_store(name, val_reg, const_flag, ctx)?;
|
||||
Ok(val_reg)
|
||||
}
|
||||
} else if matches!(
|
||||
|
||||
@@ -153,14 +153,19 @@ impl Emitter {
|
||||
/// - cell 写穿共享单元,无运行时 guard;const 拦截由本入口编译期完成。
|
||||
/// - 不可写全局内置(undefined/NaN/Infinity)的全局绑定写在此拦截:sloppy 跳过
|
||||
/// 寄存器写(槽保留入口预载原值),strict 抛 TypeError;局部遮蔽绑定不受影响。
|
||||
pub(crate) fn emit_identifier_store(&self, name: &str, val_reg: u32, const_flag: u16, ctx: &mut CompileCtx) {
|
||||
///
|
||||
/// # 副作用
|
||||
/// - live 模块顶层对导出源绑定的写入追加 `__moduleSet`,同步命名空间条目。
|
||||
pub(crate) fn emit_identifier_store(
|
||||
&self, name: &str, val_reg: u32, const_flag: u16, ctx: &mut CompileCtx,
|
||||
) -> Result<(), String> {
|
||||
// 循环 update 段的 let/const 循环变量是 per-iteration 可变绑定(CreateMutableBinding),
|
||||
// 写寄存器而非 cell,且豁免 const 检查(register_update_names 覆盖全部循环头声明名)。
|
||||
let in_loop_update = ctx.register_update_names.iter().any(|n| n == name);
|
||||
// const 再赋值编译期抛 TypeError:赋值路径(含闭包捕获 const 写 cell)统一拦截。
|
||||
if const_flag != 0 && !in_loop_update {
|
||||
let _ = self.emit_throw_error("TypeError", "Assignment to constant variable", ctx);
|
||||
return;
|
||||
let _ = self.emit_throw_error("TypeError", "Assignment to constant variable", ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
// 循环 update 段:被捕获绑定走寄存器而非 cell——C 风格 for 的 let/const
|
||||
// 循环变量每迭代新分配一个 cell,update 写寄存器供其拷入,不污染本迭代
|
||||
@@ -172,14 +177,14 @@ impl Emitter {
|
||||
if ctx.is_strict {
|
||||
let _ = self.emit_throw_error("TypeError", "cannot assign to read-only property", ctx);
|
||||
}
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(reg), Operand::Reg(val_reg), Operand::Imm(0)));
|
||||
// 可写内置名:值同步落全局对象属性,裸读(镜像)与反射不失步。
|
||||
if ctx.targets_writable_builtin(name, reg) {
|
||||
self.emit_global_put_write(name, reg, ctx);
|
||||
}
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
// 目标若是 upvalue 引用,走 STORE_UPVALUE
|
||||
@@ -190,7 +195,8 @@ impl Emitter {
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(uv_idx as u16),
|
||||
));
|
||||
return;
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
// 目标若是被捕获 cell,走 CELL_SET;仅当名字当前可解析为真实词法绑定时才写
|
||||
// cell——捕获集按名保留的块级绑定在块退出后不可解析(隐式全局登记不算),
|
||||
@@ -203,7 +209,8 @@ impl Emitter {
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
return;
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
let var_reg = ctx.lookup_or_global(name);
|
||||
@@ -213,20 +220,20 @@ impl Emitter {
|
||||
if ctx.is_strict {
|
||||
let _ = self.emit_throw_error("TypeError", "cannot assign to read-only property", ctx);
|
||||
}
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
let is_tier = self.is_global_tier_name(ctx, name);
|
||||
let is_implicit = ctx.is_implicit_global_reg(var_reg);
|
||||
if is_implicit && ctx.is_strict {
|
||||
// 严格模式未声明写:发射 ReferenceError 抛错,跳过寄存器写(值无关)。
|
||||
let _ = self.emit_strict_undeclared_write(name, ctx);
|
||||
return;
|
||||
self.emit_strict_undeclared_write(name, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
if is_tier {
|
||||
// 顶层已声明 var 裸写:写入全局对象属性(顶层 var 的唯一存储,引擎侧不保留
|
||||
// 镜像副本)。
|
||||
self.emit_tier_global_write(name, val_reg, ctx);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::STORE_VAR,
|
||||
@@ -242,6 +249,9 @@ impl Emitter {
|
||||
// enumerable/configurable 位;否则内置名镜像槽与 globalThis 反射读到不同值。
|
||||
self.emit_global_put_write(name, var_reg, ctx);
|
||||
}
|
||||
// 模块顶层对导出源绑定的写入同步命名空间条目;非 live 模块空表直接返回。
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// with 内动态写入:对象有该属性则写对象,否则回退静态写入。
|
||||
@@ -250,7 +260,9 @@ impl Emitter {
|
||||
/// - 仅在 `with_stack` 非空且名字非 with 内部绑定时调用。
|
||||
/// - 对象属性存在性判定与动态读取一致(`in` 含原型链)。
|
||||
/// - 回退目标未在静态作用域声明时不登记全局(with 外不应可见)。
|
||||
pub(crate) fn emit_with_dynamic_write(&self, name: &str, val_reg: u32, const_flag: u16, ctx: &mut CompileCtx) {
|
||||
pub(crate) fn emit_with_dynamic_write(
|
||||
&self, name: &str, val_reg: u32, const_flag: u16, ctx: &mut CompileCtx,
|
||||
) -> Result<(), String> {
|
||||
let obj_reg = ctx.innermost_with_obj().expect("with stack non-empty");
|
||||
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
|
||||
let key_reg = ctx.alloc_reg();
|
||||
@@ -274,9 +286,10 @@ impl Emitter {
|
||||
ctx.labels.set_label_pos(fallback_label, ctx.insts.len());
|
||||
// 回退只写静态作用域已声明的绑定;未声明时丢弃值(隐式全局在 with 外不可解析)。
|
||||
if ctx.scopes.symbols.lookup_any(name).is_some() {
|
||||
self.emit_identifier_store(name, val_reg, const_flag, ctx);
|
||||
self.emit_identifier_store(name, val_reg, const_flag, ctx)?;
|
||||
}
|
||||
ctx.labels.set_label_pos(end_label, ctx.insts.len());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn emit_identifier_expression(
|
||||
|
||||
@@ -477,6 +477,21 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
// —— 写穿反演:源绑定名 → 导出名集合。仅 live 模块(自导入 ns)填充:
|
||||
// 非 live 模块不激活写穿,编译产物逐字节零 IR 变化。按名排序保证多导出名
|
||||
// 映射到同一源绑定时的发射顺序确定。——
|
||||
if has_self_ns_import {
|
||||
let mut pairs: Vec<(&String, &String)> =
|
||||
export_name_map.iter().map(|(exported, source)| (source, exported)).collect();
|
||||
pairs.sort();
|
||||
for (source, exported) in pairs {
|
||||
ctx.module_local_exports
|
||||
.entry(source.clone())
|
||||
.or_default()
|
||||
.push(exported.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// —— live 命名空间预注册:早于 hoisted 函数声明的 __moduleSet 与 body 求值,
|
||||
// 按名序预注册全部本地导出名,使自导入 ns 在读点先观察到未初始化状态。 ——
|
||||
if has_self_ns_import {
|
||||
@@ -662,6 +677,30 @@ impl Emitter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 顶层对导出源绑定的写入同步到命名空间:按反演表把新值写入每个导出名。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 仅在模块顶层 live 模块激活:`module_local_exports` 只由自导入 ns 模块填充,
|
||||
/// 嵌套函数 ctx 不继承该表,行为自然为零;`name` 非导出源时直接返回。
|
||||
/// - 调用方保证 `value_reg` 是写入后的当前值;const 抛错分支不得调用本函数。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 每个命中导出名发射一次 `__moduleSet` 调用,更新命名空间条目与真实槽值。
|
||||
pub(crate) fn emit_module_write_through(
|
||||
&self, name: &str, value_reg: u32, ctx: &mut CompileCtx,
|
||||
) -> Result<(), String> {
|
||||
let Some(ns_reg) = ctx.module_ns_reg else {
|
||||
return Ok(());
|
||||
};
|
||||
let Some(export_names) = ctx.module_local_exports.get(name).cloned() else {
|
||||
return Ok(());
|
||||
};
|
||||
for export_name in export_names {
|
||||
self.emit_module_set(ctx, ns_reg, &export_name, value_reg)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 别名捕获后处理:把源/别名对合并到同一 cell。
|
||||
///
|
||||
/// # 边界与前提
|
||||
|
||||
@@ -102,7 +102,7 @@ impl Emitter {
|
||||
} else if !ctx.with_stack.is_empty() && !ctx.is_with_internal_binding(name) {
|
||||
// with 内 var 初始化:对象有该属性则写对象,否则写提升槽(动态解析)。
|
||||
// ponytail: with 内顶层 var 不写全局对象属性,with 语句本身已是稀见用例。
|
||||
self.emit_with_dynamic_write(name, src_reg, 0, ctx);
|
||||
self.emit_with_dynamic_write(name, src_reg, 0, ctx)?;
|
||||
} else {
|
||||
// const 声明路径 STORE_VAR 恒 b=0,不查运行时 guard。
|
||||
// guard 读 regs[rd] 判断槽是否已初始化,依赖槽初始为 undefined;
|
||||
|
||||
Reference in New Issue
Block a user