diff --git a/crates/oxide_vm/src/async_generator.rs b/crates/oxide_vm/src/async_generator.rs index fd2b6087..a8cfce85 100644 --- a/crates/oxide_vm/src/async_generator.rs +++ b/crates/oxide_vm/src/async_generator.rs @@ -57,6 +57,8 @@ pub(crate) enum DelegateStep { Return, /// 等内层 return()(close)的 promise 结算(外层 throw 请求,内层无 throw 方法)。 Close, + /// 等请求值 promise 结算(外层 return 请求,内层无 return 方法,规范 Await 步)。 + ReturnAwait, } /// 异步生成器挂起时的完整执行上下文快照 + 请求队列。 @@ -381,6 +383,8 @@ impl Vm { self.regs[0] = value; } Ok(DelegateOutcome::Complete { value }) => { + // 共享枚举保留同步路径的 Complete 结局;委托转发现已不产生 + // (return 请求值经 Await 步挂起结算),此臂仅作穷尽防御。 let completed = self.complete_generator_return(value); if let Some(completed) = completed? { self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); @@ -489,14 +493,14 @@ impl Vm { /// # 步骤 /// 1. Next/Throw:取内层 next/throw 方法并以请求值调用;无 throw 方法时回退 /// 内层 return()(无参 close),再无 return 方法时抛 TypeError 入 body。 - /// 2. Return:取内层 return 方法;缺失时以请求值直接完成(Complete); + /// 2. Return:取内层 return 方法;缺失时执行规范 Await 步(请求值经 + /// PromiseResolve 包装后登记恢复闭包挂起等结算,结算后以展开值完成); /// 可调用时调用。 /// 3. 调用结果 promise 直通或 PromiseResolve 包装,登记步进取续闭包 /// (Inner/Return/Close),置 `delegate_pending`。 /// /// # 返回值 /// - `Ok(Suspend)`:协议步等待(`delegate_pending` 已置,调用方经快照分支挂起); - /// - `Ok(Complete)`:内层无 return 方法,外层以请求值直接完成; /// - `Ok(Unwind)`:TypeError 已抛入 body(内层无 throw/return 方法),继续 dispatch; /// - `Err`:内层调用同步抛错,调用方走既有 Err 通道。 fn delegate_forward_async( @@ -522,9 +526,27 @@ impl Vm { return Err(self.error_message_text("TypeError", "iterator.next is not callable")); } GeneratorResumeMode::Return(v) => { - // 内层无 return 方法:外层直接完成,值为请求值。 - self.delegated_iterator = None; - return Ok(DelegateOutcome::Complete { value: v }); + // 内层无 return 方法:规范 return 分支的 Await 步——完成值是 + // 请求值经 Await 展开后的值(原生 promise 直通,其余经 + // PromiseResolve 包装),登记恢复闭包挂起等结算。 + let value_promise = if self.is_promise_value(v) { + v + } else { + match self.promise_resolve(v) { + Ok(p) => p, + Err(exc) => { + self.last_uncaught_value = Some(exc); + return Err(String::new()); + } + } + }; + let fulfill_fn = self.make_delegate_return_await_closure(gen_val, false); + let reject_fn = self.make_delegate_return_await_closure(gen_val, true); + let _ = self.perform_promise_then(value_promise, fulfill_fn, reject_fn); + self.delegated_iterator = Some(iterator); + let state = unsafe { &mut *self.async_gen_state_ptr(gen_val) }; + state.delegate_pending = Some(DelegateStep::ReturnAwait); + return Ok(DelegateOutcome::Suspend { value: JsValue::undefined() }); } GeneratorResumeMode::Throw(_) => { // 内层无 throw 方法:回退内层 return()(无参 close),步为 Close。 @@ -695,7 +717,9 @@ impl Vm { } /// 构造委托步进取续闭包:携带目标异步生成器上下文、协议步与 fulfill/reject 角色。 - pub(crate) fn make_delegate_step_closure(&mut self, ctx: JsValue, step: DelegateStep, reject_role: bool) -> JsValue { + pub(crate) fn make_delegate_step_closure( + &mut self, ctx: JsValue, step: DelegateStep, 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); @@ -713,6 +737,27 @@ impl Vm { self.add_fn_name_length(obj, "", 1); JsValue::from_js_object(ptr) } + + /// 构造委托 return 请求值 Await 恢复闭包:携带目标异步生成器上下文与 + /// fulfill/reject 角色,结算后以展开值完成生成器(拒绝时以拒绝原因终止)。 + fn make_delegate_return_await_closure(&mut self, ctx: 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_delegate_return_await_closure 是 NativeFn 函数项。 + func.set_native_fn(Some(unsafe { + NativeFnPtr::from_raw(async_gen_delegate_return_await_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)); + self.add_fn_name_length(obj, "", 1); + JsValue::from_js_object(ptr) + } } /// await 恢复闭包:读自身 prop 的异步生成器上下文与角色,恢复异步生成器继续执行。 @@ -874,9 +919,10 @@ fn async_gen_delegate_step_closure(vm: &mut Vm, args: &[u8]) -> NativeResult { let done = match vm.ordinary_get(result_obj, done_si, value) { Ok(d) => oxide_runtime_api::to_boolean(d), Err(e) => { - let exc = vm.last_uncaught_value.take().unwrap_or_else(|| { - oxide_builtins::error::create_from_text(vm, &e) - }); + let exc = vm + .last_uncaught_value + .take() + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); throw_delegate_into_body(vm, ctx, state_ptr, exc); return NativeResult::Ok(JsValue::undefined()); } @@ -885,9 +931,10 @@ fn async_gen_delegate_step_closure(vm: &mut Vm, args: &[u8]) -> NativeResult { let inner_value = match vm.ordinary_get(result_obj, value_si, value) { Ok(v) => v, Err(e) => { - let exc = vm.last_uncaught_value.take().unwrap_or_else(|| { - oxide_builtins::error::create_from_text(vm, &e) - }); + let exc = vm + .last_uncaught_value + .take() + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); throw_delegate_into_body(vm, ctx, state_ptr, exc); return NativeResult::Ok(JsValue::undefined()); } @@ -941,9 +988,12 @@ fn async_gen_delegate_step_closure(vm: &mut Vm, args: &[u8]) -> NativeResult { } DelegateStep::Close => { // close 分支(内层无 throw 方法):close 结算后抛 TypeError 入 body - // (协议违规);close 拒绝则抛拒绝原因入 body。 + // (协议违规);close 拒绝则抛拒绝原因入 body;close 结果非对象则抛 + // IteratorResult TypeError(与同步路径一致)。 let exc = if is_reject { value + } else if !value.is_object() { + oxide_builtins::error::create_type_error(vm, "IteratorResult is not an object") } else { oxide_builtins::error::create_type_error( vm, @@ -953,6 +1003,58 @@ fn async_gen_delegate_step_closure(vm: &mut Vm, args: &[u8]) -> NativeResult { throw_delegate_into_body(vm, ctx, state_ptr, exc); NativeResult::Ok(JsValue::undefined()) } + DelegateStep::ReturnAwait => { + // 该步由专用恢复闭包消费,步进取续闭包不处理(陈旧防御)。 + NativeResult::Ok(JsValue::undefined()) + } + } +} + +/// 委托 return 请求值 Await 恢复闭包:内层无 return 方法时,请求值 promise 结算后 +/// 以展开值完成生成器(规范 yield* 评估 return 分支的 Await 步);拒绝时以拒绝 +/// 原因终止生成器。 +fn async_gen_delegate_return_await_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, + "delegate return await 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 value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + if !ctx.is_object() { + return NativeResult::Ok(JsValue::undefined()); + } + let obj = unsafe { &*ctx.as_js_object_ptr() }; + if !obj.is_async_generator_obj() { + return NativeResult::Ok(JsValue::undefined()); + } + let state_ptr = vm.async_gen_state_ptr(ctx); + // 陈旧防御:状态盒的在途协议步必须与本闭包一致。 + if unsafe { (*state_ptr).delegate_pending } != Some(DelegateStep::ReturnAwait) { + return NativeResult::Ok(JsValue::undefined()); + } + let state = unsafe { &mut *state_ptr }; + if let Some(req) = state.current.as_mut() { + req.mode = if is_reject { + GeneratorResumeMode::Throw(value) + } else { + GeneratorResumeMode::Return(value) + }; + } + state.delegate_pending = None; + // 清挂起帧的委托迭代器(restore_into 会把它写回 VM,不清则恢复后再走 S0 转发)。 + state.suspended.delegated_iterator = None; + match vm.resume_async_generator(ctx) { + Ok(()) => NativeResult::Ok(JsValue::undefined()), + Err(e) => NativeResult::Err(oxide_builtins::error::create_from_text(vm, &e)), } } diff --git a/crates/oxide_vm/tests/async_gen_delegation_tests.rs b/crates/oxide_vm/tests/async_gen_delegation_tests.rs index fe6db4fe..a704b53c 100644 --- a/crates/oxide_vm/tests/async_gen_delegation_tests.rs +++ b/crates/oxide_vm/tests/async_gen_delegation_tests.rs @@ -324,3 +324,39 @@ fn t16_inner_next_sync_throw_thrown_into_body() { "\"caught:sync-e:true\"" ); } + +// T17:.return(v) 内层无 return 方法且请求值为 promise——规范 Await 步展开后 +// 以展开值完成(若引擎未 Await,r.value 为 promise 本身,字符串拼接形态不同)。 +#[test] +fn t17_return_without_inner_return_awaits_promise_value() { + assert_eq!( + eval( + "async function* g() { yield* { [Symbol.asyncIterator]() { \ + let first = true; return { \ + next() { if (first) { first = false; return Promise.resolve({ value: 1, done: false }); } \ + return Promise.resolve({ done: true }); } }; } }; } \ + (async function run() { const it = g(); await it.next(); \ + const r = await it.return(Promise.resolve('v17')); return r.value + ':' + r.done; })()" + ), + "\"v17:true\"" + ); +} + +// T18:.throw(e) 内层无 throw 方法且 close 结果非对象——抛 IteratorResult +// TypeError 入 body(与同步路径消息一致),可 catch。 +#[test] +fn t18_throw_close_non_object_result_typeerror() { + assert_eq!( + eval( + "async function* g() { try { yield* { [Symbol.asyncIterator]() { \ + let first = true; return { \ + next() { if (first) { first = false; return Promise.resolve({ value: 1, done: false }); } \ + return Promise.resolve({ done: true }); }, \ + return() { return Promise.resolve(42); } }; } }; } \ + catch (e) { return 'caught:' + e.message; } } \ + (async function run() { const it = g(); await it.next(); \ + const r = await it.throw('e18'); return r.value + ':' + r.done; })()" + ), + "\"caught:IteratorResult is not an object:true\"" + ); +}