mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: for-await-of 多层逃出逐层 LIFO 关闭并接通异步生成器路径
This commit is contained in:
@@ -65,7 +65,7 @@ pub(crate) const ASYNC_CTX_PROP: &str = "__oxide_async_ctx__";
|
|||||||
/// 恢复闭包上区分 reject 角色的属性名。
|
/// 恢复闭包上区分 reject 角色的属性名。
|
||||||
const ASYNC_REJECT_PROP: &str = "__oxide_async_reject__";
|
const ASYNC_REJECT_PROP: &str = "__oxide_async_reject__";
|
||||||
/// 逃出关闭结算闭包上存 return() promise 的属性名(陈旧防御校验用)。
|
/// 逃出关闭结算闭包上存 return() promise 的属性名(陈旧防御校验用)。
|
||||||
const ASYNC_ESCAPE_PROMISE_PROP: &str = "__oxide_async_escape_promise__";
|
pub(crate) const ASYNC_ESCAPE_PROMISE_PROP: &str = "__oxide_async_escape_promise__";
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
/// 调用异步函数返回的 capability promise:创建上下文对象 + 状态盒,立即压帧
|
/// 调用异步函数返回的 capability promise:创建上下文对象 + 状态盒,立即压帧
|
||||||
@@ -389,14 +389,16 @@ impl Vm {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 恢复逃出 for-await-of 的异步函数:return() 的 promise 结算后执行完成。
|
/// 恢复逃出 for-await-of 的异步函数:return() 的 promise 结算后继续关闭剩余
|
||||||
|
/// 条目并执行完成。
|
||||||
///
|
///
|
||||||
/// # 步骤
|
/// # 步骤
|
||||||
/// 1. 陈旧防御:状态盒 pending_async_escape.close_promise 须与本闭包 promise
|
/// 1. 陈旧防御:状态盒 pending_async_escape.close_promise 须与本闭包 promise
|
||||||
/// 匹配,不匹配则不处理(防同一 promise 被双结算)。
|
/// 匹配,不匹配则不处理(防同一 promise 被双结算)。
|
||||||
/// 2. 把挂起快照灌回 VM,取出完成并清除 pending_async_escape。
|
/// 2. 把挂起快照灌回 VM,取出完成与剩余待关条目并清除 pending_async_escape。
|
||||||
/// 3. 执行完成:Return 走 do_return,Break/Continue 跳转 target_pc 续 dispatch。
|
/// 3. 多层逃出:remaining 非空时逐层关闭(每层一轮结算),空了才执行完成。
|
||||||
/// 4. 再挂起则快照新状态;完成/异常则结算 capability。恢复调用方状态。
|
/// 4. 执行完成:Return 走 do_return,Break/Continue 跳转 target_pc 续 dispatch。
|
||||||
|
/// 5. 再挂起则快照新状态;完成/异常则结算 capability。恢复调用方状态。
|
||||||
///
|
///
|
||||||
/// # 边界与前提
|
/// # 边界与前提
|
||||||
/// - 关闭 promise 拒绝时(reject 角色),拒绝值替代在途完成:抛拒绝原因,
|
/// - 关闭 promise 拒绝时(reject 角色),拒绝值替代在途完成:抛拒绝原因,
|
||||||
@@ -406,6 +408,8 @@ impl Vm {
|
|||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let state_ptr = self.async_state_ptr(ctx);
|
let state_ptr = self.async_state_ptr(ctx);
|
||||||
let saved = self.save_inline_state(256);
|
let saved = self.save_inline_state(256);
|
||||||
|
// 清上一轮多层关闭残留的挂起信号(多层逐层结算每轮清零,防陈旧信号误消费)。
|
||||||
|
self.async_suspended = false;
|
||||||
let prev_ctx = self.async_context.take();
|
let prev_ctx = self.async_context.take();
|
||||||
let prev_dispatch = self.async_dispatch;
|
let prev_dispatch = self.async_dispatch;
|
||||||
let prev_gen_ctx = self.async_gen_context.take();
|
let prev_gen_ctx = self.async_gen_context.take();
|
||||||
@@ -438,8 +442,29 @@ impl Vm {
|
|||||||
state.phase = AsyncPhase::Running;
|
state.phase = AsyncPhase::Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取出完成并清除 pending_async_escape。
|
// 取出完成与剩余待关条目并清除 pending_async_escape。
|
||||||
let completion = self.pending_async_escape.take().unwrap().completion;
|
let (completion, mut remaining) = match self.pending_async_escape.take() {
|
||||||
|
Some(p) => (p.completion, p.remaining),
|
||||||
|
// 陈旧防御已早退,正常路径此处必为 Some;防御性兜底。
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// 多层逃出:remaining 非空时逐层关闭(每层一轮结算),空了才执行完成
|
||||||
|
// (或抛拒绝原因)。挂起信号由 register 置位,快照后返回续下一轮结算。
|
||||||
|
while let Some(next_iter) = remaining.first().cloned() {
|
||||||
|
remaining.remove(0);
|
||||||
|
match self.register_async_escape_close(next_iter, completion, remaining.clone()) {
|
||||||
|
Ok(true) => {
|
||||||
|
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(());
|
||||||
|
}
|
||||||
|
Ok(false) => continue,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 关闭拒绝:拒绝值替代在途完成。抛拒绝原因,外围 catch/finally 接管;
|
// 关闭拒绝:拒绝值替代在途完成。抛拒绝原因,外围 catch/finally 接管;
|
||||||
// 无处理器时异步函数以拒绝原因拒绝。
|
// 无处理器时异步函数以拒绝原因拒绝。
|
||||||
@@ -479,7 +504,7 @@ impl Vm {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单层路径:remaining 恒空,直接执行完成。
|
// remaining 已空,执行完成。
|
||||||
match completion {
|
match completion {
|
||||||
Completion::Return { value: ret_val, .. } => {
|
Completion::Return { value: ret_val, .. } => {
|
||||||
let result = self.do_return(ret_val)?;
|
let result = self.do_return(ret_val)?;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use oxide_types::object::{Cell, JsObject, NativeFnPtr, PropAttributes};
|
|||||||
use oxide_types::value::JsValue;
|
use oxide_types::value::JsValue;
|
||||||
|
|
||||||
use crate::generator::{DelegateOutcome, GeneratorResumeMode};
|
use crate::generator::{DelegateOutcome, GeneratorResumeMode};
|
||||||
use crate::vm::Vm;
|
use crate::vm::{Completion, Vm};
|
||||||
|
|
||||||
/// 异步生成器执行阶段。
|
/// 异步生成器执行阶段。
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@@ -429,13 +429,20 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let result = self.dispatch();
|
let result = self.dispatch();
|
||||||
self.async_gen_dispatch = prev_agd;
|
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||||
self.async_gen_context = prev_gen_ctx;
|
self.post_dispatch_async_gen(state_ptr, saved, gen_val, result)
|
||||||
self.generator_dispatch = prev_gd;
|
}
|
||||||
self.async_dispatch = prev_ad;
|
|
||||||
self.async_context = prev_ctx;
|
|
||||||
self.native_call_depth -= 1;
|
|
||||||
|
|
||||||
|
/// 异步生成器恢复的 dispatch 后处理:YIELD 让出(快照 + 让出值 unwrap 结算)、
|
||||||
|
/// AWAIT 挂起(快照)、完成/异常(结算当前请求)。
|
||||||
|
///
|
||||||
|
/// # 前提
|
||||||
|
/// 调度标志已恢复(调用方先恢复再调本函数);本函数内部按结果快照新状态并
|
||||||
|
/// 恢复调用方内联状态。
|
||||||
|
fn post_dispatch_async_gen(
|
||||||
|
&mut self, state_ptr: *mut AsyncGeneratorState, saved: Box<crate::vm::InlineSyncState>, gen_val: JsValue,
|
||||||
|
result: Result<JsValue, String>,
|
||||||
|
) -> Result<(), String> {
|
||||||
// YIELD 让出:快照挂起状态,让出值经 promise unwrap 后结算当前请求。
|
// YIELD 让出:快照挂起状态,让出值经 promise unwrap 后结算当前请求。
|
||||||
if let Some(value) = self.generator_suspended.take() {
|
if let Some(value) = self.generator_suspended.take() {
|
||||||
// AsyncGeneratorYield:让出值 PromiseResolve 包装后 await 展开
|
// AsyncGeneratorYield:让出值 PromiseResolve 包装后 await 展开
|
||||||
@@ -758,6 +765,154 @@ impl Vm {
|
|||||||
self.add_fn_name_length(obj, "", 1);
|
self.add_fn_name_length(obj, "", 1);
|
||||||
JsValue::from_js_object(ptr)
|
JsValue::from_js_object(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 构造逃出关闭结算闭包(异步生成器):携带目标异步生成器上下文对象与
|
||||||
|
/// return() promise,区分 fulfill/reject 角色。
|
||||||
|
pub(crate) fn make_async_gen_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_gen_escape_closure 是 NativeFn 函数项。
|
||||||
|
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(async_gen_escape_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(crate::async_func::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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 恢复逃出 for-await-of 的异步生成器:return() 的 promise 结算后继续关闭剩余
|
||||||
|
/// 条目并执行完成。
|
||||||
|
///
|
||||||
|
/// # 步骤
|
||||||
|
/// 1. 陈旧防御:状态盒 pending_async_escape.close_promise 须与本闭包 promise
|
||||||
|
/// 匹配,不匹配则不处理(防同一 promise 被双结算)。
|
||||||
|
/// 2. 把挂起快照灌回 VM,取出完成与剩余待关条目并清除 pending_async_escape。
|
||||||
|
/// 3. 多层逃出:remaining 非空时逐层关闭(每层一轮结算),空了才执行完成。
|
||||||
|
/// 4. 执行完成:Return 走 do_return 完成生成器,Break/Continue 跳转 target_pc
|
||||||
|
/// 续 dispatch。
|
||||||
|
/// 5. 再挂起则快照新状态;完成/异常则结算当前请求。恢复调用方状态。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - 关闭 promise 拒绝时(reject 角色),拒绝值替代在途完成:抛拒绝原因,
|
||||||
|
/// 外围 catch/finally 接管;无处理器时当前请求以拒绝原因拒绝。
|
||||||
|
pub(crate) fn resume_async_gen_escape(
|
||||||
|
&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 };
|
||||||
|
// 陈旧防御: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_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_escape。
|
||||||
|
let (completion, mut remaining) = match self.pending_async_escape.take() {
|
||||||
|
Some(p) => (p.completion, p.remaining),
|
||||||
|
// 陈旧防御已早退,正常路径此处必为 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(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 多层逃出:remaining 非空时逐层关闭(每层一轮结算),空了才执行完成
|
||||||
|
// (或抛拒绝原因)。挂起信号由 register 置位,快照后返回续下一轮结算。
|
||||||
|
while let Some(next_iter) = remaining.first().cloned() {
|
||||||
|
remaining.remove(0);
|
||||||
|
match self.register_async_escape_close(next_iter, completion, remaining.clone()) {
|
||||||
|
Ok(true) => {
|
||||||
|
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(());
|
||||||
|
}
|
||||||
|
Ok(false) => continue,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭拒绝:拒绝值替代在途完成。抛拒绝原因,外围 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.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);
|
||||||
|
return self.post_dispatch_async_gen(state_ptr, saved, ctx, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remaining 已空,执行完成。
|
||||||
|
match completion {
|
||||||
|
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 的异步生成器上下文与角色,恢复异步生成器继续执行。
|
/// await 恢复闭包:读自身 prop 的异步生成器上下文与角色,恢复异步生成器继续执行。
|
||||||
@@ -1058,6 +1213,33 @@ fn async_gen_delegate_return_await_closure(vm: &mut Vm, args: &[u8]) -> NativeRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 逃出关闭结算闭包(异步生成器):读自身 prop 的异步生成器上下文、return()
|
||||||
|
/// promise 与角色,恢复挂起帧并继续关闭剩余条目、执行完成。
|
||||||
|
fn async_gen_escape_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(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(crate::async_func::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_gen_escape(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` 取原值。
|
/// 委托结算值读取:done 与 value 的 getter 抛错经 `last_uncaught_value` 取原值。
|
||||||
enum DelegateResult {
|
enum DelegateResult {
|
||||||
/// 结算值读取成功(done 标志与委托值)。
|
/// 结算值读取成功(done 标志与委托值)。
|
||||||
|
|||||||
@@ -945,9 +945,9 @@ impl Vm {
|
|||||||
|
|
||||||
/// 逃出关闭:按 LIFO 弹出逃出的 for-in 迭代器(无 return() 语义),再关闭逃出的
|
/// 逃出关闭:按 LIFO 弹出逃出的 for-in 迭代器(无 return() 语义),再关闭逃出的
|
||||||
/// for-of 迭代器。同步迭代器同步关闭;异步迭代器(for-await-of)同步调 return()
|
/// for-of 迭代器。同步迭代器同步关闭;异步迭代器(for-await-of)同步调 return()
|
||||||
/// 得 promise,登记结算闭包后挂起。逃出路径非 suppress:return() 抛错经
|
/// 得 promise,登记结算闭包后挂起,剩余异步条目入 remaining 逐层续关。逃出路径
|
||||||
/// raise_call_error 展开,剩余迭代器由 unwind 的 close_for_of_above 以 suppress
|
/// 非 suppress:return() 抛错经 raise_call_error 展开,剩余迭代器由 unwind 的
|
||||||
/// 继续关闭——新错误替代原完成值向外传播。
|
/// close_for_of_above 以 suppress 继续关闭——新错误替代原完成值向外传播。
|
||||||
///
|
///
|
||||||
/// # 返回值
|
/// # 返回值
|
||||||
/// `Done` = 全部关闭完成,调用方继续跳转/返回动作;`Handled` = return() 抛错且
|
/// `Done` = 全部关闭完成,调用方继续跳转/返回动作;`Handled` = return() 抛错且
|
||||||
@@ -960,16 +960,14 @@ impl Vm {
|
|||||||
for _ in 0..for_in_count {
|
for _ in 0..for_in_count {
|
||||||
self.iters.pop_for_in();
|
self.iters.pop_for_in();
|
||||||
}
|
}
|
||||||
// 单层路径:首个异步条目登记关闭,其余异步条目丢弃(多层路径填 remaining)。
|
// 多层路径:异步条目按 LIFO 收集(前元素先关),同步条目当场关闭。
|
||||||
let mut first_async: Option<JsValue> = None;
|
let mut async_iters: Vec<JsValue> = Vec::new();
|
||||||
for _ in 0..for_of_count {
|
for _ in 0..for_of_count {
|
||||||
let Some(entry) = self.iters.pop_for_of() else {
|
let Some(entry) = self.iters.pop_for_of() else {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if entry.is_async {
|
if entry.is_async {
|
||||||
if first_async.is_none() {
|
async_iters.push(entry.iterator);
|
||||||
first_async = Some(entry.iterator);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let pc_before = self.pc;
|
let pc_before = self.pc;
|
||||||
@@ -984,13 +982,14 @@ impl Vm {
|
|||||||
return Ok(CloseEscapeOutcome::Handled);
|
return Ok(CloseEscapeOutcome::Handled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(iterator) = first_async {
|
// 异步条目逐层关闭:首个有 return 方法的登记挂起,其余入 remaining;无
|
||||||
match self.register_async_escape_close(iterator, completion, Vec::new()) {
|
// return 方法时继续下一层。
|
||||||
Ok(true) => {
|
let mut remaining = async_iters;
|
||||||
self.async_suspended = true;
|
while let Some(iterator) = remaining.first().cloned() {
|
||||||
return Ok(CloseEscapeOutcome::Suspended);
|
remaining.remove(0);
|
||||||
}
|
match self.register_async_escape_close(iterator, completion, remaining.clone()) {
|
||||||
Ok(false) => {}
|
Ok(true) => return Ok(CloseEscapeOutcome::Suspended),
|
||||||
|
Ok(false) => continue,
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -998,19 +997,20 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 登记逃出 for-await-of 的异步关闭:同步调 return() 得 promise,登记结算闭包,
|
/// 登记逃出 for-await-of 的异步关闭:同步调 return() 得 promise,登记结算闭包,
|
||||||
/// 置 pending_async_escape。迭代器无 return 方法时不登记(完成直接继续)。
|
/// 置 pending_async_escape 与挂起信号。迭代器无 return 方法时不登记(完成直接
|
||||||
|
/// 继续)。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - 异步生成器派发(`async_gen_dispatch`)走异步生成器状态盒与结算闭包,置
|
||||||
|
/// `async_gen_suspended`;普通异步函数走异步上下文,置 `async_suspended`。
|
||||||
|
/// - 同步生成器无异步上下文:不登记挂起(完成直接继续)。
|
||||||
///
|
///
|
||||||
/// # 返回值
|
/// # 返回值
|
||||||
/// `Ok(true)` = 已登记挂起;`Ok(false)` = 无 return 方法,无需挂起;`Err` = 关闭
|
/// `Ok(true)` = 已登记挂起;`Ok(false)` = 无 return 方法,无需挂起;`Err` = 关闭
|
||||||
/// 过程出错。
|
/// 过程出错。
|
||||||
fn register_async_escape_close(
|
pub(crate) fn register_async_escape_close(
|
||||||
&mut self, iterator: JsValue, completion: Completion, remaining: Vec<JsValue>,
|
&mut self, iterator: JsValue, completion: Completion, remaining: Vec<JsValue>,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
// 异步生成器走独立状态盒(AsyncGeneratorState),本路径的结算闭包按
|
|
||||||
// AsyncState 恢复——不登记挂起(异步迭代器保持既有跳过行为,完成直接继续)。
|
|
||||||
if self.async_gen_dispatch {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
if !iterator.is_object() {
|
if !iterator.is_object() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
@@ -1037,8 +1037,25 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// 同步生成器无异步上下文:不登记挂起(异步迭代器保持既有跳过行为,完成直接继续)。
|
// 异步生成器派发:异步生成器状态盒与结算闭包,置 async_gen_suspended。
|
||||||
let Some(ctx) = self.async_context.or(self.async_gen_context) else {
|
if self.async_gen_dispatch {
|
||||||
|
let Some(ctx) = self.async_gen_context else {
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
|
let fulfill_fn = self.make_async_gen_escape_close_fn(ctx, promise, false);
|
||||||
|
let reject_fn = self.make_async_gen_escape_close_fn(ctx, promise, true);
|
||||||
|
let _ = self.perform_promise_then(promise, fulfill_fn, reject_fn);
|
||||||
|
self.pending_async_escape = Some(PendingAsyncEscape {
|
||||||
|
close_promise: promise,
|
||||||
|
completion,
|
||||||
|
remaining,
|
||||||
|
});
|
||||||
|
self.async_gen_suspended = true;
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
// 普通异步函数:异步上下文与结算闭包,置 async_suspended。同步生成器无
|
||||||
|
// 异步上下文:不登记挂起(完成直接继续)。
|
||||||
|
let Some(ctx) = self.async_context else {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
};
|
};
|
||||||
let fulfill_fn = self.make_async_escape_close_fn(ctx, promise, false);
|
let fulfill_fn = self.make_async_escape_close_fn(ctx, promise, false);
|
||||||
@@ -1049,6 +1066,7 @@ impl Vm {
|
|||||||
completion,
|
completion,
|
||||||
remaining,
|
remaining,
|
||||||
});
|
});
|
||||||
|
self.async_suspended = true;
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -360,3 +360,29 @@ fn t18_throw_close_non_object_result_typeerror() {
|
|||||||
"\"caught:IteratorResult is not an object:true\""
|
"\"caught:IteratorResult is not an object:true\""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// T19:异步生成器体内 for-await-of 多层 return 逃出——LIFO 顺序关闭(内层先),
|
||||||
|
// 完成值经 next() 的 promise 交付({value:42, done:true})。
|
||||||
|
#[test]
|
||||||
|
fn t19_async_gen_multi_layer_return_escape_lifo() {
|
||||||
|
let source = "let log=[];\
|
||||||
|
const mk=(n)=>({[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:n,done:false})},return(){log.push('c'+n);return Promise.resolve({done:true})}}}});\
|
||||||
|
async function* g() { for await (const a of mk(1)) { for await (const b of mk(2)) { log.push('body'); return 42; } } }\
|
||||||
|
(async function run() { const it = g(); const r = await it.next(); \
|
||||||
|
return log.join(',') + '|' + r.done + ':' + r.value; })()"
|
||||||
|
.to_string();
|
||||||
|
assert_eq!(eval(&source), "\"body,c2,c1|true:42\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
// T20:异步生成器体内 for-await-of break 逃出——关闭迭代器后 body 继续,
|
||||||
|
// 后续 yield 正常交付(验证 break 跳转 target_pc 正确、生成器未误完成)。
|
||||||
|
#[test]
|
||||||
|
fn t20_async_gen_break_escape_continues() {
|
||||||
|
let source = "let log=[];\
|
||||||
|
const it={[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:1,done:false})},return(){log.push('close');return Promise.resolve({done:true})}}}};\
|
||||||
|
async function* g() { for await (const x of it) { log.push('body'); break; } yield 'after'; }\
|
||||||
|
(async function run() { const it = g(); const r = await it.next(); \
|
||||||
|
return log.join(',') + '|' + r.value + ':' + r.done; })()"
|
||||||
|
.to_string();
|
||||||
|
assert_eq!(eval(&source), "\"body,close|after:false\"");
|
||||||
|
}
|
||||||
|
|||||||
@@ -281,6 +281,104 @@ fn for_await_of_close_throw_object_identity_preserved() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── 逃出关闭测试矩阵(E1-E10):多层 LIFO 关闭与 Completion 边角 ──
|
||||||
|
//
|
||||||
|
// for-await-of 的 next() 经 await 结算,循环体在 N 层嵌套时深 N 个微任务 tick;
|
||||||
|
// 读取 log 的 then 回调须比最深的结算闭包更晚入队,故用足够长的 then 链延迟读取。
|
||||||
|
|
||||||
|
/// 延迟 N 个微任务 tick 后读取 log(N 层逃出需 N+2 个 tick 让全部结算闭包跑完)。
|
||||||
|
fn delay_read(n: usize) -> String {
|
||||||
|
let mut chain = "Promise.resolve()".to_string();
|
||||||
|
for _ in 0..n {
|
||||||
|
chain.push_str(".then(()=>{})");
|
||||||
|
}
|
||||||
|
chain.push_str(".then(()=>log.join(','))");
|
||||||
|
chain
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_await_of_break_escape_middle_layer() {
|
||||||
|
// E2b:break 逃出中间 for-await-of 层——内层迭代器关闭,外层继续迭代。
|
||||||
|
let source = "let log=[];\
|
||||||
|
const mk=(n)=>({[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:n,done:false})},return(){log.push('c'+n);return Promise.resolve({done:true})}}}});\
|
||||||
|
(async()=>{ for await (const a of mk(1)) { for await (const b of mk(2)) { log.push('body'); break; } log.push('after'); break; } })();\
|
||||||
|
".to_string()
|
||||||
|
+ &delay_read(4);
|
||||||
|
assert_eq!(eval(&source), "\"body,c2,after,c1\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_await_of_labeled_continue_closes_inner() {
|
||||||
|
// E3:labeled continue 逃出内层 for-await-of——内层迭代器每轮关闭,外层继续。
|
||||||
|
// 外层迭代器有限(两轮后 done),验证 continue 不关闭外层、外层继续迭代。
|
||||||
|
let source = "let log=[];\
|
||||||
|
let outerN=0;\
|
||||||
|
const outer={[Symbol.asyncIterator](){return{next(){outerN++;if(outerN>2)return Promise.resolve({value:undefined,done:true});return Promise.resolve({value:outerN,done:false});},return(){log.push('cO');return Promise.resolve({done:true})}}}};\
|
||||||
|
const inner={[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:1,done:false})},return(){log.push('cI');return Promise.resolve({done:true})}}}};\
|
||||||
|
(async()=>{ outer: for await (const a of outer) { for await (const b of inner) { log.push('body'); continue outer; } log.push('after-inner'); } })();\
|
||||||
|
".to_string()
|
||||||
|
+ &delay_read(6);
|
||||||
|
assert_eq!(eval(&source), "\"body,cI,body,cI\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_await_of_multi_layer_return_escape_lifo() {
|
||||||
|
// E4:多层 return 逃出(两层 for-await-of)——LIFO 顺序关闭(内层先)。
|
||||||
|
// 内层 return() 先被调(c2),外层后(c1),关闭顺序验证 LIFO。
|
||||||
|
let source = "let log=[];\
|
||||||
|
const mk=(n)=>({[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:n,done:false})},return(){log.push('c'+n);return Promise.resolve({done:true})}}}});\
|
||||||
|
(async()=>{ for await (const a of mk(1)) { for await (const b of mk(2)) { log.push('body'); return 42; } } })();\
|
||||||
|
".to_string()
|
||||||
|
+ &delay_read(4);
|
||||||
|
assert_eq!(eval(&source), "\"body,c2,c1\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_await_of_multi_layer_labeled_break_escape_lifo() {
|
||||||
|
// E5:多层 labeled break 逃出——LIFO 顺序关闭(内层先),跳转目标正确。
|
||||||
|
let source = "let log=[];\
|
||||||
|
const mk=(n)=>({[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:n,done:false})},return(){log.push('c'+n);return Promise.resolve({done:true})}}}});\
|
||||||
|
(async()=>{ outer: for await (const a of mk(1)) { for await (const b of mk(2)) { log.push('body'); break outer; } } log.push('after'); })();\
|
||||||
|
".to_string()
|
||||||
|
+ &delay_read(4);
|
||||||
|
assert_eq!(eval(&source), "\"body,c2,c1,after\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_await_of_escape_close_reject_outer_catch() {
|
||||||
|
// E6:逃出时 return() 拒绝——拒绝原因替代完成值,外围 catch 捕获。
|
||||||
|
let source = "let log=[];\
|
||||||
|
const it={[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:1,done:false})},return(){return Promise.reject('rej');}}}};\
|
||||||
|
(async()=>{ try { for await (const x of it) { log.push('body'); return 1; } } catch (e) { log.push('caught:'+e); } log.push('done'); })();\
|
||||||
|
".to_string()
|
||||||
|
+ &delay_read(3);
|
||||||
|
assert_eq!(eval(&source), "\"body,caught:rej,done\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_await_of_escape_no_return_method() {
|
||||||
|
// E8:迭代器无 return 方法——不登记挂起,完成直接继续。
|
||||||
|
let source = "let log=[];\
|
||||||
|
const it={[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:1,done:false})}}}};\
|
||||||
|
(async()=>{ for await (const x of it) { log.push('body'); return 1; } })();\
|
||||||
|
"
|
||||||
|
.to_string()
|
||||||
|
+ &delay_read(2);
|
||||||
|
assert_eq!(eval(&source), "\"body\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_await_of_escape_settlement_precedes_then() {
|
||||||
|
// E10:微任务时序——结算闭包(执行完成)先于后续 then 回调。
|
||||||
|
// break 逃出后,完成跳转(log.push('after'))在结算闭包内执行,须先于 then 回调。
|
||||||
|
let source = "let log=[];\
|
||||||
|
const it={[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:1,done:false})},return(){return Promise.resolve({done:true})}}}};\
|
||||||
|
(async()=>{ for await (const x of it) { log.push('body'); break; } log.push('after'); })();\
|
||||||
|
".to_string()
|
||||||
|
+ &delay_read(3);
|
||||||
|
assert_eq!(eval(&source), "\"body,after\"");
|
||||||
|
}
|
||||||
|
|
||||||
// ── class/object 生成器方法(异步) ──
|
// ── class/object 生成器方法(异步) ──
|
||||||
|
|
||||||
// class async 生成器方法:yield 顺序与 done 收敛。顶层 then 链驱动
|
// class async 生成器方法:yield 顺序与 done 收敛。顶层 then 链驱动
|
||||||
|
|||||||
Reference in New Issue
Block a user