mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 自增减发射面 a 槽别名写改可见活寄存器序列,防冲毁活值
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user