mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 11:11:11 +08:00
153 lines
6.1 KiB
Rust
153 lines
6.1 KiB
Rust
//! Promise 运行时:Promise 状态盒 + resolve/reject 闭包 + 微任务队列。
|
||
//!
|
||
//! Promise 对象把 `PromiseState` 状态盒(Box)挂在 `native_data`;resolve/reject
|
||
//! 是携带目标 promise 的 native 闭包函数(函数对象 prop 存 promise 引用)。
|
||
//! 反应(reaction)与 thenable 委托以 `Microtask` 入队 `Vm::job_queue`,
|
||
//! 由 `drain_microtasks` 在 `run()` 末尾与事件循环每个 turn 边界 FIFO 执行。
|
||
//! 所有盒内 JsValue 由 session GC
|
||
//! 经 Promise 对象边追踪(见 `promise_native_edges` / `drop_promise_native`)。
|
||
|
||
use oxide_types::object::JsObject;
|
||
use oxide_types::value::JsValue;
|
||
|
||
mod aggregate;
|
||
mod constructor;
|
||
mod gc_edges;
|
||
mod jobs;
|
||
mod reactions;
|
||
mod settlement;
|
||
|
||
pub(crate) use gc_edges::{drop_promise_native, promise_native_edges, promise_native_size};
|
||
pub(crate) use jobs::for_each_job_value;
|
||
pub use reactions::promise_settled_value;
|
||
|
||
/// 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__";
|
||
/// finally 处理器上存派生构造器的属性名。
|
||
const FINALLY_CTOR_PROP: &str = "__oxide_finally_ctor__";
|
||
/// finally 直通 thunk 上存透传值/拒绝原因的属性名。
|
||
const FINALLY_THUNK_VALUE_PROP: &str = "__oxide_finally_thunk_value__";
|
||
/// 能力 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 的 values,any 的 errors)。
|
||
const AGG_VALUES_PROP: &str = "__oxide_agg_values__";
|
||
/// 记录对象上存结果键平行数组(keyed 族:JS 键值序列,与 values 按下标对齐)。
|
||
const AGG_KEYS_PROP: &str = "__oxide_agg_keys__";
|
||
/// 记录对象上存能力 resolve 闭包。
|
||
const AGG_RESOLVE_PROP: &str = "__oxide_agg_resolve__";
|
||
/// 记录对象上存能力 reject 闭包。
|
||
const AGG_REJECT_PROP: &str = "__oxide_agg_reject__";
|
||
|
||
// ── Promise.try 包装闭包(W)状态属性 ──
|
||
/// W 上存用户 executor 函数。
|
||
const TRY_EXECUTOR_PROP: &str = "__oxide_try_executor__";
|
||
/// W 上存转发实参数组(resolve/reject 经调用实参传入,不落属性)。
|
||
const TRY_ARGS_PROP: &str = "__oxide_try_args__";
|
||
|
||
/// 聚合静态方法的语义模式(决定元素处理器与结算方式)。
|
||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||
enum AggregateKind {
|
||
All,
|
||
Race,
|
||
AllSettled,
|
||
Any,
|
||
}
|
||
|
||
/// IsConstructor 近似判定:可调用、非 arrow,且 native 函数须带构造器 tag
|
||
/// (与 `construct_ctor` 的校验一致);bound 包装恒接受(target 可构造性在
|
||
/// `dispatch_new_bound` 入口复核)。
|
||
fn is_constructor_value(c: JsValue) -> bool {
|
||
if !c.is_object() {
|
||
return false;
|
||
}
|
||
// SAFETY: is_object 保证指针非空且指向存活 arena 对象,此处只读函数标志并立即消费。
|
||
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
|
||
&& c_obj.type_tag != JsObject::OBJ_TYPE_BOUND)
|
||
}
|
||
|
||
// ── 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 })
|
||
}
|
||
}
|