diff --git a/crates/oxide_emit/src/expr/operator/mod.rs b/crates/oxide_emit/src/expr/operator/mod.rs index 56329b3c..51f05d65 100644 --- a/crates/oxide_emit/src/expr/operator/mod.rs +++ b/crates/oxide_emit/src/expr/operator/mod.rs @@ -648,12 +648,53 @@ impl Emitter { // 全局不可写内置:值照算(前缀返回新值、后缀返回旧值),跳过槽写。 let tmp_reg = ctx.alloc_reg(); ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(tmp_reg), Operand::Reg(reg), Operand::None)); - let result_reg = ctx.alloc_reg(); - ctx.inst(Inst::new(op, Operand::Reg(tmp_reg), Operand::Reg(result_reg), Operand::Reg(result_reg))); + // 后缀形:增减指令把转换后旧值写临时寄存器、新值写新鲜寄存器 + //(新鲜寄存器活区间跨指令,别名写不冲毁活值),结果返旧值。 + let result_reg = if update.prefix { + // 前缀形:新值直接落临时寄存器,a 槽别名 rd 合并双写。 + ctx.inst(Inst::new(op, Operand::Reg(tmp_reg), Operand::Reg(tmp_reg), Operand::None)); + tmp_reg + } else { + let old_reg = ctx.alloc_reg(); + ctx.inst(Inst::new( + OpCode::LOAD_VAR, + Operand::Reg(old_reg), + Operand::Reg(tmp_reg), + Operand::None, + )); + ctx.inst(Inst::new(op, Operand::Reg(old_reg), Operand::Reg(tmp_reg), Operand::None)); + let result_reg = ctx.alloc_reg(); + ctx.inst(Inst::new( + OpCode::LOAD_VAR, + Operand::Reg(result_reg), + Operand::Reg(tmp_reg), + Operand::None, + )); + ctx.inst(Inst::new( + OpCode::LOAD_VAR, + Operand::Reg(tmp_reg), + Operand::Reg(old_reg), + Operand::None, + )); + result_reg + }; return Ok(result_reg); } - let result_reg = ctx.alloc_reg(); - ctx.inst(Inst::new(op, Operand::Reg(reg), Operand::Reg(result_reg), Operand::Reg(result_reg))); + // 后缀形:增减指令把转换后旧值写循环变量寄存器、新值写新鲜寄存器 + //(新鲜寄存器活区间跨指令,别名写不冲毁活值),结果返旧值。 + let result_reg = if update.prefix { + // 前缀形:新值直接落循环变量寄存器,a 槽别名 rd 合并双写。 + ctx.inst(Inst::new(op, Operand::Reg(reg), Operand::Reg(reg), Operand::None)); + reg + } else { + let old_reg = ctx.alloc_reg(); + ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(old_reg), Operand::Reg(reg), Operand::None)); + ctx.inst(Inst::new(op, Operand::Reg(old_reg), Operand::Reg(reg), Operand::None)); + let result_reg = ctx.alloc_reg(); + ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(reg), Operand::None)); + ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(reg), Operand::Reg(old_reg), Operand::None)); + result_reg + }; // 可写内置名:RMW 新值同步落全局对象属性。 if ctx.targets_writable_builtin(name, reg) { self.emit_global_put_write(name, reg, ctx); @@ -737,14 +778,32 @@ impl Emitter { } let tmp_reg = ctx.alloc_reg(); ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(tmp_reg), Operand::Reg(var_reg), Operand::None)); - let result_reg = ctx.alloc_reg(); let op = match (update.operator, update.prefix) { (UpdateOperator::Increment, true) => OpCode::INC_PRE, (UpdateOperator::Increment, false) => OpCode::INC_POST, (UpdateOperator::Decrement, true) => OpCode::DEC_PRE, (UpdateOperator::Decrement, false) => OpCode::DEC_POST, }; - ctx.inst(Inst::new(op, Operand::Reg(tmp_reg), Operand::Reg(result_reg), Operand::Reg(result_reg))); + // 后缀形:增减指令把转换后旧值写临时寄存器、新值写新鲜寄存器 + //(新鲜寄存器活区间跨指令,别名写不冲毁活值),结果返旧值。 + let result_reg = if update.prefix { + // 前缀形:新值直接落临时寄存器,a 槽别名 rd 合并双写。 + ctx.inst(Inst::new(op, Operand::Reg(tmp_reg), Operand::Reg(tmp_reg), Operand::None)); + tmp_reg + } else { + let old_reg = ctx.alloc_reg(); + ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(old_reg), Operand::Reg(tmp_reg), Operand::None)); + ctx.inst(Inst::new(op, Operand::Reg(old_reg), Operand::Reg(tmp_reg), Operand::None)); + let result_reg = ctx.alloc_reg(); + ctx.inst(Inst::new( + OpCode::LOAD_VAR, + Operand::Reg(result_reg), + Operand::Reg(tmp_reg), + Operand::None, + )); + ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(tmp_reg), Operand::Reg(old_reg), Operand::None)); + result_reg + }; return Ok(result_reg); } let is_tier = self.is_global_tier_name(ctx, name); @@ -764,14 +823,32 @@ impl Emitter { Operand::None, )); } - let result_reg = ctx.alloc_reg(); let op = match (update.operator, update.prefix) { (UpdateOperator::Increment, true) => OpCode::INC_PRE, (UpdateOperator::Increment, false) => OpCode::INC_POST, (UpdateOperator::Decrement, true) => OpCode::DEC_PRE, (UpdateOperator::Decrement, false) => OpCode::DEC_POST, }; - ctx.inst(Inst::new(op, Operand::Reg(var_reg), Operand::Reg(result_reg), Operand::Reg(result_reg))); + // 后缀形:增减指令把转换后旧值写槽寄存器(取数之后)、新值写新鲜寄存器 + //(新鲜寄存器活区间跨指令,别名写不冲毁活值),结果返旧值。 + let result_reg = if update.prefix { + // 前缀形:新值直接落槽寄存器,a 槽别名 rd 合并双写。 + ctx.inst(Inst::new(op, Operand::Reg(var_reg), Operand::Reg(var_reg), Operand::None)); + var_reg + } else { + let old_reg = ctx.alloc_reg(); + ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(old_reg), Operand::Reg(var_reg), Operand::None)); + ctx.inst(Inst::new(op, Operand::Reg(old_reg), Operand::Reg(var_reg), Operand::None)); + let result_reg = ctx.alloc_reg(); + ctx.inst(Inst::new( + OpCode::LOAD_VAR, + Operand::Reg(result_reg), + Operand::Reg(var_reg), + Operand::None, + )); + ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(var_reg), Operand::Reg(old_reg), Operand::None)); + result_reg + }; if is_tier { // 顶层已声明 var 自增/自减:新值写入全局对象属性(顶层 var 的唯一存储, // 引擎侧不保留镜像副本)。 @@ -782,8 +859,8 @@ impl Emitter { // 可写内置名:RMW 新值同步落全局对象属性。 self.emit_global_put_write(name, var_reg, ctx); } - // 槽位寄存器 rd 承载更新后的新值:后缀形式 result_reg 保留旧值, - // 写穿必须取 var_reg,否则命名空间条目被写回旧值。 + // 槽位寄存器承载更新后的新值:写穿必须取 var_reg, + // 否则命名空间条目被写回旧值。 self.emit_module_write_through(name, var_reg, ctx)?; Ok(result_reg) } diff --git a/crates/oxide_emit/src/shared/binding.rs b/crates/oxide_emit/src/shared/binding.rs index 19ca9de7..de17c526 100644 --- a/crates/oxide_emit/src/shared/binding.rs +++ b/crates/oxide_emit/src/shared/binding.rs @@ -278,13 +278,8 @@ impl Emitter { Operand::Reg(idx_reg), Operand::Reg(val_reg), )); - let tmp_reg = ctx.alloc_reg(); - ctx.inst(Inst::new( - OpCode::INC_PRE, - Operand::Reg(idx_reg), - Operand::Reg(tmp_reg), - Operand::Reg(tmp_reg), - )); + // a 槽别名 rd:增减指令双写合并为一次,idx_reg 新值供下一轮 SET_ELEM 使用。 + ctx.inst(Inst::new(OpCode::INC_PRE, Operand::Reg(idx_reg), Operand::Reg(idx_reg), Operand::None)); ctx.inst(Inst::jmp(loop_start)); ctx.labels.set_label_pos(loop_end, ctx.insts.len()); Ok(rest_reg) diff --git a/crates/oxide_vm/tests/arguments_tests.rs b/crates/oxide_vm/tests/arguments_tests.rs index a00e2a28..965f6818 100644 --- a/crates/oxide_vm/tests/arguments_tests.rs +++ b/crates/oxide_vm/tests/arguments_tests.rs @@ -180,3 +180,27 @@ fn top_level_fn_named_arguments_suppresses_object() { let result = eval_str(&mut vm, "function f(){return typeof arguments; function arguments(){}} f()"); assert_eq!(result, "function"); } + +#[test] +fn global_self_increment_preserves_arguments() { + // 全局自增减(后缀)在槽寄存器内计算,arguments 对象不被别名写冲毁。 + let mut vm = Vm::new(); + let result = eval(&mut vm, "function f(a){c++; return arguments.length} f(1)").unwrap(); + assert_eq!(result.as_int(), 1); +} + +#[test] +fn global_prefix_self_increment_preserves_arguments() { + // 顶层声明 var 的前缀自增同形:新值落槽寄存器,arguments 对象完好。 + let mut vm = Vm::new(); + let result = eval(&mut vm, "var c=1; function f(a){++c; return arguments.length} f(1)").unwrap(); + assert_eq!(result.as_int(), 1); +} + +#[test] +fn global_self_decrement_preserves_arguments() { + // 顶层声明 var 的后缀自减同形:arguments 对象完好。 + let mut vm = Vm::new(); + let result = eval(&mut vm, "var c=1; function f(a){c--; return arguments.length} f(1)").unwrap(); + assert_eq!(result.as_int(), 1); +}