mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-27 04:01:11 +08:00
fix: 异步生成器 return 委托补规范 Await 步与 close 非对象检出
This commit is contained in:
@@ -57,6 +57,8 @@ pub(crate) enum DelegateStep {
|
|||||||
Return,
|
Return,
|
||||||
/// 等内层 return()(close)的 promise 结算(外层 throw 请求,内层无 throw 方法)。
|
/// 等内层 return()(close)的 promise 结算(外层 throw 请求,内层无 throw 方法)。
|
||||||
Close,
|
Close,
|
||||||
|
/// 等请求值 promise 结算(外层 return 请求,内层无 return 方法,规范 Await 步)。
|
||||||
|
ReturnAwait,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 异步生成器挂起时的完整执行上下文快照 + 请求队列。
|
/// 异步生成器挂起时的完整执行上下文快照 + 请求队列。
|
||||||
@@ -381,6 +383,8 @@ impl Vm {
|
|||||||
self.regs[0] = value;
|
self.regs[0] = value;
|
||||||
}
|
}
|
||||||
Ok(DelegateOutcome::Complete { value }) => {
|
Ok(DelegateOutcome::Complete { value }) => {
|
||||||
|
// 共享枚举保留同步路径的 Complete 结局;委托转发现已不产生
|
||||||
|
// (return 请求值经 Await 步挂起结算),此臂仅作穷尽防御。
|
||||||
let completed = self.complete_generator_return(value);
|
let completed = self.complete_generator_return(value);
|
||||||
if let Some(completed) = completed? {
|
if let Some(completed) = completed? {
|
||||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
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 方法时回退
|
/// 1. Next/Throw:取内层 next/throw 方法并以请求值调用;无 throw 方法时回退
|
||||||
/// 内层 return()(无参 close),再无 return 方法时抛 TypeError 入 body。
|
/// 内层 return()(无参 close),再无 return 方法时抛 TypeError 入 body。
|
||||||
/// 2. Return:取内层 return 方法;缺失时以请求值直接完成(Complete);
|
/// 2. Return:取内层 return 方法;缺失时执行规范 Await 步(请求值经
|
||||||
|
/// PromiseResolve 包装后登记恢复闭包挂起等结算,结算后以展开值完成);
|
||||||
/// 可调用时调用。
|
/// 可调用时调用。
|
||||||
/// 3. 调用结果 promise 直通或 PromiseResolve 包装,登记步进取续闭包
|
/// 3. 调用结果 promise 直通或 PromiseResolve 包装,登记步进取续闭包
|
||||||
/// (Inner/Return/Close),置 `delegate_pending`。
|
/// (Inner/Return/Close),置 `delegate_pending`。
|
||||||
///
|
///
|
||||||
/// # 返回值
|
/// # 返回值
|
||||||
/// - `Ok(Suspend)`:协议步等待(`delegate_pending` 已置,调用方经快照分支挂起);
|
/// - `Ok(Suspend)`:协议步等待(`delegate_pending` 已置,调用方经快照分支挂起);
|
||||||
/// - `Ok(Complete)`:内层无 return 方法,外层以请求值直接完成;
|
|
||||||
/// - `Ok(Unwind)`:TypeError 已抛入 body(内层无 throw/return 方法),继续 dispatch;
|
/// - `Ok(Unwind)`:TypeError 已抛入 body(内层无 throw/return 方法),继续 dispatch;
|
||||||
/// - `Err`:内层调用同步抛错,调用方走既有 Err 通道。
|
/// - `Err`:内层调用同步抛错,调用方走既有 Err 通道。
|
||||||
fn delegate_forward_async(
|
fn delegate_forward_async(
|
||||||
@@ -522,9 +526,27 @@ impl Vm {
|
|||||||
return Err(self.error_message_text("TypeError", "iterator.next is not callable"));
|
return Err(self.error_message_text("TypeError", "iterator.next is not callable"));
|
||||||
}
|
}
|
||||||
GeneratorResumeMode::Return(v) => {
|
GeneratorResumeMode::Return(v) => {
|
||||||
// 内层无 return 方法:外层直接完成,值为请求值。
|
// 内层无 return 方法:规范 return 分支的 Await 步——完成值是
|
||||||
self.delegated_iterator = None;
|
// 请求值经 Await 展开后的值(原生 promise 直通,其余经
|
||||||
return Ok(DelegateOutcome::Complete { value: v });
|
// 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(_) => {
|
GeneratorResumeMode::Throw(_) => {
|
||||||
// 内层无 throw 方法:回退内层 return()(无参 close),步为 Close。
|
// 内层无 throw 方法:回退内层 return()(无参 close),步为 Close。
|
||||||
@@ -695,7 +717,9 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 构造委托步进取续闭包:携带目标异步生成器上下文、协议步与 fulfill/reject 角色。
|
/// 构造委托步进取续闭包:携带目标异步生成器上下文、协议步与 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 fn_proto = self.session.builtin_world().fn_proto_val();
|
||||||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||||||
func.set_function(true);
|
func.set_function(true);
|
||||||
@@ -713,6 +737,27 @@ 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 请求值 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 的异步生成器上下文与角色,恢复异步生成器继续执行。
|
/// 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) {
|
let done = match vm.ordinary_get(result_obj, done_si, value) {
|
||||||
Ok(d) => oxide_runtime_api::to_boolean(d),
|
Ok(d) => oxide_runtime_api::to_boolean(d),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let exc = vm.last_uncaught_value.take().unwrap_or_else(|| {
|
let exc = vm
|
||||||
oxide_builtins::error::create_from_text(vm, &e)
|
.last_uncaught_value
|
||||||
});
|
.take()
|
||||||
|
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||||||
throw_delegate_into_body(vm, ctx, state_ptr, exc);
|
throw_delegate_into_body(vm, ctx, state_ptr, exc);
|
||||||
return NativeResult::Ok(JsValue::undefined());
|
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) {
|
let inner_value = match vm.ordinary_get(result_obj, value_si, value) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let exc = vm.last_uncaught_value.take().unwrap_or_else(|| {
|
let exc = vm
|
||||||
oxide_builtins::error::create_from_text(vm, &e)
|
.last_uncaught_value
|
||||||
});
|
.take()
|
||||||
|
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||||||
throw_delegate_into_body(vm, ctx, state_ptr, exc);
|
throw_delegate_into_body(vm, ctx, state_ptr, exc);
|
||||||
return NativeResult::Ok(JsValue::undefined());
|
return NativeResult::Ok(JsValue::undefined());
|
||||||
}
|
}
|
||||||
@@ -941,9 +988,12 @@ fn async_gen_delegate_step_closure(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
|||||||
}
|
}
|
||||||
DelegateStep::Close => {
|
DelegateStep::Close => {
|
||||||
// close 分支(内层无 throw 方法):close 结算后抛 TypeError 入 body
|
// close 分支(内层无 throw 方法):close 结算后抛 TypeError 入 body
|
||||||
// (协议违规);close 拒绝则抛拒绝原因入 body。
|
// (协议违规);close 拒绝则抛拒绝原因入 body;close 结果非对象则抛
|
||||||
|
// IteratorResult TypeError(与同步路径一致)。
|
||||||
let exc = if is_reject {
|
let exc = if is_reject {
|
||||||
value
|
value
|
||||||
|
} else if !value.is_object() {
|
||||||
|
oxide_builtins::error::create_type_error(vm, "IteratorResult is not an object")
|
||||||
} else {
|
} else {
|
||||||
oxide_builtins::error::create_type_error(
|
oxide_builtins::error::create_type_error(
|
||||||
vm,
|
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);
|
throw_delegate_into_body(vm, ctx, state_ptr, exc);
|
||||||
NativeResult::Ok(JsValue::undefined())
|
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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -324,3 +324,39 @@ fn t16_inner_next_sync_throw_thrown_into_body() {
|
|||||||
"\"caught:sync-e:true\""
|
"\"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\""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user