fix: TA 构造形态改读构造入口标记替代寄存器推断

This commit is contained in:
2026-09-22 19:41:55 +00:00
parent b5b456346c
commit dce132acec
10 changed files with 94 additions and 12 deletions
+28 -4
View File
@@ -46,7 +46,8 @@ impl Vm {
/// - `Err` 保留异常原值:用户回调 throw 的原始值经 catch 原样收到,不包装成 Error。
///
/// # 副作用
/// - 修改 `native_call_depth`、`regs[0]`、`regs[254]`,可能压帧或触发异常展开。
/// - 修改 `native_call_depth`、`regs[0]`、`regs[254]`,普通调用形态清零
/// `constructing_native`,可能压帧或触发异常展开。
///
/// # 注意事项
/// - `native_fn_ptr_to_fn` 是 NativeFnPtr → NativeFn 的唯一强制转换点,SAFETY 前提
@@ -72,6 +73,9 @@ impl Vm {
// `this` 寄存器里。
let saved_this = self.regs[254];
self.regs[254] = callee;
// 普通调用形态:清零构造形态标记,防止外层构造窗口残留误判
// (成员式普通调用落在构造器帧内时 new.target 槽仍为类构造器)。
self.constructing_native = false;
self.native_call_depth += 1;
let result = func(self, args_slice);
self.native_call_depth -= 1;
@@ -101,6 +105,8 @@ impl Vm {
return self.raise_type_error("CALL target is not callable");
}
if obj.native_fn().is_some() {
// 尾调用转发为普通调用形态。
self.constructing_native = false;
match self.call_function_sync(callee, this, &args) {
Ok(val) => {
self.regs[0] = val;
@@ -596,7 +602,13 @@ impl Vm {
let args: Vec<JsValue> = (0..arg_count)
.map(|i| self.regs[first_arg_reg.wrapping_add(i as u8) as usize])
.collect();
match self.call_function_sync(super_ctor, derived_this, &args) {
// 构造形态标记夹持(SUPER native 臂不写 reg255,new.target 继承
// 外层类构造器帧,形态判定只能靠本标记)。
let saved_constructing = self.constructing_native;
self.constructing_native = true;
let result = self.call_function_sync(super_ctor, derived_this, &args);
self.constructing_native = saved_constructing;
match result {
Ok(val) => {
// super() 返回实例的 [[Prototype]] 须设为 new.target.prototype
//(native 构造器不知道 new.target,由调用方设置)。
@@ -852,6 +864,8 @@ impl Vm {
.map(|_| true);
}
if obj.native_fn().is_some() {
// spread 普通调用形态:清零构造形态标记。
self.constructing_native = false;
match self.call_function_sync(callee, this_value, &args) {
Ok(v) => {
self.regs[0] = v;
@@ -983,10 +997,14 @@ impl Vm {
if ctor_obj.native_fn().is_some() {
// native 构造器:receiver 为新对象,值传递调用。newTarget 快照后置入
// reg(255) 暴露给 native 构造器(调用后恢复原值)。
// reg(255) 暴露给 native 构造器(调用后恢复原值);构造形态标记同窗
// 夹持(调用返回即恢复,先于结果分派,异常结局不残留)。
let saved_new_target = self.regs[255];
let saved_constructing = self.constructing_native;
self.regs[255] = constructor;
self.constructing_native = true;
let result = self.call_function_sync(constructor, new_obj_val, &args);
self.constructing_native = saved_constructing;
self.regs[255] = saved_new_target;
match result {
Ok(v) => {
@@ -1091,7 +1109,13 @@ impl Vm {
};
if super_obj.native_fn().is_some() {
match self.call_function_sync(super_ctor, derived_this, &args) {
// 构造形态标记夹持(SUPER native 臂不写 reg255,new.target 继承
// 外层类构造器帧,形态判定只能靠本标记)。
let saved_constructing = self.constructing_native;
self.constructing_native = true;
let result = self.call_function_sync(super_ctor, derived_this, &args);
self.constructing_native = saved_constructing;
match result {
Ok(val) => {
// super() 返回实例的 [[Prototype]] 须设为 new.target.prototype
let instance = if val.is_object() { val } else { derived_this };
+5 -1
View File
@@ -90,10 +90,14 @@ impl Vm {
let this_ptr = self.alloc_ctor_this(nt_obj)?;
JsValue::from_js_object(this_ptr)
};
// newTarget 经 reg(255) 暴露给 native 构造器(快照/恢复:call 窗口不触及 255)。
// newTarget 经 reg(255) 暴露给 native 构造器(快照/恢复:call 窗口
// 不触及 255);构造形态标记同窗夹持(调用后恢复)。
let saved_nt = self.regs[255];
let saved_constructing = self.constructing_native;
self.regs[255] = new_target;
self.constructing_native = true;
let result = self.call_function_sync(ctor, this_val, args);
self.constructing_native = saved_constructing;
self.regs[255] = saved_nt;
return match result {
Ok(ret) if ret.is_object() => Ok(ret),
+3
View File
@@ -106,6 +106,9 @@ impl Vm {
self.native_call_depth += 1;
let result = func(self, &arg_regs);
self.native_call_depth -= 1;
// 构造形态标记不跨 native 调用存活:本次调用内的置位(构造臂)
// 与清零(普通调用臂)在此收口,异常展开亦不残留。
self.constructing_native = false;
// 溢出区随本次调用结束截断回收,并还原外层的溢出区描述(嵌套调用安全)。
if args.len() > Self::SYNC_NATIVE_ARG_LIMIT {
self.spill_stack.truncate(overflow_base);
+7
View File
@@ -304,6 +304,13 @@ pub struct Vm {
/// 已做非对象回退 this)交付给恢复方(与 generator_dispatch 同语义,
/// 同样经 InlineSyncState 限定作用域于属主 dispatch)。
pub(crate) construct_dispatch: bool,
/// 当前 native 调用是否以构造形态发起(NEW/SUPER native 臂与
/// `construct_with` native 臂在调用前置 true,普通调用入口前置 false):
/// builtin 构造器(`typed_array_new`)据此判定向 receiver 物化,替代
/// 寄存器推断——native 调用与调用方共享寄存器文件,类构造器帧内的
/// new.target 槽会残留类构造器对象,按寄存器判定会把成员式普通调用
/// 误判为构造。调用结束即恢复/清零,不跨 native 调用存活。
pub(crate) constructing_native: bool,
/// 当前正在执行的异步生成器上下文对象(`OBJ_TYPE_ASYNC_GENERATOR`,持有
/// `AsyncGeneratorState` 快照)。AWAIT dispatch 据此登记异步生成器恢复反应;
/// 跨嵌套 async 调用保存/恢复(与 `async_context` 同生命周期,二者互斥占用)。
+3
View File
@@ -22,6 +22,9 @@ impl oxide_runtime_api::VmHost for Vm {
fn native_overflow_at(&self, i: usize) -> JsValue {
self.spill_stack[self.native_overflow_base + i]
}
fn constructing_native(&self) -> bool {
self.constructing_native
}
fn alloc_object(&mut self, obj: JsObject) -> *mut JsObject {
self.alloc_object(obj)
}
+10 -2
View File
@@ -88,10 +88,14 @@ impl Vm {
// 该入口统一保存/恢复调用窗口与 253/254 槽且不触碰 255,调用方
// new.target 与 this 跨 native 构造不被污染;receiver 经 arg0 打包,
// native 侧经 reg(args[0]) 读取,构造语义不变。newTarget 快照后置入
// reg(255) 暴露给 native 构造器(调用后恢复原值)。
// reg(255) 暴露给 native 构造器(调用后恢复原值);构造形态标记同窗
// 夹持(调用后恢复)。
let saved_new_target = self.regs[255];
let saved_constructing = self.constructing_native;
self.regs[255] = constructor;
self.constructing_native = true;
let result = self.call_function_sync(constructor, new_obj_val, &args);
self.constructing_native = saved_constructing;
self.regs[255] = saved_new_target;
match result {
Ok(v) => {
@@ -230,10 +234,14 @@ impl Vm {
if target_obj.native_fn().is_some() {
// native 构造器:receiver = 新对象,值传递调用(错误原值恢复后展开)。
// new.target 按 bound [[Construct]] 语义取最外层 bound 包装(wrapper_val),
// 快照后置入 reg(255) 暴露给 native 构造器(调用后恢复原值)。
// 快照后置入 reg(255) 暴露给 native 构造器(调用后恢复原值);构造
// 形态标记同窗夹持(调用后恢复)。
let saved_new_target = self.regs[255];
let saved_constructing = self.constructing_native;
self.regs[255] = wrapper_val;
self.constructing_native = true;
let result = self.call_function_sync(target_val, new_obj_val, &call_args);
self.constructing_native = saved_constructing;
self.regs[255] = saved_new_target;
match result {
Ok(v) => {
+2
View File
@@ -114,6 +114,7 @@ impl Vm {
async_suspended: false,
async_dispatch: false,
construct_dispatch: false,
constructing_native: false,
async_gen_context: None,
async_gen_dispatch: false,
async_gen_suspended: false,
@@ -245,6 +246,7 @@ impl Vm {
async_suspended: false,
async_dispatch: false,
construct_dispatch: false,
constructing_native: false,
async_gen_context: None,
async_gen_dispatch: false,
async_gen_suspended: false,