mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: TA 构造形态改读构造入口标记替代寄存器推断
This commit is contained in:
@@ -554,11 +554,14 @@ fn to_collect_len(n: f64) -> usize {
|
||||
|
||||
fn typed_array_new<H: VmHost>(vm: &mut H, args: &[u8], kind: TypedArrayKind) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
// reg 255(new.target)为对象即构造调用(NEW/SUPER_CALL/construct 三路径同形):
|
||||
// 视图数据物化到 receiver(其原型 = new.target.prototype,派生类 super() 与
|
||||
// species 构造由此拿到子类实例);普通调用(new.target 为 undefined)按规范
|
||||
// TypedArrayCreate 忽略 this、自建新对象。
|
||||
let in_construct = vm.reg(255).is_object() && this_val.is_object();
|
||||
// 调用形态取构造入口标记(NEW/SUPER native 臂与 construct_with 三入口调用前
|
||||
// 置位、普通调用入口调用前清零),不推断 new.target 寄存器:native 调用与
|
||||
// 调用方共享寄存器文件,类构造器帧内 new.target 槽残留类构造器对象,按
|
||||
// 寄存器推断会把成员式普通调用误判为构造(双物化 receiver、旧数据盒泄漏)。
|
||||
// 构造形态下视图数据物化到 receiver(其原型 = new.target.prototype,派生类
|
||||
// super() 与 species 构造由此拿到子类实例);普通形态按规范 TypedArrayCreate
|
||||
// 忽略 this、自建新对象。
|
||||
let in_construct = vm.constructing_native() && this_val.is_object();
|
||||
let first = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::int(0) };
|
||||
let bpe = kind.bytes_per_element();
|
||||
|
||||
|
||||
@@ -45,6 +45,14 @@ pub trait VmHost {
|
||||
self.native_overflow_at(idx - window)
|
||||
}
|
||||
}
|
||||
/// 当前 native 调用是否以构造形态发起(NEW/SUPER native 臂与 `construct_with`
|
||||
/// native 臂置 true,普通调用入口置 false,调用结束即恢复)。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 仅在 native 实现内部读取;构造器 builtin 据此判定向 receiver 物化,
|
||||
/// 不得用寄存器推断(native 调用与调用方共享寄存器文件,new.target
|
||||
/// 槽在类构造器帧内残留类构造器对象)。
|
||||
fn constructing_native(&self) -> bool;
|
||||
|
||||
// 对象分配 / 字符串创建
|
||||
fn alloc_object(&mut self, obj: JsObject) -> *mut JsObject;
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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` 同生命周期,二者互斥占用)。
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -691,3 +691,23 @@ fn typed_array_plain_call_and_construct_zero_drift() {
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn typed_array_plain_member_call_in_class_ctor_not_construct() {
|
||||
// 类构造器帧内对 TA 构造器的成员式普通调用是普通形态:返回全新 TA,
|
||||
// receiver 不物化(长度与 buffer 不动),receiver 为普通对象时亦不改建。
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { class Sub extends Uint8Array { constructor() { \
|
||||
super(4); this.f = Uint8Array; var r = this.f(2); this.r = r; this.len = this.length; \
|
||||
var o = {}; o.f = Uint8Array; var p = o.f(2); this.p = p; this.o = o; } } \
|
||||
var s = new Sub(); \
|
||||
return s.r !== s && s.r instanceof Uint8Array && \
|
||||
Object.getPrototypeOf(s.r) === Uint8Array.prototype && s.r.length === 2 && \
|
||||
s.len === 4 && s.length === 4 && s.buffer.byteLength === 4 && \
|
||||
s.p !== s.o && s.p.length === 2 && typeof s.o.length === 'undefined'; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user