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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -831,6 +831,7 @@ mod tests {
|
||||
construct_result_reg: None,
|
||||
constructed_this: Some(JsValue::from_js_object(child_session)),
|
||||
is_derived_constructor: false,
|
||||
super_called: false,
|
||||
continuation: FrameContinuation::None,
|
||||
});
|
||||
vm.save_stack.push(JsValue::from_js_object(frame_session));
|
||||
|
||||
@@ -283,6 +283,7 @@ impl SuspendedFrame {
|
||||
construct_result_reg: f.construct_result_reg,
|
||||
constructed_this: f.constructed_this.map(&mut rewrite),
|
||||
is_derived_constructor: f.is_derived_constructor,
|
||||
super_called: f.super_called,
|
||||
continuation: f.continuation,
|
||||
}),
|
||||
spill_stack: self.spill_stack.iter().copied().map(&mut rewrite).collect(),
|
||||
@@ -343,6 +344,7 @@ mod tests {
|
||||
construct_result_reg: None,
|
||||
constructed_this: Some(tag),
|
||||
is_derived_constructor: false,
|
||||
super_called: false,
|
||||
continuation: FrameContinuation::None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +212,14 @@ pub struct CallFrame {
|
||||
pub construct_result_reg: Option<u8>,
|
||||
pub constructed_this: Option<JsValue>,
|
||||
pub is_derived_constructor: bool,
|
||||
/// derived 构造帧是否已成功调用 super()(父构造器正常返回后置位)。
|
||||
///
|
||||
/// 置位识别依赖 ABI 不变量:`construct_result_reg == Some(254)` 仅 SUPER_CALL
|
||||
/// 压帧产生(emit 从寄存器 ≥1 分配,254 保留给 this);父构造器抛错走 unwind
|
||||
/// 弹帧不进 do_return,不置位。此标志取代依赖 regs[254] 值判定 super 状态的
|
||||
/// 旧方案——多层继承时中间 derived 帧由 SUPER_CALL 以构造 this 压入,
|
||||
/// regs[254] 恒非 undefined,值判定三重失效。
|
||||
pub super_called: bool,
|
||||
pub continuation: FrameContinuation,
|
||||
}
|
||||
|
||||
@@ -1317,6 +1325,7 @@ impl Vm {
|
||||
construct_result_reg,
|
||||
constructed_this,
|
||||
is_derived_constructor: obj.is_derived_constructor(),
|
||||
super_called: false,
|
||||
continuation,
|
||||
});
|
||||
|
||||
@@ -2365,6 +2374,7 @@ mod tests {
|
||||
construct_result_reg: None,
|
||||
constructed_this: None,
|
||||
is_derived_constructor: false,
|
||||
super_called: false,
|
||||
continuation: super::FrameContinuation::None,
|
||||
});
|
||||
vm.save_stack.push(JsValue::undefined());
|
||||
|
||||
@@ -423,12 +423,14 @@ impl Vm {
|
||||
let construct_result_reg = frame.construct_result_reg;
|
||||
let constructed_this = frame.constructed_this;
|
||||
let is_derived_constructor = frame.is_derived_constructor;
|
||||
let super_called = frame.super_called;
|
||||
let continuation = frame.continuation;
|
||||
let callee_this = self.regs[254];
|
||||
vm_trace!("RETURN frame: continuation={:?}, derived={}", continuation, is_derived_constructor);
|
||||
self.restore_frame(frame);
|
||||
if let (Some(target_reg), Some(constructed_this)) = (construct_result_reg, constructed_this) {
|
||||
if is_derived_constructor && result.is_undefined() && callee_this.is_undefined() {
|
||||
// 规范 §9.2.2.2:derived 构造器返回非对象值(含 undefined/null/原始值)
|
||||
// 且未调用 super() 时抛 ReferenceError;调过 super() 则回退构造 this。
|
||||
if is_derived_constructor && !result.is_object() && !super_called {
|
||||
self.raise_error_kind("ReferenceError", "derived constructor must call super()")?;
|
||||
return Ok(None);
|
||||
}
|
||||
@@ -447,6 +449,17 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 父构造器正常返回:super() 调用完成,置位调用方 derived 帧的 super_called。
|
||||
// 识别依据:construct_result_reg == Some(254) 仅 SUPER_CALL 压帧产生(emit
|
||||
// 从寄存器 ≥1 分配,254 保留给 this);父构造器抛错走 unwind 弹帧不进
|
||||
// 本函数,不置位——后续 this 访问 / 再调 super 仍按未初始化报错。
|
||||
if construct_result_reg == Some(254) {
|
||||
if let Some(caller) = self.frames.last_mut() {
|
||||
if caller.is_derived_constructor {
|
||||
caller.super_called = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 生成器/异步/构造内嵌 dispatch:帧全部弹出后把结果交付恢复方,而非继续执行。
|
||||
if self.frames.is_empty() && (self.generator_dispatch || self.async_dispatch || self.construct_dispatch) {
|
||||
// 构造内嵌:弹帧已把构造结果(非对象回退 this)写入 regs[0],直接交付。
|
||||
|
||||
Reference in New Issue
Block a user