mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: await using 释放挂起跨微任务续行并合并 SuppressedError
This commit is contained in:
@@ -13,7 +13,8 @@ use oxide_runtime_api::{to_boolean, NativeResult};
|
||||
use oxide_types::object::{Cell, JsObject, NativeFnPtr, PropAttributes};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use crate::vm::{Completion, Vm};
|
||||
use crate::vm::{Completion, DisposeResumeKind, InlineSyncState, Vm};
|
||||
use crate::vm_dispatch_misc::DisposePhase;
|
||||
|
||||
/// 异步函数执行阶段。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -66,6 +67,8 @@ pub(crate) const ASYNC_CTX_PROP: &str = "__oxide_async_ctx__";
|
||||
const ASYNC_REJECT_PROP: &str = "__oxide_async_reject__";
|
||||
/// 逃出关闭结算闭包上存 return() promise 的属性名(陈旧防御校验用)。
|
||||
pub(crate) const ASYNC_ESCAPE_PROMISE_PROP: &str = "__oxide_async_escape_promise__";
|
||||
/// 异步释放结算闭包上存释放方法 promise 的属性名(陈旧防御校验用)。
|
||||
pub(crate) const ASYNC_DISPOSE_PROMISE_PROP: &str = "__oxide_async_dispose_promise__";
|
||||
|
||||
impl Vm {
|
||||
/// 调用异步函数返回的 capability promise:创建上下文对象 + 状态盒,立即压帧
|
||||
@@ -380,6 +383,29 @@ impl Vm {
|
||||
JsValue::from_js_object(ptr)
|
||||
}
|
||||
|
||||
/// 构造异步释放结算闭包:携带目标异步上下文对象与释放方法 promise,区分
|
||||
/// fulfill/reject 角色。
|
||||
pub(crate) fn make_async_dispose_resume_fn(
|
||||
&mut self, ctx: JsValue, promise: JsValue, reject_role: bool,
|
||||
) -> JsValue {
|
||||
let fn_proto = self.realm.session.borrow().builtin_world().fn_proto_val();
|
||||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||||
func.set_function(true);
|
||||
// SAFETY: async_dispose_resume_closure 是 NativeFn 函数项。
|
||||
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(async_dispose_resume_closure as *const ()) }));
|
||||
func.set_native_arg_count(1);
|
||||
let ptr = self.alloc_object(func);
|
||||
let obj = unsafe { &mut *ptr };
|
||||
let ctx_si = self.kernel_core.perm_interner().intern(ASYNC_CTX_PROP).0;
|
||||
self.set_or_create_prop_value(obj, ctx_si, ctx);
|
||||
let role_si = self.kernel_core.perm_interner().intern(ASYNC_REJECT_PROP).0;
|
||||
self.set_or_create_prop_value(obj, role_si, JsValue::bool(reject_role));
|
||||
let promise_si = self.kernel_core.perm_interner().intern(ASYNC_DISPOSE_PROMISE_PROP).0;
|
||||
self.set_or_create_prop_value(obj, promise_si, promise);
|
||||
self.add_fn_name_length(obj, "", 1);
|
||||
JsValue::from_js_object(ptr)
|
||||
}
|
||||
|
||||
/// 把当前 VM 执行状态(异步 body 刚在嵌套 dispatch 中让出)快照进状态盒。
|
||||
///
|
||||
/// 异步帧弹出存 `suspended.frame`,其余栈段整段搬入(嵌套循环期间这些栈
|
||||
@@ -544,6 +570,192 @@ impl Vm {
|
||||
self.restore_inline_state(saved);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 续 dispatch 并结算:运行 body 到下一个 AWAIT/RETURN/异常,挂起则快照新状态,
|
||||
/// 完成/异常则结算 capability。恢复调用方状态。
|
||||
fn dispatch_and_finish_async(
|
||||
&mut self, state_ptr: *mut AsyncState, saved: Box<InlineSyncState>,
|
||||
prev_ctx: Option<JsValue>, prev_dispatch: bool, prev_gen_ctx: Option<JsValue>,
|
||||
prev_gen_dispatch: bool,
|
||||
) -> Result<(), String> {
|
||||
let result = self.dispatch();
|
||||
if std::mem::take(&mut self.async_suspended) {
|
||||
self.snapshot_async(unsafe { &mut *state_ptr })?;
|
||||
self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch);
|
||||
self.native_call_depth -= 1;
|
||||
self.restore_inline_state(saved);
|
||||
return Ok(());
|
||||
}
|
||||
match result {
|
||||
Ok(value) => self.finish_async(state_ptr, Ok(value))?,
|
||||
Err(e) => {
|
||||
let exc = self
|
||||
.last_uncaught_value
|
||||
.take()
|
||||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e));
|
||||
self.finish_async(state_ptr, Err(exc))?;
|
||||
}
|
||||
}
|
||||
self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch);
|
||||
self.native_call_depth -= 1;
|
||||
self.restore_inline_state(saved);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 恢复 `await using` 释放挂起的异步函数:释放方法 promise 结算后继续释放剩余
|
||||
/// 条目并执行完成。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 陈旧防御:状态盒 `pending_async_dispose.dispose_promise` 须与本闭包 promise
|
||||
/// 匹配,不匹配则不处理(防同一 promise 被双结算)。
|
||||
/// 2. 把挂起快照灌回 VM,取出水位 / 合并错误 / 恢复类别并清除
|
||||
/// `pending_async_dispose`。
|
||||
/// 3. 拒绝角色:拒绝值合并进合并错误。
|
||||
/// 4. 从水位续释放循环(复用批量释放核心);再挂起则重新登记 + 快照 + 返回。
|
||||
/// 5. 循环后执行类别:`Pop` 有合并错误则展开否则续行;`Unwind` 重压 handler 再入
|
||||
/// unwind;`Escape` 有合并错误则丢弃完成值展开否则执行完成。
|
||||
/// 6. 再挂起则快照新状态;完成 / 异常则结算 capability。恢复调用方状态。
|
||||
pub(crate) fn resume_async_dispose(
|
||||
&mut self, ctx: JsValue, promise: JsValue, is_reject: bool, value: JsValue,
|
||||
) -> Result<(), String> {
|
||||
let state_ptr = self.async_state_ptr(ctx);
|
||||
let saved = self.save_inline_state(256);
|
||||
// 清上一轮残留的挂起信号(防陈旧信号误消费)。
|
||||
self.async_suspended = false;
|
||||
let prev_ctx = self.async_context.take();
|
||||
let prev_dispatch = self.async_dispatch;
|
||||
let prev_gen_ctx = self.async_gen_context.take();
|
||||
let prev_gen_dispatch = self.async_gen_dispatch;
|
||||
self.async_dispatch = true;
|
||||
self.async_gen_dispatch = false;
|
||||
self.async_context = Some(ctx);
|
||||
self.native_call_depth += 1;
|
||||
|
||||
{
|
||||
let state = unsafe { &mut *state_ptr };
|
||||
// 陈旧防御:dispose_promise 须匹配,陈旧闭包不处理。
|
||||
let is_stale = !matches!(
|
||||
state.suspended.pending_async_dispose.as_ref(),
|
||||
Some(p) if p.dispose_promise == promise
|
||||
);
|
||||
if is_stale {
|
||||
self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch);
|
||||
self.native_call_depth -= 1;
|
||||
self.restore_inline_state(saved);
|
||||
return Ok(());
|
||||
}
|
||||
let restore_res = state.suspended.restore_into(self, state.callee);
|
||||
if restore_res.is_err() {
|
||||
self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch);
|
||||
self.native_call_depth -= 1;
|
||||
self.restore_inline_state(saved);
|
||||
return Err("async function suspended across runs is no longer valid".into());
|
||||
}
|
||||
state.phase = AsyncPhase::Running;
|
||||
}
|
||||
|
||||
// 取出水位 / 合并错误 / 恢复类别并清除 pending_async_dispose。
|
||||
let (mark, completion, kind) = match self.pending_async_dispose.take() {
|
||||
Some(p) => (p.mark, p.completion, p.kind),
|
||||
// 陈旧防御已早退,正常路径此处必为 Some;防御性兜底。
|
||||
None => {
|
||||
self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch);
|
||||
self.native_call_depth -= 1;
|
||||
self.restore_inline_state(saved);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// 拒绝角色:拒绝值合并进合并错误。
|
||||
let completion = if is_reject {
|
||||
oxide_builtins::disposable_stack::merge_dispose_error(self, completion, value)
|
||||
} else {
|
||||
completion
|
||||
};
|
||||
|
||||
// 从水位续释放循环(复用批量释放核心);再挂起则重新登记 + 快照 + 返回。
|
||||
if matches!(self.dispose_above_core(mark, kind, completion)?, DisposePhase::Suspended) {
|
||||
self.snapshot_async(unsafe { &mut *state_ptr })?;
|
||||
self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch);
|
||||
self.native_call_depth -= 1;
|
||||
self.restore_inline_state(saved);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 循环后执行类别。
|
||||
match kind {
|
||||
DisposeResumeKind::Pop => {
|
||||
// 有合并错误则展开(无处理器则 reject capability),否则续行。
|
||||
if self.exception_value.is_some() && self.unwind().is_err() {
|
||||
let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined());
|
||||
self.finish_async(state_ptr, Err(exc))?;
|
||||
self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch);
|
||||
self.native_call_depth -= 1;
|
||||
self.restore_inline_state(saved);
|
||||
return Ok(());
|
||||
}
|
||||
self.dispatch_and_finish_async(
|
||||
state_ptr, saved, prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch,
|
||||
)
|
||||
}
|
||||
DisposeResumeKind::Unwind(handler) => {
|
||||
// 重压 handler 再入 unwind(handler 已弹出,不重压则 catch/finally 丢失)。
|
||||
if let Some(h) = handler {
|
||||
self.try_stack.push(h);
|
||||
}
|
||||
if self.unwind().is_err() {
|
||||
let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined());
|
||||
self.finish_async(state_ptr, Err(exc))?;
|
||||
self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch);
|
||||
self.native_call_depth -= 1;
|
||||
self.restore_inline_state(saved);
|
||||
return Ok(());
|
||||
}
|
||||
self.dispatch_and_finish_async(
|
||||
state_ptr, saved, prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch,
|
||||
)
|
||||
}
|
||||
DisposeResumeKind::Escape(completion_val) => {
|
||||
if self.exception_value.is_some() {
|
||||
// 有合并错误:丢弃完成值,展开到外围处理器(无处理器则 reject)。
|
||||
if self.unwind().is_err() {
|
||||
let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined());
|
||||
self.finish_async(state_ptr, Err(exc))?;
|
||||
self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch);
|
||||
self.native_call_depth -= 1;
|
||||
self.restore_inline_state(saved);
|
||||
return Ok(());
|
||||
}
|
||||
self.dispatch_and_finish_async(
|
||||
state_ptr, saved, prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch,
|
||||
)
|
||||
} else {
|
||||
// 无合并错误:执行完成。
|
||||
match completion_val {
|
||||
Completion::Return { value: ret_val, .. } => {
|
||||
let result = self.do_return(ret_val)?;
|
||||
if let Some(result) = result {
|
||||
self.finish_async(state_ptr, Ok(result))?;
|
||||
self.restore_async_flags(prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch);
|
||||
self.native_call_depth -= 1;
|
||||
self.restore_inline_state(saved);
|
||||
return Ok(());
|
||||
}
|
||||
self.dispatch_and_finish_async(
|
||||
state_ptr, saved, prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch,
|
||||
)
|
||||
}
|
||||
Completion::Break { target_pc, .. } | Completion::Continue { target_pc, .. } => {
|
||||
self.pc = target_pc;
|
||||
self.dispatch_and_finish_async(
|
||||
state_ptr, saved, prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// await 恢复闭包:读自身 prop 的异步上下文与角色,恢复异步帧继续执行。
|
||||
@@ -590,6 +802,27 @@ fn async_escape_close_closure(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
}
|
||||
|
||||
/// 异步释放结算闭包:读自身 prop 的异步上下文、释放方法 promise 与角色,恢复挂起
|
||||
/// 帧并继续释放剩余条目、执行完成。
|
||||
fn async_dispose_resume_closure(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, "dispose resume handler is invalid"));
|
||||
}
|
||||
let callee_obj = unsafe { &*callee.as_js_object_ptr() };
|
||||
let ctx_si = vm.kernel_core.perm_interner().intern(ASYNC_CTX_PROP).0;
|
||||
let ctx = vm.resolve_property(callee_obj, ctx_si).unwrap_or(JsValue::undefined());
|
||||
let role_si = vm.kernel_core.perm_interner().intern(ASYNC_REJECT_PROP).0;
|
||||
let is_reject = vm.resolve_property(callee_obj, role_si).is_some_and(to_boolean);
|
||||
let promise_si = vm.kernel_core.perm_interner().intern(ASYNC_DISPOSE_PROMISE_PROP).0;
|
||||
let promise = vm.resolve_property(callee_obj, promise_si).unwrap_or(JsValue::undefined());
|
||||
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
match vm.resume_async_dispose(ctx, promise, is_reject, value) {
|
||||
Ok(()) => NativeResult::Ok(JsValue::undefined()),
|
||||
Err(e) => NativeResult::Err(oxide_builtins::error::create_from_text(vm, &e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// 初始化/重建异步函数内建对象:`%AsyncFunction.prototype%`(+ 占位 `%AsyncFunction%`)。
|
||||
///
|
||||
/// 异步函数对象的 [[Prototype]] 指向此原型(`f.constructor.name` → "AsyncFunction")。
|
||||
|
||||
@@ -21,7 +21,8 @@ use oxide_types::object::{Cell, JsObject, NativeFnPtr, PropAttributes};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use crate::generator::{DelegateOutcome, GeneratorResumeMode};
|
||||
use crate::vm::{Completion, Vm};
|
||||
use crate::vm::{Completion, DisposeResumeKind, Vm};
|
||||
use crate::vm_dispatch_misc::DisposePhase;
|
||||
|
||||
/// 异步生成器执行阶段。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -93,6 +94,8 @@ const AG_YIELD_PROMISE_PROP: &str = "__oxide_async_gen_yield_promise__";
|
||||
const AG_YIELD_RAW_PROP: &str = "__oxide_async_gen_yield_raw__";
|
||||
/// 委托步进取续闭包上存协议步的属性名。
|
||||
const AG_STEP_PROP: &str = "__oxide_async_gen_delegate_step__";
|
||||
/// 异步释放结算闭包上存释放方法 promise 的属性名(陈旧防御校验用)。
|
||||
const AG_DISPOSE_PROMISE_PROP: &str = "__oxide_async_gen_dispose_promise__";
|
||||
|
||||
impl Vm {
|
||||
/// 调用异步生成器函数返回的迭代器对象:创建异步生成器实例、挂状态并执行
|
||||
@@ -793,6 +796,29 @@ impl Vm {
|
||||
JsValue::from_js_object(ptr)
|
||||
}
|
||||
|
||||
/// 构造异步释放结算闭包(异步生成器):携带目标异步生成器上下文对象与
|
||||
/// 释放方法 promise,区分 fulfill/reject 角色。
|
||||
pub(crate) fn make_async_gen_dispose_resume_fn(
|
||||
&mut self, ctx: JsValue, promise: JsValue, reject_role: bool,
|
||||
) -> JsValue {
|
||||
let fn_proto = self.realm.session.borrow().builtin_world().fn_proto_val();
|
||||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||||
func.set_function(true);
|
||||
// SAFETY: async_gen_dispose_closure 是 NativeFn 函数项。
|
||||
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(async_gen_dispose_closure as *const ()) }));
|
||||
func.set_native_arg_count(1);
|
||||
let ptr = self.alloc_object(func);
|
||||
let obj = unsafe { &mut *ptr };
|
||||
let ctx_si = self.kernel_core.perm_interner().intern(crate::async_func::ASYNC_CTX_PROP).0;
|
||||
self.set_or_create_prop_value(obj, ctx_si, ctx);
|
||||
let role_si = self.kernel_core.perm_interner().intern(AG_REJECT_PROP).0;
|
||||
self.set_or_create_prop_value(obj, role_si, JsValue::bool(reject_role));
|
||||
let promise_si = self.kernel_core.perm_interner().intern(AG_DISPOSE_PROMISE_PROP).0;
|
||||
self.set_or_create_prop_value(obj, promise_si, promise);
|
||||
self.add_fn_name_length(obj, "", 1);
|
||||
JsValue::from_js_object(ptr)
|
||||
}
|
||||
|
||||
/// 恢复逃出 for-await-of 的异步生成器:return() 的 promise 结算后继续关闭剩余
|
||||
/// 条目并执行完成。
|
||||
///
|
||||
@@ -916,6 +942,151 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 恢复 `await using` 释放挂起的异步生成器:释放方法 promise 结算后继续释放
|
||||
/// 剩余条目并执行完成。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 陈旧防御:状态盒 `pending_async_dispose.dispose_promise` 须与本闭包 promise
|
||||
/// 匹配,不匹配则不处理(防同一 promise 被双结算)。
|
||||
/// 2. 把挂起快照灌回 VM,取出水位 / 合并错误 / 恢复类别并清除
|
||||
/// `pending_async_dispose`。
|
||||
/// 3. 拒绝角色:拒绝值合并进合并错误。
|
||||
/// 4. 从水位续释放循环(复用批量释放核心);再挂起则重新登记 + 快照 + 返回。
|
||||
/// 5. 循环后执行类别:`Pop` 有合并错误则展开否则续行;`Unwind` 重压 handler 再入
|
||||
/// unwind;`Escape` 有合并错误则丢弃完成值展开否则执行完成。
|
||||
/// 6. 再挂起则快照新状态;完成 / 异常则结算当前请求。恢复调用方状态。
|
||||
pub(crate) fn resume_async_gen_dispose(
|
||||
&mut self, ctx: JsValue, promise: JsValue, is_reject: bool, value: JsValue,
|
||||
) -> Result<(), String> {
|
||||
let state_ptr = self.async_gen_state_ptr(ctx);
|
||||
let saved = self.save_inline_state(256);
|
||||
// 清上一轮残留的挂起信号(防陈旧信号误消费)。
|
||||
self.generator_suspended = None;
|
||||
self.async_gen_suspended = false;
|
||||
let prev_ctx = self.async_context.take();
|
||||
let prev_gd = self.generator_dispatch;
|
||||
let prev_ad = self.async_dispatch;
|
||||
let prev_gen_ctx = self.async_gen_context.take();
|
||||
let prev_agd = self.async_gen_dispatch;
|
||||
self.generator_dispatch = true;
|
||||
self.async_dispatch = true;
|
||||
self.async_gen_dispatch = true;
|
||||
self.async_context = Some(ctx);
|
||||
self.async_gen_context = Some(ctx);
|
||||
self.native_call_depth += 1;
|
||||
|
||||
{
|
||||
let state = unsafe { &mut *state_ptr };
|
||||
// 陈旧防御:dispose_promise 须匹配,陈旧闭包不处理。
|
||||
let is_stale = !matches!(
|
||||
state.suspended.pending_async_dispose.as_ref(),
|
||||
Some(p) if p.dispose_promise == promise
|
||||
);
|
||||
if is_stale {
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
self.restore_inline_state(saved);
|
||||
return Ok(());
|
||||
}
|
||||
let restore_res = state.suspended.restore_into(self, state.callee);
|
||||
if restore_res.is_err() {
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
self.restore_inline_state(saved);
|
||||
return Err("async generator suspended across runs is no longer valid".into());
|
||||
}
|
||||
state.phase = AsyncGenPhase::Running;
|
||||
}
|
||||
|
||||
// 取出水位 / 合并错误 / 恢复类别并清除 pending_async_dispose。
|
||||
let (mark, completion, kind) = match self.pending_async_dispose.take() {
|
||||
Some(p) => (p.mark, p.completion, p.kind),
|
||||
// 陈旧防御已早退,正常路径此处必为 Some;防御性兜底。
|
||||
None => {
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
self.restore_inline_state(saved);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// 拒绝角色:拒绝值合并进合并错误。
|
||||
let completion = if is_reject {
|
||||
oxide_builtins::disposable_stack::merge_dispose_error(self, completion, value)
|
||||
} else {
|
||||
completion
|
||||
};
|
||||
|
||||
// 从水位续释放循环(复用批量释放核心);再挂起则重新登记 + 快照 + 返回。
|
||||
if matches!(self.dispose_above_core(mark, kind, completion)?, DisposePhase::Suspended) {
|
||||
unsafe { (*state_ptr).phase = AsyncGenPhase::AwaitSuspended };
|
||||
self.snapshot_async_generator(state_ptr)?;
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
self.restore_inline_state(saved);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 循环后执行类别。
|
||||
match kind {
|
||||
DisposeResumeKind::Pop => {
|
||||
// 有合并错误则展开(无处理器则 reject 当前请求),否则续行。
|
||||
if self.exception_value.is_some() && self.unwind().is_err() {
|
||||
let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined());
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
return self.finish_async_gen_exc(state_ptr, saved, ctx, exc);
|
||||
}
|
||||
let result = self.dispatch();
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
self.post_dispatch_async_gen(state_ptr, saved, ctx, result)
|
||||
}
|
||||
DisposeResumeKind::Unwind(handler) => {
|
||||
// 重压 handler 再入 unwind(handler 已弹出,不重压则 catch/finally 丢失)。
|
||||
if let Some(h) = handler {
|
||||
self.try_stack.push(h);
|
||||
}
|
||||
if self.unwind().is_err() {
|
||||
let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined());
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
return self.finish_async_gen_exc(state_ptr, saved, ctx, exc);
|
||||
}
|
||||
let result = self.dispatch();
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
self.post_dispatch_async_gen(state_ptr, saved, ctx, result)
|
||||
}
|
||||
DisposeResumeKind::Escape(completion_val) => {
|
||||
if self.exception_value.is_some() {
|
||||
// 有合并错误:丢弃完成值,展开到外围处理器(无处理器则 reject)。
|
||||
if self.unwind().is_err() {
|
||||
let exc = self.last_uncaught_value.take().unwrap_or(JsValue::undefined());
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
return self.finish_async_gen_exc(state_ptr, saved, ctx, exc);
|
||||
}
|
||||
let result = self.dispatch();
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
self.post_dispatch_async_gen(state_ptr, saved, ctx, result)
|
||||
} else {
|
||||
// 无合并错误:执行完成。
|
||||
match completion_val {
|
||||
Completion::Return { value: ret_val, .. } => {
|
||||
let result = self.do_return(ret_val)?;
|
||||
if let Some(result) = result {
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
return self.finish_async_gen_ok(state_ptr, saved, ctx, result);
|
||||
}
|
||||
// 嵌套帧未弹空:续 dispatch。
|
||||
let result = self.dispatch();
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
self.post_dispatch_async_gen(state_ptr, saved, ctx, result)
|
||||
}
|
||||
Completion::Break { target_pc, .. } | Completion::Continue { target_pc, .. } => {
|
||||
self.pc = target_pc;
|
||||
let result = self.dispatch();
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
self.post_dispatch_async_gen(state_ptr, saved, ctx, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// await 恢复闭包:读自身 prop 的异步生成器上下文与角色,恢复异步生成器继续执行。
|
||||
@@ -1243,6 +1414,29 @@ fn async_gen_escape_closure(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
}
|
||||
|
||||
/// 异步释放结算闭包(异步生成器):读自身 prop 的异步生成器上下文、释放方法
|
||||
/// promise 与角色,恢复挂起帧并继续释放剩余条目、执行完成。
|
||||
fn async_gen_dispose_closure(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, "dispose resume handler is invalid"));
|
||||
}
|
||||
let callee_obj = unsafe { &*callee.as_js_object_ptr() };
|
||||
let ctx_si = vm.kernel_core.perm_interner().intern(crate::async_func::ASYNC_CTX_PROP).0;
|
||||
let ctx = vm.resolve_property(callee_obj, ctx_si).unwrap_or(JsValue::undefined());
|
||||
let role_si = vm.kernel_core.perm_interner().intern(AG_REJECT_PROP).0;
|
||||
let is_reject = vm
|
||||
.resolve_property(callee_obj, role_si)
|
||||
.is_some_and(oxide_runtime_api::to_boolean);
|
||||
let promise_si = vm.kernel_core.perm_interner().intern(AG_DISPOSE_PROMISE_PROP).0;
|
||||
let promise = vm.resolve_property(callee_obj, promise_si).unwrap_or(JsValue::undefined());
|
||||
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
match vm.resume_async_gen_dispose(ctx, promise, is_reject, value) {
|
||||
Ok(()) => NativeResult::Ok(JsValue::undefined()),
|
||||
Err(e) => NativeResult::Err(oxide_builtins::error::create_from_text(vm, &e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// 委托结算值读取:done 与 value 的 getter 抛错经 `last_uncaught_value` 取原值。
|
||||
enum DelegateResult {
|
||||
/// 结算值读取成功(done 标志与委托值)。
|
||||
|
||||
@@ -11,7 +11,7 @@ use oxide_bytecode::opcode;
|
||||
use oxide_types::object::Cell;
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use crate::vm::{CallFrame, Completion, ForInIter, PendingAsyncEscape, TryHandler, Vm};
|
||||
use crate::vm::{CallFrame, Completion, ForInIter, PendingAsyncDispose, PendingAsyncEscape, TryHandler, Vm};
|
||||
use crate::vm_state::ForOfEntry;
|
||||
|
||||
/// 挂起执行上下文快照(三份状态结构体共享的执行核心)。
|
||||
@@ -42,6 +42,8 @@ pub(crate) struct SuspendedFrame {
|
||||
pub pending_completion: Option<Completion>,
|
||||
/// 逃出 for-await-of 的异步关闭在途状态(随挂起快照跨微任务存活)。
|
||||
pub pending_async_escape: Option<PendingAsyncEscape>,
|
||||
/// `await using` 资源释放的异步挂起在途状态(随挂起快照跨微任务存活)。
|
||||
pub pending_async_dispose: Option<PendingAsyncDispose>,
|
||||
}
|
||||
|
||||
impl SuspendedFrame {
|
||||
@@ -69,6 +71,7 @@ impl SuspendedFrame {
|
||||
pending_error_kind: None,
|
||||
pending_completion: None,
|
||||
pending_async_escape: None,
|
||||
pending_async_dispose: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +112,7 @@ impl SuspendedFrame {
|
||||
self.pending_error_kind = vm.pending_error_kind.take();
|
||||
self.pending_completion = vm.pending_completion.take();
|
||||
self.pending_async_escape = std::mem::take(&mut vm.pending_async_escape);
|
||||
self.pending_async_dispose = std::mem::take(&mut vm.pending_async_dispose);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -173,6 +177,7 @@ impl SuspendedFrame {
|
||||
vm.pending_error_kind = self.pending_error_kind.take();
|
||||
vm.pending_completion = self.pending_completion.take();
|
||||
vm.pending_async_escape = std::mem::take(&mut self.pending_async_escape);
|
||||
vm.pending_async_dispose = std::mem::take(&mut self.pending_async_dispose);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -231,6 +236,15 @@ impl SuspendedFrame {
|
||||
f(v);
|
||||
}
|
||||
}
|
||||
if let Some(pend) = &self.pending_async_dispose {
|
||||
f(pend.dispose_promise);
|
||||
if let Some(v) = pend.completion {
|
||||
f(v);
|
||||
}
|
||||
if let crate::vm::DisposeResumeKind::Escape(Completion::Return { value, .. }) = pend.kind {
|
||||
f(value);
|
||||
}
|
||||
}
|
||||
for iter in &self.for_in_iters {
|
||||
if iter.is_null() {
|
||||
continue;
|
||||
|
||||
@@ -118,6 +118,14 @@ impl Vm {
|
||||
}
|
||||
loop {
|
||||
steps += 1;
|
||||
// 异步释放挂起:unwind 经 dispose_above 挂起时须让内嵌 dispatch 返回
|
||||
// (挂起信号由 register_dispose_suspend 置位,此处统一消费,覆盖 THROW
|
||||
// 与各错误处理器路径;AWAIT/BREAK/CONTINUE/RETURN/DISPOSE_POP 各臂已
|
||||
// 就地返回,此处为兜底)。
|
||||
if self.async_suspended || self.async_gen_suspended {
|
||||
self.profiling.set_instruction_count(steps);
|
||||
return Ok(JsValue::undefined());
|
||||
}
|
||||
// 执行期 GC 安全点:仅在顶层 dispatch(native_call_depth == 0)
|
||||
// 的指令边界触发——嵌套 dispatch(builtin 经 call_function_sync 重入
|
||||
// 执行 JS 回调、generator/async 恢复)期间,调用方寄存器窗口副本存于
|
||||
@@ -294,6 +302,12 @@ impl Vm {
|
||||
}
|
||||
OpCode::DISPOSE_POP => {
|
||||
self.dispatch_dispose_pop()?;
|
||||
// `await using` 释放的异步挂起:挂起时须像 AWAIT 一样让内嵌
|
||||
// dispatch 返回,由恢复方快照状态。
|
||||
if self.async_suspended || self.async_gen_suspended {
|
||||
self.profiling.set_instruction_count(steps);
|
||||
return Ok(JsValue::undefined());
|
||||
}
|
||||
}
|
||||
OpCode::CELL_GET => {
|
||||
self.dispatch_cell_get(rd, a, b)?;
|
||||
|
||||
@@ -8,7 +8,7 @@ use super::frames::Completion;
|
||||
use super::Vm;
|
||||
use crate::session_gc::SessionGc;
|
||||
|
||||
/// GC 根组来源:`for_each_value` 枚举的 26 个根组,变体顺序与根清单
|
||||
/// GC 根组来源:`for_each_value` 枚举的 27 个根组,变体顺序与根清单
|
||||
/// 的枚举顺序一致。
|
||||
///
|
||||
/// 变体下标是逐组计数数组(`SessionGc::root_counts`)的下标;`COUNT` 与
|
||||
@@ -31,6 +31,7 @@ pub(crate) enum RootGroup {
|
||||
AsyncContext,
|
||||
AsyncGenContext,
|
||||
PendingAsyncEscape,
|
||||
PendingAsyncDispose,
|
||||
InlineCallee,
|
||||
TemplateObjects,
|
||||
NumberToStringCache,
|
||||
@@ -45,7 +46,7 @@ pub(crate) enum RootGroup {
|
||||
|
||||
impl RootGroup {
|
||||
/// 根组总数(与变体数同源,绑定逐组计数数组的长度)。
|
||||
pub const COUNT: usize = 26;
|
||||
pub const COUNT: usize = 27;
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
@@ -53,7 +54,7 @@ impl Vm {
|
||||
/// 覆盖执行核心的全部 JsValue 持有点:regs/帧/各栈段/cell/在途异常与完成/
|
||||
/// 挂起信号/迭代器/微任务/global/Worker 对象注册表。
|
||||
///
|
||||
/// 闭包接收根组来源(`RootGroup`)与根值:组是枚举顺序中的 26 根组之一,
|
||||
/// 闭包接收根组来源(`RootGroup`)与根值:组是枚举顺序中的 27 根组之一,
|
||||
/// 调用方按组计数(如 `SessionGc` 的逐组计数)。
|
||||
pub(crate) fn for_each_value(&self, mut f: impl FnMut(RootGroup, JsValue)) {
|
||||
for value in &self.regs {
|
||||
@@ -121,6 +122,16 @@ impl Vm {
|
||||
f(RootGroup::PendingAsyncEscape, v);
|
||||
}
|
||||
}
|
||||
// 在途异步释放的 promise/合并错误/完成值都是 GC 根。
|
||||
if let Some(pend) = &self.pending_async_dispose {
|
||||
f(RootGroup::PendingAsyncDispose, pend.dispose_promise);
|
||||
if let Some(v) = pend.completion {
|
||||
f(RootGroup::PendingAsyncDispose, v);
|
||||
}
|
||||
if let super::DisposeResumeKind::Escape(Completion::Return { value, .. }) = pend.kind {
|
||||
f(RootGroup::PendingAsyncDispose, value);
|
||||
}
|
||||
}
|
||||
f(RootGroup::InlineCallee, self.inline_callee.unwrap_or(JsValue::undefined()));
|
||||
// 标签模板对象缓存:命中的模板对象是 GC 根(未根 → sweep 搬移/回收悬垂)。
|
||||
for &cached in self.template_objects.values() {
|
||||
|
||||
@@ -159,6 +159,31 @@ pub(crate) struct PendingAsyncEscape {
|
||||
pub(crate) remaining: Vec<JsValue>,
|
||||
}
|
||||
|
||||
/// `await using` 资源释放的异步挂起在途状态:释放方法的 promise 挂起等待结算,
|
||||
/// 结算闭包(微任务)恢复挂起帧后继续释放剩余条目并执行完成。
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PendingAsyncDispose {
|
||||
/// 正在等待的释放方法 promise(结算闭包陈旧防御校验用)。
|
||||
pub(crate) dispose_promise: JsValue,
|
||||
/// 作用域水位:恢复后继续释放水位以上条目(LIFO)。
|
||||
pub(crate) mark: usize,
|
||||
/// 在途合并错误(SuppressedError 链跨挂起累积)。
|
||||
pub(crate) completion: Option<JsValue>,
|
||||
/// 释放循环结束后的恢复动作类别。
|
||||
pub(crate) kind: DisposeResumeKind,
|
||||
}
|
||||
|
||||
/// 释放循环结束后的恢复动作类别(三穿越点)。
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) enum DisposeResumeKind {
|
||||
/// 作用域出口正常完成:有合并错误则展开,否则续行。
|
||||
Pop,
|
||||
/// 异常穿越:handler 已弹出,恢复时重压后再入 unwind。
|
||||
Unwind(Option<TryHandler>),
|
||||
/// return/break/continue 穿越:有合并错误则丢弃完成值并展开,否则执行完成。
|
||||
Escape(Completion),
|
||||
}
|
||||
|
||||
/// 基于寄存器的 JS 虚拟机:持有执行状态、寄存器文件、调用栈与 session 内存。
|
||||
///
|
||||
/// 执行入口为 [`Vm::run`](见 `vm_runtime` 模块);内存模型为统一入口分配 +
|
||||
@@ -268,6 +293,9 @@ pub struct Vm {
|
||||
/// 逃出 for-await-of 的异步关闭在途状态:return() 的 promise 挂起等待结算,
|
||||
/// 结算闭包(微任务)恢复挂起帧后继续关闭剩余条目并执行完成。
|
||||
pub(crate) pending_async_escape: Option<PendingAsyncEscape>,
|
||||
/// `await using` 资源释放的异步挂起在途状态:释放方法的 promise 挂起等待
|
||||
/// 结算,结算闭包(微任务)恢复挂起帧后继续释放剩余条目并执行完成。
|
||||
pub(crate) pending_async_dispose: Option<PendingAsyncDispose>,
|
||||
pub(crate) root_reg_limit: u8,
|
||||
pub(crate) active_reg_limit: u8,
|
||||
pub(crate) native_call_depth: usize,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::vm::{Completion, FrameArgs, FrameContinuation, PendingAsyncEscape, TryHandler, Vm};
|
||||
use crate::vm_dispatch_misc::DisposePhase;
|
||||
use crate::vm_trace;
|
||||
use oxide_bytecode::opcode;
|
||||
use oxide_runtime_api::VmHost;
|
||||
@@ -1037,10 +1038,15 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
// 逃出资源释放(规范序:IteratorClose 先、DisposeResources 后):逆序释放
|
||||
// 顶部 dispose_count 条。释放方法抛错时新错误替代完成值,展开到外围处理器。
|
||||
if self.dispose_top_n(completion.dispose_count()) {
|
||||
self.unwind()?;
|
||||
return Ok(CloseEscapeOutcome::Handled);
|
||||
// 顶部 dispose_count 条。释放方法抛错时新错误替代完成值,展开到外围处理器;
|
||||
// 异步释放挂起时登记在途状态并让出(结算闭包续)。
|
||||
match self.dispose_top_n(completion.dispose_count(), completion)? {
|
||||
DisposePhase::Threw => {
|
||||
self.unwind()?;
|
||||
return Ok(CloseEscapeOutcome::Handled);
|
||||
}
|
||||
DisposePhase::Suspended => return Ok(CloseEscapeOutcome::Suspended),
|
||||
DisposePhase::Clean => {}
|
||||
}
|
||||
// 异步条目逐层关闭:首个有 return 方法的登记挂起,其余入 remaining;无
|
||||
// return 方法时继续下一层。
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use crate::vm::{ForInIter, FrameArgs, FrameContinuation, Vm, MAX_PROTO_CHAIN_DEPTH};
|
||||
use crate::vm::{
|
||||
Completion, DisposeResumeKind, ForInIter, FrameArgs, FrameContinuation, PendingAsyncDispose,
|
||||
TryHandler, Vm, MAX_PROTO_CHAIN_DEPTH,
|
||||
};
|
||||
use crate::vm_trace;
|
||||
use oxide_builtins::iterator::is_callable;
|
||||
use oxide_runtime_api::{push_units_to, to_boolean, to_units_full, VmHost};
|
||||
use oxide_types::object::{JsObject, PropAttributes};
|
||||
use oxide_types::private_key::{
|
||||
@@ -9,11 +13,23 @@ use oxide_types::private_key::{
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
/// 单资源释放结局(规范 Dispose 语义):`Done` = 释放成功;`NoMethod` = 无释放方法
|
||||
/// (非对象 / 方法未定义 / 不可调用,跳过);`Err(v)` = 释放方法抛错(v 为原始异常值)。
|
||||
/// (非对象 / 方法未定义 / 不可调用,跳过);`Err(v)` = 释放方法抛错(v 为原始异常值);
|
||||
/// `Suspended(promise)` = 异步释放已挂起(promise 为释放方法结果经 PromiseResolve 包装
|
||||
/// 后登记的结算 promise,调用方据此登记 `PendingAsyncDispose`)。
|
||||
enum DisposeOutcome {
|
||||
Done,
|
||||
NoMethod,
|
||||
Err(JsValue),
|
||||
Suspended(JsValue),
|
||||
}
|
||||
|
||||
/// 批量释放(`dispose_above` / `dispose_top_n`)结局:`Clean` = 全部正常;
|
||||
/// `Threw` = 有释放方法抛错(合并错误已写入 `exception_value`);`Suspended` =
|
||||
/// 异步挂起已登记(`PendingAsyncDispose` 已置,调用方须快照并早退)。
|
||||
pub(crate) enum DisposePhase {
|
||||
Clean,
|
||||
Threw,
|
||||
Suspended,
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
@@ -705,11 +721,23 @@ impl Vm {
|
||||
let mut completion: Option<JsValue> = None;
|
||||
while self.dispose_stack.len() > mark {
|
||||
let (value, hint) = self.dispose_stack.pop().expect("水位以上必有条目");
|
||||
match self.dispose_value(value, hint) {
|
||||
match self.dispose_value(value, hint)? {
|
||||
DisposeOutcome::Done | DisposeOutcome::NoMethod => {}
|
||||
DisposeOutcome::Err(exc) => {
|
||||
completion = oxide_builtins::disposable_stack::merge_dispose_error(self, completion, exc);
|
||||
}
|
||||
DisposeOutcome::Suspended(promise) => {
|
||||
// 异步挂起:登记在途状态(水位已在循环前弹出,恢复后续循环不
|
||||
// 重复弹),置挂起信号让派发循环退出由恢复方快照。
|
||||
self.pending_async_dispose = Some(PendingAsyncDispose {
|
||||
dispose_promise: promise,
|
||||
mark,
|
||||
completion,
|
||||
kind: DisposeResumeKind::Pop,
|
||||
});
|
||||
self.disposing = false;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
self.disposing = false;
|
||||
@@ -721,41 +749,52 @@ impl Vm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 逆序释放 `depth` 以上资源并截断释放栈到 `depth`,同步弹出水位栈中
|
||||
/// `>= depth` 的基线条目(保两栈一致,防异常路径基线泄漏)。
|
||||
/// 批量释放核心:逆序释放 `depth` 以上条目并截断释放栈到 `depth`,同步弹出
|
||||
/// 水位栈中 `>= depth` 的基线条目(保两栈一致,防异常路径基线泄漏)。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 在途异常作 completion 种子(异常穿越时被折叠进 suppressed)。
|
||||
/// 1. 在途异常作 completion 种子(`seed`,异常穿越时被折叠进 suppressed)。
|
||||
/// 2. 逐条弹出并释放(`dispose_value`);多个释放方法抛错时按规范折叠成
|
||||
/// SuppressedError 链(后抛为 error、前值为 suppressed),循环不因错中断。
|
||||
/// 3. 收尾写回 completion:有合并错误则替代在途异常并更新错误类型;无合并
|
||||
/// 3. 异步挂起时登记 `PendingAsyncDispose`(携给定 `kind` 与在途合并错误)并
|
||||
/// 返回 `Suspended`。
|
||||
/// 4. 收尾写回 completion:有合并错误则替代在途异常并更新错误类型;无合并
|
||||
/// 错误则还原在途异常(类型不变)。
|
||||
/// 4. 截断释放栈后,弹出水位栈中 `>= depth` 的基线条目。
|
||||
/// 5. 截断释放栈后,弹出水位栈中 `>= depth` 的基线条目。
|
||||
///
|
||||
/// # 返回值
|
||||
/// `true` = 有释放方法抛错(合并错误已写入 `exception_value`);`false` = 全部正常。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 释放栈截断到 `depth`、水位栈弹出 `>= depth` 的基线。
|
||||
/// - 有释放方法抛错时改写 `exception_value`/`pending_error_kind`。
|
||||
pub(crate) fn dispose_above(&mut self, depth: usize) -> bool {
|
||||
// 重入守卫:释放方法抛错触发的嵌套 unwind 会重入本函数,置位时直接返回,
|
||||
// 防重复释放与合并(合并链会被二次折叠)。
|
||||
/// # 边界与前提
|
||||
/// - 重入守卫:释放方法抛错触发的嵌套 unwind 会重入本函数,`disposing` 置位时
|
||||
/// 直接返回(防重复释放与合并,合并链会被二次折叠)。
|
||||
/// - 挂起路径基线水位暂不弹(恢复续循环后统一弹)。
|
||||
pub(crate) fn dispose_above_core(
|
||||
&mut self, depth: usize, kind: DisposeResumeKind, seed: Option<JsValue>,
|
||||
) -> Result<DisposePhase, String> {
|
||||
if self.disposing {
|
||||
return false;
|
||||
return Ok(DisposePhase::Clean);
|
||||
}
|
||||
self.disposing = true;
|
||||
let mut completion: Option<JsValue> = self.exception_value;
|
||||
let mut completion: Option<JsValue> = seed;
|
||||
let mut threw = false;
|
||||
let truncated = self.dispose_stack.len() > depth;
|
||||
while self.dispose_stack.len() > depth {
|
||||
let (value, hint) = self.dispose_stack.pop().expect("水位以上必有条目");
|
||||
match self.dispose_value(value, hint) {
|
||||
match self.dispose_value(value, hint)? {
|
||||
DisposeOutcome::Done | DisposeOutcome::NoMethod => {}
|
||||
DisposeOutcome::Err(exc) => {
|
||||
completion = oxide_builtins::disposable_stack::merge_dispose_error(self, completion, exc);
|
||||
threw = true;
|
||||
}
|
||||
DisposeOutcome::Suspended(promise) => {
|
||||
// 异步挂起:登记在途状态,基线水位暂不弹(恢复续循环后统一弹)。
|
||||
self.pending_async_dispose = Some(PendingAsyncDispose {
|
||||
dispose_promise: promise,
|
||||
mark: depth,
|
||||
completion,
|
||||
kind,
|
||||
});
|
||||
self.disposing = false;
|
||||
return Ok(DisposePhase::Suspended);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(exc) = completion {
|
||||
@@ -772,77 +811,139 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
self.disposing = false;
|
||||
threw
|
||||
Ok(if threw { DisposePhase::Threw } else { DisposePhase::Clean })
|
||||
}
|
||||
|
||||
/// 异常穿越释放:逆序释放 `depth` 以上资源。在途异常作 completion 种子(被折叠
|
||||
/// 进 suppressed)。挂起时携 `Unwind(handler)`(handler 已弹出,恢复时重压再入
|
||||
/// unwind)。
|
||||
pub(crate) fn dispose_above(
|
||||
&mut self, depth: usize, handler: Option<TryHandler>,
|
||||
) -> Result<DisposePhase, String> {
|
||||
self.dispose_above_core(depth, DisposeResumeKind::Unwind(handler), self.exception_value)
|
||||
}
|
||||
|
||||
/// 释放栈顶部 `n` 条资源(逃出释放:return/break/continue 完成值逃出作用域时
|
||||
/// 逆序释放被逃出的资源)。`n` 超过栈长时按全量释放。
|
||||
///
|
||||
/// # 返回值
|
||||
/// 同 `dispose_above`:`true` = 有释放方法抛错。
|
||||
pub(crate) fn dispose_top_n(&mut self, n: usize) -> bool {
|
||||
/// 逆序释放被逃出的资源)。`n` 超过栈长时按全量释放。在途 completion 初值为
|
||||
/// None(完成值非 throw),挂起时携 `Escape(completion)` 供恢复后执行。
|
||||
pub(crate) fn dispose_top_n(
|
||||
&mut self, n: usize, completion: Completion,
|
||||
) -> Result<DisposePhase, String> {
|
||||
let depth = self.dispose_stack.len().saturating_sub(n);
|
||||
self.dispose_above(depth)
|
||||
self.dispose_above_core(depth, DisposeResumeKind::Escape(completion), None)
|
||||
}
|
||||
|
||||
/// 单资源释放(规范 Dispose 语义):非对象跳过;按释放提示取方法(同步只取
|
||||
/// Symbol.dispose;异步先取 Symbol.asyncDispose,未定义回退 Symbol.dispose),
|
||||
/// 不可调用跳过;以资源自身为 this 零参调用。
|
||||
/// 单资源释放(规范 Dispose 语义):按释放提示取方法(同步只取 Symbol.dispose;
|
||||
/// 异步先取 Symbol.asyncDispose,未定义回退 Symbol.dispose),以资源自身为 this
|
||||
/// 零参调用。
|
||||
///
|
||||
/// # 返回值
|
||||
/// `Done` = 释放成功;`NoMethod` = 无释放方法(跳过);`Err(v)` = 释放方法抛错
|
||||
/// (v 为原始异常值,经 `last_uncaught_value` 恢复,无则按错误文本建普通 Error)。
|
||||
/// (v 为原始异常值,经 `last_uncaught_value` 恢复,无则按错误文本建普通 Error);
|
||||
/// `Suspended(promise)` = 异步释放已挂起(promise 为释放方法结果经 PromiseResolve
|
||||
/// 包装后登记的结算 promise,调用方据此登记 `PendingAsyncDispose`)。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 取方法 / 调用方法任一步抛错均归入 `Err`(getter 抛错与调用抛错同处置)。
|
||||
/// - 异步方法结果为对象时须 Await 挂起,归后续任务;本期同步调用,结果丢弃。
|
||||
fn dispose_value(&mut self, value: JsValue, hint: u16) -> DisposeOutcome {
|
||||
/// - 异步提示恒挂起:方法未定义时结果取 undefined,仍经 PromiseResolve 包成新
|
||||
/// promise 让出一次微任务(规范 `await using` 的 Await 步无条件执行)。
|
||||
fn dispose_value(&mut self, value: JsValue, hint: u16) -> Result<DisposeOutcome, String> {
|
||||
// 取方法抛错(getter 抛错)归入 Err 结局(合并进链)。
|
||||
let method = match self.lookup_dispose_method(value, hint) {
|
||||
Ok(m) => m,
|
||||
Err(exc) => return Ok(DisposeOutcome::Err(exc)),
|
||||
};
|
||||
// 异步提示且有异步上下文:调用方法(未定义时结果取 undefined),结果无条件
|
||||
// Await 挂起。无异步上下文(顶层 await using)回退同步释放。
|
||||
if hint == 1 && (self.async_context.is_some() || self.async_gen_context.is_some()) {
|
||||
let result = if is_callable(method) {
|
||||
match self.call_function_sync(method, value, &[]) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Ok(DisposeOutcome::Err(self.dispose_exc(e))),
|
||||
}
|
||||
} else {
|
||||
JsValue::undefined()
|
||||
};
|
||||
let promise = match self.promise_resolve(result) {
|
||||
Ok(p) => p,
|
||||
Err(exc) => {
|
||||
let (p, _, _) = self.new_promise_capability();
|
||||
let _ = self.reject_promise(p, exc);
|
||||
p
|
||||
}
|
||||
};
|
||||
self.register_dispose_suspend(promise)?;
|
||||
return Ok(DisposeOutcome::Suspended(promise));
|
||||
}
|
||||
// 同步(或无异步上下文的异步提示):不可调用跳过;调用成功 Done,抛错 Err。
|
||||
if !is_callable(method) {
|
||||
return Ok(DisposeOutcome::NoMethod);
|
||||
}
|
||||
match self.call_function_sync(method, value, &[]) {
|
||||
Ok(_) => Ok(DisposeOutcome::Done),
|
||||
Err(e) => Ok(DisposeOutcome::Err(self.dispose_exc(e))),
|
||||
}
|
||||
}
|
||||
|
||||
/// 取释放方法:异步提示先取 Symbol.asyncDispose,未定义回退 Symbol.dispose;
|
||||
/// 同步提示只取 Symbol.dispose。非对象取 undefined。getter 抛错时返回原始
|
||||
/// 异常值(经 `last_uncaught_value` 恢复,无则按错误文本建普通 Error)。
|
||||
fn lookup_dispose_method(&mut self, value: JsValue, hint: u16) -> Result<JsValue, JsValue> {
|
||||
if !value.is_object() {
|
||||
return DisposeOutcome::NoMethod;
|
||||
return Ok(JsValue::undefined());
|
||||
}
|
||||
let val_obj = unsafe { &*value.as_js_object_ptr() };
|
||||
let dispose_key = encode_symbol_key(self.realm_id(), WELL_KNOWN_SYMBOL_DISPOSE);
|
||||
let method = if hint == 1 {
|
||||
let async_key = encode_symbol_key(self.realm_id(), WELL_KNOWN_SYMBOL_ASYNC_DISPOSE);
|
||||
let async_method = match self.ordinary_get(val_obj, async_key, value) {
|
||||
Ok(m) => m,
|
||||
Err(e) => return self.dispose_thrown(e),
|
||||
};
|
||||
let async_method = self
|
||||
.ordinary_get(val_obj, async_key, value)
|
||||
.map_err(|e| self.dispose_exc(e))?;
|
||||
if async_method.is_undefined() {
|
||||
match self.ordinary_get(val_obj, dispose_key, value) {
|
||||
Ok(m) => m,
|
||||
Err(e) => return self.dispose_thrown(e),
|
||||
}
|
||||
self.ordinary_get(val_obj, dispose_key, value).map_err(|e| self.dispose_exc(e))?
|
||||
} else {
|
||||
async_method
|
||||
}
|
||||
} else {
|
||||
match self.ordinary_get(val_obj, dispose_key, value) {
|
||||
Ok(m) => m,
|
||||
Err(e) => return self.dispose_thrown(e),
|
||||
}
|
||||
self.ordinary_get(val_obj, dispose_key, value).map_err(|e| self.dispose_exc(e))?
|
||||
};
|
||||
if !method.is_object() {
|
||||
return DisposeOutcome::NoMethod;
|
||||
}
|
||||
let method_obj = unsafe { &*method.as_js_object_ptr() };
|
||||
if !method_obj.is_function() {
|
||||
return DisposeOutcome::NoMethod;
|
||||
}
|
||||
match self.call_function_sync(method, value, &[]) {
|
||||
Ok(_) => DisposeOutcome::Done,
|
||||
Err(e) => self.dispose_thrown(e),
|
||||
}
|
||||
Ok(method)
|
||||
}
|
||||
|
||||
/// 释放方法抛错时恢复原始异常值(经 `last_uncaught_value`,无则按错误文本建
|
||||
/// 普通 Error),归入 `Err` 结局。
|
||||
fn dispose_thrown(&mut self, e: String) -> DisposeOutcome {
|
||||
let exc = self
|
||||
.last_uncaught_value
|
||||
/// 登记异步释放挂起:按派发上下文(异步生成器 / 普通异步函数)构造结算闭包,
|
||||
/// 登记 fulfill/reject 恢复反应并置挂起信号。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 异步生成器派发(`async_gen_dispatch`)走异步生成器状态盒与结算闭包,置
|
||||
/// `async_gen_suspended`;普通异步函数走异步上下文,置 `async_suspended`。
|
||||
/// - 无对应上下文(非异步上下文内的异步释放)返回 Err,不静默降级。
|
||||
fn register_dispose_suspend(&mut self, promise: JsValue) -> Result<(), String> {
|
||||
if self.async_gen_dispatch {
|
||||
let Some(ctx) = self.async_gen_context else {
|
||||
return Err("async dispose in async generator without context".into());
|
||||
};
|
||||
let fulfill_fn = self.make_async_gen_dispose_resume_fn(ctx, promise, false);
|
||||
let reject_fn = self.make_async_gen_dispose_resume_fn(ctx, promise, true);
|
||||
let _ = self.perform_promise_then(promise, fulfill_fn, reject_fn);
|
||||
self.async_gen_suspended = true;
|
||||
return Ok(());
|
||||
}
|
||||
let Some(ctx) = self.async_context else {
|
||||
return Err("async dispose outside async function".into());
|
||||
};
|
||||
let fulfill_fn = self.make_async_dispose_resume_fn(ctx, promise, false);
|
||||
let reject_fn = self.make_async_dispose_resume_fn(ctx, promise, true);
|
||||
let _ = self.perform_promise_then(promise, fulfill_fn, reject_fn);
|
||||
self.async_suspended = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 释放路径抛错时恢复原始异常值(经 `last_uncaught_value`,无则按错误文本建
|
||||
/// 普通 Error)。
|
||||
fn dispose_exc(&mut self, e: String) -> JsValue {
|
||||
self.last_uncaught_value
|
||||
.take()
|
||||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e));
|
||||
DisposeOutcome::Err(exc)
|
||||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e))
|
||||
}
|
||||
|
||||
pub(crate) fn dispatch_for_of_init(&mut self, a: usize) -> Result<(), String> {
|
||||
|
||||
@@ -5,6 +5,7 @@ use oxide_bytecode::module::CompiledModule;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
|
||||
use crate::vm::{CallFrame, FrameArgs, FrameContinuation, InlineSyncState, TableGen, Vm};
|
||||
use crate::vm_dispatch_misc::DisposePhase;
|
||||
use crate::{vm_debug, vm_info, vm_trace, vm_warn};
|
||||
use oxide_types::object::{Cell, JsObject};
|
||||
use oxide_types::value::JsValue;
|
||||
@@ -329,9 +330,10 @@ impl Vm {
|
||||
/// (`n_registers ≤ 254`,含 RegAlloc 最高合法物理槽 253)。
|
||||
pub(crate) fn save_inline_state(&mut self, regs_end: usize) -> Box<InlineSyncState> {
|
||||
vm_trace!("save_inline_state: pc={} depth={}", self.pc, self.frames.len());
|
||||
// 固化不变量:内联 state-swap 边界不携带在途异步逃出(挂起态快照前已搬入
|
||||
// 状态盒,settle 前恒为 None)。
|
||||
// 固化不变量:内联 state-swap 边界不携带在途异步逃出/释放(挂起态快照前
|
||||
// 已搬入状态盒,settle 前恒为 None)。
|
||||
debug_assert!(self.pending_async_escape.is_none());
|
||||
debug_assert!(self.pending_async_dispose.is_none());
|
||||
let window = regs_end.min(254);
|
||||
let mut window_regs = self.inline_reg_pool.take().unwrap_or_default();
|
||||
window_regs.clear();
|
||||
@@ -344,8 +346,9 @@ impl Vm {
|
||||
/// 单回,窗口外寄存器 callee 未触碰无需恢复。
|
||||
pub(crate) fn restore_inline_state(&mut self, mut saved: Box<InlineSyncState>) {
|
||||
vm_trace!("restore_inline_state: pc={}", saved.pc);
|
||||
// 固化不变量:内联 state-swap 边界不携带在途异步逃出(与 save 侧同)。
|
||||
// 固化不变量:内联 state-swap 边界不携带在途异步逃出/释放(与 save 侧同)。
|
||||
debug_assert!(self.pending_async_escape.is_none());
|
||||
debug_assert!(self.pending_async_dispose.is_none());
|
||||
let vm = self;
|
||||
let _window_regs: Vec<JsValue> = Vec::new();
|
||||
inline_core_fields!(vm, saved, inline_restore, _window_regs);
|
||||
@@ -871,8 +874,14 @@ impl Vm {
|
||||
// 对该处理器作用域内被中断的 for-of 循环执行 IteratorClose。
|
||||
self.close_for_of_above(handler.for_of_depth);
|
||||
// 异常穿越释放:逆序释放该作用域内登记的资源(规范序 IteratorClose 先、
|
||||
// DisposeResources 后)。释放方法抛错时新错误替代在途异常继续向外展开。
|
||||
self.dispose_above(handler.dispose_depth);
|
||||
// DisposeResources 后)。释放方法抛错时新错误替代在途异常继续向外展开;
|
||||
// 异步释放挂起时登记在途状态并让出(恢复方重压 handler 再入本函数)。
|
||||
if matches!(
|
||||
self.dispose_above(handler.dispose_depth, Some(handler))?,
|
||||
DisposePhase::Suspended
|
||||
) {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(finally_pc) = handler.finally_pc {
|
||||
if handler.finally_active {
|
||||
// 新异常在 finally 体内抛出:覆盖在途异常与完成,继续向外展开,
|
||||
@@ -902,8 +911,11 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
self.close_for_of_above(0);
|
||||
// 未捕获兜底:释放栈上全部资源(异常穿越全作用域)。
|
||||
self.dispose_above(0);
|
||||
// 未捕获兜底:释放栈上全部资源(异常穿越全作用域)。无 handler(未捕获路径);
|
||||
// 异步释放挂起时登记在途状态并让出(恢复方直接再入本函数走未捕获路径)。
|
||||
if matches!(self.dispose_above(0, None)?, DisposePhase::Suspended) {
|
||||
return Ok(());
|
||||
}
|
||||
while let Some(frame) = self.frames.pop() {
|
||||
self.cell_stack.pop();
|
||||
self.restore_frame(frame);
|
||||
|
||||
@@ -144,6 +144,7 @@ impl Vm {
|
||||
pending_error_kind: None,
|
||||
pending_completion: None,
|
||||
pending_async_escape: None,
|
||||
pending_async_dispose: None,
|
||||
root_reg_limit: 0,
|
||||
active_reg_limit: 0,
|
||||
native_call_depth: 0,
|
||||
@@ -308,6 +309,7 @@ impl Vm {
|
||||
pending_error_kind: None,
|
||||
pending_completion: None,
|
||||
pending_async_escape: None,
|
||||
pending_async_dispose: None,
|
||||
root_reg_limit: 0,
|
||||
active_reg_limit: 0,
|
||||
native_call_depth: 0,
|
||||
@@ -543,6 +545,8 @@ impl Vm {
|
||||
self.pending_completion = None;
|
||||
// 在途异步逃出是执行期状态:跨 run/reset 不保留,残留将悬垂。
|
||||
self.pending_async_escape = None;
|
||||
// 在途异步释放同属执行期状态:跨 run/reset 不保留,残留将悬垂。
|
||||
self.pending_async_dispose = None;
|
||||
self.generator_suspended = None;
|
||||
self.delegated_iterator = None;
|
||||
self.generator_dispatch = false;
|
||||
|
||||
Reference in New Issue
Block a user