mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 晋升 Promise 的结算传导到克隆——原件 fulfill/reject 时同步结算克隆
顶层 var 读侧引用晋升克隆,而原件随 epoch 释放;此前克隆是 pending 态静态 副本,原件结算不传导,克隆排队反应永不触发(表现为存 pending Promise 的顶层 var 后续 then 悬挂)。clone 时不再复制反应(原件结算自带触发,避免双触发), pending 原件记克隆指针,fulfill/reject 结算后传导到克隆。
This commit is contained in:
@@ -46,6 +46,9 @@ pub(crate) struct PromiseState {
|
||||
/// resolve/reject 是否已被调用过(Resolve Promise Functions 的 alreadyResolved)。
|
||||
/// 首次调用后置位,后续任何 resolve/reject(含 thenable 委托期间)均 no-op。
|
||||
pub already_resolved: bool,
|
||||
/// 原件 pending 时被晋升出的 session 克隆指针(原件结算时传导到克隆);
|
||||
/// 非 pending 原件恒为空指针。
|
||||
pub promoted_clone: *mut JsObject,
|
||||
}
|
||||
|
||||
/// 一条微任务(job)。
|
||||
@@ -121,6 +124,7 @@ impl Vm {
|
||||
resolve_fn: JsValue::undefined(),
|
||||
reject_fn: JsValue::undefined(),
|
||||
already_resolved: false,
|
||||
promoted_clone: std::ptr::null_mut(),
|
||||
});
|
||||
obj.set_native_data(Box::into_raw(state) as *mut u8);
|
||||
JsValue::from_js_object(ptr)
|
||||
@@ -434,6 +438,13 @@ impl Vm {
|
||||
reject: r.reject,
|
||||
});
|
||||
}
|
||||
// 原件若已晋升出克隆,把结算传导到克隆:克隆上晋升后新挂的反应方随此触发
|
||||
// (顶层 var 读克隆,原件反应已在本处直接触发,不重复传导)。
|
||||
let clone_ptr = unsafe { (*state_ptr).promoted_clone };
|
||||
if !clone_ptr.is_null() {
|
||||
let clone = JsValue::from_js_object(clone_ptr);
|
||||
let _ = self.fulfill_promise(clone, value);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -459,6 +470,12 @@ impl Vm {
|
||||
reject: r.reject,
|
||||
});
|
||||
}
|
||||
// 原件若已晋升出克隆,把拒绝传导到克隆(同 fulfill:顶层 var 读克隆)。
|
||||
let clone_ptr = unsafe { (*state_ptr).promoted_clone };
|
||||
if !clone_ptr.is_null() {
|
||||
let clone = JsValue::from_js_object(clone_ptr);
|
||||
let _ = self.reject_promise(clone, reason);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -838,6 +855,7 @@ fn promise_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
resolve_fn: resolve,
|
||||
reject_fn: reject,
|
||||
already_resolved: false,
|
||||
promoted_clone: std::ptr::null_mut(),
|
||||
});
|
||||
obj.set_native_data(Box::into_raw(state) as *mut u8);
|
||||
let executor = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
@@ -1836,25 +1854,25 @@ pub(crate) fn clone_promise_native_with_rewrite(
|
||||
let Some(state) = promise_state_ref(old) else {
|
||||
return;
|
||||
};
|
||||
let pending = state.state == PromiseStateKind::Pending;
|
||||
let cloned = PromiseState {
|
||||
state: state.state,
|
||||
result: rewrite(state.result),
|
||||
reactions: state
|
||||
.reactions
|
||||
.iter()
|
||||
.map(|r| PromiseReaction {
|
||||
promise: rewrite(r.promise),
|
||||
resolve: rewrite(r.resolve),
|
||||
reject: rewrite(r.reject),
|
||||
handler: rewrite(r.handler),
|
||||
is_fulfill: r.is_fulfill,
|
||||
})
|
||||
.collect(),
|
||||
// 不复制原件反应:原件结算时自带触发,克隆仅累积晋升后新挂的反应,避免双重触发。
|
||||
reactions: Vec::new(),
|
||||
resolve_fn: rewrite(state.resolve_fn),
|
||||
reject_fn: rewrite(state.reject_fn),
|
||||
already_resolved: state.already_resolved,
|
||||
promoted_clone: std::ptr::null_mut(),
|
||||
};
|
||||
new.set_native_data(Box::into_raw(Box::new(cloned)) as *mut u8);
|
||||
// 原件 pending 时记下克隆指针:原件结算时把结果传导到克隆,克隆上晋升后新挂
|
||||
// 的反应方随之触发(顶层 var 读侧引用克隆,原件随 epoch 释放,结算须在原件还活着时传导)。
|
||||
if pending {
|
||||
if let Some(src) = promise_state_mut(old) {
|
||||
src.promoted_clone = new as *mut JsObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 只读核算 Promise 状态盒字节(不释放),供 GC 账目核算。
|
||||
|
||||
Reference in New Issue
Block a user