feat: for-await-of + Symbol.asyncIterator + AsyncFromSyncIterator

This commit is contained in:
爱特每羊队
2026-08-10 03:21:37 +08:00
parent 89a4e1bb86
commit 012a8e5110
15 changed files with 696 additions and 16 deletions
+2 -1
View File
@@ -109,7 +109,8 @@ fn decode_symbol_key<H: VmHost>(vm: &H, key: u32) -> JsValue {
4 => world.sym_split.as_ptr(),
5 => world.sym_to_primitive.as_ptr(),
6 => world.sym_has_instance.as_ptr(),
_ => world.sym_match_all.as_ptr(),
7 => world.sym_match_all.as_ptr(),
_ => world.sym_async_iterator.as_ptr(),
};
return JsValue::from_js_object(ptr as *mut JsObject);
}
+7
View File
@@ -207,6 +207,13 @@ define_opcodes! {
YIELD_STAR = 0x78 => "YIELD_STAR",
// `await`:rd=被等待的值(PromiseResolve 包装);挂起异步帧,恢复值经 reg 0 交付。
AWAIT = 0x79 => "AWAIT",
// for-await-of 步进:INIT(a=可迭代值) 取异步迭代器;NEXT 调用迭代器 next(),
// 结果写 rd(随后由 AWAIT 等待);DONE 读取 AWAIT 恢复值(a 槽)的 done 写 rd;
// CLOSE 执行异步 IteratorClose(return() 结果 await 后继续)。
FOR_AWAIT_OF_INIT = 0x7A => "FOR_AWAIT_OF_INIT",
FOR_AWAIT_OF_NEXT = 0x7B => "FOR_AWAIT_OF_NEXT",
FOR_AWAIT_OF_DONE = 0x7C => "FOR_AWAIT_OF_DONE",
FOR_AWAIT_OF_CLOSE = 0x7D => "FOR_AWAIT_OF_CLOSE",
// ── 位运算 (0x80-0x8F) ──
BIT_AND = 0x80 => "BIT_AND",
+68 -10
View File
@@ -1,16 +1,28 @@
//! for-of 语句 emit:`emit_for_of_statement` 迭代器协议遍历。
//! for-of 与 for-await-of 语句 emit。
//!
//! 同步 for-of 用 FOR_OF_* 指令;`for await` 用 FOR_AWAIT_OF_*:初始化取异步
//! 迭代器(缺失 `@@asyncIterator` 时回退 AsyncFromSyncIterator),每步
//! `next()` 结果经 `AWAIT` 挂起后检查 done。体内 await 语义由 `AWAIT` 指令
//! 原生提供(每次迭代都 await)。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{ForStatementLeft, Statement};
use oxide_parser::{ForOfStatement, ForStatementLeft, Statement};
impl Emitter {
pub(crate) fn emit_for_of_statement(&self, stmt: &Statement, ctx: &mut CompileCtx) -> Result<Option<u32>, String> {
let Statement::ForOfStatement(fo) = stmt else {
return Ok(None);
};
if fo.r#await {
return self.emit_for_await_of_statement(fo, ctx);
}
self.emit_sync_for_of_statement(fo, ctx)
}
fn emit_sync_for_of_statement(&self, fo: &ForOfStatement, ctx: &mut CompileCtx) -> Result<Option<u32>, String> {
let start_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
let iter_src_reg = self.emit_expression(&fo.right, ctx)?;
@@ -23,7 +35,59 @@ impl Emitter {
ctx.inst(Inst::jmp_if_false(has_reg, end_label));
let val_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::FOR_OF_NEXT, Operand::Reg(val_reg), Operand::None, Operand::None));
match &fo.left {
self.emit_for_of_left_assignment(&fo.left, val_reg, ctx)?;
self.emit_statement(&fo.body, ctx)?;
ctx.inst(Inst::jmp(start_label));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
ctx.inst(Inst::new(OpCode::FOR_OF_CLOSE, Operand::None, Operand::None, Operand::None));
ctx.pop_label_scopes(n_labeled);
ctx.pop_loop();
Ok(None)
}
/// for-await-of:异步迭代器协议遍历,每步经 `AWAIT` 挂起等待 next() 结果。
///
/// 指令序列:INIT 取异步迭代器 → 循环顶 NEXT 调 next() 写 promise → `AWAIT`
/// 挂起(恢复值经 reg 0 交付)→ LOAD_VAR 拷贝为结果对象 → DONE 检查 done →
/// FOR_OF_NEXT 读 value → 绑定左侧 → 循环体 → CLOSE 异步收尾。
fn emit_for_await_of_statement(&self, fo: &ForOfStatement, ctx: &mut CompileCtx) -> Result<Option<u32>, String> {
let start_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
let iter_src_reg = self.emit_expression(&fo.right, ctx)?;
ctx.inst(Inst::new(OpCode::FOR_AWAIT_OF_INIT, Operand::None, Operand::Reg(iter_src_reg), Operand::None));
ctx.labels.set_label_pos(start_label, ctx.insts.len());
ctx.push_loop(end_label, start_label);
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
let next_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::FOR_AWAIT_OF_NEXT, Operand::Reg(next_reg), Operand::None, Operand::None));
ctx.inst(Inst::await_expr(Operand::Reg(next_reg)));
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::None, Operand::None));
let has_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::FOR_AWAIT_OF_DONE,
Operand::Reg(has_reg),
Operand::Reg(result_reg),
Operand::None,
));
ctx.inst(Inst::jmp_if_false(has_reg, end_label));
let val_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::FOR_OF_NEXT, Operand::Reg(val_reg), Operand::None, Operand::None));
self.emit_for_of_left_assignment(&fo.left, val_reg, ctx)?;
self.emit_statement(&fo.body, ctx)?;
ctx.inst(Inst::jmp(start_label));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
ctx.inst(Inst::new(OpCode::FOR_AWAIT_OF_CLOSE, Operand::None, Operand::None, Operand::None));
ctx.pop_label_scopes(n_labeled);
ctx.pop_loop();
Ok(None)
}
/// for-of/for-await-of 左侧绑定:把当前迭代值 `val_reg` 写入声明/赋值目标。
fn emit_for_of_left_assignment(
&self, left: &ForStatementLeft, val_reg: u32, ctx: &mut CompileCtx,
) -> Result<(), String> {
match left {
ForStatementLeft::VariableDeclaration(decl) => {
for d in &decl.declarations {
self.emit_binding_pattern(&d.id, val_reg, decl.kind, false, ctx)?;
@@ -42,12 +106,6 @@ impl Emitter {
}
_ => return Err("unsupported for-of left-hand side".into()),
}
self.emit_statement(&fo.body, ctx)?;
ctx.inst(Inst::jmp(start_label));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
ctx.inst(Inst::new(OpCode::FOR_OF_CLOSE, Operand::None, Operand::None, Operand::None));
ctx.pop_label_scopes(n_labeled);
ctx.pop_loop();
Ok(None)
Ok(())
}
}
+6 -1
View File
@@ -71,8 +71,10 @@ impl Inst {
| OpCode::SPILL
| OpCode::FOR_IN_INIT
| OpCode::FOR_OF_INIT
| OpCode::FOR_AWAIT_OF_INIT
| OpCode::FOR_IN_CLEANUP
| OpCode::FOR_OF_CLOSE
| OpCode::FOR_AWAIT_OF_CLOSE
| OpCode::SUSPEND_BODY => None,
// 其余指令 rd 即 def(算术/比较/位/逻辑/加载族/迭代器 NEXT 等)
_ => reg_of(&self.rd),
@@ -308,8 +310,11 @@ impl Inst {
push_operand(&mut uses, &self.a);
}
// for-in/of 迭代器:INIT 读 a;NEXT/DONE 读迭代器栈隐式状态
OpCode::FOR_IN_INIT | OpCode::FOR_OF_INIT => push_operand(&mut uses, &self.a),
OpCode::FOR_IN_INIT | OpCode::FOR_OF_INIT | OpCode::FOR_AWAIT_OF_INIT => push_operand(&mut uses, &self.a),
OpCode::FOR_IN_NEXT | OpCode::FOR_IN_DONE | OpCode::FOR_OF_NEXT | OpCode::FOR_OF_DONE => {}
// for-await-of:NEXT 无寄存器 use;DONE 读取 AWAIT 恢复值(a 槽)的 done
OpCode::FOR_AWAIT_OF_NEXT | OpCode::FOR_AWAIT_OF_CLOSE => {}
OpCode::FOR_AWAIT_OF_DONE => push_operand(&mut uses, &self.a),
// REST_OBJECT:读 a(src)与可选 b(运行时 excluded 数组),ext 是 excluded_idx 常量
OpCode::REST_OBJECT => {
push_operand(&mut uses, &self.a);
+8
View File
@@ -242,6 +242,7 @@ pub struct BuiltinWorld {
pub sym_to_primitive: P<JsObject>,
pub sym_has_instance: P<JsObject>,
pub sym_match_all: P<JsObject>,
pub sym_async_iterator: P<JsObject>,
pub stub_objects: Vec<P<JsObject>>,
}
@@ -628,6 +629,7 @@ impl BuiltinWorld {
BuiltinId::SymToPrimitive => &self.sym_to_primitive,
BuiltinId::SymHasInstance => &self.sym_has_instance,
BuiltinId::SymMatchAll => &self.sym_match_all,
BuiltinId::SymAsyncIterator => &self.sym_async_iterator,
}
}
@@ -668,6 +670,7 @@ impl BuiltinWorld {
let sym_to_primitive = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
let sym_has_instance = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
let sym_match_all = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
let sym_async_iterator = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
let stub_objects = Vec::new();
let world = Self {
@@ -739,6 +742,7 @@ impl BuiltinWorld {
sym_to_primitive,
sym_has_instance,
sym_match_all,
sym_async_iterator,
stub_objects,
};
wire_builtin_world_links(&world);
@@ -811,6 +815,7 @@ impl BuiltinWorld {
sym_to_primitive,
sym_has_instance,
sym_match_all,
sym_async_iterator,
) = if dirty.symbol_family {
let (symbol_proto, symbol_constructor) = make_named_pair(string_forge, shape_forge, labels, "Symbol");
(
@@ -824,6 +829,7 @@ impl BuiltinWorld {
P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
)
} else {
(
@@ -837,6 +843,7 @@ impl BuiltinWorld {
current.sym_to_primitive.clone(),
current.sym_has_instance.clone(),
current.sym_match_all.clone(),
current.sym_async_iterator.clone(),
)
};
@@ -981,6 +988,7 @@ impl BuiltinWorld {
sym_to_primitive,
sym_has_instance,
sym_match_all,
sym_async_iterator,
stub_objects,
};
wire_builtin_world_links(&world);
+5 -2
View File
@@ -225,7 +225,7 @@ pub struct KernelSession {
/// 维护注意:每个新增的 `BuiltinWorld` 对象字段都必须加到这里以及
/// `KernelSession::dirty_since_snapshot()`,以便选择性重置重建正确的
/// builtin 家族。
pub const NUM_BUILTINS: usize = 67;
pub const NUM_BUILTINS: usize = 68;
/// 内置对象枚举 id,与 `BuiltinWorld` 中的存储槽一一对应。
///
@@ -301,6 +301,7 @@ pub enum BuiltinId {
SymToPrimitive = 64,
SymHasInstance = 65,
SymMatchAll = 66,
SymAsyncIterator = 67,
}
impl BuiltinId {
@@ -373,6 +374,7 @@ impl BuiltinId {
BuiltinId::SymToPrimitive,
BuiltinId::SymHasInstance,
BuiltinId::SymMatchAll,
BuiltinId::SymAsyncIterator,
];
}
@@ -557,7 +559,8 @@ impl KernelSession {
|| gen(BuiltinId::SymIterator) != snap(BuiltinId::SymIterator)
|| gen(BuiltinId::SymToPrimitive) != snap(BuiltinId::SymToPrimitive)
|| gen(BuiltinId::SymHasInstance) != snap(BuiltinId::SymHasInstance)
|| gen(BuiltinId::SymMatchAll) != snap(BuiltinId::SymMatchAll),
|| gen(BuiltinId::SymMatchAll) != snap(BuiltinId::SymMatchAll)
|| gen(BuiltinId::SymAsyncIterator) != snap(BuiltinId::SymAsyncIterator),
math: gen(BuiltinId::MathObject) != snap(BuiltinId::MathObject),
json: gen(BuiltinId::JsonObject) != snap(BuiltinId::JsonObject),
date: gen(BuiltinId::DateConstructor) != snap(BuiltinId::DateConstructor)
+1 -1
View File
@@ -17,7 +17,7 @@ pub const PRIVATE_NAME_BASE: u32 = 0x8000_0000;
pub const SYMBOL_KEY_BASE: u32 = 0xA000_0000;
/// 保留给 well-known symbol 的键槽位数(位于 Symbol 键区间最低端)。
pub const WELL_KNOWN_SYMBOL_COUNT: u32 = 8;
pub const WELL_KNOWN_SYMBOL_COUNT: u32 = 9;
/// 用户 symbol 下标的保留位掩码(低 28 位)。
const SYMBOL_INDEX_MASK: u32 = 0x0FFF_FFFF;
+402
View File
@@ -0,0 +1,402 @@
//! AsyncFromSyncIterator:把同步迭代器包装为异步迭代器,供 for-await-of 回退消费。
//!
//! GetAsyncIterator 对没有 `@@asyncIterator` 的普通可迭代对象(数组/字符串等)
//! 走同步迭代协议取迭代器,再包一层 AsyncFromSyncIterator:其 `next`/`return`/`throw`
//! 转发内层同步迭代器并把结果包成 Promise(非对象结果按 TypeError 拒绝),
//! `@@asyncIterator` 返回自身。
use oxide_builtins::iterator::make_iter_result;
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_runtime_api::NativeResult;
use oxide_types::object::{JsObject, NativeFnPtr};
use oxide_types::private_key::make_well_known_symbol_key;
use oxide_types::value::JsValue;
use crate::vm::Vm;
/// AsyncFromSyncIterator 对象上存内层同步迭代器的属性名。
const INNER_PROP: &str = "__inner__";
/// `@@asyncIterator` 的 well-known symbol 键序号。
const ASYNC_ITERATOR_SYMBOL_ID: u32 = 8;
/// GetAsyncIterator(ECMA-262):取 `value[@@asyncIterator]`,不可调用时回退同步
/// 迭代器并包 AsyncFromSyncIterator。
///
/// # 步骤
/// 1. ToObject 后读取 `@@asyncIterator`,可调用则调用并校验结果为对象。
/// 2. 否则经同步迭代协议取迭代器包装器,包成 AsyncFromSyncIterator。
///
/// # 返回值
/// - `Ok(iterator)`:异步迭代器对象;
/// - `Err`:`@@asyncIterator` getter/调用抛错或 ToObject 失败,透传原异常值。
pub(crate) fn make_async_iterator(vm: &mut Vm, value: JsValue) -> Result<JsValue, JsValue> {
let obj_value = if value.is_object() {
value
} else {
match oxide_runtime_api::to_object(value, vm) {
Ok(o) => o,
Err(e) => return Err(oxide_builtins::error::create_type_error(vm, &e)),
}
};
let obj = unsafe { &*obj_value.as_js_object_ptr() };
let aiter_key = make_well_known_symbol_key(ASYNC_ITERATOR_SYMBOL_ID);
let method = match vm.ordinary_get(obj, aiter_key, obj_value) {
Ok(m) => m,
Err(e) => {
let exc = vm
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_type_error(vm, &e));
return Err(exc);
}
};
if oxide_builtins::iterator::is_callable(method) {
let iterator = match vm.call_function_sync(method, obj_value, &[]) {
Ok(it) => it,
Err(e) => {
let exc = vm
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_type_error(vm, &e));
return Err(exc);
}
};
if !iterator.is_object() {
return Err(oxide_builtins::error::create_type_error(
vm,
"Result of the Symbol.asyncIterator method is not an object",
));
}
return Ok(iterator);
}
let sync = oxide_builtins::iterator::make_iterator_for_value(vm, value)?;
Ok(vm.create_async_from_sync_iterator(sync))
}
impl Vm {
/// 创建 AsyncFromSyncIterator 包装器:挂内层同步迭代器,装 next/return/throw 与
/// `@@asyncIterator`(返回自身)方法。
pub(crate) fn create_async_from_sync_iterator(&mut self, sync_iter: JsValue) -> JsValue {
let next_fn = make_wrapper_fn(self, async_from_sync_next as *const ());
let return_fn = make_wrapper_fn(self, async_from_sync_return as *const ());
let throw_fn = make_wrapper_fn(self, async_from_sync_throw as *const ());
let self_fn = make_wrapper_fn(self, async_from_sync_symbol_async_iterator as *const ());
let object_proto = self.session.builtin_world().object_proto.as_ptr() as *mut JsObject;
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto)));
let obj = unsafe { &mut *ptr };
let inner_si = self.kernel_core.perm_interner().intern(INNER_PROP).0;
self.set_or_create_prop_value(obj, inner_si, sync_iter);
let next_si = self.kernel_core.perm_interner().intern("next").0;
self.set_or_create_prop_value(obj, next_si, next_fn);
let return_si = self.kernel_core.perm_interner().intern("return").0;
self.set_or_create_prop_value(obj, return_si, return_fn);
let throw_si = self.kernel_core.perm_interner().intern("throw").0;
self.set_or_create_prop_value(obj, throw_si, throw_fn);
let aiter_key = make_well_known_symbol_key(ASYNC_ITERATOR_SYMBOL_ID);
self.set_or_create_prop_value(obj, aiter_key, self_fn);
JsValue::from_js_object(ptr)
}
}
/// 构造包装器方法 native 函数对象(name/length 属性由 `add_fn_name_length` 补全)。
fn make_wrapper_fn(vm: &mut Vm, native_fn: *const ()) -> JsValue {
let fn_proto = vm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true);
// SAFETY: native_fn 来自 NativeFn 函数项。
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(native_fn) }));
func.set_native_arg_count(1);
let ptr = vm.alloc_object(func);
let obj = unsafe { &mut *ptr };
vm.add_fn_name_length(obj, "", 1);
JsValue::from_js_object(ptr)
}
/// 读取包装器对象上的内层同步迭代器;接收者非法或内层缺失时返回 TypeError。
fn sync_inner(vm: &mut Vm, this_val: JsValue) -> Result<JsValue, JsValue> {
if !this_val.is_object() {
return Err(oxide_builtins::error::create_type_error(
vm,
"AsyncFromSyncIterator methods called on non-object",
));
}
let obj = unsafe { &*this_val.as_js_object_ptr() };
let inner_si = vm.kernel_core.perm_interner().intern(INNER_PROP).0;
match vm.ordinary_get(obj, inner_si, this_val) {
Ok(inner) if !inner.is_undefined() => Ok(inner),
_ => Err(oxide_builtins::error::create_type_error(vm, "AsyncFromSyncIterator has no sync iterator")),
}
}
/// AsyncFromSyncIteratorContinuation 的 unwrap 函数闭包上存目标 resolve 的属性名。
const ASFS_RESOLVE_PROP: &str = "__oxide_asfs_resolve__";
/// unwrap 函数闭包上存 done 标志的属性名。
const ASFS_DONE_PROP: &str = "__oxide_asfs_done__";
/// reject-close 闭包上存目标 reject 的属性名。
const ASFS_REJECT_PROP: &str = "__oxide_asfs_reject__";
/// reject-close 闭包上存内层同步迭代器的属性名。
const ASFS_INNER_PROP: &str = "__oxide_asfs_inner__";
/// AsyncFromSyncIteratorContinuation:解出同步迭代器结果对象的 done/value,
/// value 经 PromiseResolve 后 await,最终以 `{value: 解开值, done}` 结算能力。
/// 任一步骤抛错(done/value getter、PromiseResolve 的 constructor getter)都拒绝;
/// `close_on_rejection` 时 valueWrapper 拒绝还会先关闭内层同步迭代器。
///
/// # 参数
/// - `inner`:内层同步迭代器(关闭目标)。
/// - `result`:内层同步方法调用结果(`Err` 为调用抛出的字符串展平文本)。
fn continue_async_from_sync(vm: &mut Vm, inner: JsValue, result: Result<JsValue, String>, close_on_rejection: bool) -> NativeResult {
let (promise, resolve, reject) = vm.new_promise_capability();
let reject_with = |vm: &mut Vm, exc: JsValue| {
if close_on_rejection {
close_sync_iterator(vm, inner);
}
let _ = vm.reject_promise(promise, exc);
};
match result {
Ok(r) if r.is_object() => {
let result_obj = unsafe { &*r.as_js_object_ptr() };
let done_si = vm.kernel_core.perm_interner().intern("done").0;
let done = match vm.ordinary_get(result_obj, done_si, r) {
Ok(d) => oxide_runtime_api::to_boolean(d),
Err(e) => {
let exc = vm
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e));
reject_with(vm, exc);
return NativeResult::Ok(promise);
}
};
let value_si = vm.kernel_core.perm_interner().intern("value").0;
let value = match vm.ordinary_get(result_obj, value_si, r) {
Ok(v) => v,
Err(e) => {
let exc = vm
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e));
reject_with(vm, exc);
return NativeResult::Ok(promise);
}
};
let value_wrapper = match vm.promise_resolve(value) {
Ok(w) => w,
Err(e) => {
reject_with(vm, e);
return NativeResult::Ok(promise);
}
};
let fulfill = make_unwrap_fn(vm, resolve, done);
let on_rejected = if close_on_rejection {
make_reject_close_fn(vm, reject, inner)
} else {
reject
};
let _ = vm.perform_promise_then(value_wrapper, fulfill, on_rejected);
NativeResult::Ok(promise)
}
Ok(_) => {
let err = oxide_builtins::error::create_type_error(vm, "sync iterator result is not an object");
reject_with(vm, err);
NativeResult::Ok(promise)
}
Err(e) => {
let exc = vm
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e));
reject_with(vm, exc);
NativeResult::Ok(promise)
}
}
}
/// 同步关闭内层迭代器(IteratorClose 的 return 调用),忽略 return 自身抛错。
fn close_sync_iterator(vm: &mut Vm, inner: JsValue) {
if !inner.is_object() {
return;
}
let inner_obj = unsafe { &*inner.as_js_object_ptr() };
let return_si = vm.kernel_core.perm_interner().intern("return").0;
let return_fn = match vm.ordinary_get(inner_obj, return_si, inner) {
Ok(f) => f,
Err(_) => return,
};
if oxide_builtins::iterator::is_callable(return_fn) {
let _ = vm.call_function_sync(return_fn, inner, &[]);
}
}
/// 构造 valueWrapper 拒绝时关闭迭代器的闭包:携带目标 reject 与内层同步迭代器。
fn make_reject_close_fn(vm: &mut Vm, reject: JsValue, inner: JsValue) -> JsValue {
let fn_proto = vm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true);
// SAFETY: async_from_sync_reject_close 是 NativeFn 函数项。
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(async_from_sync_reject_close as *const ()) }));
func.set_native_arg_count(1);
let ptr = vm.alloc_object(func);
let obj = unsafe { &mut *ptr };
let rej_si = vm.kernel_core.perm_interner().intern(ASFS_REJECT_PROP).0;
vm.set_or_create_prop_value(obj, rej_si, reject);
let inner_si = vm.kernel_core.perm_interner().intern(ASFS_INNER_PROP).0;
vm.set_or_create_prop_value(obj, inner_si, inner);
vm.add_fn_name_length(obj, "", 1);
JsValue::from_js_object(ptr)
}
/// reject-close 闭包:关闭内层同步迭代器后以原拒绝原因结算能力。
fn async_from_sync_reject_close(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, "reject handler is invalid"));
}
let callee_obj = unsafe { &*callee.as_js_object_ptr() };
let rej_si = vm.kernel_core.perm_interner().intern(ASFS_REJECT_PROP).0;
let reject = vm.resolve_property(callee_obj, rej_si).unwrap_or(JsValue::undefined());
let inner_si = vm.kernel_core.perm_interner().intern(ASFS_INNER_PROP).0;
let inner = vm.resolve_property(callee_obj, inner_si).unwrap_or(JsValue::undefined());
let error = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
close_sync_iterator(vm, inner);
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[error]);
NativeResult::Ok(JsValue::undefined())
}
/// 构造 AsyncFromSyncIteratorContinuation 的 value unwrap 闭包:携带目标 resolve 与
/// done 标志,valueWrapper settle 后把解开值包成 `{value, done}` 结算。
fn make_unwrap_fn(vm: &mut Vm, resolve: JsValue, done: bool) -> JsValue {
let fn_proto = vm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true);
// SAFETY: async_from_sync_unwrap 是 NativeFn 函数项。
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(async_from_sync_unwrap as *const ()) }));
func.set_native_arg_count(1);
let ptr = vm.alloc_object(func);
let obj = unsafe { &mut *ptr };
let res_si = vm.kernel_core.perm_interner().intern(ASFS_RESOLVE_PROP).0;
vm.set_or_create_prop_value(obj, res_si, resolve);
let done_si = vm.kernel_core.perm_interner().intern(ASFS_DONE_PROP).0;
vm.set_or_create_prop_value(obj, done_si, JsValue::bool(done));
vm.add_fn_name_length(obj, "", 1);
JsValue::from_js_object(ptr)
}
/// value unwrap 闭包:读自身 prop 的 resolve 与 done,把入参包装为迭代器结果结算。
fn async_from_sync_unwrap(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, "unwrap handler is invalid"));
}
let callee_obj = unsafe { &*callee.as_js_object_ptr() };
let res_si = vm.kernel_core.perm_interner().intern(ASFS_RESOLVE_PROP).0;
let resolve = vm.resolve_property(callee_obj, res_si).unwrap_or(JsValue::undefined());
let done_si = vm.kernel_core.perm_interner().intern(ASFS_DONE_PROP).0;
let done = vm
.resolve_property(callee_obj, done_si)
.map_or(false, oxide_runtime_api::to_boolean);
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let result = make_iter_result(vm, value, done);
let _ = vm.call_function_sync(resolve, JsValue::undefined(), &[result]);
NativeResult::Ok(JsValue::undefined())
}
/// `AsyncFromSyncIterator.next(value)`:转发内层 `next`,结果经 continuation 结算。
/// 未传实参时不向 `next` 传参(与 IteratorNext 的空实参调用一致)。
fn async_from_sync_next(vm: &mut Vm, args: &[u8]) -> NativeResult {
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
let inner = match sync_inner(vm, this_val) {
Ok(i) => i,
Err(e) => return NativeResult::Err(e),
};
let next_si = vm.kernel_core.perm_interner().intern("next").0;
let next_fn = match vm.ordinary_get(unsafe { &*inner.as_js_object_ptr() }, next_si, inner) {
Ok(f) => f,
Err(e) => {
let exc = vm
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e));
return NativeResult::Err(exc);
}
};
let result = if args.len() > 1 {
vm.call_function_sync(next_fn, inner, &[vm.reg(args[1])])
} else {
vm.call_function_sync(next_fn, inner, &[])
};
continue_async_from_sync(vm, inner, result, true)
}
/// `AsyncFromSyncIterator.return(value)`:内层无 `return` 时直接以 `{value, done:true}`
/// 完成,否则转发并经 continuation 结算。
fn async_from_sync_return(vm: &mut Vm, args: &[u8]) -> NativeResult {
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
let arg = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let inner = match sync_inner(vm, this_val) {
Ok(i) => i,
Err(e) => return NativeResult::Err(e),
};
let return_si = vm.kernel_core.perm_interner().intern("return").0;
let return_fn = match vm.ordinary_get(unsafe { &*inner.as_js_object_ptr() }, return_si, inner) {
Ok(f) => f,
Err(e) => {
let exc = vm
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e));
return NativeResult::Err(exc);
}
};
if !oxide_builtins::iterator::is_callable(return_fn) {
let result = make_iter_result(vm, arg, true);
let (promise, _, _) = vm.new_promise_capability();
let _ = vm.resolve_promise(promise, result);
return NativeResult::Ok(promise);
}
let result = if args.len() > 1 {
vm.call_function_sync(return_fn, inner, &[arg])
} else {
vm.call_function_sync(return_fn, inner, &[])
};
continue_async_from_sync(vm, inner, result, false)
}
/// `AsyncFromSyncIterator.throw(value)`:内层无 `throw` 时拒绝,否则转发并经 continuation 结算。
fn async_from_sync_throw(vm: &mut Vm, args: &[u8]) -> NativeResult {
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
let arg = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let inner = match sync_inner(vm, this_val) {
Ok(i) => i,
Err(e) => return NativeResult::Err(e),
};
let throw_si = vm.kernel_core.perm_interner().intern("throw").0;
let throw_fn = match vm.ordinary_get(unsafe { &*inner.as_js_object_ptr() }, throw_si, inner) {
Ok(f) => f,
Err(e) => {
let exc = vm
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e));
return NativeResult::Err(exc);
}
};
if !oxide_builtins::iterator::is_callable(throw_fn) {
let (promise, _, _reject) = vm.new_promise_capability();
let err = oxide_builtins::error::create_type_error(vm, "sync iterator has no throw method");
let _ = vm.reject_promise(promise, err);
return NativeResult::Ok(promise);
}
let result = if args.len() > 1 {
vm.call_function_sync(throw_fn, inner, &[arg])
} else {
vm.call_function_sync(throw_fn, inner, &[])
};
continue_async_from_sync(vm, inner, result, false)
}
/// `AsyncFromSyncIterator[@@asyncIterator]`:返回自身。
fn async_from_sync_symbol_async_iterator(vm: &mut Vm, args: &[u8]) -> NativeResult {
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
NativeResult::Ok(this_val)
}
+12 -1
View File
@@ -391,11 +391,22 @@ impl Vm {
/// - 异步生成器内(`async_gen_dispatch`)登记异步生成器恢复闭包并置
/// `async_gen_suspended`;普通异步函数走 `async_suspended`。
pub(crate) fn dispatch_await(&mut self, rd: usize) -> Result<(), String> {
let value = self.regs[rd];
self.perform_await(value)
}
/// await 核心:PromiseResolve 包装被等待值、登记恢复反应,置挂起信号。
///
/// # 副作用
/// - 被等待值为原生 Promise 时直接复用,否则建新 promise 并 PromiseResolve。
/// - 经 `perform_promise_then` 登记 fulfill/reject 恢复反应(微任务入队)。
/// - 异步生成器内(`async_gen_dispatch`)登记异步生成器恢复闭包并置
/// `async_gen_suspended`;普通异步函数走 `async_suspended`。
pub(crate) fn perform_await(&mut self, value: JsValue) -> Result<(), String> {
let ctx = match self.async_context {
Some(c) => c,
None => return Err("AWAIT executed outside async function".into()),
};
let value = self.regs[rd];
let promise = if self.is_promise_value(value) {
value
} else {
+18
View File
@@ -826,6 +826,12 @@ pub(crate) fn async_generator_throw(vm: &mut Vm, args: &[u8]) -> NativeResult {
}
}
/// `%AsyncGeneratorPrototype%[@@asyncIterator]`:异步生成器自身即是异步迭代器,返回 `this`。
pub(crate) fn async_generator_symbol_async_iterator(vm: &mut Vm, args: &[u8]) -> NativeResult {
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
NativeResult::Ok(this_val)
}
/// 初始化/重建异步生成器内建对象:`%AsyncGeneratorPrototype%`、
/// `%AsyncGeneratorFunction.prototype%` 与占位 `%AsyncGeneratorFunction%`。
///
@@ -853,6 +859,18 @@ pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) {
ag_proto.set_shape_id(tag_shape);
let tag_pos = ag_proto.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("AsyncGenerator").0)));
ag_proto.set_data_meta(tag_pos, PropAttributes::new(false, false, true));
// @@asyncIterator:返回自身(异步生成器是异步可迭代对象,供 for-await-of 消费)。
let aiter_key = oxide_types::private_key::make_well_known_symbol_key(8);
let _ = oxide_kernel::builtin::BuiltinWorld::bind_method_key_static(
&mut ag_proto,
sh,
sf,
aiter_key,
"@@asyncIterator",
unsafe { oxide_types::object::NativeFnPtr::from_raw(async_generator_symbol_async_iterator as *const ()) },
0,
fn_proto_val,
);
vm.async_generator_proto = P::new(*ag_proto);
// %AsyncGeneratorFunction.prototype%:proto = Function.prototype,constructor = %AsyncGeneratorFunction%。
@@ -66,6 +66,10 @@ pub fn bind_symbol(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
"matchAll",
JsValue::from_js_object(session.builtin_world().sym_match_all.as_ptr() as *mut JsObject),
),
(
"asyncIterator",
JsValue::from_js_object(session.builtin_world().sym_async_iterator.as_ptr() as *mut JsObject),
),
] {
bind_well_known_symbol(core, ctor, name, val);
}
+1
View File
@@ -8,6 +8,7 @@
//! session 内存回收;`bindings` 把内置对象绑定到每个 session 的 global 上。
mod async_func;
mod async_from_sync;
mod async_generator;
/// 内置对象绑定模块:向 session 的 global 对象安装 Object/Array/... 及各原型。
pub mod bindings;
+33
View File
@@ -373,6 +373,39 @@ impl Vm {
Ok(())
}
/// PromiseResolve(%Promise%, value)核心:value 为原生 Promise 时读取其
/// `constructor`,与 %Promise% 相同则原样返回;否则新建能力并经能力 resolve
/// 结算(thenable 委托)。constructor getter / 结算抛错时透传原异常值。
pub(crate) fn promise_resolve(&mut self, value: JsValue) -> Result<JsValue, JsValue> {
if self.is_promise_value(value) {
let obj = unsafe { &*value.as_js_object_ptr() };
let ctor_si = self.kernel_core.perm_interner().intern("constructor").0;
let ctor = match self.ordinary_get(obj, ctor_si, value) {
Ok(c) => c,
Err(e) => {
let exc = self
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(self, &e));
return Err(exc);
}
};
let intrinsic = JsValue::from_js_object(self.promise_constructor.as_ptr() as *mut JsObject);
if oxide_runtime_api::same_value(ctor, intrinsic) {
return Ok(value);
}
}
let (promise, _resolve, _) = self.new_promise_capability();
if let Err(e) = self.resolve_promise(promise, value) {
let exc = self
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(self, &e));
return Err(exc);
}
Ok(promise)
}
/// `PerformPromiseThen` 核心:注册 fulfill/reject 两条反应;已 settle 则直接入队。
pub(crate) fn perform_promise_then(
&mut self, this_val: JsValue, on_fulfilled: JsValue, on_rejected: JsValue,
+24
View File
@@ -782,6 +782,8 @@ impl Vm {
Some(6)
} else if std::ptr::eq(ptr, world.sym_match_all.as_ptr()) {
Some(7)
} else if std::ptr::eq(ptr, world.sym_async_iterator.as_ptr()) {
Some(8)
} else {
None
};
@@ -1520,6 +1522,28 @@ impl Vm {
self.dispatch_for_of_close()?;
}
OpCode::FOR_AWAIT_OF_INIT => {
self.dispatch_for_await_of_init(a)?;
}
OpCode::FOR_AWAIT_OF_NEXT => {
self.dispatch_for_await_of_next(rd)?;
}
OpCode::FOR_AWAIT_OF_DONE => {
self.dispatch_for_await_of_done(rd, a)?;
}
OpCode::FOR_AWAIT_OF_CLOSE => {
self.dispatch_for_await_of_close()?;
// 异步 IteratorClose 可能经 await 挂起(return() 的 promise),
// 挂起时须像 AWAIT 一样让内嵌 dispatch 返回,由恢复方快照状态。
if self.async_suspended || self.async_gen_suspended {
self.profiling.set_instruction_count(steps);
return Ok(JsValue::undefined());
}
}
OpCode::REST_OBJECT => {
self.dispatch_rest_object(rd, a, b)?;
}
+105
View File
@@ -460,6 +460,111 @@ impl Vm {
}
}
/// for-await-of 初始化:按 GetAsyncIterator 协议取异步迭代器(缺失 `@@asyncIterator`
/// 时回退同步迭代器并包 AsyncFromSyncIterator),压入 for-of 迭代器栈。
pub(crate) fn dispatch_for_await_of_init(&mut self, a: usize) -> Result<(), String> {
vm_trace!("FOR_AWAIT_OF_INIT r{}={:?}", a, self.regs[a]);
let iterable = self.regs[a];
match crate::async_from_sync::make_async_iterator(self, iterable) {
Ok(iterator) => {
self.iters.push_for_of(iterator);
self.iters.clear_last_for_of_result();
Ok(())
}
Err(err) => {
self.exception_value = Some(err);
self.pending_error_kind = Some(self.thrown_error_kind(err));
self.unwind()
}
}
}
/// for-await-of 步进:调用迭代器 `next()`,把返回的 promise 写入 rd。
/// 随后的 `AWAIT` 负责挂起等待;next() 抛出时弹出迭代器并透传(与同步 for-of 一致)。
pub(crate) fn dispatch_for_await_of_next(&mut self, rd: usize) -> Result<(), String> {
vm_trace!("FOR_AWAIT_OF_NEXT rd={}", rd);
self.last_uncaught_value = None;
let Some(iterator) = self.iters.last_for_of() else {
return Err("FOR_AWAIT_OF_NEXT without active iterator".into());
};
if !iterator.is_object() {
return Err("FOR_AWAIT_OF_NEXT iterator is not an object".into());
}
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
let next_si = self.kernel_core.perm_interner().intern("next").0;
let next_fn = match self.ordinary_get(iter_obj, next_si, iterator) {
Ok(v) => v,
Err(e) => return self.throw_for_of_error(e),
};
let result = match self.call_function_sync(next_fn, iterator, &[]) {
Ok(v) => v,
Err(e) => return self.throw_for_of_error(e),
};
self.regs[rd] = result;
Ok(())
}
/// for-await-of 步进完成检查:读取 `AWAIT` 恢复值(a 槽,即迭代器结果对象)的
/// `done`,写入 last_for_of_result 并把 `!done` 写 rd(供 JMP_IF_FALSE 分支)。
pub(crate) fn dispatch_for_await_of_done(&mut self, rd: usize, a: usize) -> Result<(), String> {
vm_trace!("FOR_AWAIT_OF_DONE rd={} r{}={:?}", rd, a, self.regs[a]);
let result = self.regs[a];
if !result.is_object() {
return self.raise_type_error("iterator result is not an object");
}
self.iters.set_last_for_of_result(result);
let result_obj = unsafe { &*result.as_js_object_ptr() };
let done_si = self.kernel_core.perm_interner().intern("done").0;
let done_val = match self.ordinary_get(result_obj, done_si, result) {
Ok(v) => v,
Err(e) => return self.throw_for_of_error(e),
};
self.regs[rd] = JsValue::bool(!to_boolean(done_val));
Ok(())
}
/// for-await-of 收尾:迭代器自然 done 时跳过;否则执行异步 IteratorClose——
/// 调用 `return()`,其返回的 promise 经 await 挂起,恢复后继续循环后的指令。
pub(crate) fn dispatch_for_await_of_close(&mut self) -> Result<(), String> {
vm_trace!("FOR_AWAIT_OF_CLOSE");
let Some(iterator) = self.iters.pop_for_of() else {
return Ok(());
};
let result = self.iters.last_for_of_result();
if result.is_object() {
let result_obj = unsafe { &*result.as_js_object_ptr() };
let done_si = self.kernel_core.perm_interner().intern("done").0;
if let Ok(done_val) = self.ordinary_get(result_obj, done_si, result) {
if to_boolean(done_val) {
return Ok(());
}
}
}
if !iterator.is_object() {
return Ok(());
}
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
let return_si = self.kernel_core.perm_interner().intern("return").0;
let return_fn = match self.ordinary_get(iter_obj, return_si, iterator) {
Ok(v) => v,
Err(e) => return Err(e),
};
if !return_fn.is_object() {
return Ok(());
}
if !unsafe { &*return_fn.as_js_object_ptr() }.is_function() {
return Ok(());
}
let inner = match self.call_function_sync(return_fn, iterator, &[]) {
Ok(v) => v,
Err(e) => return Err(e),
};
if !inner.is_object() {
return self.raise_type_error("iterator return() result is not an object");
}
self.perform_await(inner)
}
pub(crate) fn dispatch_for_of_done(&mut self, rd: usize) -> Result<(), String> {
vm_trace!("FOR_OF_DONE rd={}", rd);
let Some(iterator) = self.iters.last_for_of() else {