1898 lines
86 KiB
Rust
1898 lines
86 KiB
Rust
//! Promise 运行时:Promise 状态盒 + resolve/reject 闭包 + 微任务队列。
|
||
//!
|
||
//! Promise 对象把 `PromiseState` 状态盒(Box)挂在 `native_data`;resolve/reject
|
||
//! 是携带目标 promise 的 native 闭包函数(函数对象 prop 存 promise 引用)。
|
||
//! 反应(reaction)与 thenable 委托以 `Microtask` 入队 `Vm::job_queue`,
|
||
//! 由 `run()` 末尾的 drain 循环 FIFO 执行。所有盒内 JsValue 由 session GC
|
||
//! 经 Promise 对象边追踪(见 `promise_native_edges` / `rewrite_promise_native` /
|
||
//! `clone_promise_native_with_rewrite` / `drop_promise_native`)。
|
||
|
||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||
use oxide_runtime_api::NativeResult;
|
||
use oxide_types::mem::P;
|
||
use oxide_types::object::{JsObject, NativeFnPtr, PropAttributes};
|
||
use oxide_types::private_key::make_int_key;
|
||
use oxide_types::value::JsValue;
|
||
|
||
use crate::native::NativeFn;
|
||
use crate::vm::{FrameArgs, FrameContinuation, Vm};
|
||
use crate::vm_warn;
|
||
|
||
/// Promise 的 settled 状态。
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||
pub(crate) enum PromiseStateKind {
|
||
Pending,
|
||
Fulfilled,
|
||
Rejected,
|
||
}
|
||
|
||
/// `then` 注册的一条反应:派生 promise 的能力(promise + resolve/reject)+ 处理器。
|
||
#[derive(Clone)]
|
||
pub(crate) struct PromiseReaction {
|
||
pub promise: JsValue,
|
||
pub resolve: JsValue,
|
||
pub reject: JsValue,
|
||
pub handler: JsValue,
|
||
pub is_fulfill: bool,
|
||
}
|
||
|
||
/// Promise 状态盒:存于 Promise 对象 `native_data`,所有 JsValue 是 GC 边。
|
||
pub(crate) struct PromiseState {
|
||
pub state: PromiseStateKind,
|
||
pub result: JsValue,
|
||
pub reactions: Vec<PromiseReaction>,
|
||
/// 本 promise 能力上的 resolve/reject 闭包(thenable 委托入队时取用)。
|
||
pub resolve_fn: JsValue,
|
||
pub reject_fn: JsValue,
|
||
/// resolve/reject 是否已被调用过(Resolve Promise Functions 的 alreadyResolved)。
|
||
/// 首次调用后置位,后续任何 resolve/reject(含 thenable 委托期间)均 no-op。
|
||
pub already_resolved: bool,
|
||
}
|
||
|
||
/// 一条微任务(job)。
|
||
pub(crate) enum Microtask {
|
||
/// 反应任务:调 `handler(argument)`,结果经能力 resolve/reject 交付;空处理器直通。
|
||
Reaction {
|
||
is_fulfill: bool,
|
||
handler: JsValue,
|
||
argument: JsValue,
|
||
resolve: JsValue,
|
||
reject: JsValue,
|
||
},
|
||
/// thenable 委托任务:调 `then(thenable, resolve, reject)`。
|
||
Thenable {
|
||
thenable: JsValue,
|
||
then: JsValue,
|
||
resolve: JsValue,
|
||
reject: JsValue,
|
||
},
|
||
}
|
||
|
||
/// 单次 drain 的微任务处理上限,防止无终止的自我产生链导致活锁。
|
||
const MAX_DRAIN_JOBS: usize = 1_000_000;
|
||
|
||
/// 闭包函数对象上存目标 promise 的属性名。
|
||
const PROMISE_PROP: &str = "__oxide_promise__";
|
||
/// thenable 委托结算代理标志:绕过 alreadyResolved(委托是真正结算路径)。
|
||
const DELEGATED_PROP: &str = "__oxide_delegated__";
|
||
/// finally 处理器上存 onFinally 回调的属性名。
|
||
const ON_FINALLY_PROP: &str = "__oxide_on_finally__";
|
||
/// finally 处理器上区分 reject 角色的属性名。
|
||
const FINALLY_REJECT_PROP: &str = "__oxide_finally_reject__";
|
||
/// 能力 executor 上捕获 resolve/reject 的属性名。
|
||
const CAP_RESOLVE_PROP: &str = "__oxide_cap_resolve__";
|
||
const CAP_REJECT_PROP: &str = "__oxide_cap_reject__";
|
||
|
||
// ── 聚合静态方法(all/race/allSettled/any)内部状态属性 ──
|
||
/// 元素处理器函数上存共享记录对象的属性名。
|
||
const AGG_RECORD_PROP: &str = "__oxide_agg_record__";
|
||
/// 元素处理器函数上存元素下标的属性名。
|
||
const AGG_INDEX_PROP: &str = "__oxide_agg_index__";
|
||
/// 元素处理器函数上存"已调用一次"标志的属性名。
|
||
const AGG_ALREADY_PROP: &str = "__oxide_agg_already__";
|
||
/// 记录对象上存剩余未结算元素计数(含尾部哨兵 1)。
|
||
const AGG_REMAINING_PROP: &str = "__oxide_agg_remaining__";
|
||
/// 记录对象上存结果数组(all/allSettled 的 values,any 的 errors)。
|
||
const AGG_VALUES_PROP: &str = "__oxide_agg_values__";
|
||
/// 记录对象上存能力 resolve 闭包。
|
||
const AGG_RESOLVE_PROP: &str = "__oxide_agg_resolve__";
|
||
/// 记录对象上存能力 reject 闭包。
|
||
const AGG_REJECT_PROP: &str = "__oxide_agg_reject__";
|
||
|
||
/// 聚合静态方法的语义模式(决定元素处理器与结算方式)。
|
||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||
enum AggregateKind {
|
||
All,
|
||
Race,
|
||
AllSettled,
|
||
Any,
|
||
}
|
||
|
||
impl Vm {
|
||
/// 创建空 Promise 对象(proto = `%Promise.prototype%`),状态盒为 Pending。
|
||
fn create_promise_object(&mut self) -> JsValue {
|
||
let proto_val = JsValue::from_js_object(self.promise_proto.as_ptr() as *mut JsObject);
|
||
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
|
||
let obj = unsafe { &mut *ptr };
|
||
obj.type_tag = JsObject::OBJ_TYPE_PROMISE;
|
||
let state = Box::new(PromiseState {
|
||
state: PromiseStateKind::Pending,
|
||
result: JsValue::undefined(),
|
||
reactions: Vec::new(),
|
||
resolve_fn: JsValue::undefined(),
|
||
reject_fn: JsValue::undefined(),
|
||
already_resolved: false,
|
||
});
|
||
obj.set_native_data(Box::into_raw(state) as *mut u8);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// 新建 Promise 能力 `(promise, resolve, reject)`:resolve/reject 为携带
|
||
/// 目标 promise 的 native 闭包,同时写入状态盒供 thenable 委托取用。
|
||
pub(crate) fn new_promise_capability(&mut self) -> (JsValue, JsValue, JsValue) {
|
||
let promise = self.create_promise_object();
|
||
let resolve = self.make_resolve_reject_fn(promise, false, false);
|
||
let reject = self.make_resolve_reject_fn(promise, true, false);
|
||
let state = self.promise_state_ptr(promise);
|
||
let state = unsafe { &mut *state };
|
||
state.resolve_fn = resolve;
|
||
state.reject_fn = reject;
|
||
(promise, resolve, reject)
|
||
}
|
||
|
||
/// NewPromiseCapability(C):按构造器 C 建能力。C 为内置 Promise 时走直接路径,
|
||
/// 否则经 GetCapabilitiesExecutor 间接构造 `new C(executor)`。
|
||
fn new_promise_capability_with_ctor(&mut self, ctor: JsValue) -> Result<(JsValue, JsValue, JsValue), JsValue> {
|
||
let intrinsic = JsValue::from_js_object(self.promise_constructor.as_ptr() as *mut JsObject);
|
||
if oxide_runtime_api::same_value(ctor, intrinsic) {
|
||
return Ok(self.new_promise_capability());
|
||
}
|
||
// GetCapabilitiesExecutor:捕获 resolve/reject 到自身 prop。
|
||
let executor = self.make_capability_executor();
|
||
// 构造 C(executor);结果须为对象。
|
||
let promise = self.construct_ctor(ctor, &[executor])?;
|
||
if !promise.is_object() {
|
||
return Err(oxide_builtins::error::create_type_error(
|
||
self,
|
||
"Promise constructor returned a non-object",
|
||
));
|
||
}
|
||
let (resolve, reject) = {
|
||
let exec_obj = unsafe { &*executor.as_js_object_ptr() };
|
||
let res_si = self.kernel_core.perm_interner().intern(CAP_RESOLVE_PROP).0;
|
||
let rej_si = self.kernel_core.perm_interner().intern(CAP_REJECT_PROP).0;
|
||
let r = self.resolve_property(exec_obj, res_si).unwrap_or(JsValue::undefined());
|
||
let j = self.resolve_property(exec_obj, rej_si).unwrap_or(JsValue::undefined());
|
||
(r, j)
|
||
};
|
||
if !oxide_builtins::iterator::is_callable(resolve) || !oxide_builtins::iterator::is_callable(reject) {
|
||
return Err(oxide_builtins::error::create_type_error(
|
||
self,
|
||
"Promise resolve and reject functions must be callable",
|
||
));
|
||
}
|
||
Ok((promise, resolve, reject))
|
||
}
|
||
|
||
/// 构造 GetCapabilitiesExecutor:调用时把 resolve/reject 存入自身 prop。
|
||
fn make_capability_executor(&mut self) -> JsValue {
|
||
let fn_proto = self.session.builtin_world().fn_proto_val();
|
||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||
func.set_function(true);
|
||
// SAFETY: capability_executor 是 NativeFn 函数项。
|
||
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(capability_executor as *const ()) }));
|
||
func.set_native_arg_count(2);
|
||
let ptr = self.alloc_object(func);
|
||
let obj = unsafe { &mut *ptr };
|
||
self.add_fn_name_length(obj, "", 2);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// 构造调用(Construct(C, args)):native 构造器值传递调用,bytecode 构造器
|
||
/// 压构造帧执行(含 derived 构造器 super() 语义),返回值非对象时回退到新对象。
|
||
fn construct_ctor(&mut self, ctor: JsValue, args: &[JsValue]) -> Result<JsValue, JsValue> {
|
||
// IsConstructor 校验:arrow / 非构造 native / 普通值拒绝。
|
||
if !is_constructor_value(ctor) {
|
||
return Err(oxide_builtins::error::create_type_error(self, "constructor is not a constructor"));
|
||
}
|
||
let ctor_obj = unsafe { &*ctor.as_js_object_ptr() };
|
||
// native 构造器:receiver 为新对象,值传递调用(%Promise% 主路径)。
|
||
if ctor_obj.native_fn().is_some() {
|
||
let this_ptr = self.alloc_ctor_this(ctor_obj)?;
|
||
let this_val = JsValue::from_js_object(this_ptr);
|
||
return match self.call_function_sync(ctor, this_val, args) {
|
||
Ok(ret) if ret.is_object() => Ok(ret),
|
||
Ok(_) => Ok(this_val),
|
||
Err(e) => Err(self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e))),
|
||
};
|
||
}
|
||
self.call_constructor_bytecode_inline(ctor, ctor_obj, args)
|
||
}
|
||
|
||
/// 分配构造 this:proto = ctor.prototype(缺省 Object.prototype)。
|
||
fn alloc_ctor_this(&mut self, ctor_obj: &JsObject) -> Result<*mut JsObject, JsValue> {
|
||
let proto_si = self.kernel_core.perm_interner().intern("prototype").0;
|
||
let proto_val = match self.resolve_property(ctor_obj, proto_si) {
|
||
Some(p) if p.is_object() => p,
|
||
_ => JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject),
|
||
};
|
||
Ok(self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)))
|
||
}
|
||
|
||
/// bytecode 构造器构造调用:压构造帧内嵌 dispatch 执行(derived 构造器
|
||
/// super() 前 this = undefined,new.target = ctor),结果经 `do_return` 交付
|
||
/// regs[0](非对象回退构造 this)。
|
||
///
|
||
/// # 副作用
|
||
/// - 经 `save_inline_state` / `restore_inline_state` 保存恢复调用方执行状态。
|
||
/// - `construct_dispatch` 标志令构造帧弹出时交付结果而非继续执行。
|
||
fn call_constructor_bytecode_inline(
|
||
&mut self, ctor: JsValue, ctor_obj: &JsObject, args: &[JsValue],
|
||
) -> Result<JsValue, JsValue> {
|
||
let sub_idx = ctor_obj.sub_module_index() as usize;
|
||
if sub_idx == 0 || sub_idx >= self.sub_modules.len() {
|
||
return Err(oxide_builtins::error::create_type_error(self, "constructor is not a constructor"));
|
||
}
|
||
// 生成器/异步函数不是构造器。
|
||
if self.sub_modules[sub_idx].is_generator || self.sub_modules[sub_idx].is_async {
|
||
return Err(oxide_builtins::error::create_type_error(self, "constructor is not a constructor"));
|
||
}
|
||
let new_obj_ptr = self.alloc_ctor_this(ctor_obj)?;
|
||
let new_obj_val = JsValue::from_js_object(new_obj_ptr);
|
||
// derived 构造器 super() 前 this 为 undefined,基类 this = 新对象。
|
||
let this_value = if ctor_obj.is_derived_constructor() {
|
||
JsValue::undefined()
|
||
} else {
|
||
new_obj_val
|
||
};
|
||
let window = self.active_reg_limit.max(self.sub_modules[sub_idx].n_registers).max(1) as usize;
|
||
let saved = self.save_inline_state(window);
|
||
let prev_construct = self.construct_dispatch;
|
||
self.construct_dispatch = true;
|
||
let result = self
|
||
.push_bytecode_frame(
|
||
ctor,
|
||
this_value,
|
||
FrameArgs::Slice(args),
|
||
Some(0),
|
||
Some(new_obj_val),
|
||
ctor,
|
||
FrameContinuation::None,
|
||
0,
|
||
)
|
||
.and_then(|_| self.dispatch());
|
||
self.construct_dispatch = prev_construct;
|
||
self.restore_inline_state(saved);
|
||
match result {
|
||
Ok(v) => Ok(v),
|
||
Err(e) => Err(self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e))),
|
||
}
|
||
}
|
||
|
||
/// 构造携带目标 promise 的 native 闭包(resolve 或 reject 角色)。
|
||
/// `delegated` 为 true 表示 thenable 委托用的结算代理:绕过 alreadyResolved
|
||
/// (委托是唯一真正的结算路径,由 then 的 resolve/reject 触发),但 state != Pending
|
||
/// 仍阻止二次结算。
|
||
fn make_resolve_reject_fn(&mut self, promise: JsValue, reject_role: bool, delegated: bool) -> JsValue {
|
||
let native_fn: NativeFn = if reject_role { promise_reject_closure } else { promise_resolve_closure };
|
||
let fn_proto = self.session.builtin_world().fn_proto_val();
|
||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||
func.set_function(true);
|
||
// SAFETY: native_fn 是 NativeFn 函数项。
|
||
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(native_fn as *const ()) }));
|
||
func.set_native_arg_count(1);
|
||
let ptr = self.alloc_object(func);
|
||
let obj = unsafe { &mut *ptr };
|
||
let si = self.kernel_core.perm_interner().intern(PROMISE_PROP).0;
|
||
self.set_or_create_prop_value(obj, si, promise);
|
||
let dsi = self.kernel_core.perm_interner().intern(DELEGATED_PROP).0;
|
||
self.set_or_create_prop_value(obj, dsi, JsValue::bool(delegated));
|
||
self.add_fn_name_length(obj, "", 1);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// 从 resolve/reject 闭包函数对象读取目标 promise。
|
||
fn promise_from_callee(&self) -> Option<JsValue> {
|
||
let callee = self.regs[254];
|
||
if !callee.is_object() {
|
||
return None;
|
||
}
|
||
let obj = unsafe { &*callee.as_js_object_ptr() };
|
||
let si = self.kernel_core.perm_interner().intern(PROMISE_PROP).0;
|
||
match self.resolve_property(obj, si) {
|
||
Some(v) if v.is_object() => Some(v),
|
||
_ => None,
|
||
}
|
||
}
|
||
|
||
/// 当前 resolve/reject 闭包是否为 thenable 委托结算代理(绕过 alreadyResolved)。
|
||
fn callee_delegated_flag(&self) -> bool {
|
||
let callee = self.regs[254];
|
||
if !callee.is_object() {
|
||
return false;
|
||
}
|
||
let obj = unsafe { &*callee.as_js_object_ptr() };
|
||
let si = self.kernel_core.perm_interner().intern(DELEGATED_PROP).0;
|
||
self.resolve_property(obj, si)
|
||
.map(|v| v.is_bool() && v.as_bool())
|
||
.unwrap_or(false)
|
||
}
|
||
|
||
/// 取出 Promise 状态盒指针(调用方须先校验 `is_promise_value`)。
|
||
fn promise_state_ptr(&self, promise: JsValue) -> *mut PromiseState {
|
||
unsafe { (*promise.as_js_object_ptr()).native_data() as *mut PromiseState }
|
||
}
|
||
|
||
/// 是否原生 Promise 对象。
|
||
pub(crate) fn is_promise_value(&self, v: JsValue) -> bool {
|
||
v.is_object() && {
|
||
let ptr = v.as_js_object_ptr();
|
||
!ptr.is_null() && unsafe { &*ptr }.is_promise_obj()
|
||
}
|
||
}
|
||
|
||
/// 校验值的原型链含 `%Promise.prototype%`(`new Promise` 构造出的实例特征)。
|
||
fn has_promise_proto(&self, v: JsValue) -> bool {
|
||
if !v.is_object() {
|
||
return false;
|
||
}
|
||
let target = self.promise_proto.as_ptr() as *mut JsObject;
|
||
let mut cursor = v;
|
||
for _ in 0..crate::vm::MAX_PROTO_CHAIN_DEPTH {
|
||
if !cursor.is_object() {
|
||
return false;
|
||
}
|
||
let ptr = cursor.as_js_object_ptr();
|
||
if ptr.is_null() {
|
||
return false;
|
||
}
|
||
if std::ptr::eq(ptr, target) {
|
||
return true;
|
||
}
|
||
cursor = unsafe { &*ptr }.proto();
|
||
}
|
||
false
|
||
}
|
||
|
||
/// 入队一条微任务(追加到队尾,保证 FIFO)。
|
||
fn enqueue(&mut self, job: Microtask) {
|
||
self.job_queue.push_back(job);
|
||
}
|
||
|
||
/// `PromiseResolve` 核心:`x === promise` 抛 TypeError;thenable 委托入队;
|
||
/// 其余直接以 `x` 完成 promise。
|
||
///
|
||
/// # 副作用
|
||
/// - 可能入队 Thenable 微任务,或直接 settle 目标 promise。
|
||
/// - then getter 抛错时拒绝目标 promise(错误在内部消化,调用方无需处理)。
|
||
pub(crate) fn resolve_promise(&mut self, promise: JsValue, x: JsValue) -> Result<(), String> {
|
||
// alreadyResolved 守卫在 resolve 闭包层(首次调用置位,含 thenable 委托期间)。
|
||
// 本函数自身不检查:委托闭包调用它时须放行(委托才是真正结算路径);
|
||
// 二次结算由 fulfill/reject 的 state != Pending 守卫兜底。
|
||
if oxide_runtime_api::same_value(x, promise) {
|
||
let err = oxide_builtins::error::create_type_error(self, "Chaining cycle detected for promise");
|
||
return self.reject_promise(promise, err);
|
||
}
|
||
if x.is_object() {
|
||
let x_obj = unsafe { &*x.as_js_object_ptr() };
|
||
let then_si = self.kernel_core.perm_interner().intern("then").0;
|
||
let then = match self.ordinary_get(x_obj, then_si, x) {
|
||
Ok(v) => v,
|
||
Err(e) => {
|
||
let exc = self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e));
|
||
return self.reject_promise(promise, exc);
|
||
}
|
||
};
|
||
if oxide_builtins::iterator::is_callable(then) {
|
||
// thenable 委托期间本 promise 仍未 settle,但 already_resolved 已置位,
|
||
// 后续 executor 的 resolve/reject 均 no-op。委托用独立结算代理闭包
|
||
// (绕过 alreadyResolved——委托才是真正结算路径),仍受 state != Pending 守卫。
|
||
let state = self.promise_state_ptr(promise);
|
||
let state = unsafe { &mut *state };
|
||
state.already_resolved = true;
|
||
let resolve = self.make_resolve_reject_fn(promise, false, true);
|
||
let reject = self.make_resolve_reject_fn(promise, true, true);
|
||
self.enqueue(Microtask::Thenable {
|
||
thenable: x,
|
||
then,
|
||
resolve,
|
||
reject,
|
||
});
|
||
return Ok(());
|
||
}
|
||
}
|
||
self.fulfill_promise(promise, x)
|
||
}
|
||
|
||
/// 以 `value` 完成 promise:只 settle 一次,完成后触发该态反应入队。
|
||
pub(crate) fn fulfill_promise(&mut self, promise: JsValue, value: JsValue) -> Result<(), String> {
|
||
let state_ptr = self.promise_state_ptr(promise);
|
||
let settled = {
|
||
let state = unsafe { &mut *state_ptr };
|
||
if state.state != PromiseStateKind::Pending {
|
||
return Ok(());
|
||
}
|
||
state.state = PromiseStateKind::Fulfilled;
|
||
state.result = value;
|
||
std::mem::take(&mut state.reactions)
|
||
};
|
||
// 只触发 fulfill 反应;reject 反应留待拒绝路径。
|
||
for r in settled.into_iter().filter(|r| r.is_fulfill) {
|
||
self.enqueue(Microtask::Reaction {
|
||
is_fulfill: true,
|
||
handler: r.handler,
|
||
argument: value,
|
||
resolve: r.resolve,
|
||
reject: r.reject,
|
||
});
|
||
}
|
||
Ok(())
|
||
}
|
||
|
||
/// 以 `reason` 拒绝 promise:只 settle 一次,完成后触发该态反应入队。
|
||
pub(crate) fn reject_promise(&mut self, promise: JsValue, reason: JsValue) -> Result<(), String> {
|
||
let state_ptr = self.promise_state_ptr(promise);
|
||
let settled = {
|
||
let state = unsafe { &mut *state_ptr };
|
||
if state.state != PromiseStateKind::Pending {
|
||
return Ok(());
|
||
}
|
||
state.state = PromiseStateKind::Rejected;
|
||
state.result = reason;
|
||
std::mem::take(&mut state.reactions)
|
||
};
|
||
// 只触发 reject 反应;fulfill 反应留待完成路径。
|
||
for r in settled.into_iter().filter(|r| !r.is_fulfill) {
|
||
self.enqueue(Microtask::Reaction {
|
||
is_fulfill: false,
|
||
handler: r.handler,
|
||
argument: reason,
|
||
resolve: r.resolve,
|
||
reject: r.reject,
|
||
});
|
||
}
|
||
Ok(())
|
||
}
|
||
|
||
/// PromiseResolve(%Promise%, value)核心:value 为原生 Promise 时读取其
|
||
/// `constructor`,与 %Promise% 相同则原样返回;否则新建能力并经能力 resolve
|
||
/// 结算(thenable 委托)。constructor getter / 结算抛错时透传原异常值。
|
||
pub(crate) fn promise_resolve(&mut self, value: JsValue) -> Result<JsValue, JsValue> {
|
||
if self.is_promise_value(value) {
|
||
let obj = unsafe { &*value.as_js_object_ptr() };
|
||
let ctor_si = self.kernel_core.perm_interner().intern("constructor").0;
|
||
let ctor = match self.ordinary_get(obj, ctor_si, value) {
|
||
Ok(c) => c,
|
||
Err(e) => {
|
||
let exc = self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e));
|
||
return Err(exc);
|
||
}
|
||
};
|
||
let intrinsic = JsValue::from_js_object(self.promise_constructor.as_ptr() as *mut JsObject);
|
||
if oxide_runtime_api::same_value(ctor, intrinsic) {
|
||
return Ok(value);
|
||
}
|
||
}
|
||
let (promise, _resolve, _) = self.new_promise_capability();
|
||
if let Err(e) = self.resolve_promise(promise, value) {
|
||
let exc = self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e));
|
||
return Err(exc);
|
||
}
|
||
Ok(promise)
|
||
}
|
||
|
||
/// `PerformPromiseThen` 入口(内置能力):注册 fulfill/reject 反应并返回派生
|
||
/// promise。能力恒为 `%Promise%`——供引擎内部 await 机制(async /
|
||
/// async generator / AsyncFromSync)使用,规范上这些路径由调用方提供能力,
|
||
/// 不读 `this.constructor`,避免 await 子类 promise 时意外经子类构造器派生。
|
||
pub(crate) fn perform_promise_then(
|
||
&mut self, this_val: JsValue, on_fulfilled: JsValue, on_rejected: JsValue,
|
||
) -> Result<JsValue, JsValue> {
|
||
let capability = self.new_promise_capability();
|
||
self.perform_promise_then_cap(this_val, on_fulfilled, on_rejected, capability)
|
||
}
|
||
|
||
/// `PerformPromiseThen` 核心:以调用方给定能力注册 fulfill/reject 两条反应;
|
||
/// 已 settle 则直接入队。能力三元组由调用方提供——`promise_then_species`
|
||
/// 传 species 派生能力,内部 await 路径经薄包装传内置能力。
|
||
fn perform_promise_then_cap(
|
||
&mut self, this_val: JsValue, on_fulfilled: JsValue, on_rejected: JsValue,
|
||
capability: (JsValue, JsValue, JsValue),
|
||
) -> Result<JsValue, JsValue> {
|
||
if !self.is_promise_value(this_val) {
|
||
return Err(oxide_builtins::error::create_type_error(
|
||
self,
|
||
"Method Promise.prototype.then called on incompatible receiver",
|
||
));
|
||
}
|
||
let on_fulfilled = if oxide_builtins::iterator::is_callable(on_fulfilled) {
|
||
on_fulfilled
|
||
} else {
|
||
JsValue::undefined()
|
||
};
|
||
let on_rejected = if oxide_builtins::iterator::is_callable(on_rejected) {
|
||
on_rejected
|
||
} else {
|
||
JsValue::undefined()
|
||
};
|
||
let (new_promise, resolve, reject) = capability;
|
||
let state_ptr = self.promise_state_ptr(this_val);
|
||
let (kind, result) = {
|
||
let state = unsafe { &mut *state_ptr };
|
||
(state.state, state.result)
|
||
};
|
||
match kind {
|
||
PromiseStateKind::Pending => {
|
||
let state = unsafe { &mut *state_ptr };
|
||
state.reactions.push(PromiseReaction {
|
||
promise: new_promise,
|
||
resolve,
|
||
reject,
|
||
handler: on_fulfilled,
|
||
is_fulfill: true,
|
||
});
|
||
state.reactions.push(PromiseReaction {
|
||
promise: new_promise,
|
||
resolve,
|
||
reject,
|
||
handler: on_rejected,
|
||
is_fulfill: false,
|
||
});
|
||
}
|
||
PromiseStateKind::Fulfilled => {
|
||
self.enqueue(Microtask::Reaction {
|
||
is_fulfill: true,
|
||
handler: on_fulfilled,
|
||
argument: result,
|
||
resolve,
|
||
reject,
|
||
});
|
||
}
|
||
PromiseStateKind::Rejected => {
|
||
self.enqueue(Microtask::Reaction {
|
||
is_fulfill: false,
|
||
handler: on_rejected,
|
||
argument: result,
|
||
resolve,
|
||
reject,
|
||
});
|
||
}
|
||
}
|
||
Ok(new_promise)
|
||
}
|
||
|
||
/// `Promise.prototype.then` 的派生入口:IsPromise 校验后按 `this.constructor`
|
||
/// 选派生构造器(SpeciesConstructor 的 constructor 语义),建能力并注册反应。
|
||
fn promise_then_species(
|
||
&mut self, this_val: JsValue, on_fulfilled: JsValue, on_rejected: JsValue,
|
||
) -> Result<JsValue, JsValue> {
|
||
if !self.is_promise_value(this_val) {
|
||
return Err(oxide_builtins::error::create_type_error(
|
||
self,
|
||
"Method Promise.prototype.then called on incompatible receiver",
|
||
));
|
||
}
|
||
let ctor = self.species_constructor(this_val)?;
|
||
let capability = self.new_promise_capability_with_ctor(ctor)?;
|
||
self.perform_promise_then_cap(this_val, on_fulfilled, on_rejected, capability)
|
||
}
|
||
|
||
/// 读 `promise.constructor` 选派生构造器(SpeciesConstructor 的 constructor
|
||
/// 语义):constructor 为 undefined 时退回内置 `%Promise%`,非可构造函数抛
|
||
/// TypeError。constructor getter 抛错时透传原异常值。
|
||
///
|
||
/// # 边界与前提
|
||
/// - 调用方已做 IsPromise 校验,`promise` 必为 Promise 对象。
|
||
/// - constructor 为 null/非对象/非构造器均抛 TypeError。
|
||
///
|
||
/// # 注意事项
|
||
/// - 不读 `@@species`:`%Promise%` 未注册 species getter,子类经原型链读到
|
||
/// undefined 会错误退回内置;`@@species` 改写支持待补
|
||
/// `Promise[Symbol.species]` getter 时一并落地。
|
||
fn species_constructor(&mut self, promise: JsValue) -> Result<JsValue, JsValue> {
|
||
let obj = unsafe { &*promise.as_js_object_ptr() };
|
||
let ctor_si = self.kernel_core.perm_interner().intern("constructor").0;
|
||
let ctor = match self.ordinary_get(obj, ctor_si, promise) {
|
||
Ok(c) => c,
|
||
Err(e) => {
|
||
let exc = self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e));
|
||
return Err(exc);
|
||
}
|
||
};
|
||
if ctor.is_undefined() {
|
||
return Ok(JsValue::from_js_object(self.promise_constructor.as_ptr() as *mut JsObject));
|
||
}
|
||
if !is_constructor_value(ctor) {
|
||
return Err(oxide_builtins::error::create_type_error(self, "Species constructor is not a constructor"));
|
||
}
|
||
Ok(ctor)
|
||
}
|
||
|
||
/// drain 微任务队列:FIFO 逐条处理直到清空或达到上限。
|
||
///
|
||
/// # 副作用
|
||
/// - 任务内调用 JS 回调(`call_function_sync`),可能入队新任务。
|
||
/// - 单任务抛错不中断 drain(未处理拒绝按规范不可见)。
|
||
pub(crate) fn drain_job_queue(&mut self) {
|
||
let mut count = 0usize;
|
||
while let Some(job) = self.job_queue.pop_front() {
|
||
count += 1;
|
||
if count > MAX_DRAIN_JOBS {
|
||
vm_warn!("drain_job_queue: exceeded {MAX_DRAIN_JOBS} microtasks, aborting");
|
||
break;
|
||
}
|
||
self.run_microtask(job);
|
||
}
|
||
}
|
||
|
||
/// 执行单条微任务。
|
||
fn run_microtask(&mut self, job: Microtask) {
|
||
match job {
|
||
Microtask::Reaction {
|
||
is_fulfill,
|
||
handler,
|
||
argument,
|
||
resolve,
|
||
reject,
|
||
} => {
|
||
// 空处理器(undefined/非可调用)→ 值直通:fulfill 调 resolve,reject 调 reject。
|
||
let handler_result = if oxide_builtins::iterator::is_callable(handler) {
|
||
self.call_function_sync(handler, JsValue::undefined(), &[argument])
|
||
} else if is_fulfill {
|
||
Ok(argument)
|
||
} else {
|
||
let _ = self.call_function_sync(reject, JsValue::undefined(), &[argument]);
|
||
return;
|
||
};
|
||
match handler_result {
|
||
Ok(x) => {
|
||
let _ = self.call_function_sync(resolve, JsValue::undefined(), &[x]);
|
||
}
|
||
Err(e) => {
|
||
let exc = self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e));
|
||
let _ = self.call_function_sync(reject, JsValue::undefined(), &[exc]);
|
||
}
|
||
}
|
||
}
|
||
Microtask::Thenable {
|
||
thenable,
|
||
then,
|
||
resolve,
|
||
reject,
|
||
} => {
|
||
// 委托调用;抛错则拒绝目标 promise。
|
||
match self.call_function_sync(then, thenable, &[resolve, reject]) {
|
||
Ok(_) => {}
|
||
Err(e) => {
|
||
let exc = self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e));
|
||
let _ = self.call_function_sync(reject, JsValue::undefined(), &[exc]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 初始化/重建 Promise 内建对象:`%Promise%` 构造器与 `%Promise.prototype%`,
|
||
/// 绑定到 global 的 `Promise` 槽。
|
||
///
|
||
/// 在 VM 创建与 `full_reset` 后调用——原型继承自 session 的 Object/Function
|
||
/// 原型,session 重建后须重挂并重绑 global 槽。
|
||
pub(crate) fn init_promise_intrinsics(&mut self) {
|
||
let sf = self.kernel_core.perm_interner().as_ref();
|
||
let sh = self.kernel_core.shape_forge().as_ref();
|
||
let fn_proto_val = self.session.builtin_world().fn_proto_val();
|
||
let object_proto_val =
|
||
JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
|
||
|
||
// %Promise.prototype%:proto = Object.prototype,方法 then/catch/finally + @@toStringTag。
|
||
let mut proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, object_proto_val));
|
||
let ctor_si = sf.intern("constructor").0;
|
||
let ctor_shape = sh.make_shape(proto.shape_id(), ctor_si);
|
||
proto.set_shape_id(ctor_shape);
|
||
proto.push_prop(JsValue::undefined());
|
||
proto.set_data_meta(0u32, PropAttributes::new(true, false, true));
|
||
oxide_kernel::bind_methods_static!(
|
||
&mut proto,
|
||
sf,
|
||
sh,
|
||
fn_proto_val,
|
||
("then", promise_then as *const (), 2),
|
||
("catch", promise_catch as *const (), 1),
|
||
("finally", promise_finally as *const (), 1),
|
||
);
|
||
let tag_si = sf.intern("@@toStringTag").0;
|
||
let tag_shape = sh.make_shape(proto.shape_id(), tag_si);
|
||
proto.set_shape_id(tag_shape);
|
||
let tag_pos = proto.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("Promise").0)));
|
||
proto.set_data_meta(tag_pos, PropAttributes::new(false, false, true));
|
||
|
||
// %Promise% 构造器:proto = Function.prototype,静态方法 resolve/reject。
|
||
// 自身属性顺序:length、name、prototype(CreateBuiltinFunction 顺序)。
|
||
let mut ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val));
|
||
ctor.set_function(true);
|
||
ctor.set_native_arg_count(1);
|
||
// SAFETY: promise_constructor 是 NativeFn 函数项。
|
||
ctor.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(promise_constructor as *const ()) }));
|
||
ctor.type_tag = JsObject::OBJ_TYPE_CONSTRUCTOR;
|
||
let length_si = sf.intern("length").0;
|
||
let ctor_shape1 = sh.make_shape(ctor.shape_id(), length_si);
|
||
ctor.set_shape_id(ctor_shape1);
|
||
let lpos = ctor.push_prop(JsValue::int(1));
|
||
ctor.set_data_meta(lpos, PropAttributes::new(false, false, true));
|
||
let name_si = sf.intern("name").0;
|
||
let ctor_shape2 = sh.make_shape(ctor.shape_id(), name_si);
|
||
ctor.set_shape_id(ctor_shape2);
|
||
let npos = ctor.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("Promise").0)));
|
||
ctor.set_data_meta(npos, PropAttributes::new(false, false, true));
|
||
let proto2_si = sf.intern("prototype").0;
|
||
let ctor_shape3 = sh.make_shape(ctor.shape_id(), proto2_si);
|
||
ctor.set_shape_id(ctor_shape3);
|
||
ctor.push_prop(JsValue::undefined());
|
||
ctor.set_data_meta(2u32, PropAttributes::new(false, false, false));
|
||
oxide_kernel::bind_methods_static!(
|
||
&mut ctor,
|
||
sf,
|
||
sh,
|
||
fn_proto_val,
|
||
("resolve", promise_static_resolve as *const (), 1),
|
||
("reject", promise_static_reject as *const (), 1),
|
||
("all", promise_static_all as *const (), 1),
|
||
("race", promise_static_race as *const (), 1),
|
||
("allSettled", promise_static_all_settled as *const (), 1),
|
||
("any", promise_static_any as *const (), 1),
|
||
);
|
||
|
||
// 固定地址后互相接线:proto.constructor ↔ ctor.prototype。
|
||
self.promise_proto = P::new(*proto);
|
||
self.promise_constructor = P::new(*ctor);
|
||
let proto_mut = unsafe { &mut *self.promise_proto.as_mut_ptr() };
|
||
proto_mut.set_prop_at(0u32, JsValue::from_js_object(self.promise_constructor.as_ptr() as *mut JsObject));
|
||
let ctor_mut = unsafe { &mut *self.promise_constructor.as_mut_ptr() };
|
||
// prototype 槽位在 length/name 之后(下标 2)。
|
||
ctor_mut.set_prop_at(2u32, JsValue::from_js_object(self.promise_proto.as_ptr() as *mut JsObject));
|
||
|
||
// 绑定 global:槽已存在则更新(full_reset 未重建 global 时旧槽指向已弃 ctor)。
|
||
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject;
|
||
let global = unsafe { &mut *global_ptr };
|
||
let si = self.kernel_core.perm_interner().intern("Promise").0;
|
||
let ctor_val = JsValue::from_js_object(self.promise_constructor.as_ptr() as *mut JsObject);
|
||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(global.shape_id(), si) {
|
||
global.set_prop_at(pos, ctor_val);
|
||
} else {
|
||
let shape = self.kernel_core.shape_forge().make_shape(global.shape_id(), si);
|
||
global.set_shape_id(shape);
|
||
let pos = global.push_prop(ctor_val);
|
||
// global 数据属性:writable:true、enumerable:false、configurable:true。
|
||
global.set_data_meta(pos, PropAttributes::new(true, false, true));
|
||
global.bump_generation();
|
||
}
|
||
|
||
// Promise.any 的拒绝路径依赖 AggregateError 内建。
|
||
self.init_aggregate_error_intrinsics();
|
||
}
|
||
}
|
||
|
||
/// IsConstructor 近似判定:可调用、非 arrow,且 native 函数须带构造器 tag
|
||
/// (与 `construct_ctor` 的校验一致)。
|
||
fn is_constructor_value(c: JsValue) -> bool {
|
||
if !c.is_object() {
|
||
return false;
|
||
}
|
||
let c_obj = unsafe { &*c.as_js_object_ptr() };
|
||
c_obj.is_function()
|
||
&& !c_obj.is_arrow()
|
||
&& !(c_obj.native_fn().is_some() && c_obj.type_tag != JsObject::OBJ_TYPE_CONSTRUCTOR)
|
||
}
|
||
|
||
/// 读取 Promise 的 settled 值(CLI 格式化用):`Some((is_fulfilled, value))`,
|
||
/// Pending 返回 `None`。
|
||
pub fn promise_settled_value(obj: &JsObject) -> Option<(bool, JsValue)> {
|
||
let state = promise_state_ref(obj)?;
|
||
match state.state {
|
||
PromiseStateKind::Pending => None,
|
||
PromiseStateKind::Fulfilled => Some((true, state.result)),
|
||
PromiseStateKind::Rejected => Some((false, state.result)),
|
||
}
|
||
}
|
||
|
||
/// `Promise` 构造器:设置状态盒并同步调用 executor(resolve, reject)。
|
||
fn promise_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
// `new` 调用时 this 是 proto 链含 %Promise.prototype% 的新对象;裸调用拒绝。
|
||
if !vm.has_promise_proto(this_val) {
|
||
return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "Promise must be called with new"));
|
||
}
|
||
let obj = unsafe { &mut *this_val.as_js_object_ptr() };
|
||
obj.type_tag = JsObject::OBJ_TYPE_PROMISE;
|
||
let resolve = vm.make_resolve_reject_fn(this_val, false, false);
|
||
let reject = vm.make_resolve_reject_fn(this_val, true, false);
|
||
let state = Box::new(PromiseState {
|
||
state: PromiseStateKind::Pending,
|
||
result: JsValue::undefined(),
|
||
reactions: Vec::new(),
|
||
resolve_fn: resolve,
|
||
reject_fn: reject,
|
||
already_resolved: false,
|
||
});
|
||
obj.set_native_data(Box::into_raw(state) as *mut u8);
|
||
let executor = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
if !oxide_builtins::iterator::is_callable(executor) {
|
||
return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "Promise executor is not a function"));
|
||
}
|
||
match vm.call_function_sync(executor, JsValue::undefined(), &[resolve, reject]) {
|
||
Ok(_) => NativeResult::Ok(this_val),
|
||
Err(e) => {
|
||
// executor 抛错:以抛出的值为拒绝原因(原值经 last_uncaught_value 保留)。
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
let _ = vm.reject_promise(this_val, exc);
|
||
NativeResult::Ok(this_val)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// resolve 闭包:`resolve(x)` 对目标 promise 执行 PromiseResolve。
|
||
/// 非委托闭包入口检查 alreadyResolved(首次调用置位,后续 no-op);
|
||
/// 委托闭包(thenable 的 resolve)绕过该检查直接结算。
|
||
fn promise_resolve_closure(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let Some(promise) = vm.promise_from_callee() else {
|
||
return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "resolve function is invalid"));
|
||
};
|
||
let delegated = vm.callee_delegated_flag();
|
||
let x = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
if !delegated {
|
||
// 非委托:alreadyResolved 守卫——首次调用置位,含 thenable 委托期间。
|
||
let state = vm.promise_state_ptr(promise);
|
||
let state = unsafe { &mut *state };
|
||
if state.already_resolved {
|
||
return NativeResult::Ok(JsValue::undefined());
|
||
}
|
||
state.already_resolved = true;
|
||
}
|
||
if let Err(e) = vm.resolve_promise(promise, x) {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
let _ = vm.reject_promise(promise, exc);
|
||
}
|
||
NativeResult::Ok(JsValue::undefined())
|
||
}
|
||
|
||
/// reject 闭包:`reject(x)` 直接以 x 拒绝目标 promise。
|
||
fn promise_reject_closure(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let Some(promise) = vm.promise_from_callee() else {
|
||
return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "reject function is invalid"));
|
||
};
|
||
let delegated = vm.callee_delegated_flag();
|
||
let reason = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
if !delegated {
|
||
let state = vm.promise_state_ptr(promise);
|
||
let state = unsafe { &mut *state };
|
||
if state.already_resolved {
|
||
return NativeResult::Ok(JsValue::undefined());
|
||
}
|
||
state.already_resolved = true;
|
||
}
|
||
let _ = vm.reject_promise(promise, reason);
|
||
NativeResult::Ok(JsValue::undefined())
|
||
}
|
||
|
||
/// `Promise.prototype.then(onFulfilled, onRejected)`:按 `this.constructor` 派生
|
||
/// 并注册反应,返回派生 promise(子类实例走子类构造器)。
|
||
fn promise_then(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let on_fulfilled = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let on_rejected = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||
match vm.promise_then_species(this_val, on_fulfilled, on_rejected) {
|
||
Ok(promise) => NativeResult::Ok(promise),
|
||
Err(err) => NativeResult::Err(err),
|
||
}
|
||
}
|
||
|
||
/// `Promise.prototype.catch(onRejected)`:等价 `then(undefined, onRejected)`,
|
||
/// 经 Invoke 语义调用 `this.then`(可被用户覆盖的 then)。
|
||
fn promise_catch(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let on_rejected = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
match vm.invoke_then(this_val, &[JsValue::undefined(), on_rejected]) {
|
||
Ok(result) => NativeResult::Ok(result),
|
||
Err(err) => NativeResult::Err(err),
|
||
}
|
||
}
|
||
|
||
/// `Promise.prototype.finally(onFinally)`:调 onFinally 后透传原值/原拒绝原因;
|
||
/// 经 Invoke 语义调用 `this.then`。
|
||
fn promise_finally(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let on_finally = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let (then_finally, reject_finally) = if oxide_builtins::iterator::is_callable(on_finally) {
|
||
(vm.make_finally_handler(on_finally, false), vm.make_finally_handler(on_finally, true))
|
||
} else {
|
||
(JsValue::undefined(), JsValue::undefined())
|
||
};
|
||
match vm.invoke_then(this_val, &[then_finally, reject_finally]) {
|
||
Ok(result) => NativeResult::Ok(result),
|
||
Err(err) => NativeResult::Err(err),
|
||
}
|
||
}
|
||
|
||
impl Vm {
|
||
/// Invoke 语义:`GetV(this, "then")` 后以原接收者调用,透传 getter/调用抛错。
|
||
fn invoke_then(&mut self, this_val: JsValue, args: &[JsValue]) -> Result<JsValue, JsValue> {
|
||
let then_si = self.kernel_core.perm_interner().intern("then").0;
|
||
// GetV:原始值先 ToObject 再读 then;getter 抛错透传原异常。
|
||
let get_receiver = if this_val.is_object() {
|
||
this_val
|
||
} else {
|
||
match oxide_runtime_api::to_object(this_val, self) {
|
||
Ok(o) => o,
|
||
Err(e) => return Err(oxide_builtins::error::create_type_error(self, &e)),
|
||
}
|
||
};
|
||
let receiver_obj = unsafe { &*get_receiver.as_js_object_ptr() };
|
||
let then = match self.ordinary_get(receiver_obj, then_si, this_val) {
|
||
Ok(v) => v,
|
||
Err(e) => {
|
||
let exc = self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e));
|
||
return Err(exc);
|
||
}
|
||
};
|
||
if !oxide_builtins::iterator::is_callable(then) {
|
||
return Err(oxide_builtins::error::create_type_error(self, "then is not a function"));
|
||
}
|
||
match self.call_function_sync(then, this_val, args) {
|
||
Ok(v) => Ok(v),
|
||
Err(e) => Err(self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e))),
|
||
}
|
||
}
|
||
|
||
/// 构造 finally 处理器 native 闭包:调 onFinally 后,fulfill 角色返回原值,
|
||
/// reject 角色重抛原拒绝原因。
|
||
fn make_finally_handler(&mut self, on_finally: JsValue, reject_role: bool) -> JsValue {
|
||
let fn_proto = self.session.builtin_world().fn_proto_val();
|
||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||
func.set_function(true);
|
||
// SAFETY: promise_finally_handler 是 NativeFn 函数项。
|
||
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(promise_finally_handler as *const ()) }));
|
||
func.set_native_arg_count(0);
|
||
let ptr = self.alloc_object(func);
|
||
let obj = unsafe { &mut *ptr };
|
||
let of_si = self.kernel_core.perm_interner().intern(ON_FINALLY_PROP).0;
|
||
self.set_or_create_prop_value(obj, of_si, on_finally);
|
||
let rj_si = self.kernel_core.perm_interner().intern(FINALLY_REJECT_PROP).0;
|
||
self.set_or_create_prop_value(obj, rj_si, JsValue::bool(reject_role));
|
||
self.add_fn_name_length(obj, "", 1);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// 给 native 函数对象补 `length`/`name` 数据属性(length 先于 name,符合
|
||
/// CreateBuiltinFunction 属性顺序)。
|
||
pub(crate) fn add_fn_name_length(&mut self, obj: &mut JsObject, name: &str, length: u8) {
|
||
let attrs = PropAttributes::new(false, false, true);
|
||
let sh = self.kernel_core.shape_forge().as_ref();
|
||
let sf = self.kernel_core.perm_interner().as_ref();
|
||
let length_si = sf.intern("length").0;
|
||
let length_shape = sh.make_shape(obj.shape_id(), length_si);
|
||
obj.set_shape_id(length_shape);
|
||
let lpos = obj.push_prop(JsValue::int(length as i32));
|
||
obj.set_data_meta(lpos, attrs);
|
||
let name_si = sf.intern("name").0;
|
||
let name_shape = sh.make_shape(obj.shape_id(), name_si);
|
||
obj.set_shape_id(name_shape);
|
||
let npos = obj.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern(name).0)));
|
||
obj.set_data_meta(npos, attrs);
|
||
}
|
||
|
||
/// 创建聚合静态方法(all/race/allSettled/any)的共享记录对象:剩余计数
|
||
/// 初始 1,结果数组(race 无)与能力 resolve/reject 闭包全部存为自身属性。
|
||
fn make_agg_record(&mut self, values: JsValue, resolve: JsValue, reject: JsValue) -> JsValue {
|
||
let proto_val = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
|
||
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
|
||
let obj = unsafe { &mut *ptr };
|
||
let rem_si = self.kernel_core.perm_interner().intern(AGG_REMAINING_PROP).0;
|
||
self.set_or_create_prop_value(obj, rem_si, JsValue::int(1));
|
||
let val_si = self.kernel_core.perm_interner().intern(AGG_VALUES_PROP).0;
|
||
self.set_or_create_prop_value(obj, val_si, values);
|
||
let res_si = self.kernel_core.perm_interner().intern(AGG_RESOLVE_PROP).0;
|
||
self.set_or_create_prop_value(obj, res_si, resolve);
|
||
let rej_si = self.kernel_core.perm_interner().intern(AGG_REJECT_PROP).0;
|
||
self.set_or_create_prop_value(obj, rej_si, reject);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// 创建聚合静态方法的元素处理器闭包:携带共享记录与元素下标,`already` 标志
|
||
/// 初始 false。内部状态属性非枚举且追加在 length/name 之后,保持内建函数
|
||
/// "length 先于 name" 的属性序。
|
||
fn make_agg_element_fn(&mut self, native_fn: NativeFn, record: JsValue, index: i32) -> JsValue {
|
||
let fn_proto = self.session.builtin_world().fn_proto_val();
|
||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||
func.set_function(true);
|
||
// SAFETY: native_fn 是 NativeFn 函数项。
|
||
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(native_fn as *const ()) }));
|
||
func.set_native_arg_count(1);
|
||
let ptr = self.alloc_object(func);
|
||
let obj = unsafe { &mut *ptr };
|
||
self.add_fn_name_length(obj, "", 1);
|
||
let sh = self.kernel_core.shape_forge().as_ref();
|
||
let attrs = PropAttributes::new(false, false, false);
|
||
let rec_si = self.kernel_core.perm_interner().intern(AGG_RECORD_PROP).0;
|
||
let rec_shape = sh.make_shape(obj.shape_id(), rec_si);
|
||
obj.set_shape_id(rec_shape);
|
||
let rec_pos = obj.push_prop(record);
|
||
obj.set_data_meta(rec_pos, attrs);
|
||
let idx_si = self.kernel_core.perm_interner().intern(AGG_INDEX_PROP).0;
|
||
let idx_shape = sh.make_shape(obj.shape_id(), idx_si);
|
||
obj.set_shape_id(idx_shape);
|
||
let idx_pos = obj.push_prop(JsValue::int(index));
|
||
obj.set_data_meta(idx_pos, attrs);
|
||
let al_si = self.kernel_core.perm_interner().intern(AGG_ALREADY_PROP).0;
|
||
let al_shape = sh.make_shape(obj.shape_id(), al_si);
|
||
obj.set_shape_id(al_shape);
|
||
let al_pos = obj.push_prop(JsValue::bool(false));
|
||
obj.set_data_meta(al_pos, attrs);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// 构造 allSettled 的结算记录 `{status, <value_field>: value}` 普通对象。
|
||
fn make_settled_record(&mut self, status: &str, value_field: &str, value: JsValue) -> JsValue {
|
||
let proto_val = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
|
||
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
|
||
let obj = unsafe { &mut *ptr };
|
||
let status_si = self.kernel_core.perm_interner().intern("status").0;
|
||
let status_val = self.new_string(status);
|
||
self.set_or_create_prop_value(obj, status_si, status_val);
|
||
let field_si = self.kernel_core.perm_interner().intern(value_field).0;
|
||
self.set_or_create_prop_value(obj, field_si, value);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// 构造 AggregateError 实例(proto = %AggregateError.prototype%):message 非
|
||
/// undefined 时 ToString 建自身属性,errors 存为数据属性。
|
||
fn make_aggregate_error(&mut self, errors: JsValue, message: JsValue) -> JsValue {
|
||
let proto_val = JsValue::from_js_object(self.aggregate_error_proto.as_ptr() as *mut JsObject);
|
||
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
|
||
let obj = unsafe { &mut *ptr };
|
||
// message/errors 为数据属性:writable、非枚举、configurable(CreateMethodProperty)。
|
||
let attrs = PropAttributes::new(true, false, true);
|
||
if !message.is_undefined() {
|
||
let msg_str = oxide_runtime_api::to_string_full(message, self).unwrap_or_default();
|
||
let msg_si = self.kernel_core.perm_interner().intern("message").0;
|
||
let msg_val = self.new_string(&msg_str);
|
||
let _ = self.define_data_property(obj, msg_si, msg_val, attrs);
|
||
}
|
||
let err_si = self.kernel_core.perm_interner().intern("errors").0;
|
||
let _ = self.define_data_property(obj, err_si, errors, attrs);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// 把 errors 可迭代值收集为新数组(IterableToList)。不可迭代抛 TypeError。
|
||
fn aggregate_errors_to_list(&mut self, errors: JsValue) -> Result<JsValue, JsValue> {
|
||
let array_proto = JsValue::from_js_object(self.session.builtin_world().array_proto.as_ptr() as *mut JsObject);
|
||
let ptr = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0, self.epoch.bump()));
|
||
let list = JsValue::from_js_object(ptr);
|
||
let mut index = 0usize;
|
||
oxide_builtins::iterator::iterate_elements(self, errors, |_vm, elem| {
|
||
// SAFETY: list 是本函数新建的存活数组对象。
|
||
let list_obj = unsafe { &mut *list.as_js_object_ptr() };
|
||
list_obj.set_prop_at(index, elem);
|
||
index += 1;
|
||
Ok(())
|
||
})?;
|
||
Ok(list)
|
||
}
|
||
|
||
/// 初始化/重建 AggregateError 内建对象:`%AggregateError%` 构造器与
|
||
/// `%AggregateError.prototype%`(proto = %Error.prototype%),绑定 global 槽。
|
||
///
|
||
/// 与 `init_promise_intrinsics` 同生命周期(VM 创建 + full_reset),
|
||
/// `Promise.any` 的拒绝路径依赖此内建。
|
||
pub(crate) fn init_aggregate_error_intrinsics(&mut self) {
|
||
let sf = self.kernel_core.perm_interner().as_ref();
|
||
let sh = self.kernel_core.shape_forge().as_ref();
|
||
let fn_proto_val = self.session.builtin_world().fn_proto_val();
|
||
let error_proto_val =
|
||
JsValue::from_js_object(self.session.builtin_world().error_proto.as_ptr() as *mut JsObject);
|
||
|
||
// %AggregateError.prototype%:proto = %Error.prototype%,constructor/name/message 数据属性。
|
||
let mut proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, error_proto_val));
|
||
let ctor_si = sf.intern("constructor").0;
|
||
let ctor_shape = sh.make_shape(proto.shape_id(), ctor_si);
|
||
proto.set_shape_id(ctor_shape);
|
||
proto.push_prop(JsValue::undefined());
|
||
proto.set_data_meta(0u32, PropAttributes::new(true, false, true));
|
||
let name_si = sf.intern("name").0;
|
||
let name_shape = sh.make_shape(proto.shape_id(), name_si);
|
||
proto.set_shape_id(name_shape);
|
||
let name_pos = proto.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("AggregateError").0)));
|
||
proto.set_data_meta(name_pos, PropAttributes::new(true, false, true));
|
||
let msg_si = sf.intern("message").0;
|
||
let msg_shape = sh.make_shape(proto.shape_id(), msg_si);
|
||
proto.set_shape_id(msg_shape);
|
||
let msg_pos = proto.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("").0)));
|
||
proto.set_data_meta(msg_pos, PropAttributes::new(true, false, true));
|
||
|
||
// %AggregateError% 构造器:proto = %Function.prototype%,length 2。
|
||
let mut ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val));
|
||
ctor.set_function(true);
|
||
ctor.type_tag = JsObject::OBJ_TYPE_CONSTRUCTOR;
|
||
// SAFETY: aggregate_error_constructor 是 NativeFn 函数项。
|
||
ctor.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(aggregate_error_constructor as *const ()) }));
|
||
ctor.set_native_arg_count(2);
|
||
let length_si = sf.intern("length").0;
|
||
let ctor_shape1 = sh.make_shape(ctor.shape_id(), length_si);
|
||
ctor.set_shape_id(ctor_shape1);
|
||
let lpos = ctor.push_prop(JsValue::int(2));
|
||
ctor.set_data_meta(lpos, PropAttributes::new(false, false, true));
|
||
let name2_si = sf.intern("name").0;
|
||
let ctor_shape2 = sh.make_shape(ctor.shape_id(), name2_si);
|
||
ctor.set_shape_id(ctor_shape2);
|
||
let npos = ctor.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("AggregateError").0)));
|
||
ctor.set_data_meta(npos, PropAttributes::new(false, false, true));
|
||
let proto2_si = sf.intern("prototype").0;
|
||
let ctor_shape3 = sh.make_shape(ctor.shape_id(), proto2_si);
|
||
ctor.set_shape_id(ctor_shape3);
|
||
ctor.push_prop(JsValue::undefined());
|
||
ctor.set_data_meta(2u32, PropAttributes::new(false, false, false));
|
||
|
||
// 固定地址后互相接线:proto.constructor ↔ ctor.prototype。
|
||
self.aggregate_error_proto = P::new(*proto);
|
||
self.aggregate_error_constructor = P::new(*ctor);
|
||
let proto_mut = unsafe { &mut *self.aggregate_error_proto.as_mut_ptr() };
|
||
proto_mut
|
||
.set_prop_at(0u32, JsValue::from_js_object(self.aggregate_error_constructor.as_ptr() as *mut JsObject));
|
||
let ctor_mut = unsafe { &mut *self.aggregate_error_constructor.as_mut_ptr() };
|
||
ctor_mut.set_prop_at(2u32, JsValue::from_js_object(self.aggregate_error_proto.as_ptr() as *mut JsObject));
|
||
|
||
// 绑定 global(槽已存在则更新)。
|
||
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject;
|
||
let global = unsafe { &mut *global_ptr };
|
||
let si = self.kernel_core.perm_interner().intern("AggregateError").0;
|
||
let ctor_val = JsValue::from_js_object(self.aggregate_error_constructor.as_ptr() as *mut JsObject);
|
||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(global.shape_id(), si) {
|
||
global.set_prop_at(pos, ctor_val);
|
||
} else {
|
||
let shape = self.kernel_core.shape_forge().make_shape(global.shape_id(), si);
|
||
global.set_shape_id(shape);
|
||
let pos = global.push_prop(ctor_val);
|
||
global.set_data_meta(pos, PropAttributes::new(true, false, true));
|
||
global.bump_generation();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// finally 处理器闭包:读自身 prop 的 onFinally 与角色,调用后透传/重抛。
|
||
fn promise_finally_handler(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let callee = vm.reg(254);
|
||
if !callee.is_object() {
|
||
return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "finally handler is invalid"));
|
||
}
|
||
let callee_obj = unsafe { &*callee.as_js_object_ptr() };
|
||
let of_si = vm.kernel_core.perm_interner().intern(ON_FINALLY_PROP).0;
|
||
let on_finally = vm.resolve_property(callee_obj, of_si).unwrap_or(JsValue::undefined());
|
||
let rj_si = vm.kernel_core.perm_interner().intern(FINALLY_REJECT_PROP).0;
|
||
let is_reject = vm
|
||
.resolve_property(callee_obj, rj_si)
|
||
.is_some_and(oxide_runtime_api::to_boolean);
|
||
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
match vm.call_function_sync(on_finally, JsValue::undefined(), &[]) {
|
||
Ok(_) => {
|
||
if is_reject {
|
||
NativeResult::Err(value)
|
||
} else {
|
||
NativeResult::Ok(value)
|
||
}
|
||
}
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
NativeResult::Err(exc)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// `Promise.resolve(x)`:`x` 为原生 Promise 且 `x.constructor === this` 时直接返回;
|
||
/// 否则按 `this`(构造器)建能力并 PromiseResolve。
|
||
fn promise_static_resolve(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let ctor = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let x = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
if vm.is_promise_value(x) {
|
||
let x_obj = unsafe { &*x.as_js_object_ptr() };
|
||
let ctor_si = vm.kernel_core.perm_interner().intern("constructor").0;
|
||
let x_ctor = match vm.ordinary_get(x_obj, ctor_si, x) {
|
||
Ok(c) => c,
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
return NativeResult::Err(exc);
|
||
}
|
||
};
|
||
if oxide_runtime_api::same_value(x_ctor, ctor) {
|
||
return NativeResult::Ok(x);
|
||
}
|
||
}
|
||
let (promise, resolve, _) = match vm.new_promise_capability_with_ctor(ctor) {
|
||
Ok(t) => t,
|
||
Err(err) => return NativeResult::Err(err),
|
||
};
|
||
// PromiseResolve:调用能力 resolve(自定义构造器可能产生非原生 promise)。
|
||
match vm.call_function_sync(resolve, JsValue::undefined(), &[x]) {
|
||
Ok(_) => NativeResult::Ok(promise),
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
NativeResult::Err(exc)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// `Promise.reject(x)`:按 `this`(构造器)建能力并直接拒绝。
|
||
fn promise_static_reject(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let ctor = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let x = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let (promise, _, reject) = match vm.new_promise_capability_with_ctor(ctor) {
|
||
Ok(t) => t,
|
||
Err(err) => return NativeResult::Err(err),
|
||
};
|
||
match vm.call_function_sync(reject, JsValue::undefined(), &[x]) {
|
||
Ok(_) => NativeResult::Ok(promise),
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
NativeResult::Err(exc)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// `Promise.all(iterable)`:全部元素结算后以结果数组完成,任一拒绝则拒绝。
|
||
fn promise_static_all(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let ctor = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let iterable = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
match perform_promise_combine(vm, ctor, iterable, AggregateKind::All) {
|
||
Ok(promise) => NativeResult::Ok(promise),
|
||
Err(err) => NativeResult::Err(err),
|
||
}
|
||
}
|
||
|
||
/// `Promise.race(iterable)`:任一元素先结算即按该结果完成/拒绝。
|
||
fn promise_static_race(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let ctor = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let iterable = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
match perform_promise_combine(vm, ctor, iterable, AggregateKind::Race) {
|
||
Ok(promise) => NativeResult::Ok(promise),
|
||
Err(err) => NativeResult::Err(err),
|
||
}
|
||
}
|
||
|
||
/// `Promise.allSettled(iterable)`:全部元素结算后以 `{status, value|reason}` 数组完成。
|
||
fn promise_static_all_settled(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let ctor = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let iterable = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
match perform_promise_combine(vm, ctor, iterable, AggregateKind::AllSettled) {
|
||
Ok(promise) => NativeResult::Ok(promise),
|
||
Err(err) => NativeResult::Err(err),
|
||
}
|
||
}
|
||
|
||
/// `Promise.any(iterable)`:任一元素完成即完成;全部拒绝则以 AggregateError(errors) 拒绝。
|
||
fn promise_static_any(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let ctor = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let iterable = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
match perform_promise_combine(vm, ctor, iterable, AggregateKind::Any) {
|
||
Ok(promise) => NativeResult::Ok(promise),
|
||
Err(err) => NativeResult::Err(err),
|
||
}
|
||
}
|
||
|
||
/// 聚合静态方法的共享核心:迭代可迭代输入,逐元素调 `C.resolve` 建 promise 并注册反应,
|
||
/// 按模式在全部/任一结算后交付能力 promise。
|
||
///
|
||
/// # 步骤
|
||
/// 1. 建能力(NewPromiseCapability(C) 抛错同步上抛),取 C.resolve 一次(不可调用 → 拒绝)。
|
||
/// 2. 建共享记录(剩余计数 = 1 + 元素数,结果数组,能力 resolve/reject)。
|
||
/// 3. 迭代元素:逐元素 `Call(C.resolve, C, «elem»)` 后 `Invoke(promise.then, 元素处理器)`。
|
||
/// 4. 迭代完成时哨兵计数递减;为 0 时结算(all/allSettled 完成数组,any 拒绝 AggregateError)。
|
||
///
|
||
/// # 边界与前提
|
||
/// - 迭代异常按来源区分是否 IteratorClose:next 调用与 then 注册抛错关闭迭代器,
|
||
/// 迭代结果对象的 done/value 读取抛错按规范直接拒绝(不关闭)。
|
||
/// - 元素处理器同步触发时(thenable 直接调 onFulfilled),剩余计数先 +1 再注册,
|
||
/// 保证中途结算仍能等齐全部元素。
|
||
fn perform_promise_combine(
|
||
vm: &mut Vm, ctor: JsValue, iterable: JsValue, kind: AggregateKind,
|
||
) -> Result<JsValue, JsValue> {
|
||
let (promise, resolve, reject) = vm.new_promise_capability_with_ctor(ctor)?;
|
||
|
||
// 取 C.resolve 一次(getter 抛错或不可调用 → 拒绝能力)。
|
||
let resolve_si = vm.kernel_core.perm_interner().intern("resolve").0;
|
||
let promise_resolve = if ctor.is_object() {
|
||
// SAFETY: ctor 是存活对象。
|
||
let ctor_obj = unsafe { &*ctor.as_js_object_ptr() };
|
||
match vm.ordinary_get(ctor_obj, resolve_si, ctor) {
|
||
Ok(v) => v,
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[exc]);
|
||
return Ok(promise);
|
||
}
|
||
}
|
||
} else {
|
||
JsValue::undefined()
|
||
};
|
||
if !oxide_builtins::iterator::is_callable(promise_resolve) {
|
||
let exc = oxide_builtins::error::create_type_error(vm, "resolve is not a function");
|
||
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[exc]);
|
||
return Ok(promise);
|
||
}
|
||
|
||
// 结果数组(race 不需要)。
|
||
let values = if kind == AggregateKind::Race {
|
||
JsValue::undefined()
|
||
} else {
|
||
let array_proto = JsValue::from_js_object(vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject);
|
||
let ptr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0, vm.epoch.bump()));
|
||
JsValue::from_js_object(ptr)
|
||
};
|
||
let record = vm.make_agg_record(values, resolve, reject);
|
||
|
||
// GetIterator 失败 → 拒绝(尚无迭代器可关闭)。
|
||
let iterator = match oxide_builtins::iterator::make_iterator_for_value(vm, iterable) {
|
||
Ok(it) => it,
|
||
Err(err) => {
|
||
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[err]);
|
||
return Ok(promise);
|
||
}
|
||
};
|
||
|
||
enum IterAbrupt {
|
||
Close(JsValue),
|
||
NoClose(JsValue),
|
||
}
|
||
let mut index: i32 = 0;
|
||
let result: Result<(), IterAbrupt> = (|| {
|
||
let next_si = vm.kernel_core.perm_interner().intern("next").0;
|
||
let done_si = vm.kernel_core.perm_interner().intern("done").0;
|
||
let value_si = vm.kernel_core.perm_interner().intern("value").0;
|
||
// SAFETY: iterator 是存活对象。
|
||
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
|
||
let next_fn = vm
|
||
.ordinary_get(iter_obj, next_si, iterator)
|
||
.map_err(|e| IterAbrupt::Close(agg_engine_error(vm, &e)))?;
|
||
loop {
|
||
let step = vm
|
||
.call_function_sync(next_fn, iterator, &[])
|
||
.map_err(|e| IterAbrupt::Close(agg_engine_error(vm, &e)))?;
|
||
if !step.is_object() {
|
||
return Err(IterAbrupt::NoClose(oxide_builtins::error::create_type_error(
|
||
vm,
|
||
"iterator result is not an object",
|
||
)));
|
||
}
|
||
// SAFETY: step 是存活对象。
|
||
let step_obj = unsafe { &*step.as_js_object_ptr() };
|
||
let done = vm
|
||
.ordinary_get(step_obj, done_si, step)
|
||
.map_err(|e| IterAbrupt::NoClose(agg_engine_error(vm, &e)))?;
|
||
if oxide_runtime_api::to_boolean(done) {
|
||
return Ok(());
|
||
}
|
||
let elem = vm
|
||
.ordinary_get(step_obj, value_si, step)
|
||
.map_err(|e| IterAbrupt::NoClose(agg_engine_error(vm, &e)))?;
|
||
let next_promise = vm
|
||
.call_function_sync(promise_resolve, ctor, &[elem])
|
||
.map_err(|e| IterAbrupt::Close(agg_engine_error(vm, &e)))?;
|
||
|
||
// 剩余计数先 +1 再注册:thenable 同步结算时 handler 依赖该计数已含自身。
|
||
let cur = agg_read_remaining(vm, record);
|
||
agg_write_remaining(vm, record, cur + 1);
|
||
match kind {
|
||
AggregateKind::All => {
|
||
let re = vm.make_agg_element_fn(promise_all_resolve_element, record, index);
|
||
vm.invoke_then(next_promise, &[re, reject]).map_err(IterAbrupt::Close)?;
|
||
}
|
||
AggregateKind::Race => {
|
||
// race 直接把能力 resolve/reject 作为反应处理器(规范无元素函数包装,
|
||
// 能力结算一次后其余调用为 no-op)。
|
||
vm.invoke_then(next_promise, &[resolve, reject]).map_err(IterAbrupt::Close)?;
|
||
}
|
||
AggregateKind::AllSettled => {
|
||
let re = vm.make_agg_element_fn(promise_all_settled_resolve_element, record, index);
|
||
let rj = vm.make_agg_element_fn(promise_all_settled_reject_element, record, index);
|
||
vm.invoke_then(next_promise, &[re, rj]).map_err(IterAbrupt::Close)?;
|
||
}
|
||
AggregateKind::Any => {
|
||
// any 的完成侧直接用能力 resolve;拒绝侧用带 AlreadyCalled 的 reject 元素。
|
||
let rj = vm.make_agg_element_fn(promise_any_reject_element, record, index);
|
||
vm.invoke_then(next_promise, &[resolve, rj]).map_err(IterAbrupt::Close)?;
|
||
}
|
||
}
|
||
index += 1;
|
||
}
|
||
})();
|
||
|
||
match result {
|
||
Ok(()) => {
|
||
// 迭代完成:哨兵 1 递减;为 0 时结算(race 无计数语义)。
|
||
let remaining = agg_read_remaining(vm, record) - 1;
|
||
agg_write_remaining(vm, record, remaining);
|
||
match kind {
|
||
AggregateKind::All | AggregateKind::AllSettled => {
|
||
if remaining == 0 {
|
||
let values = agg_record_val(vm, record, AGG_VALUES_PROP);
|
||
agg_call_resolve(vm, record, values);
|
||
}
|
||
}
|
||
AggregateKind::Any => {
|
||
if remaining == 0 {
|
||
let errors = agg_record_val(vm, record, AGG_VALUES_PROP);
|
||
let agg = vm.make_aggregate_error(errors, JsValue::undefined());
|
||
let rej = agg_record_val(vm, record, AGG_REJECT_PROP);
|
||
let _ = vm.call_function_sync(rej, JsValue::undefined(), &[agg]);
|
||
}
|
||
}
|
||
AggregateKind::Race => {}
|
||
}
|
||
}
|
||
Err(IterAbrupt::Close(e)) => {
|
||
close_agg_iterator(vm, iterator);
|
||
let rej = agg_record_val(vm, record, AGG_REJECT_PROP);
|
||
let _ = vm.call_function_sync(rej, JsValue::undefined(), &[e]);
|
||
}
|
||
Err(IterAbrupt::NoClose(e)) => {
|
||
let rej = agg_record_val(vm, record, AGG_REJECT_PROP);
|
||
let _ = vm.call_function_sync(rej, JsValue::undefined(), &[e]);
|
||
}
|
||
}
|
||
Ok(promise)
|
||
}
|
||
|
||
/// 聚合元素处理器的公共 prologue:取共享记录与下标;`already` 已置位返回 None
|
||
/// (元素函数只生效一次),否则置位后返回记录。
|
||
fn agg_element_state(vm: &mut Vm) -> Option<(JsValue, i32)> {
|
||
let callee = vm.reg(254);
|
||
if !callee.is_object() {
|
||
return None;
|
||
}
|
||
let callee_ptr = callee.as_js_object_ptr();
|
||
let rec_si = vm.kernel_core.perm_interner().intern(AGG_RECORD_PROP).0;
|
||
let idx_si = vm.kernel_core.perm_interner().intern(AGG_INDEX_PROP).0;
|
||
let al_si = vm.kernel_core.perm_interner().intern(AGG_ALREADY_PROP).0;
|
||
// SAFETY: callee 是当前调用的存活函数对象。
|
||
let callee_ref = unsafe { &*callee_ptr };
|
||
if vm
|
||
.resolve_property(callee_ref, al_si)
|
||
.is_some_and(oxide_runtime_api::to_boolean)
|
||
{
|
||
return None;
|
||
}
|
||
let record = vm.resolve_property(callee_ref, rec_si).unwrap_or(JsValue::undefined());
|
||
let index = vm
|
||
.resolve_property(callee_ref, idx_si)
|
||
.map_or(0, |v| if v.is_int() { v.as_int() } else { 0 });
|
||
// SAFETY: 同一 callee 对象,此处仅写 already 标志。
|
||
vm.set_or_create_prop_value(unsafe { &mut *callee_ptr }, al_si, JsValue::bool(true));
|
||
Some((record, index))
|
||
}
|
||
|
||
/// 读取记录对象属性(非对象/缺失返回 undefined)。
|
||
fn agg_record_val(vm: &Vm, record: JsValue, prop: &str) -> JsValue {
|
||
if !record.is_object() {
|
||
return JsValue::undefined();
|
||
}
|
||
let si = vm.kernel_core.perm_interner().intern(prop).0;
|
||
// SAFETY: record 是存活对象。
|
||
vm.resolve_property(unsafe { &*record.as_js_object_ptr() }, si)
|
||
.unwrap_or(JsValue::undefined())
|
||
}
|
||
|
||
/// 读取记录剩余计数。
|
||
fn agg_read_remaining(vm: &Vm, record: JsValue) -> i32 {
|
||
let v = agg_record_val(vm, record, AGG_REMAINING_PROP);
|
||
if v.is_int() {
|
||
v.as_int()
|
||
} else {
|
||
0
|
||
}
|
||
}
|
||
|
||
/// 写回记录剩余计数。
|
||
fn agg_write_remaining(vm: &mut Vm, record: JsValue, n: i32) {
|
||
if !record.is_object() {
|
||
return;
|
||
}
|
||
let si = vm.kernel_core.perm_interner().intern(AGG_REMAINING_PROP).0;
|
||
// SAFETY: record 是存活对象。
|
||
vm.set_or_create_prop_value(unsafe { &mut *record.as_js_object_ptr() }, si, JsValue::int(n));
|
||
}
|
||
|
||
/// 调用记录上的能力 resolve;抛错时改以能力 reject 拒绝(IfAbruptRejectPromise)。
|
||
fn agg_call_resolve(vm: &mut Vm, record: JsValue, arg: JsValue) {
|
||
let resolve = agg_record_val(vm, record, AGG_RESOLVE_PROP);
|
||
if let Err(e) = vm.call_function_sync(resolve, JsValue::undefined(), &[arg]) {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
let reject = agg_record_val(vm, record, AGG_REJECT_PROP);
|
||
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[exc]);
|
||
}
|
||
}
|
||
|
||
/// 把 `call_function_sync` 的错误文本恢复为原始异常值。
|
||
fn agg_engine_error(vm: &mut Vm, err: &str) -> JsValue {
|
||
vm.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, err))
|
||
}
|
||
|
||
/// IteratorClose:调用迭代器的 `return()`(可调用时),忽略其抛错。
|
||
fn close_agg_iterator(vm: &mut Vm, iterator: JsValue) {
|
||
if !iterator.is_object() {
|
||
return;
|
||
}
|
||
let return_si = vm.kernel_core.perm_interner().intern("return").0;
|
||
// SAFETY: iterator 是存活对象。
|
||
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
|
||
if let Ok(ret) = vm.ordinary_get(iter_obj, return_si, iterator) {
|
||
if oxide_builtins::iterator::is_callable(ret) {
|
||
let _ = vm.call_function_sync(ret, iterator, &[]);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// `Promise.all` resolve 元素:写 `values[index]`,剩余计数归零时完成数组。
|
||
fn promise_all_resolve_element(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let Some((record, index)) = agg_element_state(vm) else {
|
||
return NativeResult::Ok(JsValue::undefined());
|
||
};
|
||
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let values = agg_record_val(vm, record, AGG_VALUES_PROP);
|
||
if values.is_object() {
|
||
let key_si = make_int_key(index as u32);
|
||
// SAFETY: values 是存活数组对象;直写元素区不触发数组 setter。
|
||
vm.set_or_create_prop_value(unsafe { &mut *values.as_js_object_ptr() }, key_si, value);
|
||
}
|
||
let remaining = agg_read_remaining(vm, record) - 1;
|
||
agg_write_remaining(vm, record, remaining);
|
||
if remaining == 0 {
|
||
agg_call_resolve(vm, record, values);
|
||
}
|
||
NativeResult::Ok(JsValue::undefined())
|
||
}
|
||
|
||
// `Promise.race` 使用能力 resolve/reject 直连,无独立元素函数。
|
||
|
||
/// `Promise.allSettled` resolve 元素:写 `{status:'fulfilled', value}` 记录。
|
||
fn promise_all_settled_resolve_element(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let Some((record, index)) = agg_element_state(vm) else {
|
||
return NativeResult::Ok(JsValue::undefined());
|
||
};
|
||
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let values = agg_record_val(vm, record, AGG_VALUES_PROP);
|
||
if values.is_object() {
|
||
let settled = vm.make_settled_record("fulfilled", "value", value);
|
||
let key_si = make_int_key(index as u32);
|
||
// SAFETY: values 是存活数组对象。
|
||
vm.set_or_create_prop_value(unsafe { &mut *values.as_js_object_ptr() }, key_si, settled);
|
||
}
|
||
let remaining = agg_read_remaining(vm, record) - 1;
|
||
agg_write_remaining(vm, record, remaining);
|
||
if remaining == 0 {
|
||
agg_call_resolve(vm, record, values);
|
||
}
|
||
NativeResult::Ok(JsValue::undefined())
|
||
}
|
||
|
||
/// `Promise.allSettled` reject 元素:写 `{status:'rejected', reason}` 记录。
|
||
fn promise_all_settled_reject_element(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let Some((record, index)) = agg_element_state(vm) else {
|
||
return NativeResult::Ok(JsValue::undefined());
|
||
};
|
||
let reason = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let values = agg_record_val(vm, record, AGG_VALUES_PROP);
|
||
if values.is_object() {
|
||
let settled = vm.make_settled_record("rejected", "reason", reason);
|
||
let key_si = make_int_key(index as u32);
|
||
// SAFETY: values 是存活数组对象。
|
||
vm.set_or_create_prop_value(unsafe { &mut *values.as_js_object_ptr() }, key_si, settled);
|
||
}
|
||
let remaining = agg_read_remaining(vm, record) - 1;
|
||
agg_write_remaining(vm, record, remaining);
|
||
if remaining == 0 {
|
||
agg_call_resolve(vm, record, values);
|
||
}
|
||
NativeResult::Ok(JsValue::undefined())
|
||
}
|
||
|
||
/// `Promise.any` reject 元素:写 `errors[index]`,全部拒绝时以 AggregateError 拒绝。
|
||
fn promise_any_reject_element(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let Some((record, index)) = agg_element_state(vm) else {
|
||
return NativeResult::Ok(JsValue::undefined());
|
||
};
|
||
let reason = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let errors = agg_record_val(vm, record, AGG_VALUES_PROP);
|
||
if errors.is_object() {
|
||
let key_si = make_int_key(index as u32);
|
||
// SAFETY: errors 是存活数组对象。
|
||
vm.set_or_create_prop_value(unsafe { &mut *errors.as_js_object_ptr() }, key_si, reason);
|
||
}
|
||
let remaining = agg_read_remaining(vm, record) - 1;
|
||
agg_write_remaining(vm, record, remaining);
|
||
if remaining == 0 {
|
||
let agg = vm.make_aggregate_error(errors, JsValue::undefined());
|
||
let reject = agg_record_val(vm, record, AGG_REJECT_PROP);
|
||
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[agg]);
|
||
}
|
||
NativeResult::Ok(JsValue::undefined())
|
||
}
|
||
|
||
/// `AggregateError(errors, message)` 构造器:message 非 undefined 时先 ToString 建
|
||
/// 自身属性,再把 errors 可迭代收集为 `errors` 数据属性。
|
||
fn aggregate_error_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let errors = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let message = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||
let this = if this_val.is_object() {
|
||
this_val.as_js_object_ptr()
|
||
} else {
|
||
let proto_val = JsValue::from_js_object(vm.aggregate_error_proto.as_ptr() as *mut JsObject);
|
||
vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val))
|
||
};
|
||
if !message.is_undefined() {
|
||
let msg_str = match oxide_runtime_api::to_string_full(message, vm) {
|
||
Ok(s) => s,
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
return NativeResult::Err(exc);
|
||
}
|
||
};
|
||
let msg_si = vm.kernel_core.perm_interner().intern("message").0;
|
||
let msg_val = vm.new_string(&msg_str);
|
||
// SAFETY: this 是本次构造的存活对象。
|
||
let _ = vm.define_data_property(unsafe { &mut *this }, msg_si, msg_val, PropAttributes::new(true, false, true));
|
||
}
|
||
let errors_list = match vm.aggregate_errors_to_list(errors) {
|
||
Ok(list) => list,
|
||
Err(err) => return NativeResult::Err(err),
|
||
};
|
||
let err_si = vm.kernel_core.perm_interner().intern("errors").0;
|
||
let _ = vm.define_data_property(unsafe { &mut *this }, err_si, errors_list, PropAttributes::new(true, false, true));
|
||
NativeResult::Ok(JsValue::from_js_object(this))
|
||
}
|
||
|
||
/// GetCapabilitiesExecutor:捕获 resolve/reject 到自身 prop;能力已持有任一
|
||
/// 非 undefined 值时再次调用抛 TypeError。
|
||
fn capability_executor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let callee = vm.reg(254);
|
||
if !callee.is_object() {
|
||
return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "executor is invalid"));
|
||
}
|
||
let obj = unsafe { &*callee.as_js_object_ptr() };
|
||
let res_si = vm.kernel_core.perm_interner().intern(CAP_RESOLVE_PROP).0;
|
||
let rej_si = vm.kernel_core.perm_interner().intern(CAP_REJECT_PROP).0;
|
||
let held = vm.resolve_property(obj, res_si).is_some_and(|v| !v.is_undefined())
|
||
|| vm.resolve_property(obj, rej_si).is_some_and(|v| !v.is_undefined());
|
||
if held {
|
||
return NativeResult::Err(oxide_builtins::error::create_type_error(
|
||
vm,
|
||
"Promise capability executor has already been called",
|
||
));
|
||
}
|
||
let resolve = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let reject = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||
let obj = unsafe { &mut *callee.as_js_object_ptr() };
|
||
vm.set_or_create_prop_value(obj, res_si, resolve);
|
||
vm.set_or_create_prop_value(obj, rej_si, reject);
|
||
NativeResult::Ok(JsValue::undefined())
|
||
}
|
||
|
||
// ── session GC 支撑:状态盒中的 JsValues 作为 Promise 对象边追踪 ──
|
||
|
||
fn promise_state_ref(obj: &JsObject) -> Option<&PromiseState> {
|
||
let ptr = obj.native_data() as *const PromiseState;
|
||
if ptr.is_null() {
|
||
None
|
||
} else {
|
||
// SAFETY: native_data 由 Box::into_raw 分配,生命周期与 Promise 对象一致。
|
||
Some(unsafe { &*ptr })
|
||
}
|
||
}
|
||
|
||
#[expect(clippy::mut_from_ref)]
|
||
fn promise_state_mut(obj: &JsObject) -> Option<&mut PromiseState> {
|
||
let ptr = obj.native_data() as *mut PromiseState;
|
||
if ptr.is_null() {
|
||
None
|
||
} else {
|
||
// SAFETY: 同上,改写发生在 GC 移动/清扫期间,对象仍存活。
|
||
Some(unsafe { &mut *ptr })
|
||
}
|
||
}
|
||
|
||
/// Promise 状态盒内所有对象引用(GC mark 边)。
|
||
pub(crate) fn promise_native_edges(obj: &JsObject) -> Vec<JsValue> {
|
||
let Some(state) = promise_state_ref(obj) else {
|
||
return Vec::new();
|
||
};
|
||
let mut edges = Vec::new();
|
||
let push = |v: JsValue, edges: &mut Vec<JsValue>| {
|
||
if v.is_object() {
|
||
edges.push(v);
|
||
}
|
||
};
|
||
push(state.result, &mut edges);
|
||
push(state.resolve_fn, &mut edges);
|
||
push(state.reject_fn, &mut edges);
|
||
for r in &state.reactions {
|
||
push(r.promise, &mut edges);
|
||
push(r.resolve, &mut edges);
|
||
push(r.reject, &mut edges);
|
||
push(r.handler, &mut edges);
|
||
}
|
||
edges
|
||
}
|
||
|
||
/// 用转发函数重写状态盒中的所有 JsValue(session GC 移动式清扫 / promote 用)。
|
||
pub(crate) fn rewrite_promise_native(obj: &JsObject, mut rewrite: impl FnMut(JsValue) -> JsValue) {
|
||
let Some(state) = promise_state_mut(obj) else {
|
||
return;
|
||
};
|
||
state.result = rewrite(state.result);
|
||
state.resolve_fn = rewrite(state.resolve_fn);
|
||
state.reject_fn = rewrite(state.reject_fn);
|
||
for r in &mut state.reactions {
|
||
r.promise = rewrite(r.promise);
|
||
r.resolve = rewrite(r.resolve);
|
||
r.reject = rewrite(r.reject);
|
||
r.handler = rewrite(r.handler);
|
||
}
|
||
}
|
||
|
||
/// 深拷贝状态盒到新对象(promote / sweep 用):新对象持独立 Box,源盒可安全释放。
|
||
pub(crate) fn clone_promise_native_with_rewrite(
|
||
old: &JsObject, new: &mut JsObject, mut rewrite: impl FnMut(JsValue) -> JsValue,
|
||
) {
|
||
let Some(state) = promise_state_ref(old) else {
|
||
return;
|
||
};
|
||
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(),
|
||
resolve_fn: rewrite(state.resolve_fn),
|
||
reject_fn: rewrite(state.reject_fn),
|
||
already_resolved: state.already_resolved,
|
||
};
|
||
new.set_native_data(Box::into_raw(Box::new(cloned)) as *mut u8);
|
||
}
|
||
|
||
/// 释放 Promise 状态盒(对象被回收时),返回释放字节数。
|
||
pub(crate) fn drop_promise_native(obj: &JsObject) -> u64 {
|
||
if !obj.is_promise_obj() {
|
||
return 0;
|
||
}
|
||
let ptr = obj.native_data() as *mut PromiseState;
|
||
if ptr.is_null() {
|
||
return 0;
|
||
}
|
||
// SAFETY: 指针来自 Box::into_raw,只在对象被回收时释放一次。
|
||
let state = unsafe { Box::from_raw(ptr) };
|
||
std::mem::size_of::<PromiseState>() as u64
|
||
+ state.reactions.capacity() as u64 * std::mem::size_of::<PromiseReaction>() as u64
|
||
}
|
||
|
||
/// 供外部遍历微任务队列(GC mark/rewrite 用)。
|
||
pub(crate) fn for_each_job_value(job: &Microtask, mut f: impl FnMut(JsValue)) {
|
||
match job {
|
||
Microtask::Reaction {
|
||
handler,
|
||
argument,
|
||
resolve,
|
||
reject,
|
||
..
|
||
} => {
|
||
f(*handler);
|
||
f(*argument);
|
||
f(*resolve);
|
||
f(*reject);
|
||
}
|
||
Microtask::Thenable {
|
||
thenable,
|
||
then,
|
||
resolve,
|
||
reject,
|
||
} => {
|
||
f(*thenable);
|
||
f(*then);
|
||
f(*resolve);
|
||
f(*reject);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 供外部改写微任务队列中的 JsValue(session GC sweep 用)。
|
||
pub(crate) fn rewrite_job_values(job: &mut Microtask, mut rewrite: impl FnMut(JsValue) -> JsValue) {
|
||
match job {
|
||
Microtask::Reaction {
|
||
handler,
|
||
argument,
|
||
resolve,
|
||
reject,
|
||
..
|
||
} => {
|
||
*handler = rewrite(*handler);
|
||
*argument = rewrite(*argument);
|
||
*resolve = rewrite(*resolve);
|
||
*reject = rewrite(*reject);
|
||
}
|
||
Microtask::Thenable {
|
||
thenable,
|
||
then,
|
||
resolve,
|
||
reject,
|
||
} => {
|
||
*thenable = rewrite(*thenable);
|
||
*then = rewrite(*then);
|
||
*resolve = rewrite(*resolve);
|
||
*reject = rewrite(*reject);
|
||
}
|
||
}
|
||
}
|