mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 19:21:11 +08:00
fix: 脚本顶层 var/function 声明落 globalThis(DEFINE_GLOBAL_PROP 非可配置数据属性)
This commit is contained in:
@@ -166,6 +166,9 @@ pub struct CompileCtx {
|
||||
pub(crate) is_generator: bool,
|
||||
/// 本函数是否为异步函数体(`async function` / async 箭头),`assemble_ir` 回写到 IR。
|
||||
pub(crate) is_async: bool,
|
||||
/// 是否为脚本顶层模块(emit_program 的根上下文)。顶层 var/function 声明需
|
||||
/// 同步写全局对象属性(脚本环境记录的 var 可经 globalThis 反射);函数体为 false。
|
||||
pub(crate) is_global_scope: bool,
|
||||
pub(crate) static_block_this_reg: Option<u8>,
|
||||
pub(crate) field_buffer: Option<FieldBuffer>,
|
||||
/// 类构造器模块中 `@@field_keys` upvalue 下标(实例字段 computed key 数组)。
|
||||
@@ -274,6 +277,7 @@ impl CompileCtx {
|
||||
in_static_method: false,
|
||||
is_generator: false,
|
||||
is_async: false,
|
||||
is_global_scope: false,
|
||||
static_block_this_reg: None,
|
||||
field_buffer: None,
|
||||
field_keys_uv: None,
|
||||
@@ -1245,12 +1249,30 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
/// 把脚本顶层 var/function 绑定的当前值同步写入全局对象属性,使顶层声明
|
||||
/// 可经 `globalThis` 反射(脚本环境记录的 var 绑定全局对象属性)。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 仅顶层模块上下文调用:顶层 `this`(物理寄存器 254)恒为全局对象。
|
||||
/// - let/const/class 不落全局对象,不得调用本函数。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 定义全局对象数据属性(可写/可枚举/不可配置),属性缺失时新建。
|
||||
pub(crate) fn emit_global_prop_write(&self, name: &str, val_reg: u32, ctx: &mut CompileCtx) {
|
||||
let idx = ctx.add_constant(Constant::String(name.to_string()));
|
||||
let key_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
|
||||
ctx.inst(Inst::define_global_prop(Operand::This, Operand::Reg(val_reg), Operand::Reg(key_reg)));
|
||||
}
|
||||
|
||||
/// 把完整程序编译为顶层模块体的 IRFunction。
|
||||
///
|
||||
/// 调用方为 `oxide_compiler::Compiler::compile`:本函数完成 emit 半程,
|
||||
/// 随后由 `oxide_ir::lower::lower` 降为字节码。
|
||||
pub fn emit_program(&self, program: &oxide_parser::Program) -> Result<IRFunction, String> {
|
||||
let mut ctx = CompileCtx::new();
|
||||
// 脚本顶层:var/function 声明需落到全局对象,let/const/class 不进全局。
|
||||
ctx.is_global_scope = true;
|
||||
ctx.pre_register_builtins();
|
||||
self.predeclare_function_declarations(&program.body, &mut ctx);
|
||||
|
||||
|
||||
@@ -74,6 +74,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);
|
||||
} else {
|
||||
// const 声明路径 STORE_VAR 恒 b=0,不查运行时 guard。
|
||||
@@ -88,6 +89,10 @@ impl Emitter {
|
||||
));
|
||||
}
|
||||
ctx.init_var(name);
|
||||
// 脚本顶层 var:同步写全局对象,使 globalThis.x 反射声明值。
|
||||
if ctx.is_global_scope && matches!(kind, VariableDeclarationKind::Var) {
|
||||
self.emit_global_prop_write(name, src_reg, ctx);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -240,9 +245,7 @@ impl Emitter {
|
||||
}
|
||||
|
||||
/// 向 excluded 数组下标 `idx` 写入一个键:`key_val` 为运行时寄存器值,否则用 `key_str` 常量。
|
||||
fn emit_push_excluded_key(
|
||||
&self, arr: u32, key_val: Option<u32>, key_str: &str, idx: usize, ctx: &mut CompileCtx,
|
||||
) {
|
||||
fn emit_push_excluded_key(&self, arr: u32, key_val: Option<u32>, key_str: &str, idx: usize, ctx: &mut CompileCtx) {
|
||||
let val_reg = match key_val {
|
||||
Some(kv) => kv,
|
||||
None => {
|
||||
@@ -255,7 +258,12 @@ impl Emitter {
|
||||
let elem_idx = ctx.alloc_reg();
|
||||
let cidx = ctx.add_constant(Constant::Int(idx as i32));
|
||||
ctx.inst(Inst::load_const(Operand::Reg(elem_idx), cidx));
|
||||
ctx.inst(Inst::new(OpCode::SET_ELEM, Operand::Reg(arr), Operand::Reg(elem_idx), Operand::Reg(val_reg)));
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::SET_ELEM,
|
||||
Operand::Reg(arr),
|
||||
Operand::Reg(elem_idx),
|
||||
Operand::Reg(val_reg),
|
||||
));
|
||||
}
|
||||
|
||||
fn emit_assignment_maybe_default(
|
||||
|
||||
@@ -60,6 +60,10 @@ impl Emitter {
|
||||
} else {
|
||||
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(var_reg), Operand::Reg(var_reg), Operand::None));
|
||||
}
|
||||
// 脚本顶层函数声明:同步写全局对象,使 globalThis 可反射函数名。
|
||||
if ctx.is_global_scope {
|
||||
self.emit_global_prop_write(&name, var_reg, ctx);
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,10 @@ impl Emitter {
|
||||
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(target_reg), Operand::Reg(tmp), Operand::None));
|
||||
}
|
||||
ctx.init_var(bi.name.as_str());
|
||||
// 脚本顶层 var 无初始化:仍须写全局对象属性(值为 undefined)。
|
||||
if ctx.is_global_scope && matches!(decl.kind, VariableDeclarationKind::Var) {
|
||||
self.emit_global_prop_write(bi.name.as_str(), tmp, ctx);
|
||||
}
|
||||
r = Some(var_reg);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user