fix: 构造帧 super 状态改显式标志修复多层继承与 return 语义

derived 构造器 super 状态改由 CallFrame.super_called 显式标志承载,
取代依赖 regs[254] 值判定:多层继承中间 derived 帧由 SUPER_CALL 压入
this=构造对象,值判定三重失效(未调 super 不报错 / this-before-super
失效 / 合法 super() 误判 more-than-once)。父构造器正常返回经
construct_result_reg==Some(254) 识别置位调用方帧(该 ABI 不变量仅
SUPER_CALL 压帧满足),抛错走 unwind 不置位。

do_return 检查放宽为非对象返回值(含 undefined/null/原始值)且未调
super 时抛 ReferenceError(规范 §9.2.2.2),调过 super 回退构造 this。

super 构造器改取当前帧 callee 原型而非 newTarget 原型:newTarget 跨
SUPER_CALL 压帧保持为最外层类,取其原型在中间 derived 层解析回同一
父类导致无限压帧。
This commit is contained in:
2026-08-16 01:23:52 +08:00
parent 3df08dddff
commit 8c4b766e70
7 changed files with 163 additions and 8 deletions
+35 -4
View File
@@ -416,7 +416,7 @@ impl Vm {
self.raise_error_kind("ReferenceError", "super() used outside derived constructor")?;
return Ok(true);
}
if !self.regs[254].is_undefined() {
if frame.super_called {
self.raise_error_kind("ReferenceError", "super() called more than once")?;
return Ok(true);
}
@@ -424,6 +424,7 @@ impl Vm {
self.raise_error_kind("ReferenceError", "super() without derived this")?;
return Ok(true);
};
let callee = frame.callee;
let new_target = self.regs[255];
if !new_target.is_object() {
@@ -431,7 +432,15 @@ impl Vm {
return Ok(true);
}
let new_target_obj = unsafe { &*new_target.as_js_object_ptr() };
let super_ctor = new_target_obj.proto();
// super 构造器取当前帧 callee(执行中的 derived 构造器)的原型,而非 newTarget:
// newTarget 跨 SUPER_CALL 压帧保持为最外层类,取其原型在中间 derived 层会
// 解析回同一父类,导致父帧被反复压入(多层继承栈溢出)。
if !callee.is_object() {
self.raise_error_kind("TypeError", "super() without constructor callee")?;
return Ok(true);
}
let callee_obj = unsafe { &*callee.as_js_object_ptr() };
let super_ctor = callee_obj.proto();
if !super_ctor.is_object() {
self.raise_error_kind("TypeError", "super constructor is not an object")?;
return Ok(true);
@@ -459,6 +468,7 @@ impl Vm {
}
self.regs[254] = instance;
self.regs[rd] = self.regs[254];
self.mark_super_called();
}
NativeResult::Err(err_val) => {
self.exception_value = Some(err_val);
@@ -479,6 +489,7 @@ impl Vm {
}
self.regs[254] = instance;
self.regs[rd] = self.regs[254];
self.mark_super_called();
}
Err(e) => return Err(e),
}
@@ -528,6 +539,16 @@ impl Vm {
Ok(())
}
/// 置位当前 derived 帧的 super_called:native super 构造器同步返回后标记
/// super() 已成功调用(字节码父构造器路径由 do_return 在返回时置位)。
fn mark_super_called(&mut self) {
if let Some(frame) = self.frames.last_mut() {
if frame.is_derived_constructor {
frame.super_called = true;
}
}
}
pub(crate) fn dispatch_super_get_prop(&mut self, rd: usize, a: usize, b: usize) -> Result<bool, String> {
vm_trace!("SUPER_GET_PROP rd={} a={} b={}", rd, a, b);
let key_val = self.regs[b];
@@ -891,7 +912,7 @@ impl Vm {
self.raise_error_kind("ReferenceError", "super() used outside derived constructor")?;
return Ok(true);
}
if !self.regs[254].is_undefined() {
if frame.super_called {
self.raise_error_kind("ReferenceError", "super() called more than once")?;
return Ok(true);
}
@@ -899,13 +920,22 @@ impl Vm {
self.raise_error_kind("ReferenceError", "super() without derived this")?;
return Ok(true);
};
let callee = frame.callee;
let new_target = self.regs[255];
if !new_target.is_object() {
self.raise_error_kind("TypeError", "super() new.target is not an object")?;
return Ok(true);
}
let new_target_obj = unsafe { &*new_target.as_js_object_ptr() };
let super_ctor = new_target_obj.proto();
// 同 dispatch_super_call:super 构造器取当前帧 callee 的原型(newTarget
// 保持为最外层类,取其原型在中间 derived 层会反复压入同一父帧)。
if !callee.is_object() {
self.raise_error_kind("TypeError", "super() without constructor callee")?;
return Ok(true);
}
let callee_obj = unsafe { &*callee.as_js_object_ptr() };
let super_ctor = callee_obj.proto();
if !super_ctor.is_object() {
self.raise_error_kind("TypeError", "super constructor is not an object")?;
return Ok(true);
@@ -931,6 +961,7 @@ impl Vm {
}
self.regs[254] = instance;
self.regs[rd] = instance;
self.mark_super_called();
}
Err(_) => {
let exc = self
+6 -2
View File
@@ -119,9 +119,13 @@ impl Vm {
pub(crate) fn dispatch_load_var(&mut self, rd: usize, a: usize) -> Result<bool, String> {
vm_trace!("LOAD_VAR rd={} r{}={:?}", rd, a, self.regs[a]);
// a==254 即读 this:derived 构造帧在 super() 成功前读 this 抛 ReferenceError。
if a == 254
&& self.frames.last().map(|frame| frame.is_derived_constructor).unwrap_or(false)
&& self.regs[a].is_undefined()
&& self
.frames
.last()
.map(|frame| frame.is_derived_constructor && !frame.super_called)
.unwrap_or(false)
{
self.raise_error_kind("ReferenceError", "must call super constructor before using 'this'")?;
return Ok(true);