fix(emit): 调用参数打包连续寄存器 + 捕获参数建 cell + TEMPLATE_STR ext 重映射(修复 JSON/closures/template 回归)
This commit is contained in:
@@ -750,6 +750,17 @@ impl Emitter {
|
||||
ctx.own_bindings = self.collect_own_binding_names(¶m_names, body_stmts);
|
||||
ctx.captured_bindings = self.collect_captured_bindings(body_stmts, &ctx.own_bindings);
|
||||
|
||||
// 被捕获的参数也必须建 cell(MAKE_CELL):否则子函数经 lazy upvalue 路径读
|
||||
// 自身寄存器(依赖调用者寄存器残留),vreg 化/RegAlloc 移动寄存器后读到垃圾。
|
||||
// 与 var/let/const 的 MAKE_CELL 语义一致(binding.rs:50)。
|
||||
for spec in param_specs {
|
||||
let name = spec.register_name();
|
||||
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||
let reg = ctx.lookup(name)?;
|
||||
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(reg), Operand::Imm(cell_idx as u16), Operand::None));
|
||||
}
|
||||
}
|
||||
|
||||
// Free variable analysis for upvalue capture (Ordinary + Arrow functions only)
|
||||
if matches!(body_context, FunctionBodyContext::Ordinary | FunctionBodyContext::Arrow) {
|
||||
ctx.current_upvalue_captures =
|
||||
|
||||
@@ -20,7 +20,7 @@ impl Emitter {
|
||||
arg_regs.push(self.emit_expression(expr, ctx)?);
|
||||
}
|
||||
}
|
||||
let first_arg_reg = if arg_regs.is_empty() { 0u32 } else { arg_regs[0] };
|
||||
let first_arg_reg = if arg_regs.is_empty() { 0u32 } else { pack_arg_regs(&mut arg_regs, ctx) };
|
||||
let result_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::super_call(
|
||||
Operand::Reg(result_reg),
|
||||
@@ -88,7 +88,7 @@ impl Emitter {
|
||||
arg_regs.push(self.emit_expression(expr, ctx)?);
|
||||
}
|
||||
}
|
||||
let first_arg_reg = if arg_regs.is_empty() { 0u32 } else { arg_regs[0] };
|
||||
let first_arg_reg = if arg_regs.is_empty() { 0u32 } else { pack_arg_regs(&mut arg_regs, ctx) };
|
||||
let op = match &call.callee {
|
||||
Expression::Identifier(ident) if ctx.is_builtin(ident.name.as_str()) => OpCode::CALL_NATIVE,
|
||||
_ => OpCode::CALL,
|
||||
@@ -124,3 +124,23 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 把调用参数打包到连续寄存器块(VM 按 `regs[first_arg + i]` 连续读参数,D-17/调用契约)。
|
||||
/// vreg 化(05-02)后各参数由独立 vreg 承载,复杂表达式(对象/数组字面量、嵌套调用)
|
||||
/// 的临时寄存器会使参数 vreg 不连续——这里检测到不连续时用 MOV 打包到新连续块。
|
||||
/// 返回首参寄存器;参数为空时返回 0。
|
||||
fn pack_arg_regs(arg_regs: &mut [u32], ctx: &mut CompileCtx) -> u32 {
|
||||
let consecutive = arg_regs.windows(2).all(|w| w[1] == w[0] + 1);
|
||||
if consecutive {
|
||||
return arg_regs[0];
|
||||
}
|
||||
// 预留连续块(单调 alloc_reg 保证 base..base+n 连续)
|
||||
let base = ctx.alloc_reg();
|
||||
for _ in 1..arg_regs.len() {
|
||||
ctx.alloc_reg();
|
||||
}
|
||||
for (i, ®) in arg_regs.iter().enumerate() {
|
||||
ctx.inst(Inst::inst_mov(Operand::Reg(base + i as u32), Operand::Reg(reg)));
|
||||
}
|
||||
base
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user