feat: for-await-of 逃出关闭异步 await return() 结算后恢复帧

This commit is contained in:
2026-09-27 19:48:19 +00:00
parent c9f8597491
commit 9ab19fb472
11 changed files with 457 additions and 65 deletions
+172 -1
View File
@@ -13,7 +13,7 @@ use oxide_runtime_api::{to_boolean, NativeResult};
use oxide_types::object::{Cell, JsObject, NativeFnPtr, PropAttributes};
use oxide_types::value::JsValue;
use crate::vm::Vm;
use crate::vm::{Completion, Vm};
/// 异步函数执行阶段。
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -64,6 +64,8 @@ pub(crate) enum AsyncResumeMode {
pub(crate) const ASYNC_CTX_PROP: &str = "__oxide_async_ctx__";
/// 恢复闭包上区分 reject 角色的属性名。
const ASYNC_REJECT_PROP: &str = "__oxide_async_reject__";
/// 逃出关闭结算闭包上存 return() promise 的属性名(陈旧防御校验用)。
const ASYNC_ESCAPE_PROMISE_PROP: &str = "__oxide_async_escape_promise__";
impl Vm {
/// 调用异步函数返回的 capability promise:创建上下文对象 + 状态盒,立即压帧
@@ -356,6 +358,27 @@ impl Vm {
JsValue::from_js_object(ptr)
}
/// 构造逃出关闭结算闭包:携带目标异步上下文对象与 return() promise,区分
/// fulfill/reject 角色。
pub(crate) fn make_async_escape_close_fn(&mut self, ctx: JsValue, promise: JsValue, reject_role: bool) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true);
// SAFETY: async_escape_close_closure 是 NativeFn 函数项。
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(async_escape_close_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_ESCAPE_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`,其余栈段整段搬入(嵌套循环期间这些栈
@@ -365,6 +388,133 @@ impl Vm {
state.phase = AsyncPhase::Suspended;
Ok(())
}
/// 恢复逃出 for-await-of 的异步函数:return() 的 promise 结算后执行完成。
///
/// # 步骤
/// 1. 陈旧防御:状态盒 pending_async_escape.close_promise 须与本闭包 promise
/// 匹配,不匹配则不处理(防同一 promise 被双结算)。
/// 2. 把挂起快照灌回 VM,取出完成并清除 pending_async_escape。
/// 3. 执行完成:Return 走 do_return,Break/Continue 跳转 target_pc 续 dispatch。
/// 4. 再挂起则快照新状态;完成/异常则结算 capability。恢复调用方状态。
///
/// # 边界与前提
/// - 关闭 promise 拒绝时(reject 角色),拒绝值替代在途完成:抛拒绝原因,
/// 外围 catch/finally 接管;无处理器时异步函数以拒绝原因拒绝。
fn resume_async_escape(
&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);
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 };
// 陈旧防御:close_promise 须匹配,陈旧闭包不处理。
let is_stale = !matches!(
state.suspended.pending_async_escape.as_ref(),
Some(p) if p.close_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_escape。
let completion = self.pending_async_escape.take().unwrap().completion;
// 关闭拒绝:拒绝值替代在途完成。抛拒绝原因,外围 catch/finally 接管;
// 无处理器时异步函数以拒绝原因拒绝。
if is_reject {
self.exception_value = Some(value);
self.pending_error_kind = Some(self.thrown_error_kind(value));
if self.unwind().is_err() {
let exc = self.last_uncaught_value.take().unwrap_or(value);
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(());
}
let result = self.dispatch();
// 处理器体内再挂起(await):快照新状态后退出。
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);
return Ok(());
}
// 单层路径:remaining 恒空,直接执行完成。
match completion {
Completion::Return { value: ret_val, .. } => {
let result = self.do_return(ret_val)?;
if let Some(result) = result {
self.finish_async(state_ptr, Ok(result))?;
}
}
Completion::Break { target_pc, .. } | Completion::Continue { target_pc, .. } => {
self.pc = target_pc;
let result = self.dispatch();
// 完成跳转后 body 继续执行到下一个 await/return/异常。
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 恢复闭包:读自身 prop 的异步上下文与角色,恢复异步帧继续执行。
@@ -390,6 +540,27 @@ fn async_await_resume_closure(vm: &mut Vm, args: &[u8]) -> NativeResult {
}
}
/// 逃出关闭结算闭包:读自身 prop 的异步上下文、return() promise 与角色,恢复挂起
/// 帧并执行完成。
fn async_escape_close_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, "escape close 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_ESCAPE_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_escape(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")。