fix: 尾调用内联臂补 pc 守卫防覆盖 catch 参数

This commit is contained in:
2026-10-09 17:29:23 +00:00
parent 4030cb4224
commit 0df3f9d5fd
4 changed files with 52 additions and 21 deletions
+7 -1
View File
@@ -137,8 +137,14 @@ impl Vm {
let sub = self.callee_module(obj);
if matches!(sub, Some(m) if m.is_async || m.is_generator) {
self.constructing_native = false;
let gen_pc = self.pc;
let result = self.call_bytecode_function_inline(callee, obj, this, &args)?;
self.regs[0] = result;
// 参数初始化抛错已就地展开(unwind 改写 pc 至 catch):异常值已
// 写入 catch 参数,再写结果寄存器会覆盖之——仅在初始化成功(pc 未动)
// 时交付结果。
if self.pc == gen_pc {
self.regs[0] = result;
}
return Ok(());
}
}
@@ -450,3 +450,28 @@ fn function_bind_async_generator_target_returns_iterator() {
let result = eval(&mut vm, "async function* g(){ return 99; } typeof g.bind(null)()").unwrap();
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "object");
}
#[test]
fn function_call_generator_param_default_throw_keeps_catch_value() {
// 生成器目标带抛错的参数默认值,经 call/apply/bind 调用且调用点在 try/catch 内:
// catch 参数须是抛出的原值 42,不得被占位迭代器对象覆盖。
let mut vm = Vm::new();
let result = eval(
&mut vm,
"function* g(x = (function(){ throw 42; })()) { yield 1; } try { g.call(null); } catch (e) { e; }",
)
.unwrap();
assert_eq!(result, JsValue::int(42));
let result = eval(
&mut vm,
"function* g(x = (function(){ throw 42; })()) { yield 1; } try { g.apply(null, []); } catch (e) { e; }",
)
.unwrap();
assert_eq!(result, JsValue::int(42));
let result = eval(
&mut vm,
"function* g(x = (function(){ throw 42; })()) { yield 1; } try { g.bind(null)(); } catch (e) { e; }",
)
.unwrap();
assert_eq!(result, JsValue::int(42));
}