Files
OxideJS-New/crates/oxide_vm/src/promise/mod.rs
T

153 lines
6.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 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 })
}
}