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();
|
let tmp_reg = ctx.alloc_reg();
|
||||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(tmp_reg), Operand::Reg(reg), Operand::None));
|
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();
|
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);
|
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();
|
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 新值同步落全局对象属性。
|
// 可写内置名:RMW 新值同步落全局对象属性。
|
||||||
if ctx.targets_writable_builtin(name, reg) {
|
if ctx.targets_writable_builtin(name, reg) {
|
||||||
self.emit_global_put_write(name, reg, ctx);
|
self.emit_global_put_write(name, reg, ctx);
|
||||||
@@ -737,14 +778,32 @@ impl Emitter {
|
|||||||
}
|
}
|
||||||
let tmp_reg = ctx.alloc_reg();
|
let tmp_reg = ctx.alloc_reg();
|
||||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(tmp_reg), Operand::Reg(var_reg), Operand::None));
|
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) {
|
let op = match (update.operator, update.prefix) {
|
||||||
(UpdateOperator::Increment, true) => OpCode::INC_PRE,
|
(UpdateOperator::Increment, true) => OpCode::INC_PRE,
|
||||||
(UpdateOperator::Increment, false) => OpCode::INC_POST,
|
(UpdateOperator::Increment, false) => OpCode::INC_POST,
|
||||||
(UpdateOperator::Decrement, true) => OpCode::DEC_PRE,
|
(UpdateOperator::Decrement, true) => OpCode::DEC_PRE,
|
||||||
(UpdateOperator::Decrement, false) => OpCode::DEC_POST,
|
(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);
|
return Ok(result_reg);
|
||||||
}
|
}
|
||||||
let is_tier = self.is_global_tier_name(ctx, name);
|
let is_tier = self.is_global_tier_name(ctx, name);
|
||||||
@@ -764,14 +823,32 @@ impl Emitter {
|
|||||||
Operand::None,
|
Operand::None,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let result_reg = ctx.alloc_reg();
|
|
||||||
let op = match (update.operator, update.prefix) {
|
let op = match (update.operator, update.prefix) {
|
||||||
(UpdateOperator::Increment, true) => OpCode::INC_PRE,
|
(UpdateOperator::Increment, true) => OpCode::INC_PRE,
|
||||||
(UpdateOperator::Increment, false) => OpCode::INC_POST,
|
(UpdateOperator::Increment, false) => OpCode::INC_POST,
|
||||||
(UpdateOperator::Decrement, true) => OpCode::DEC_PRE,
|
(UpdateOperator::Decrement, true) => OpCode::DEC_PRE,
|
||||||
(UpdateOperator::Decrement, false) => OpCode::DEC_POST,
|
(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 {
|
if is_tier {
|
||||||
// 顶层已声明 var 自增/自减:新值写入全局对象属性(顶层 var 的唯一存储,
|
// 顶层已声明 var 自增/自减:新值写入全局对象属性(顶层 var 的唯一存储,
|
||||||
// 引擎侧不保留镜像副本)。
|
// 引擎侧不保留镜像副本)。
|
||||||
@@ -782,8 +859,8 @@ impl Emitter {
|
|||||||
// 可写内置名:RMW 新值同步落全局对象属性。
|
// 可写内置名:RMW 新值同步落全局对象属性。
|
||||||
self.emit_global_put_write(name, var_reg, ctx);
|
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)?;
|
self.emit_module_write_through(name, var_reg, ctx)?;
|
||||||
Ok(result_reg)
|
Ok(result_reg)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -278,13 +278,8 @@ impl Emitter {
|
|||||||
Operand::Reg(idx_reg),
|
Operand::Reg(idx_reg),
|
||||||
Operand::Reg(val_reg),
|
Operand::Reg(val_reg),
|
||||||
));
|
));
|
||||||
let tmp_reg = ctx.alloc_reg();
|
// a 槽别名 rd:增减指令双写合并为一次,idx_reg 新值供下一轮 SET_ELEM 使用。
|
||||||
ctx.inst(Inst::new(
|
ctx.inst(Inst::new(OpCode::INC_PRE, Operand::Reg(idx_reg), Operand::Reg(idx_reg), Operand::None));
|
||||||
OpCode::INC_PRE,
|
|
||||||
Operand::Reg(idx_reg),
|
|
||||||
Operand::Reg(tmp_reg),
|
|
||||||
Operand::Reg(tmp_reg),
|
|
||||||
));
|
|
||||||
ctx.inst(Inst::jmp(loop_start));
|
ctx.inst(Inst::jmp(loop_start));
|
||||||
ctx.labels.set_label_pos(loop_end, ctx.insts.len());
|
ctx.labels.set_label_pos(loop_end, ctx.insts.len());
|
||||||
Ok(rest_reg)
|
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()");
|
let result = eval_str(&mut vm, "function f(){return typeof arguments; function arguments(){}} f()");
|
||||||
assert_eq!(result, "function");
|
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