mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 模板表达式高位寄存器槽保留
This commit is contained in:
@@ -37,7 +37,7 @@ impl Inst {
|
||||
/// # 边界与前提
|
||||
/// - `Range`:nargs=ext[0],从指定槽起连续 nargs 个寄存器。
|
||||
/// - `SpreadArgs`:ext[1..] 每个字 `& 0x7FFF_FFFF`。
|
||||
/// - `TemplateExprs`:ext[1..] 中 `seg>>31==1` 的低 8 位。
|
||||
/// - `TemplateExprs`:ext[1..] 中 `seg>>31==1` 的低 31 位。
|
||||
/// - `BrandReg`:ext[0] 非 0 才产生 use。
|
||||
/// - `ExtReg`:ext[0] `& 0x7FFF_FFFF`(高位标记的寄存器号)。
|
||||
pub fn use_regs(&self) -> SmallVec<[u32; 4]> {
|
||||
@@ -58,7 +58,7 @@ impl Inst {
|
||||
SlotSpec::TemplateExprs => {
|
||||
for seg in self.ext.iter().skip(1) {
|
||||
if seg >> 31 == 1 {
|
||||
uses.push(seg & 0xFF);
|
||||
uses.push(seg & 0x7FFF_FFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,9 +260,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn template_str_parses_expr_regs_from_ext() {
|
||||
// ext[0] 跳过;后续 seg>>31==1 则低 8 位是 expr_reg(emit 8 位编码)
|
||||
let with_expr = Inst::template_str(Operand::Reg(1), 2, 10, &[0x1234, 0x8000_0000 | 5]);
|
||||
assert_eq!(with_expr.use_regs().as_slice(), &[5]);
|
||||
// ext[0] 跳过;表达式段在 RegAlloc 前保留完整 u32 vreg。
|
||||
let with_expr = Inst::template_str(Operand::Reg(1), 2, 10, &[0x1234, 0x8000_0000 | 300]);
|
||||
assert_eq!(with_expr.use_regs().as_slice(), &[300]);
|
||||
|
||||
// 纯 quasi(无表达式):不误报寄存器
|
||||
let no_expr = Inst::template_str(Operand::Reg(1), 1, 10, &[0x1234]);
|
||||
|
||||
@@ -197,7 +197,7 @@ fn rewrite_inst(
|
||||
let rd = rewrite(inst.rd);
|
||||
let mut a = rewrite(inst.a);
|
||||
let mut b = rewrite(inst.b);
|
||||
// TEMPLATE_STR 的 ext 编码表达式寄存器(seg>>31==1 时低 8 位为 expr_reg)——必须随
|
||||
// TEMPLATE_STR 的 ext 编码表达式寄存器(seg>>31==1 时低 31 位为 expr_reg)——必须随
|
||||
// RegAlloc 重映射,否则读旧 vreg 号对应的物理槽(错值)。spread 调用系 ext[1..] 每个
|
||||
// 字是完整 spread 源 vreg,同样需重映射到物理号。
|
||||
let ext = match inst.op {
|
||||
@@ -205,9 +205,9 @@ fn rewrite_inst(
|
||||
let mut ext = inst.ext.clone();
|
||||
for seg in ext.iter_mut().skip(1) {
|
||||
if *seg >> 31 == 1 {
|
||||
let r = *seg & 0xFF;
|
||||
let r = *seg & 0x7FFF_FFFF;
|
||||
let nr = remap_ext_reg(r, slot_color, map);
|
||||
*seg = (*seg & !0xFFu32) | (nr & 0xFF);
|
||||
*seg = 0x8000_0000 | nr;
|
||||
}
|
||||
}
|
||||
ext
|
||||
@@ -445,6 +445,18 @@ mod tests {
|
||||
assert_eq!(f.insts[1].rd, Operand::Reg(12));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn template_expr_ext_rewrites_full_vreg() {
|
||||
let inst = Inst::template_str(Operand::Reg(1), 3, 0, &[0, 0x8000_0000 | 300, 1]);
|
||||
let mut map = AllocMap::new();
|
||||
map.map.insert(1, Alloc::Phys(2));
|
||||
map.map.insert(300, Alloc::Phys(200));
|
||||
let f = rewrite_with_map(vec![inst], map);
|
||||
|
||||
assert_eq!(f.insts[0].rd, Operand::Reg(2));
|
||||
assert_eq!(f.insts[0].ext.as_slice(), &[3 << 16, 0, 0x8000_0000 | 200, 1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scattered_args_insert_mov_bridge() {
|
||||
let insts = vec![Inst::call(Operand::Reg(2), Operand::Reg(3), Operand::Reg(4), 3)];
|
||||
|
||||
@@ -199,8 +199,8 @@ impl Vm {
|
||||
let seg = self.bytecode[self.pc];
|
||||
self.pc += 1;
|
||||
if (seg >> 31) == 1 {
|
||||
let reg = (seg & 0x7F) as u8;
|
||||
let val = self.regs[reg as usize];
|
||||
let reg = (seg & 0x7FFF_FFFF) as usize;
|
||||
let val = self.regs[reg];
|
||||
let s = if val.is_string() {
|
||||
// SAFETY: val 是字符串值。
|
||||
unsafe { (*val.as_string_ptr()).data.clone() }
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
use oxide_bytecode::module::Constant;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_compiler::compiler::Compiler;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
use oxide_ir::IRFunction;
|
||||
use oxide_parser::Allocator;
|
||||
use oxide_types::value::JsValue;
|
||||
use oxide_vm::vm::Vm;
|
||||
@@ -87,6 +92,36 @@ fn template_numeric_expression() {
|
||||
assert_eq!(to_str(&vm, result.unwrap()), "2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn template_expression_reads_physical_register_above_127() {
|
||||
let mut ir = IRFunction::new();
|
||||
ir.constants = vec![Constant::String("value".to_string()), Constant::String(String::new())];
|
||||
ir.n_registers = 202;
|
||||
ir.insts = vec![
|
||||
Inst::load_const(Operand::Reg(200), 0),
|
||||
Inst::template_str(Operand::Reg(201), 3, 0, &[1, 0x8000_0000 | 200, 1]),
|
||||
Inst::inst_mov(Operand::Reg(0), Operand::Reg(201)),
|
||||
Inst::new(OpCode::HALT, Operand::None, Operand::None, Operand::None),
|
||||
];
|
||||
|
||||
let module = oxide_ir::lower::lower(&ir).expect("lower template IR");
|
||||
let mut vm = Vm::new();
|
||||
let result = vm.run(&module).expect("run template IR");
|
||||
assert_eq!(to_str(&vm, result), "value");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn template_expression_survives_high_vreg_regalloc() {
|
||||
let mut source = String::from("function f() {");
|
||||
for i in 0..180 {
|
||||
source.push_str(&format!("let v{i}={i};"));
|
||||
}
|
||||
source.push_str("let value='unit'; return `${value}s`; } f();");
|
||||
|
||||
let (vm, result) = eval_val(&source);
|
||||
assert_eq!(to_str(&vm, result.unwrap()), "units");
|
||||
}
|
||||
|
||||
// ── 模板标签调用测试(基础)──
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user