mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 间接 eval 读全局词法环境镜像并补齐写路径
This commit is contained in:
@@ -426,6 +426,9 @@ impl Emitter {
|
||||
Operand::Reg(ctor_reg),
|
||||
Operand::None,
|
||||
));
|
||||
// 顶层词法双写镜像:类声明值同步写镜像,使跨脚本(间接 eval)读经
|
||||
// 镜像见当前值。
|
||||
self.emit_global_lex_mirror_write(name, ctor_reg, ctx);
|
||||
if let Some(cell_idx) = class_self_cell {
|
||||
// 以构造器初始化类名 cell 并解除 TDZ(占位 cell 已由类元素闭包在 hoist 期创建)。
|
||||
ctx.inst(Inst::new(
|
||||
|
||||
@@ -887,6 +887,15 @@ impl CompileCtx {
|
||||
matches!(self.scopes.symbols.lookup_any_binding(name), Some((binding, 0)) if !binding.lexical)
|
||||
}
|
||||
|
||||
/// 名字是否解析到顶层词法绑定(全局词法环境):scope 0 的 let/const/class/
|
||||
/// 导入绑定。顶层词法绑定的值存储是全局词法环境记录(镜像),所有写路径
|
||||
/// (声明/赋值/复合/逻辑/update/解构)须同步镜像,否则跨脚本(间接 eval)
|
||||
/// 读经镜像见陈旧值。块级词法(scope >0)与顶层 var/隐式全局(lexical 不置位)
|
||||
/// 不属全局词法环境,不写镜像。
|
||||
pub(crate) fn is_global_lexical_binding(&self, name: &str) -> bool {
|
||||
matches!(self.scopes.symbols.lookup_any_binding(name), Some((binding, 0)) if binding.lexical)
|
||||
}
|
||||
|
||||
/// 写目标是否为只读全局内置(undefined/NaN/Infinity 的全局绑定——全局对象上
|
||||
/// 数据属性 {writable:false, configurable:false},put 永不成功)。名字在只读
|
||||
/// 名单内且解析到全局内置槽;声明臂与赋值臂共用本谓词。
|
||||
|
||||
@@ -91,6 +91,7 @@ impl Emitter {
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(uv as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, val_reg, ctx);
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
Ok(val_reg)
|
||||
} else if let Some((cell_idx, binding_reg)) = ctx.visible_cell(name) {
|
||||
@@ -108,6 +109,7 @@ impl Emitter {
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, val_reg, ctx);
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
Ok(val_reg)
|
||||
} else {
|
||||
@@ -162,6 +164,9 @@ impl Emitter {
|
||||
// 可写内置名:RMW 新值同步落全局对象属性。
|
||||
self.emit_global_put_write(name, var_reg, ctx);
|
||||
}
|
||||
// 顶层词法双写镜像:RMW 新值同步写镜像,使跨脚本(间接 eval)读经镜像
|
||||
// 见当前值。
|
||||
self.emit_global_lex_mirror_write(name, var_reg, ctx);
|
||||
// live 模块顶层复合赋值同样写穿命名空间条目。
|
||||
self.emit_module_write_through(name, var_reg, ctx)?;
|
||||
Ok(var_reg)
|
||||
@@ -609,6 +614,9 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 顶层词法双写镜像:短路通过后新值同步写镜像,使跨脚本(间接
|
||||
// eval)读经镜像见当前值。
|
||||
self.emit_global_lex_mirror_write(name, val_reg, ctx);
|
||||
// 逻辑赋值仅在短路通过后到达此处:写穿同步命名空间条目。
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
ctx.inst(Inst::new(
|
||||
|
||||
@@ -79,8 +79,9 @@ impl Emitter {
|
||||
|| ctx.is_implicit_global_reg(var_reg)
|
||||
|| (ctx.is_builtin(name) && !ctx.is_local_shadowing_builtin(name))
|
||||
{
|
||||
// 全局词法环境读:先查镜像(顶层 let/const 真源),未命中回退全局对象属性。
|
||||
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
|
||||
ctx.inst(Inst::new(OpCode::LOAD_GLOBAL, Operand::Reg(r), Operand::Const(key_idx), Operand::None));
|
||||
ctx.inst(Inst::new(OpCode::LOAD_GLOBAL_LEX, Operand::Reg(r), Operand::Const(key_idx), Operand::None));
|
||||
} else {
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(r), Operand::Reg(var_reg), Operand::None));
|
||||
}
|
||||
@@ -139,22 +140,22 @@ impl Emitter {
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
} else if self.is_global_tier_name(ctx, name) {
|
||||
// 顶层已声明 var:with 对象无该属性时回退读全局对象属性(顶层 var 的唯一
|
||||
// 存储,引擎侧不保留镜像副本)。
|
||||
// 顶层已声明 var:with 对象无该属性时回退读全局词法环境(镜像优先,
|
||||
// 未命中回退全局对象属性)。
|
||||
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::LOAD_GLOBAL,
|
||||
OpCode::LOAD_GLOBAL_LEX,
|
||||
Operand::Reg(result_reg),
|
||||
Operand::Const(key_idx),
|
||||
Operand::None,
|
||||
));
|
||||
} else if let Some(reg) = ctx.scopes.symbols.lookup_any(name) {
|
||||
// 已知 builtin 名(非局部遮蔽)读 A 侧全局对象属性,与静态读臂同形;
|
||||
// 局部遮蔽绑定保持 LOAD_VAR 读局部槽。
|
||||
// 已知 builtin 名(非局部遮蔽)读全局词法环境(镜像优先,未命中回退
|
||||
// 全局对象属性),与静态读臂同形;局部遮蔽绑定保持 LOAD_VAR 读局部槽。
|
||||
if ctx.is_builtin(name) && !ctx.is_local_shadowing_builtin(name) {
|
||||
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::LOAD_GLOBAL,
|
||||
OpCode::LOAD_GLOBAL_LEX,
|
||||
Operand::Reg(result_reg),
|
||||
Operand::Const(key_idx),
|
||||
Operand::None,
|
||||
@@ -171,6 +172,17 @@ impl Emitter {
|
||||
Ok(result_reg)
|
||||
}
|
||||
|
||||
/// 顶层词法绑定镜像写:写目标是顶层词法绑定(全局词法环境)时把新值同步写
|
||||
/// 镜像,使跨脚本(间接 eval)读经镜像见当前值。eval 脚本顶层词法落自身声明
|
||||
/// 环境,不写镜像;非顶层词法(块级)与顶层 var/隐式全局不属全局词法环境,
|
||||
/// 不写镜像。
|
||||
pub(crate) fn emit_global_lex_mirror_write(&self, name: &str, val_reg: u32, ctx: &mut CompileCtx) {
|
||||
if ctx.is_global_scope && !ctx.is_eval_script && ctx.is_global_lexical_binding(name) {
|
||||
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
|
||||
ctx.inst(Inst::store_global_lex(Operand::Reg(val_reg), key_idx));
|
||||
}
|
||||
}
|
||||
|
||||
/// 静态标识符写入:upvalue / 被捕获 cell / 普通槽(含 const guard)。
|
||||
///
|
||||
/// # 边界与前提
|
||||
@@ -229,6 +241,7 @@ impl Emitter {
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(uv_idx as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, val_reg, ctx);
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
@@ -243,6 +256,7 @@ impl Emitter {
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, val_reg, ctx);
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
@@ -282,6 +296,9 @@ impl Emitter {
|
||||
// enumerable/configurable 位;否则内置名镜像槽与 globalThis 反射读到不同值。
|
||||
self.emit_global_put_write(name, var_reg, ctx);
|
||||
}
|
||||
// 顶层词法双写镜像:宿主脚本(主脚本 + 宿主 evalScript)顶层 let/const 赋值
|
||||
// 同步写镜像,使跨脚本(间接 eval)读经镜像可见当前值。
|
||||
self.emit_global_lex_mirror_write(name, val_reg, ctx);
|
||||
// 模块顶层对导出源绑定的写入同步命名空间条目;非 live 模块空表直接返回。
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
Ok(())
|
||||
|
||||
@@ -915,6 +915,7 @@ impl Emitter {
|
||||
Operand::Reg(new_reg),
|
||||
Operand::Imm(uv as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, new_reg, ctx);
|
||||
self.emit_module_write_through(name, new_reg, ctx)?;
|
||||
Ok(if update.prefix { new_reg } else { old_reg })
|
||||
} else if let Some((cell_idx, binding_reg)) = ctx.visible_cell(name) {
|
||||
@@ -943,6 +944,7 @@ impl Emitter {
|
||||
Operand::Reg(new_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, new_reg, ctx);
|
||||
self.emit_module_write_through(name, new_reg, ctx)?;
|
||||
Ok(if update.prefix { new_reg } else { old_reg })
|
||||
} else {
|
||||
@@ -1048,6 +1050,9 @@ impl Emitter {
|
||||
// 可写内置名:RMW 新值同步落全局对象属性。
|
||||
self.emit_global_put_write(name, var_reg, ctx);
|
||||
}
|
||||
// 顶层词法双写镜像:更新后新值同步写镜像,使跨脚本(间接 eval)读经
|
||||
// 镜像见当前值。
|
||||
self.emit_global_lex_mirror_write(name, var_reg, ctx);
|
||||
// 槽位寄存器承载更新后的新值:写穿必须取 var_reg,
|
||||
// 否则命名空间条目被写回旧值。
|
||||
self.emit_module_write_through(name, var_reg, ctx)?;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use crate::symbol_table::ScopeKind;
|
||||
use crate::{CompileCtx, Emitter};
|
||||
use oxide_bytecode::module::Constant;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
@@ -394,6 +395,18 @@ impl Emitter {
|
||||
VariableDeclarationKind::Let
|
||||
},
|
||||
);
|
||||
// 顶层词法双写镜像:宿主脚本(主脚本 + 宿主 evalScript)顶层 let/const
|
||||
// 落全局词法环境,预声明期先写 undefined 占位(无初始化器声明即终值;
|
||||
// 带初始化器声明由声明点写真实值覆盖)。eval 脚本顶层词法落自身声明
|
||||
// 环境,不写镜像;块级词法(scope >0)不属全局词法环境,不写镜像。
|
||||
if ctx.is_global_scope
|
||||
&& !ctx.is_eval_script
|
||||
&& ctx.is_global_lexical_binding(bi.name.as_str())
|
||||
{
|
||||
let key_idx = ctx.add_constant(Constant::String(bi.name.to_string()));
|
||||
let undef_reg = self.emit_undefined(ctx);
|
||||
ctx.inst(Inst::store_global_lex(Operand::Reg(undef_reg), key_idx));
|
||||
}
|
||||
// 块级遮蔽绑定:名字在捕获集且最内层为块作用域时,追加新 cell
|
||||
// 索引并发未初始化 MAKE_CELL(TDZ 占位)。声明点与闭包捕获据
|
||||
// 绑定字段走新索引,不原位覆写函数级同名绑定的名字排序索引;
|
||||
|
||||
@@ -129,6 +129,11 @@ impl Emitter {
|
||||
Operand::Imm(0),
|
||||
));
|
||||
}
|
||||
// 顶层词法双写镜像:宿主脚本(主脚本 + 宿主 evalScript)顶层 let/const 落
|
||||
// 全局词法环境,声明点把值写镜像,使跨脚本(间接 eval)读经镜像可见。
|
||||
// eval 脚本顶层词法落自身声明环境,不写镜像;块级词法(scope >0)与顶层
|
||||
// var 不属全局词法环境,不写镜像。
|
||||
self.emit_global_lex_mirror_write(name, src_reg, ctx);
|
||||
ctx.init_var(name);
|
||||
// 脚本顶层 var:同步写全局对象,使 globalThis.x 反射声明值。
|
||||
if ctx.is_global_scope && matches!(kind, VariableDeclarationKind::Var) {
|
||||
@@ -168,6 +173,7 @@ impl Emitter {
|
||||
Operand::Reg(src_reg),
|
||||
Operand::Imm(uv_idx as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, src_reg, ctx);
|
||||
self.emit_module_write_through(name, src_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
@@ -181,6 +187,7 @@ impl Emitter {
|
||||
Operand::Reg(src_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, src_reg, ctx);
|
||||
self.emit_module_write_through(name, src_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
@@ -217,6 +224,8 @@ impl Emitter {
|
||||
// 可写内置名:值同步落全局对象属性。
|
||||
self.emit_global_put_write(name, var_reg, ctx);
|
||||
}
|
||||
// 顶层词法双写镜像:值同步写镜像,使跨脚本(间接 eval)读经镜像见当前值。
|
||||
self.emit_global_lex_mirror_write(name, src_reg, ctx);
|
||||
// live 模块顶层解构赋值目标同样写穿命名空间条目。
|
||||
self.emit_module_write_through(name, src_reg, ctx)?;
|
||||
Ok(())
|
||||
@@ -397,6 +406,7 @@ impl Emitter {
|
||||
Operand::Reg(src_reg),
|
||||
Operand::Imm(uv_idx as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, src_reg, ctx);
|
||||
self.emit_module_write_through(name, src_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
@@ -410,6 +420,7 @@ impl Emitter {
|
||||
Operand::Reg(src_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, src_reg, ctx);
|
||||
self.emit_module_write_through(name, src_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
@@ -446,6 +457,8 @@ impl Emitter {
|
||||
// 可写内置名:值同步落全局对象属性。
|
||||
self.emit_global_put_write(name, var_reg, ctx);
|
||||
}
|
||||
// 顶层词法双写镜像:值同步写镜像,使跨脚本(间接 eval)读经镜像见当前值。
|
||||
self.emit_global_lex_mirror_write(name, src_reg, ctx);
|
||||
// live 模块顶层解构赋值目标同样写穿命名空间条目。
|
||||
self.emit_module_write_through(name, src_reg, ctx)?;
|
||||
Ok(())
|
||||
@@ -516,6 +529,7 @@ impl Emitter {
|
||||
Operand::Reg(prop_reg),
|
||||
Operand::Imm(uv_idx as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, prop_reg, ctx);
|
||||
self.emit_module_write_through(name, prop_reg, ctx)?;
|
||||
continue;
|
||||
}
|
||||
@@ -529,6 +543,7 @@ impl Emitter {
|
||||
Operand::Reg(prop_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_global_lex_mirror_write(name, prop_reg, ctx);
|
||||
self.emit_module_write_through(name, prop_reg, ctx)?;
|
||||
continue;
|
||||
}
|
||||
@@ -565,6 +580,8 @@ impl Emitter {
|
||||
// 可写内置名:值同步落全局对象属性(其余属性继续赋值)。
|
||||
self.emit_global_put_write(name, var_reg, ctx);
|
||||
}
|
||||
// 顶层词法双写镜像:值同步写镜像,使跨脚本(间接 eval)读经镜像见当前值。
|
||||
self.emit_global_lex_mirror_write(name, prop_reg, ctx);
|
||||
// live 模块顶层解构赋值目标同样写穿命名空间条目。
|
||||
self.emit_module_write_through(name, prop_reg, ctx)?;
|
||||
}
|
||||
|
||||
@@ -132,8 +132,12 @@ impl Emitter {
|
||||
let mut static_regs = words;
|
||||
let first_arg_reg = if static_regs.is_empty() { 0u32 } else { pack_arg_regs(&mut static_regs, ctx) };
|
||||
let op = match &call.callee {
|
||||
// 可选链调用(eval?.)是间接求值:走通用 CALL 而非 CALL_NATIVE,
|
||||
// 不传直接求值上下文(规范 ChainEvaluation 的 eval 特判)。
|
||||
Expression::Identifier(ident)
|
||||
if ctx.is_builtin(ident.name.as_str()) && !ctx.is_local_shadowing_builtin(ident.name.as_str()) =>
|
||||
if ctx.is_builtin(ident.name.as_str())
|
||||
&& !ctx.is_local_shadowing_builtin(ident.name.as_str())
|
||||
&& !call.optional =>
|
||||
{
|
||||
OpCode::CALL_NATIVE
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user