mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
refactor: Promise 结算构造队列拆入 promise 子模块
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
//! Promise 构造与内建安装:`Construct(C, args)` 通用路径(native /
|
||||
//! bytecode 构造器)与 %Promise% 内建对象初始化。
|
||||
//!
|
||||
//! `init_promise_intrinsics` 在 VM 创建与 `full_reset` 后调用:原型继承
|
||||
//! session 的 Object/Function 原型,session 重建后须重挂并重绑 global 槽。
|
||||
|
||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||
use oxide_runtime_api::NativeResult;
|
||||
use oxide_types::object::{JsObject, NativeFnPtr, PropAttributes};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use crate::vm::{FrameArgs, FrameContinuation, Vm};
|
||||
|
||||
use super::{
|
||||
is_constructor_value, promise_catch, promise_finally, promise_static_all, promise_static_all_settled,
|
||||
promise_static_any, promise_static_race, promise_static_reject, promise_static_resolve,
|
||||
promise_static_with_resolvers, promise_then, PromiseState, PromiseStateKind,
|
||||
};
|
||||
|
||||
impl Vm {
|
||||
/// 创建空 Promise 对象(proto = `%Promise.prototype%`),状态盒为 Pending。
|
||||
pub(super) 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,
|
||||
promoted_clone: std::ptr::null_mut(),
|
||||
});
|
||||
obj.set_native_data(Box::into_raw(state) as *mut u8);
|
||||
JsValue::from_js_object(ptr)
|
||||
}
|
||||
|
||||
/// 构造调用(Construct(C, args)):native 构造器值传递调用,bytecode 构造器
|
||||
/// 压构造帧执行(含 derived 构造器 super() 语义),返回值非对象时回退到新对象。
|
||||
pub(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> {
|
||||
// 按构造器自身记录的表代际解析:代际表缺失(已回收)或下标越界与
|
||||
// 原生函数哨兵同口径报 TypeError。
|
||||
let callee_module = match self.callee_module(ctor_obj) {
|
||||
Some(m) => m,
|
||||
None => {
|
||||
return Err(oxide_builtins::error::create_type_error(self, "constructor is not a constructor"));
|
||||
}
|
||||
};
|
||||
if callee_module.is_generator || callee_module.is_async {
|
||||
return Err(oxide_builtins::error::create_type_error(self, "constructor is not a constructor"));
|
||||
}
|
||||
// 先拷出寄存器数,释放对代际表的借用后再进入可变借用区。
|
||||
let callee_reg_count = callee_module.n_registers;
|
||||
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
|
||||
};
|
||||
// 入口已解析代际表:读 n_registers 定保存窗口。
|
||||
let window = self.active_reg_limit.max(callee_reg_count).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 内建对象:`%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 world = self.session.builtin_world();
|
||||
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,
|
||||
world,
|
||||
("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,
|
||||
world,
|
||||
("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),
|
||||
("withResolvers", promise_static_with_resolvers as *const (), 0),
|
||||
);
|
||||
|
||||
// 固定地址后互相接线:proto.constructor ↔ ctor.prototype。
|
||||
Self::swap_intrinsic_proto(&mut self.promise_proto, *proto);
|
||||
Self::swap_intrinsic_proto(&mut self.promise_constructor, *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();
|
||||
}
|
||||
}
|
||||
|
||||
/// `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,
|
||||
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() };
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
//! 微任务队列:FIFO drain 执行与 session GC 的队列值遍历 / 改写。
|
||||
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use crate::vm::Vm;
|
||||
use crate::vm_warn;
|
||||
|
||||
use super::{Microtask, MAX_DRAIN_JOBS};
|
||||
|
||||
impl Vm {
|
||||
/// 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 供外部遍历微任务队列(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,13 @@ 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;
|
||||
use crate::vm::Vm;
|
||||
|
||||
mod constructor;
|
||||
mod jobs;
|
||||
mod settlement;
|
||||
|
||||
pub(crate) use jobs::{for_each_job_value, rewrite_job_values};
|
||||
|
||||
/// Promise 的 settled 状态。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -114,413 +119,6 @@ enum AggregateKind {
|
||||
}
|
||||
|
||||
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,
|
||||
promoted_clone: std::ptr::null_mut(),
|
||||
});
|
||||
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> {
|
||||
// 按构造器自身记录的表代际解析:代际表缺失(已回收)或下标越界与
|
||||
// 原生函数哨兵同口径报 TypeError。
|
||||
let callee_module = match self.callee_module(ctor_obj) {
|
||||
Some(m) => m,
|
||||
None => {
|
||||
return Err(oxide_builtins::error::create_type_error(self, "constructor is not a constructor"));
|
||||
}
|
||||
};
|
||||
if callee_module.is_generator || callee_module.is_async {
|
||||
return Err(oxide_builtins::error::create_type_error(self, "constructor is not a constructor"));
|
||||
}
|
||||
// 先拷出寄存器数,释放对代际表的借用后再进入可变借用区。
|
||||
let callee_reg_count = callee_module.n_registers;
|
||||
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
|
||||
};
|
||||
// 入口已解析代际表:读 n_registers 定保存窗口。
|
||||
let window = self.active_reg_limit.max(callee_reg_count).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,
|
||||
});
|
||||
}
|
||||
// 原件若已晋升出克隆,把结算传导到克隆:克隆上晋升后新挂的反应方随此触发
|
||||
// (顶层 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(())
|
||||
}
|
||||
|
||||
/// 以 `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,
|
||||
});
|
||||
}
|
||||
// 原件若已晋升出克隆,把拒绝传导到克隆(同 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(())
|
||||
}
|
||||
|
||||
/// 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)使用,规范上这些路径由调用方提供能力,
|
||||
@@ -650,177 +248,6 @@ impl Vm {
|
||||
}
|
||||
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 world = self.session.builtin_world();
|
||||
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,
|
||||
world,
|
||||
("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,
|
||||
world,
|
||||
("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),
|
||||
("withResolvers", promise_static_with_resolvers as *const (), 0),
|
||||
);
|
||||
|
||||
// 固定地址后互相接线:proto.constructor ↔ ctor.prototype。
|
||||
Self::swap_intrinsic_proto(&mut self.promise_proto, *proto);
|
||||
Self::swap_intrinsic_proto(&mut self.promise_constructor, *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
|
||||
@@ -846,92 +273,6 @@ pub fn promise_settled_value(obj: &JsObject) -> Option<(bool, JsValue)> {
|
||||
}
|
||||
}
|
||||
|
||||
/// `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,
|
||||
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() };
|
||||
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 {
|
||||
@@ -1768,32 +1109,6 @@ fn aggregate_error_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
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> {
|
||||
@@ -2001,61 +1316,3 @@ pub(crate) fn drop_promise_native(obj: &JsObject) -> u64 {
|
||||
drop(state);
|
||||
bytes
|
||||
}
|
||||
|
||||
/// 供外部遍历微任务队列(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,389 @@
|
||||
//! Promise 能力与结算:能力构造、resolve/reject 闭包构造,
|
||||
//! PromiseResolve / fulfill / reject 结算路径。
|
||||
//!
|
||||
//! 结算单次性:闭包首调置位 `already_resolved`,`state != Pending`
|
||||
//! 最终守卫;结算后反应入微任务队列,并沿 `promoted_clone` 链传导克隆。
|
||||
|
||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||
use oxide_runtime_api::NativeResult;
|
||||
use oxide_types::object::{JsObject, NativeFnPtr};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use crate::native::NativeFn;
|
||||
use crate::vm::Vm;
|
||||
|
||||
use super::{
|
||||
Microtask, PromiseState, PromiseStateKind, CAP_REJECT_PROP, CAP_RESOLVE_PROP, DELEGATED_PROP, PROMISE_PROP,
|
||||
};
|
||||
|
||||
impl Vm {
|
||||
/// 新建 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)`。
|
||||
pub(super) 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)
|
||||
}
|
||||
|
||||
/// 构造携带目标 promise 的 native 闭包(resolve 或 reject 角色)。
|
||||
/// `delegated` 为 true 表示 thenable 委托用的结算代理:绕过 alreadyResolved
|
||||
/// (委托是唯一真正的结算路径,由 then 的 resolve/reject 触发),但 state != Pending
|
||||
/// 仍阻止二次结算。
|
||||
pub(super) 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`)。
|
||||
pub(super) 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` 构造出的实例特征)。
|
||||
pub(super) 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)。
|
||||
pub(super) 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,
|
||||
});
|
||||
}
|
||||
// 原件若已晋升出克隆,把结算传导到克隆:克隆上晋升后新挂的反应方随此触发
|
||||
// (顶层 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(())
|
||||
}
|
||||
|
||||
/// 以 `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,
|
||||
});
|
||||
}
|
||||
// 原件若已晋升出克隆,把拒绝传导到克隆(同 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(())
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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())
|
||||
}
|
||||
|
||||
/// 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())
|
||||
}
|
||||
Reference in New Issue
Block a user