fix: 自增减发射面 a 槽别名写改可见活寄存器序列,防冲毁活值

This commit is contained in:
2026-09-26 21:17:47 +00:00
parent 3bb6b1e353
commit 631d430772
3 changed files with 113 additions and 17 deletions
+85 -8
View File
@@ -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 = 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(op, Operand::Reg(tmp_reg), Operand::Reg(result_reg), Operand::Reg(result_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 = 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(op, Operand::Reg(reg), Operand::Reg(result_reg), Operand::Reg(result_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)
}
+2 -7
View File
@@ -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)
+24
View File
@@ -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);
}