diff --git a/crates/oxide_bytecode/src/module.rs b/crates/oxide_bytecode/src/module.rs index d8084b51..ad171948 100644 --- a/crates/oxide_bytecode/src/module.rs +++ b/crates/oxide_bytecode/src/module.rs @@ -70,6 +70,8 @@ pub struct CompiledModule { pub needs_home_object: bool, /// 是否为生成器函数体(`function*`):调用返回迭代器对象,body 挂起/恢复执行。 pub is_generator: bool, + /// 是否为异步函数体(`async function` / async 箭头):调用返回 promise,body 挂起/恢复执行。 + pub is_async: bool, pub upvalue_captures: Vec, pub cells_needed: u8, /// 全局扁平模块 id:编译末端 flatten 阶段分配(顶层 0,子模块 DFS 递增)。 @@ -96,6 +98,7 @@ impl CompiledModule { is_derived_constructor: false, needs_home_object: false, is_generator: false, + is_async: false, upvalue_captures: Vec::new(), cells_needed: 0, flat_id: 0, @@ -127,6 +130,7 @@ impl Clone for CompiledModule { is_derived_constructor: self.is_derived_constructor, needs_home_object: self.needs_home_object, is_generator: self.is_generator, + is_async: self.is_async, upvalue_captures: self.upvalue_captures.clone(), cells_needed: self.cells_needed, flat_id: self.flat_id, diff --git a/crates/oxide_bytecode/src/opcode.rs b/crates/oxide_bytecode/src/opcode.rs index d6f55245..ce050ce9 100644 --- a/crates/oxide_bytecode/src/opcode.rs +++ b/crates/oxide_bytecode/src/opcode.rs @@ -203,6 +203,8 @@ define_opcodes! { SUSPEND_BODY = 0x77 => "SUSPEND_BODY", // `yield*` 委托:rd=内层可迭代对象;委托完成值经 reg 0 交付(与 YIELD 同协议)。 YIELD_STAR = 0x78 => "YIELD_STAR", + // `await`:rd=被等待的值(PromiseResolve 包装);挂起异步帧,恢复值经 reg 0 交付。 + AWAIT = 0x79 => "AWAIT", // ── 位运算 (0x80-0x8F) ── BIT_AND = 0x80 => "BIT_AND", diff --git a/crates/oxide_emit/src/class/method.rs b/crates/oxide_emit/src/class/method.rs index bf60f7fb..dcaf1786 100644 --- a/crates/oxide_emit/src/class/method.rs +++ b/crates/oxide_emit/src/class/method.rs @@ -98,18 +98,36 @@ impl Emitter { .map(|c| ("@@class_brand", *c)) .into_iter() .collect(); - let mut method_module = self.compile_function_body_with_field_hooks( - ¶m_names, - body_stmts, - ctx, - false, - self_binding, - FunctionBodyContext::ClassElement, - None:: Result<(), String>>, - false, - &[], - &extra_uv, - )?; + let method_value = method.value.as_ref(); + let mut method_module = if method_value.r#async { + self.compile_function_body_with_field_hooks_gen( + ¶m_names, + body_stmts, + ctx, + false, + self_binding, + FunctionBodyContext::ClassElement, + None:: Result<(), String>>, + false, + &[], + &extra_uv, + false, + true, + )? + } else { + self.compile_function_body_with_field_hooks( + ¶m_names, + body_stmts, + ctx, + false, + self_binding, + FunctionBodyContext::ClassElement, + None:: Result<(), String>>, + false, + &[], + &extra_uv, + )? + }; ctx.in_instance_method = saved_instance; ctx.in_static_method = saved_static; // 访问器函数名带 "get "/"set " 前缀(SetFunctionName 语义),普通方法裸属性名。 diff --git a/crates/oxide_emit/src/closure.rs b/crates/oxide_emit/src/closure.rs index 05516cac..12983ccc 100644 --- a/crates/oxide_emit/src/closure.rs +++ b/crates/oxide_emit/src/closure.rs @@ -579,6 +579,11 @@ impl Emitter { self.collect_capture_names_expr(a, ref_set, shadow, out); } } + // await 表达式:被等待的值里引用的父变量须纳入捕获(与 yield 同因—— + // 异步体挂起恢复后寄存器已被覆盖,只能经 cell 读取)。 + Expression::AwaitExpression(ae) => { + self.collect_capture_names_expr(&ae.argument, ref_set, shadow, out); + } Expression::ChainExpression(c) => self.collect_capture_names_chain(&c.expression, ref_set, shadow, out), _ => {} } @@ -891,6 +896,7 @@ impl Emitter { self.collect_captured_expr(a, own, out); } } + Expression::AwaitExpression(ae) => self.collect_captured_expr(&ae.argument, own, out), Expression::ChainExpression(c) => self.collect_captured_chain(&c.expression, own, out), _ => {} } diff --git a/crates/oxide_emit/src/emit.rs b/crates/oxide_emit/src/emit.rs index dc676000..1c5d184e 100644 --- a/crates/oxide_emit/src/emit.rs +++ b/crates/oxide_emit/src/emit.rs @@ -163,6 +163,8 @@ pub struct CompileCtx { pub(crate) in_static_method: bool, /// 本函数是否为生成器函数体(`function*`),`assemble_ir` 回写到 IR。 pub(crate) is_generator: bool, + /// 本函数是否为异步函数体(`async function` / async 箭头),`assemble_ir` 回写到 IR。 + pub(crate) is_async: bool, pub(crate) static_block_this_reg: Option, pub(crate) field_buffer: Option, /// 类构造器模块中 `@@field_keys` upvalue 下标(实例字段 computed key 数组)。 @@ -265,6 +267,7 @@ impl CompileCtx { in_instance_method: false, in_static_method: false, is_generator: false, + is_async: false, static_block_this_reg: None, field_buffer: None, field_keys_uv: None, @@ -607,6 +610,7 @@ impl CompileCtx { is_derived_constructor: false, needs_home_object: false, is_generator: self.is_generator, + is_async: self.is_async, captured_this_const_idx: 0, function_name: None, function_length: self.function_length, @@ -705,19 +709,36 @@ impl Emitter { &self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, is_expression_body: bool, is_arrow: bool, ) -> Result { - self.compile_function_body_with_flags(param_specs, body_stmts, parent_ctx, is_expression_body, is_arrow, false) + self.compile_function_body_with_flags(param_specs, body_stmts, parent_ctx, is_expression_body, is_arrow, false, false) } /// 编译函数体并显式指定生成器标志(`function*` 走此入口)。 pub(crate) fn compile_generator_body<'a>( &self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, ) -> Result { - self.compile_function_body_with_flags(param_specs, body_stmts, parent_ctx, false, false, true) + self.compile_function_body_with_flags(param_specs, body_stmts, parent_ctx, false, false, true, false) + } + + /// 编译异步函数体(`async function` / async 箭头走此入口):`is_async` 使 + /// `assemble_ir` 标记模块,VM 调用时按异步函数协议执行。 + pub(crate) fn compile_async_body<'a>( + &self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, + is_expression_body: bool, is_arrow: bool, + ) -> Result { + self.compile_function_body_with_flags( + param_specs, + body_stmts, + parent_ctx, + is_expression_body, + is_arrow, + false, + true, + ) } fn compile_function_body_with_flags<'a>( &self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, - is_expression_body: bool, is_arrow: bool, is_generator: bool, + is_expression_body: bool, is_arrow: bool, is_generator: bool, is_async: bool, ) -> Result { let body_context = if is_arrow { FunctionBodyContext::Arrow @@ -732,6 +753,7 @@ impl Emitter { &[], body_context, is_generator, + is_async, ) } @@ -739,7 +761,7 @@ impl Emitter { pub(crate) fn compile_function_body_with_bindings_gen<'a>( &self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext, - is_generator: bool, + is_generator: bool, is_async: bool, ) -> Result { self.compile_function_body_with_field_hooks_gen( param_specs, @@ -753,6 +775,7 @@ impl Emitter { &[], &[], is_generator, + is_async, ) } @@ -785,6 +808,7 @@ impl Emitter { extra_capture_exprs, extra_upvalue_names, false, + false, ) } @@ -793,13 +817,14 @@ impl Emitter { &self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext, mut emit_fields: Option, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>], - extra_upvalue_names: &[(&str, u8)], is_generator: bool, + extra_upvalue_names: &[(&str, u8)], is_generator: bool, is_async: bool, ) -> Result where E: FnMut(&Emitter, &mut CompileCtx) -> Result<(), String>, { let mut ctx = CompileCtx::new(); ctx.is_generator = is_generator; + ctx.is_async = is_async; // length = 第一个带默认值形参之前的形参数(解构默认与标识符默认同规则); // rest 参数不在 param_specs 中(独立字段),天然不计入。 @@ -1158,6 +1183,7 @@ impl Emitter { | Expression::NewExpression(_) => self.emit_function_domain(expr, ctx), Expression::Identifier(ident) => self.emit_identifier_expression(ident, ctx), Expression::YieldExpression(ye) => self.emit_yield_expression(ye, ctx), + Expression::AwaitExpression(ae) => self.emit_await_expression(ae, ctx), Expression::CallExpression(_) => self.emit_call_domain(expr, ctx), Expression::ThisExpression(_) => self.emit_this_expression(ctx), Expression::SequenceExpression(seq) => self.emit_sequence_expression(seq, ctx), diff --git a/crates/oxide_emit/src/expr/await_expr.rs b/crates/oxide_emit/src/expr/await_expr.rs new file mode 100644 index 00000000..c2367180 --- /dev/null +++ b/crates/oxide_emit/src/expr/await_expr.rs @@ -0,0 +1,21 @@ +//! `await` 表达式 emit:求值被等待的值后发 `AWAIT` 指令,结果经 reg 0 交付。 + +use crate::{CompileCtx, Emitter}; +use oxide_bytecode::opcode::OpCode; +use oxide_ir::inst::Inst; +use oxide_ir::operand::Operand; +use oxide_parser::AwaitExpression; + +impl Emitter { + pub(crate) fn emit_await_expression( + &self, ae: &AwaitExpression, ctx: &mut CompileCtx, + ) -> Result { + // 求值被等待的值(`await undefined` 时求值 undefined)。 + let value_reg = self.emit_expression(&ae.argument, ctx)?; + ctx.inst(Inst::await_expr(Operand::Reg(value_reg))); + // promise settle 后恢复值经 reg 0 交付(与 YIELD/CALL 同协议)。 + let result_reg = ctx.alloc_reg(); + ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::None, Operand::None)); + Ok(result_reg) + } +} diff --git a/crates/oxide_emit/src/expr/function/mod.rs b/crates/oxide_emit/src/expr/function/mod.rs index e872cb03..6e40ab2a 100644 --- a/crates/oxide_emit/src/expr/function/mod.rs +++ b/crates/oxide_emit/src/expr/function/mod.rs @@ -41,7 +41,11 @@ impl Emitter { let body_stmts = &arrow.body.statements; let is_expr_body = arrow.expression; - let mut sub_module = self.compile_function_body(¶m_names, body_stmts, ctx, is_expr_body, true)?; + let mut sub_module = if arrow.r#async { + self.compile_async_body(¶m_names, body_stmts, ctx, is_expr_body, true)? + } else { + self.compile_function_body(¶m_names, body_stmts, ctx, is_expr_body, true)? + }; sub_module.is_arrow = true; ctx.nested.push(sub_module); @@ -78,6 +82,8 @@ impl Emitter { let mut sub_module = if fe.generator { self.compile_generator_body(¶m_names, body_stmts, ctx)? + } else if fe.r#async { + self.compile_async_body(¶m_names, body_stmts, ctx, false, false)? } else { self.compile_function_body(¶m_names, body_stmts, ctx, false, false)? }; diff --git a/crates/oxide_emit/src/expr/mod.rs b/crates/oxide_emit/src/expr/mod.rs index 2d51ccfc..0d42962a 100644 --- a/crates/oxide_emit/src/expr/mod.rs +++ b/crates/oxide_emit/src/expr/mod.rs @@ -7,6 +7,7 @@ use crate::{CompileCtx, Emitter}; use oxide_parser::Expression; pub mod assignment; +pub mod await_expr; pub mod call; pub mod function; pub mod identifier; diff --git a/crates/oxide_emit/src/prepass.rs b/crates/oxide_emit/src/prepass.rs index 694299f0..a06aa3db 100644 --- a/crates/oxide_emit/src/prepass.rs +++ b/crates/oxide_emit/src/prepass.rs @@ -216,6 +216,12 @@ impl Emitter { self.pre_scan_builtin_chain(&chain.expression, ctx); } Expression::ParenthesizedExpression(p) => self.pre_scan_builtin_expr(&p.expression, ctx), + Expression::YieldExpression(ye) => { + if let Some(a) = &ye.argument { + self.pre_scan_builtin_expr(a, ctx); + } + } + Expression::AwaitExpression(ae) => self.pre_scan_builtin_expr(&ae.argument, ctx), Expression::ArrowFunctionExpression(_) | Expression::FunctionExpression(_) | Expression::ClassExpression(_) => {} diff --git a/crates/oxide_emit/src/stmt/declaration/function_decl.rs b/crates/oxide_emit/src/stmt/declaration/function_decl.rs index 1d109073..843d4b4a 100644 --- a/crates/oxide_emit/src/stmt/declaration/function_decl.rs +++ b/crates/oxide_emit/src/stmt/declaration/function_decl.rs @@ -35,6 +35,8 @@ impl Emitter { let body_stmts: &[Statement] = if let Some(body) = &fd.body { &body.statements } else { &[] }; let mut sub_module = if fd.generator { self.compile_generator_body(¶m_names, body_stmts, ctx)? + } else if fd.r#async { + self.compile_async_body(¶m_names, body_stmts, ctx, false, false)? } else { self.compile_function_body(¶m_names, body_stmts, ctx, false, false)? }; diff --git a/crates/oxide_ir/src/contract.rs b/crates/oxide_ir/src/contract.rs index 499a203f..1bd94610 100644 --- a/crates/oxide_ir/src/contract.rs +++ b/crates/oxide_ir/src/contract.rs @@ -20,7 +20,7 @@ impl Inst { // CALL 系:结果隐式写 reg 0,rd 是 callee 的 use OpCode::CALL | OpCode::CALL_NATIVE | OpCode::CALL_SPREAD => Some(0), // YIELD/YIELD_STAR:恢复时 next(v) 的 v / 委托完成值经 reg 0 交付(与 CALL 同协议) - OpCode::YIELD | OpCode::YIELD_STAR => Some(0), + OpCode::YIELD | OpCode::YIELD_STAR | OpCode::AWAIT => Some(0), // GET_PROP 系:结果写 a/b 槽而非 rd OpCode::GET_PROP | OpCode::IC_GET_PROP => reg_of(&self.a), OpCode::GET_PROP_DYNAMIC => reg_of(&self.b), @@ -228,8 +228,12 @@ impl Inst { } // HALT:隐式读 reg 0(顶层返回值) OpCode::HALT => uses.push(0), - // RETURN/THROW/YIELD/YIELD_STAR:读 rd(None→0) - OpCode::RETURN | OpCode::THROW | OpCode::YIELD | OpCode::YIELD_STAR => push_operand(&mut uses, &self.rd), + // RETURN/THROW/YIELD/YIELD_STAR/AWAIT:读 rd(None→0) + OpCode::RETURN + | OpCode::THROW + | OpCode::YIELD + | OpCode::YIELD_STAR + | OpCode::AWAIT => push_operand(&mut uses, &self.rd), // 加载族:a 槽是 Const/Imm 立即数,无寄存器 use OpCode::LOAD_CONST | OpCode::CREATE_CLOSURE diff --git a/crates/oxide_ir/src/inst.rs b/crates/oxide_ir/src/inst.rs index 7cd71603..ebf73119 100644 --- a/crates/oxide_ir/src/inst.rs +++ b/crates/oxide_ir/src/inst.rs @@ -284,6 +284,12 @@ impl Inst { Self::new(OpCode::SUSPEND_BODY, Operand::None, Operand::None, Operand::None) } + /// `await` 让出:`rd` 为被等待的值(运行时 PromiseResolve 包装);异步帧挂起, + /// promise settle 后恢复,值经 reg 0 交付(与 YIELD 同协议)。 + pub fn await_expr(src: Operand) -> Self { + Self::new(OpCode::AWAIT, src, Operand::None, Operand::None) + } + // ── 跳转族:label 放 b 槽,offset 计算是 lowering 职责 ── /// 无条件跳转。label 放 b 槽,offset 由 lowering 回填。 diff --git a/crates/oxide_ir/src/lib.rs b/crates/oxide_ir/src/lib.rs index 5c7bc6dc..03dbd0f5 100644 --- a/crates/oxide_ir/src/lib.rs +++ b/crates/oxide_ir/src/lib.rs @@ -52,6 +52,8 @@ pub struct IRFunction { pub needs_home_object: bool, /// 是否为生成器函数体(`function*`)。 pub is_generator: bool, + /// 是否为异步函数体(`async function` / async 箭头)。 + pub is_async: bool, pub captured_this_const_idx: u16, pub function_name: Option, /// 函数 `length` 属性值:第一个带默认值/解构默认的形参之前的形参数(rest 不计)。 @@ -83,6 +85,7 @@ impl IRFunction { is_derived_constructor: false, needs_home_object: false, is_generator: false, + is_async: false, captured_this_const_idx: 0, function_name: None, function_length: 0, diff --git a/crates/oxide_ir/src/lower.rs b/crates/oxide_ir/src/lower.rs index cb032b0a..368cee80 100644 --- a/crates/oxide_ir/src/lower.rs +++ b/crates/oxide_ir/src/lower.rs @@ -90,6 +90,7 @@ pub fn lower(f: &IRFunction) -> Result { is_derived_constructor: f.is_derived_constructor, needs_home_object: f.needs_home_object, is_generator: f.is_generator, + is_async: f.is_async, upvalue_captures: f.upvalue_captures.clone(), cells_needed: f.cells_needed, flat_id: 0, diff --git a/crates/oxide_test262/src/main.rs b/crates/oxide_test262/src/main.rs index dce34651..54a90e4c 100644 --- a/crates/oxide_test262/src/main.rs +++ b/crates/oxide_test262/src/main.rs @@ -401,7 +401,6 @@ fn is_skipped(meta: &TestMeta) -> Option { let excluded_features = [ "Proxy", "BigInt", - "async-functions", "Intl", "Temporal", "module", diff --git a/crates/oxide_types/src/object.rs b/crates/oxide_types/src/object.rs index a0eb0844..4e1a724e 100644 --- a/crates/oxide_types/src/object.rs +++ b/crates/oxide_types/src/object.rs @@ -402,6 +402,8 @@ impl JsObject { pub const OBJ_TYPE_GENERATOR: u8 = 10; /// Promise 对象:状态盒(Pending/Fulfilled/Rejected + reactions)存于 `native_data`。 pub const OBJ_TYPE_PROMISE: u8 = 11; + /// 异步函数执行上下文(隐藏对象):`AsyncState` 快照存于 `native_data`。 + pub const OBJ_TYPE_ASYNC: u8 = 12; /// `is_session_epoch` 字段中的 session 标记位。 pub const SESSION_EPOCH_BIT: u8 = 0x01; /// `is_session_epoch` 字段中的 GC 标记位。 @@ -457,6 +459,11 @@ impl JsObject { pub fn is_promise_obj(&self) -> bool { self.type_tag == Self::OBJ_TYPE_PROMISE } + /// 是否异步函数执行上下文对象。 + #[inline] + pub fn is_async_obj(&self) -> bool { + self.type_tag == Self::OBJ_TYPE_ASYNC + } /// 构造无属性、可扩展的空对象(`new Object()` 的基础对象)。 pub fn new_empty(shape_id: ShapeId, proto: JsValue) -> Self { diff --git a/crates/oxide_vm/src/async_func.rs b/crates/oxide_vm/src/async_func.rs new file mode 100644 index 00000000..218f643c --- /dev/null +++ b/crates/oxide_vm/src/async_func.rs @@ -0,0 +1,706 @@ +//! 异步函数运行时:异步帧快照挂起/恢复 + await 微任务驱动。 +//! +//! 策略:`async function` 调用返回 capability promise(状态存 `AsyncState`), +//! body 立即同步执行到第一个 `AWAIT`(与 generator 的惰性不同)。`await` 求值 +//! 被等待值、PromiseResolve 包装后登记恢复反应;promise settle 后微任务经 +//! `Vm::async_context` 驱动的嵌套 dispatch 恢复异步帧,执行到下一个 +//! `AWAIT`/`RETURN`/异常。挂起快照/恢复机械复用 generator 的 regs/pc/bytecode/ +//! spill/save/try/cell 栈段搬运。`AWAIT` 经 `Vm::async_suspended` 信号让内嵌 +//! dispatch 返回,恢复方据此快照挂起状态。 + +use std::sync::Arc; + +use oxide_bytecode::opcode; +use oxide_kernel::shape_forge::EMPTY_SHAPE_ID; +use oxide_runtime_api::{to_boolean, NativeResult}; +use oxide_types::mem::P; +use oxide_types::object::{Cell, JsObject, NativeFnPtr, PropAttributes}; +use oxide_types::value::JsValue; + +use crate::vm::{CallFrame, Completion, ForInIter, FrameContinuation, TryHandler, Vm}; + +/// 异步函数执行阶段。 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum AsyncPhase { + /// 尚未开始执行(调用时压帧前)。 + New, + /// 正在执行(body 运行在嵌套 dispatch 循环中)。 + Running, + /// 已在 `await` 挂起。 + Suspended, + /// 已正常返回 / 异常结束。 + Completed, +} + +/// 异步函数挂起时的完整执行上下文快照 + capability。 +/// +/// 存在异步上下文对象 `native_data`(`Box`),跨 await 微任务存活;其中所有 +/// `JsValue` 由 session GC 经上下文对象边追踪(见 `session_gc`)。 +pub(crate) struct AsyncState { + pub phase: AsyncPhase, + /// 异步函数对象(首次执行时压帧用)。 + pub callee: JsValue, + /// 首次调用实参。 + pub args: Vec, + /// 首次调用时的方法接收者(`obj.g()` 的 `obj`),压帧时作 `this` 绑定。 + pub this_value: JsValue, + /// 完成后返回值。 + pub result: JsValue, + /// 调用返回给调用方的 capability promise。 + pub promise: JsValue, + /// capability 上的 resolve/reject 闭包(完成时结算用)。 + pub resolve: JsValue, + pub reject: JsValue, + // ── 挂起时的执行上下文 ── + pub regs: Box<[JsValue; 256]>, + pub pc: usize, + pub bytecode: Vec, + /// 异步模块 flat_id(恢复时重激活 immutables)。 + pub sub_idx: u32, + pub active_reg_limit: u8, + pub root_reg_limit: u8, + /// 异步帧(压入时由 push_bytecode_frame 构造,挂起时弹出存此)。 + pub frame: Option, + pub spill_stack: Vec, + pub save_stack: Vec, + pub cell_stack: Vec>, + pub try_stack: Vec, + pub for_in_iters: Vec<*mut ForInIter<'static>>, + pub for_of_iters: Vec, + pub last_for_of_result: JsValue, + pub saved_bytecode_stack: Vec>, + pub saved_immutables_stack: Vec<*const [JsValue]>, + /// 在途异常/完成(异常展开穿越 await 挂起时保留,恢复后继续展开)。 + pub exception_value: Option, + pub pending_exception: Option, + pub pending_error_kind: Option<&'static str>, + pub pending_completion: Option, +} + +/// 一次 await 恢复的注入模式。 +#[derive(Debug, Clone, Copy)] +pub(crate) enum AsyncResumeMode { + /// 普通恢复:fulfilled 值作为 `await` 表达式结果(写 reg 0)。 + Next(JsValue), + /// 拒绝恢复:在挂起点抛错(可被 catch/finally 捕获)。 + Throw(JsValue), +} + +/// 异步上下文对象上存 capability 闭包的属性名(await 恢复闭包定位上下文用)。 +const ASYNC_CTX_PROP: &str = "__oxide_async_ctx__"; +/// 恢复闭包上区分 reject 角色的属性名。 +const ASYNC_REJECT_PROP: &str = "__oxide_async_reject__"; + +impl Vm { + /// 调用异步函数返回的 capability promise:创建上下文对象 + 状态盒,立即压帧 + /// 同步执行 body 到第一个 AWAIT/RETURN/异常,返回 pending promise。 + /// + /// # 副作用 + /// - 上下文对象状态从 `New` 转为 `Running`;AWAIT 挂起后转为 `Suspended`。 + /// - 参数默认值副作用、body 到首个 await 的同步执行在调用时刻完成。 + pub(crate) fn create_async_object( + &mut self, callee: JsValue, this_value: JsValue, args: &[JsValue], + ) -> Result { + let (promise, resolve, reject) = self.new_promise_capability(); + let ctx_val = self.create_async_context(callee, this_value, args, promise, resolve, reject); + self.start_async(ctx_val)?; + Ok(promise) + } + + /// 分配异步上下文对象(`OBJ_TYPE_ASYNC`),AsyncState 状态盒挂 `native_data`。 + fn create_async_context( + &mut self, callee: JsValue, this_value: JsValue, args: &[JsValue], promise: JsValue, resolve: JsValue, + reject: JsValue, + ) -> JsValue { + let proto_val = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject); + let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)); + let obj = unsafe { &mut *ptr }; + obj.type_tag = JsObject::OBJ_TYPE_ASYNC; + let state = Box::new(AsyncState { + phase: AsyncPhase::New, + callee, + args: args.to_vec(), + this_value, + result: JsValue::undefined(), + promise, + resolve, + reject, + regs: Box::new([JsValue::undefined(); 256]), + pc: 0, + bytecode: Vec::new(), + sub_idx: 0, + active_reg_limit: 0, + root_reg_limit: 0, + frame: None, + spill_stack: Vec::new(), + save_stack: Vec::new(), + cell_stack: Vec::new(), + try_stack: Vec::new(), + for_in_iters: Vec::new(), + for_of_iters: Vec::new(), + last_for_of_result: JsValue::undefined(), + saved_bytecode_stack: Vec::new(), + saved_immutables_stack: Vec::new(), + exception_value: None, + pending_exception: None, + pending_error_kind: None, + pending_completion: None, + }); + obj.set_native_data(Box::into_raw(state) as *mut u8); + JsValue::from_js_object(ptr) + } + + /// 取出异步上下文对象的状态指针(调用方须先校验 `is_async_obj`)。 + fn async_state_ptr(&self, ctx_val: JsValue) -> *mut AsyncState { + unsafe { (*ctx_val.as_js_object_ptr()).native_data() as *mut AsyncState } + } + + /// 首次启动异步体:压入异步帧并在嵌套 dispatch 中执行到第一个 AWAIT/RETURN/异常。 + /// + /// # 步骤 + /// 1. 用 `InlineSyncState` 保存调用方 VM 状态,清空 VM 后压入异步帧。 + /// 2. 嵌套 `dispatch()` 运行 body;AWAIT 置 `async_suspended` 使 dispatch 返回。 + /// 3. 挂起则快照;完成则 resolve capability;异常则 reject。恢复调用方状态。 + fn start_async(&mut self, ctx_val: JsValue) -> Result<(), String> { + let state_ptr = self.async_state_ptr(ctx_val); + let saved = self.save_inline_state(); + self.async_suspended = false; + let prev_ctx = self.async_context.take(); + let prev_dispatch = self.async_dispatch; + self.async_dispatch = true; + self.async_context = Some(ctx_val); + self.native_call_depth += 1; + + self.regs = [JsValue::undefined(); 256]; + self.pc = 0; + self.bytecode = Vec::new(); + self.active_reg_limit = 1; + self.root_reg_limit = 1; + self.try_stack.clear(); + self.iters.for_in_iters.clear(); + self.iters.for_of_iters.clear(); + self.iters.last_for_of_result = JsValue::undefined(); + self.spill_stack.clear(); + self.save_stack.clear(); + self.saved_bytecode_stack.clear(); + self.saved_immutables_stack.clear(); + self.cell_stack.clear(); + self.inline_callee = None; + let callee = unsafe { (*state_ptr).callee }; + let this_value = unsafe { (*state_ptr).this_value }; + let args = unsafe { std::mem::take(&mut (*state_ptr).args) }; + let push_res = self.push_bytecode_frame( + callee, + this_value, + &args, + None, + None, + JsValue::undefined(), + FrameContinuation::None, + ); + unsafe { (*state_ptr).args = args }; + if let Err(e) = push_res { + self.async_dispatch = prev_dispatch; + self.async_context = prev_ctx; + self.native_call_depth -= 1; + self.restore_inline_state(saved); + return Err(e); + } + unsafe { (*state_ptr).phase = AsyncPhase::Running }; + + let result = self.dispatch(); + self.async_dispatch = prev_dispatch; + self.async_context = prev_ctx; + self.native_call_depth -= 1; + + if std::mem::take(&mut self.async_suspended) { + let state = unsafe { &mut *state_ptr }; + self.snapshot_async(state)?; + self.restore_inline_state(saved); + return Ok(()); + } + + match result { + Ok(value) => { + self.finish_async(state_ptr, Ok(value))?; + self.restore_inline_state(saved); + Ok(()) + } + Err(e) => { + let exc = self + .last_uncaught_value + .take() + .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + self.finish_async(state_ptr, Err(exc))?; + self.restore_inline_state(saved); + Ok(()) + } + } + } + + /// 恢复异步体一步执行:`await` 的 promise settle 后由恢复闭包调用。 + /// + /// # 步骤 + /// 1. 用 `InlineSyncState` 保存调用方 VM 状态,把挂起快照灌回 VM。 + /// 2. 注入 await 结果(fulfilled 写 reg 0 / rejected 注入异常并展开)。 + /// 3. 嵌套 `dispatch()` 运行 body 到下一个 AWAIT/RETURN/异常。 + /// 4. 挂起则快照新状态;完成/异常则结算 capability。恢复调用方状态。 + pub(crate) fn resume_async(&mut self, ctx_val: JsValue, mode: AsyncResumeMode) -> Result<(), String> { + let state_ptr = self.async_state_ptr(ctx_val); + let saved = self.save_inline_state(); + self.async_suspended = false; + let prev_ctx = self.async_context.take(); + let prev_dispatch = self.async_dispatch; + self.async_dispatch = true; + self.async_context = Some(ctx_val); + self.native_call_depth += 1; + + { + let state = unsafe { &mut *state_ptr }; + self.regs = *state.regs; + self.pc = state.pc; + self.bytecode = std::mem::take(&mut state.bytecode); + let subs = Arc::clone(&self.sub_modules); + if (state.sub_idx as usize) < subs.len() { + self.activate_immutables(state.sub_idx as usize, &subs[state.sub_idx as usize].constants); + } else { + // 挂起状态跨 run:sub_modules 已重建,无法恢复(与生成器同限制)。 + self.async_dispatch = prev_dispatch; + self.async_context = prev_ctx; + self.native_call_depth -= 1; + self.restore_inline_state(saved); + return Err("async function suspended across runs is no longer valid".into()); + } + self.active_reg_limit = state.active_reg_limit; + self.root_reg_limit = state.root_reg_limit; + self.frames.clear(); + if let Some(frame) = state.frame.take() { + self.frames.push(frame); + } + self.spill_stack = std::mem::take(&mut state.spill_stack); + self.save_stack = std::mem::take(&mut state.save_stack); + self.cell_stack = std::mem::take(&mut state.cell_stack); + self.try_stack = std::mem::take(&mut state.try_stack); + self.iters.for_in_iters = std::mem::take(&mut state.for_in_iters); + self.iters.for_of_iters = std::mem::take(&mut state.for_of_iters); + self.iters.last_for_of_result = state.last_for_of_result; + self.saved_bytecode_stack = std::mem::take(&mut state.saved_bytecode_stack); + self.saved_immutables_stack = std::mem::take(&mut state.saved_immutables_stack); + self.exception_value = state.exception_value.take(); + self.pending_exception = state.pending_exception.take(); + self.pending_error_kind = state.pending_error_kind.take(); + self.pending_completion = state.pending_completion.take(); + self.inline_callee = None; + state.phase = AsyncPhase::Running; + } + + // 注入 await 结果:fulfilled 写 reg 0;rejected 恢复异常上下文并展开。 + if let AsyncResumeMode::Throw(exc) = mode { + self.exception_value = Some(exc); + self.pending_error_kind = Some(self.thrown_error_kind(exc)); + if self.unwind().is_err() { + // 异常逃逸出异步帧(无 catch/finally):结算为 reject。 + self.async_dispatch = prev_dispatch; + self.async_context = prev_ctx; + self.native_call_depth -= 1; + let thrown = self.last_uncaught_value.take().unwrap_or(exc); + self.finish_async(state_ptr, Err(thrown))?; + self.restore_inline_state(saved); + return Ok(()); + } + } else if let AsyncResumeMode::Next(value) = mode { + self.regs[0] = value; + } + + let result = self.dispatch(); + self.async_dispatch = prev_dispatch; + self.async_context = prev_ctx; + self.native_call_depth -= 1; + + if std::mem::take(&mut self.async_suspended) { + let state = unsafe { &mut *state_ptr }; + self.snapshot_async(state)?; + self.restore_inline_state(saved); + return Ok(()); + } + + match result { + Ok(value) => { + self.finish_async(state_ptr, Ok(value))?; + self.restore_inline_state(saved); + Ok(()) + } + Err(e) => { + let exc = self + .last_uncaught_value + .take() + .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + self.finish_async(state_ptr, Err(exc))?; + self.restore_inline_state(saved); + Ok(()) + } + } + } + + /// 结算异步函数:正常结束 resolve capability,异常结束 reject capability。 + fn finish_async(&mut self, state_ptr: *mut AsyncState, outcome: Result) -> Result<(), String> { + let (promise, value) = { + let state = unsafe { &mut *state_ptr }; + state.phase = AsyncPhase::Completed; + match &outcome { + Ok(v) => { + state.result = *v; + (state.promise, *v) + } + Err(e) => { + state.result = JsValue::undefined(); + (state.promise, *e) + } + } + }; + match outcome { + Ok(_) => { + let _ = self.resolve_promise(promise, value); + } + Err(_) => { + let _ = self.reject_promise(promise, value); + } + } + Ok(()) + } + + /// `await` dispatch:PromiseResolve 包装被等待值、登记恢复反应,置挂起信号。 + /// + /// # 副作用 + /// - 被等待值为原生 Promise 时直接复用,否则建新 promise 并 PromiseResolve。 + /// - 经 `perform_promise_then` 登记 fulfill/reject 恢复反应(微任务入队)。 + pub(crate) fn dispatch_await(&mut self, rd: usize) -> 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 { + let (p, _, _) = self.new_promise_capability(); + let _ = self.resolve_promise(p, value); + p + }; + let fulfill_fn = self.make_async_await_resume_fn(ctx, false); + let reject_fn = self.make_async_await_resume_fn(ctx, true); + let _ = self.perform_promise_then(promise, fulfill_fn, reject_fn); + self.async_suspended = true; + Ok(()) + } + + /// 构造 await 恢复闭包:携带目标异步上下文对象,区分 fulfill/reject 角色。 + fn make_async_await_resume_fn(&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_await_resume_closure 是 NativeFn 函数项。 + func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(async_await_resume_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)); + self.add_fn_name_length(obj, "", 1); + JsValue::from_js_object(ptr) + } + + /// 把当前 VM 执行状态(异步 body 刚在嵌套 dispatch 中让出)快照进状态盒。 + /// + /// 异步帧弹出存 `frame`,其余栈段整段搬入(嵌套循环期间这些栈只含异步数据)。 + fn snapshot_async(&mut self, state: &mut AsyncState) -> Result<(), String> { + let frame = self + .frames + .pop() + .ok_or_else(|| "async frame missing on await".to_string())?; + state.frame = Some(frame); + state.regs = Box::new(self.regs); + state.pc = self.pc; + state.bytecode = std::mem::take(&mut self.bytecode); + state.sub_idx = if state.callee.is_object() { + unsafe { (*state.callee.as_js_object_ptr()).sub_module_index() } + } else { + 0 + }; + state.active_reg_limit = self.active_reg_limit; + state.root_reg_limit = self.root_reg_limit; + state.spill_stack = std::mem::take(&mut self.spill_stack); + state.save_stack = std::mem::take(&mut self.save_stack); + state.cell_stack = std::mem::take(&mut self.cell_stack); + state.try_stack = std::mem::take(&mut self.try_stack); + state.for_in_iters = std::mem::take(&mut self.iters.for_in_iters); + state.for_of_iters = std::mem::take(&mut self.iters.for_of_iters); + state.last_for_of_result = self.iters.last_for_of_result; + state.saved_bytecode_stack = std::mem::take(&mut self.saved_bytecode_stack); + state.saved_immutables_stack = std::mem::take(&mut self.saved_immutables_stack); + state.exception_value = self.exception_value.take(); + state.pending_exception = self.pending_exception.take(); + state.pending_error_kind = self.pending_error_kind.take(); + state.pending_completion = self.pending_completion.take(); + state.phase = AsyncPhase::Suspended; + Ok(()) + } +} + +/// await 恢复闭包:读自身 prop 的异步上下文与角色,恢复异步帧继续执行。 +fn async_await_resume_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, "await resume 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) + .map_or(false, to_boolean); + let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let mode = if is_reject { + AsyncResumeMode::Throw(value) + } else { + AsyncResumeMode::Next(value) + }; + match vm.resume_async(ctx, mode) { + Ok(()) => NativeResult::Ok(JsValue::undefined()), + Err(e) => NativeResult::Err(oxide_builtins::error::create_error(vm, &e)), + } +} + +/// 初始化/重建异步函数内建对象:`%AsyncFunction.prototype%`(+ 占位 `%AsyncFunction%`)。 +/// +/// 异步函数对象的 [[Prototype]] 指向此原型(`f.constructor.name` → "AsyncFunction")。 +/// 动态 `AsyncFunction` 构造器创建未实现,调用抛 TypeError。 +pub(crate) fn init_async_intrinsics(vm: &mut Vm) { + let sf = vm.kernel_core.perm_interner().as_ref(); + let sh = vm.kernel_core.shape_forge().as_ref(); + let fn_proto_val = vm.session.builtin_world().fn_proto_val(); + + // %AsyncFunction% 构造器:proto = Function.prototype,调用抛错(动态创建未实现)。 + let mut af_ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val)); + af_ctor.set_function(true); + af_ctor.set_native_arg_count(1); + // SAFETY: async_function_stub 是 NativeFn 函数项。 + af_ctor.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(async_function_stub as *const ()) })); + + // %AsyncFunction.prototype%:proto = Function.prototype,constructor = %AsyncFunction%。 + let mut af_proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val)); + let name_si = sf.intern("name").0; + let ctor_shape = sh.make_shape(af_ctor.shape_id(), name_si); + af_ctor.set_shape_id(ctor_shape); + let npos = af_ctor.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("AsyncFunction").0))); + af_ctor.set_data_meta(npos, PropAttributes::new(false, false, true)); + let proto_si = sf.intern("prototype").0; + let ctor_shape2 = sh.make_shape(af_ctor.shape_id(), proto_si); + af_ctor.set_shape_id(ctor_shape2); + let ppos = af_ctor.push_prop(JsValue::from_js_object(af_proto.as_mut() as *mut JsObject)); + af_ctor.set_data_meta(ppos, PropAttributes::new(false, false, false)); + // af_proto.constructor = %AsyncFunction%(构造器对象泄漏持有,与 builtin 方法 wrapper 同生命周期)。 + let ctor_si = sf.intern("constructor").0; + let pshape = sh.make_shape(af_proto.shape_id(), ctor_si); + af_proto.set_shape_id(pshape); + let cpos = af_proto.push_prop(JsValue::from_js_object(Box::into_raw(af_ctor))); + af_proto.set_data_meta(cpos, PropAttributes::new(false, false, true)); + // af_proto[Symbol.toStringTag] = "AsyncFunction"(数据属性,w/e/c = false/false/true)。 + let tag_si = sf.intern("@@toStringTag").0; + let tag_shape = sh.make_shape(af_proto.shape_id(), tag_si); + af_proto.set_shape_id(tag_shape); + let tag_pos = af_proto.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("AsyncFunction").0))); + af_proto.set_data_meta(tag_pos, PropAttributes::new(false, false, true)); + + vm.async_function_proto = P::new(*af_proto); +} + +/// `%AsyncFunction%` 占位:动态异步函数创建未实现,调用抛错。 +fn async_function_stub(vm: &mut Vm, _args: &[u8]) -> NativeResult { + NativeResult::Err(oxide_builtins::error::create_type_error( + vm, + "AsyncFunction constructor is not supported", + )) +} + +// ── session GC 支撑:状态快照中的 JsValues 作为异步上下文对象边追踪 ── + +fn async_state_mut(obj: &JsObject) -> Option<&mut AsyncState> { + let ptr = obj.native_data() as *mut AsyncState; + if ptr.is_null() { + None + } else { + // SAFETY: native_data 在 create_async_context 中由 Box::into_raw 分配, + // 生命周期与异步上下文对象一致;GC 只在 reset(无执行状态)时运行。 + Some(unsafe { &mut *ptr }) + } +} + +/// 异步状态内所有对象引用的扁平列表(GC mark 边)。 +pub(crate) fn async_native_edges(obj: &JsObject) -> Vec { + let Some(state) = async_state_mut(obj) else { + return Vec::new(); + }; + let mut edges = Vec::new(); + let push = |v: JsValue, edges: &mut Vec| { + if v.is_object() { + edges.push(v); + } + }; + push(state.callee, &mut edges); + edges.extend(state.args.iter().copied().filter(|v| v.is_object())); + push(state.result, &mut edges); + push(state.promise, &mut edges); + push(state.resolve, &mut edges); + push(state.reject, &mut edges); + edges.extend(state.regs.iter().copied().filter(|v| v.is_object())); + if let Some(frame) = &state.frame { + push(frame.saved_this, &mut edges); + push(frame.saved_new_target, &mut edges); + push(frame.callee, &mut edges); + if let Some(ct) = frame.constructed_this { + push(ct, &mut edges); + } + } + edges.extend(state.spill_stack.iter().copied().filter(|v| v.is_object())); + edges.extend(state.save_stack.iter().copied().filter(|v| v.is_object())); + for cells in &state.cell_stack { + for &cell_ptr in cells { + if cell_ptr.is_null() { + continue; + } + // SAFETY: cell 由 session_epoch 分配,本 session 内指针有效。 + let cell = unsafe { &*cell_ptr }; + push(cell.value, &mut edges); + } + } + edges.extend(state.for_of_iters.iter().copied().filter(|v| v.is_object())); + push(state.last_for_of_result, &mut edges); + edges +} + +/// 用转发函数重写状态快照中的所有 JsValue(session GC 移动式清扫 / promote 用)。 +pub(crate) fn rewrite_async_native(obj: &JsObject, mut rewrite: impl FnMut(JsValue) -> JsValue) { + let Some(state) = async_state_mut(obj) else { + return; + }; + state.callee = rewrite(state.callee); + for v in &mut state.args { + *v = rewrite(*v); + } + state.result = rewrite(state.result); + state.promise = rewrite(state.promise); + state.resolve = rewrite(state.resolve); + state.reject = rewrite(state.reject); + for v in state.regs.iter_mut() { + *v = rewrite(*v); + } + if let Some(frame) = &mut state.frame { + frame.saved_this = rewrite(frame.saved_this); + frame.saved_new_target = rewrite(frame.saved_new_target); + frame.callee = rewrite(frame.callee); + frame.constructed_this = frame.constructed_this.map(&mut rewrite); + } + for v in &mut state.spill_stack { + *v = rewrite(*v); + } + for v in &mut state.save_stack { + *v = rewrite(*v); + } + for cells in &mut state.cell_stack { + for &mut cell_ptr in cells.iter_mut() { + if cell_ptr.is_null() { + continue; + } + // SAFETY: cell 由 session_epoch 分配,本 session 内指针有效。 + let cell = unsafe { &mut *cell_ptr }; + cell.value = rewrite(cell.value); + } + } + for v in &mut state.for_of_iters { + *v = rewrite(*v); + } + state.last_for_of_result = rewrite(state.last_for_of_result); +} + +/// 深拷贝状态盒到新对象(promote / sweep 用):新对象持独立 Box,源盒可安全释放。 +pub(crate) fn clone_async_native_with_rewrite( + old: &JsObject, new: &mut JsObject, mut rewrite: impl FnMut(JsValue) -> JsValue, +) { + let Some(state) = async_state_mut(old) else { + return; + }; + let cloned = AsyncState { + phase: state.phase, + callee: rewrite(state.callee), + args: state.args.iter().copied().map(&mut rewrite).collect(), + this_value: state.this_value, + result: rewrite(state.result), + promise: rewrite(state.promise), + resolve: rewrite(state.resolve), + reject: rewrite(state.reject), + regs: Box::new({ + let mut regs = [JsValue::undefined(); 256]; + for (i, v) in state.regs.iter().enumerate() { + regs[i] = rewrite(*v); + } + regs + }), + pc: state.pc, + bytecode: state.bytecode.clone(), + sub_idx: state.sub_idx, + active_reg_limit: state.active_reg_limit, + root_reg_limit: state.root_reg_limit, + frame: state.frame.as_ref().map(|f| CallFrame { + return_addr: f.return_addr, + function_name: f.function_name, + caller_reg_limit: f.caller_reg_limit, + saved_reg_offset: f.saved_reg_offset, + spill_offset: f.spill_offset, + arguments_base: f.arguments_base, + arguments_count: f.arguments_count, + saved_this: rewrite(f.saved_this), + saved_new_target: rewrite(f.saved_new_target), + callee: rewrite(f.callee), + construct_result_reg: f.construct_result_reg, + constructed_this: f.constructed_this.map(&mut rewrite), + is_derived_constructor: f.is_derived_constructor, + continuation: f.continuation, + }), + spill_stack: state.spill_stack.iter().copied().map(&mut rewrite).collect(), + save_stack: state.save_stack.iter().copied().map(&mut rewrite).collect(), + cell_stack: state.cell_stack.clone(), + try_stack: state.try_stack.clone(), + for_in_iters: state.for_in_iters.clone(), + for_of_iters: state.for_of_iters.iter().copied().map(&mut rewrite).collect(), + last_for_of_result: rewrite(state.last_for_of_result), + saved_bytecode_stack: state.saved_bytecode_stack.clone(), + saved_immutables_stack: state.saved_immutables_stack.clone(), + exception_value: state.exception_value.map(&mut rewrite), + pending_exception: state.pending_exception.map(&mut rewrite), + pending_error_kind: state.pending_error_kind, + pending_completion: state.pending_completion, + }; + new.set_native_data(Box::into_raw(Box::new(cloned)) as *mut u8); +} + +/// 释放异步状态盒(对象被 GC 回收时),返回释放字节数。 +pub(crate) fn drop_async_native(obj: &JsObject) -> u64 { + if !obj.is_async_obj() { + return 0; + } + let ptr = obj.native_data() as *mut AsyncState; + if ptr.is_null() { + return 0; + } + // SAFETY: 指针来自 create_async_context 的 Box::into_raw,只在 GC 回收时释放一次。 + let state = unsafe { Box::from_raw(ptr) }; + std::mem::size_of::() as u64 + + state.bytecode.len() as u64 * std::mem::size_of::() as u64 + + state.spill_stack.capacity() as u64 * std::mem::size_of::() as u64 + + state.save_stack.capacity() as u64 * std::mem::size_of::() as u64 + + state.args.capacity() as u64 * std::mem::size_of::() as u64 +} diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs index 722c16d4..f19c30dc 100644 --- a/crates/oxide_vm/src/dispatch/call.rs +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -748,6 +748,12 @@ impl Vm { self.regs[0] = gen; return Ok(false); } + // 异步函数调用返回 capability promise,立即同步执行 body 到首个 await。 + if sub_idx < self.sub_modules.len() && self.sub_modules[sub_idx].is_async { + let promise = self.create_async_object(callee, this_value, &args)?; + self.regs[0] = promise; + return Ok(false); + } self.push_bytecode_frame( callee, this_value, @@ -840,6 +846,12 @@ impl Vm { { return self.raise_type_error("g is not a constructor").map(|_| true); } + // 异步函数不是构造器:`new f()` 抛 TypeError。 + if (ctor_obj.sub_module_index() as usize) < self.sub_modules.len() + && self.sub_modules[ctor_obj.sub_module_index() as usize].is_async + { + return self.raise_type_error("g is not a constructor").map(|_| true); + } if self.frames.len() >= self.kernel_core.config.max_call_depth { return Err(self.error_message_text("RangeError", "Maximum call stack size exceeded")); } diff --git a/crates/oxide_vm/src/lib.rs b/crates/oxide_vm/src/lib.rs index 7a1a2f19..8cb894d2 100644 --- a/crates/oxide_vm/src/lib.rs +++ b/crates/oxide_vm/src/lib.rs @@ -9,6 +9,7 @@ /// 内置对象绑定模块:向 session 的 global 对象安装 Object/Array/... 及各原型。 pub mod bindings; +mod async_func; mod dispatch; mod generator; mod ic_helper; diff --git a/crates/oxide_vm/src/promise.rs b/crates/oxide_vm/src/promise.rs index 4f63457f..b7841b34 100644 --- a/crates/oxide_vm/src/promise.rs +++ b/crates/oxide_vm/src/promise.rs @@ -97,7 +97,7 @@ impl Vm { /// 新建 Promise 能力 `(promise, resolve, reject)`:resolve/reject 为携带 /// 目标 promise 的 native 闭包,同时写入状态盒供 thenable 委托取用。 - fn new_promise_capability(&mut self) -> (JsValue, JsValue, JsValue) { + pub(crate) fn new_promise_capability(&mut self) -> (JsValue, JsValue, JsValue) { let promise = self.create_promise_object(); let resolve = self.make_resolve_reject_fn(promise, false); let reject = self.make_resolve_reject_fn(promise, true); @@ -222,7 +222,7 @@ impl Vm { } /// 是否原生 Promise 对象。 - fn is_promise_value(&self, v: JsValue) -> bool { + pub(crate) fn is_promise_value(&self, v: JsValue) -> bool { v.is_object() && { let ptr = v.as_js_object_ptr(); !ptr.is_null() && unsafe { &*ptr }.is_promise_obj() @@ -349,7 +349,7 @@ impl Vm { } /// `PerformPromiseThen` 核心:注册 fulfill/reject 两条反应;已 settle 则直接入队。 - fn perform_promise_then( + pub(crate) fn perform_promise_then( &mut self, this_val: JsValue, on_fulfilled: JsValue, on_rejected: JsValue, ) -> Result { if !self.is_promise_value(this_val) { @@ -746,7 +746,7 @@ impl Vm { /// 给 native 函数对象补 `length`/`name` 数据属性(length 先于 name,符合 /// CreateBuiltinFunction 属性顺序)。 - fn add_fn_name_length(&mut self, obj: &mut JsObject, name: &str, length: u8) { + pub(crate) fn add_fn_name_length(&mut self, obj: &mut JsObject, name: &str, length: u8) { let attrs = PropAttributes::new(false, false, true); let sh = self.kernel_core.shape_forge().as_ref(); let sf = self.kernel_core.perm_interner().as_ref(); diff --git a/crates/oxide_vm/src/session_arena.rs b/crates/oxide_vm/src/session_arena.rs index 3243d455..5f58ca16 100644 --- a/crates/oxide_vm/src/session_arena.rs +++ b/crates/oxide_vm/src/session_arena.rs @@ -75,6 +75,11 @@ impl Vm { crate::promise::clone_promise_native_with_rewrite(src_ref, dst_ref, |value| { self.promote_value_if_epoch_object(value, forwarding) }); + } else if src_ref.is_async_obj() { + // 异步状态盒深拷贝到新对象:源盒随 epoch 释放,互不共享。 + crate::async_func::clone_async_native_with_rewrite(src_ref, dst_ref, |value| { + self.promote_value_if_epoch_object(value, forwarding) + }); } dst } diff --git a/crates/oxide_vm/src/session_gc.rs b/crates/oxide_vm/src/session_gc.rs index bcafc09f..9307bf3f 100644 --- a/crates/oxide_vm/src/session_gc.rs +++ b/crates/oxide_vm/src/session_gc.rs @@ -95,6 +95,9 @@ impl SessionGc { if obj.is_promise_obj() { edges.extend(crate::promise::promise_native_edges(obj)); } + if obj.is_async_obj() { + edges.extend(crate::async_func::async_native_edges(obj)); + } // 遍历 upvalue cell 中的对象引用。 for cell_ptr in obj.upvalues_slice() { if cell_ptr.is_null() { @@ -164,6 +167,13 @@ impl SessionGc { } } } + if obj.is_async_obj() { + for value in crate::async_func::async_native_edges(obj) { + if value.is_string() { + live.insert(value.as_string_ptr_mut()); + } + } + } } pub(crate) fn mark(&mut self, vm: &Vm) { @@ -275,6 +285,7 @@ impl SessionGc { freed_bytes += data_view::drop_data_view_native(obj); freed_bytes += crate::generator::drop_generator_native(obj); freed_bytes += crate::promise::drop_promise_native(obj); + freed_bytes += crate::async_func::drop_async_native(obj); freed_bytes } @@ -333,6 +344,8 @@ impl SessionGc { data_view::clone_data_view_native_with_rewrite(old_ref, new_ref, |value| value); } else if old_ref.is_promise_obj() { crate::promise::clone_promise_native_with_rewrite(old_ref, new_ref, |value| value); + } else if old_ref.is_async_obj() { + crate::async_func::clone_async_native_with_rewrite(old_ref, new_ref, |value| value); } forwarding.insert(old_ptr, new_ptr); freed_bytes += Self::drop_session_object_heap_data(old_ptr); @@ -366,6 +379,8 @@ impl SessionGc { crate::generator::rewrite_generator_native(obj, |value| rewrite_forwarded_value(value, &forwarding)); } else if obj.is_promise_obj() { crate::promise::rewrite_promise_native(obj, |value| rewrite_forwarded_value(value, &forwarding)); + } else if obj.is_async_obj() { + crate::async_func::rewrite_async_native(obj, |value| rewrite_forwarded_value(value, &forwarding)); } } diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index eef9ddc1..1cff42b6 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -138,6 +138,7 @@ pub struct ForInIter<'bump> { } /// try/catch/finally 处理记录,异常展开时用于定位跳转目标与清理范围。 +#[derive(Debug, Clone, Copy)] pub struct TryHandler { pub catch_pc: Option, pub finally_pc: Option, @@ -249,6 +250,8 @@ pub struct Vm { pub promise_constructor: P, /// `%Promise.prototype%`:Promise 实例的原型(then/catch/finally 方法挂此)。 pub promise_proto: P, + /// `%AsyncFunction.prototype%`:异步函数对象的原型(`constructor` 指向 `%AsyncFunction%`)。 + pub async_function_proto: P, /// 微任务队列(Promise reactions / thenable 委托),`run()` 末尾 FIFO drain。 pub(crate) job_queue: VecDeque, pub math_rng_state: u64, @@ -302,6 +305,15 @@ pub struct Vm { pub(crate) generator_init_step: bool, /// 参数初始化步中已越过 body 起点标记的信号(`initialize_generator` 消费后复位)。 pub(crate) generator_body_started: bool, + /// 当前正在执行的异步函数上下文对象(`OBJ_TYPE_ASYNC`,持有 AsyncState 快照)。 + /// AWAIT dispatch 据此登记恢复反应;跨嵌套 async 调用保存/恢复。 + pub(crate) async_context: Option, + /// 异步体 `dispatch()` 让出时的信号:AWAIT 置 true,恢复方(async 内嵌 dispatch + /// 循环)取走并快照挂起状态。false = 正常返回/异常。 + pub(crate) async_suspended: bool, + /// 当前是否处于异步函数内嵌 dispatch 循环:异步帧弹出且 frames 清空时, + /// `do_return` 据此把结果交付给恢复方(与 generator_dispatch 同语义)。 + pub(crate) async_dispatch: bool, /// 分组保存 session arena / GC 簿记状态。 pub(crate) gc_state: GcState, /// 分组保存 `Symbol` intern 状态。 @@ -1551,6 +1563,13 @@ impl Vm { } } + OpCode::AWAIT => { + // 异步帧挂起:登记恢复反应后内嵌 dispatch 返回,恢复方快照挂起状态。 + self.dispatch_await(rd)?; + self.profiling.set_instruction_count(steps); + return Ok(JsValue::undefined()); + } + _ => { return Err(format!("opcode {op} not yet implemented")); } diff --git a/crates/oxide_vm/src/vm_dispatch_ctrl.rs b/crates/oxide_vm/src/vm_dispatch_ctrl.rs index e9ac4850..810f27e3 100644 --- a/crates/oxide_vm/src/vm_dispatch_ctrl.rs +++ b/crates/oxide_vm/src/vm_dispatch_ctrl.rs @@ -41,6 +41,12 @@ impl Vm { self.regs[0] = gen; return Ok(false); } + // 异步函数调用返回 capability promise,立即同步执行 body 到首个 await。 + if sub_idx < self.sub_modules.len() && self.sub_modules[sub_idx].is_async { + let promise = self.create_async_object(callee, self.regs[this_reg as usize], &args)?; + self.regs[0] = promise; + return Ok(false); + } self.push_bytecode_frame( callee, self.regs[this_reg as usize], @@ -327,8 +333,8 @@ impl Vm { } } } - // 生成器内嵌 dispatch:帧全部弹出后把结果交付恢复方,而非继续执行。 - if self.frames.is_empty() && self.generator_dispatch { + // 生成器/异步内嵌 dispatch:帧全部弹出后把结果交付恢复方,而非继续执行。 + if self.frames.is_empty() && (self.generator_dispatch || self.async_dispatch) { return Ok(Some(result)); } Ok(None) diff --git a/crates/oxide_vm/src/vm_dispatch_misc.rs b/crates/oxide_vm/src/vm_dispatch_misc.rs index 08f701ad..fd36223b 100644 --- a/crates/oxide_vm/src/vm_dispatch_misc.rs +++ b/crates/oxide_vm/src/vm_dispatch_misc.rs @@ -99,6 +99,10 @@ impl Vm { if self.sub_modules[sub_idx].is_generator { return self.raise_type_error("g is not a constructor").map(|_| true); } + // 异步函数不是构造器:`new f()` 抛 TypeError。 + if self.sub_modules[sub_idx].is_async { + return self.raise_type_error("g is not a constructor").map(|_| true); + } if self.frames.len() >= self.kernel_core.config.max_call_depth { return Err(self.error_message_text("RangeError", "Maximum call stack size exceeded")); diff --git a/crates/oxide_vm/src/vm_runtime.rs b/crates/oxide_vm/src/vm_runtime.rs index bf493bca..1d02e043 100644 --- a/crates/oxide_vm/src/vm_runtime.rs +++ b/crates/oxide_vm/src/vm_runtime.rs @@ -116,6 +116,10 @@ impl Vm { if self.sub_modules[sub_idx].is_generator { return self.create_generator_object(callee, receiver, args); } + // 异步函数调用返回 capability promise,立即同步执行 body 到首个 await。 + if self.sub_modules[sub_idx].is_async { + return self.create_async_object(callee, receiver, args); + } self.native_call_depth += 1; let subs = Arc::clone(&self.sub_modules); diff --git a/crates/oxide_vm/src/vm_support.rs b/crates/oxide_vm/src/vm_support.rs index d7402fa7..15245538 100644 --- a/crates/oxide_vm/src/vm_support.rs +++ b/crates/oxide_vm/src/vm_support.rs @@ -37,6 +37,7 @@ impl Vm { generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), promise_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), promise_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), + async_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), job_queue: VecDeque::new(), math_rng_state: 0, sub_modules: Arc::new(Vec::new()), @@ -62,6 +63,9 @@ impl Vm { generator_dispatch: false, generator_init_step: false, generator_body_started: false, + async_context: None, + async_suspended: false, + async_dispatch: false, gc_state: GcState { session_epoch: bumpalo::Bump::new(), session_gc: crate::session_gc::SessionGc::new(), @@ -91,6 +95,7 @@ impl Vm { }; vm.init_generator_intrinsics(); vm.init_promise_intrinsics(); + vm.init_async_intrinsics(); // Promise 全局绑定发生在快照采集之后,重录快照避免首次 full_reset 误判脏。 vm.session.record_snapshot(); vm_info!("Vm created"); @@ -117,6 +122,7 @@ impl Vm { generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), promise_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), promise_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), + async_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), job_queue: VecDeque::new(), math_rng_state: 0, sub_modules: Arc::new(Vec::new()), @@ -142,6 +148,9 @@ impl Vm { generator_dispatch: false, generator_init_step: false, generator_body_started: false, + async_context: None, + async_suspended: false, + async_dispatch: false, gc_state: GcState { session_epoch: bumpalo::Bump::new(), session_gc: crate::session_gc::SessionGc::new(), @@ -171,6 +180,7 @@ impl Vm { }; vm.init_generator_intrinsics(); vm.init_promise_intrinsics(); + vm.init_async_intrinsics(); // Promise 全局绑定发生在快照采集之后,重录快照避免首次 full_reset 误判脏。 vm.session.record_snapshot(); vm_info!("Vm created (pool)"); @@ -185,6 +195,13 @@ impl Vm { crate::generator::init_generator_intrinsics(self); } + /// 初始化/重建异步函数内建对象(`%AsyncFunction.prototype%`)。 + /// + /// 在 VM 创建与 `full_reset`(session 重建)后调用。 + pub(crate) fn init_async_intrinsics(&mut self) { + crate::async_func::init_async_intrinsics(self); + } + /// 全量隔离重置:仅重建被污染的内置对象与 global,并清空所有执行状态与内存。 /// /// 用于在多次 JS 执行之间达到完全隔离:session 内未被污染的 builtin 保留原指针。 @@ -201,6 +218,7 @@ impl Vm { self.object_prototype = P::clone(&self.session.builtin_world().object_proto); self.init_generator_intrinsics(); self.init_promise_intrinsics(); + self.init_async_intrinsics(); // 快照须在 Promise 全局绑定之后采集:绑定会修改 global 世代。 self.session.record_snapshot(); self.clear_full_reset_state(); @@ -215,6 +233,7 @@ impl Vm { self.object_prototype = P::clone(&self.session.builtin_world().object_proto); self.init_generator_intrinsics(); self.init_promise_intrinsics(); + self.init_async_intrinsics(); self.session.record_snapshot(); self.clear_full_reset_state(); } @@ -274,6 +293,9 @@ impl Vm { self.generator_dispatch = false; self.generator_init_step = false; self.generator_body_started = false; + self.async_context = None; + self.async_suspended = false; + self.async_dispatch = false; self.native_call_depth = 0; // 微任务队列是执行期状态:跨 run 不保留。 self.job_queue.clear(); @@ -343,8 +365,11 @@ impl Vm { // 生成器函数对象:原型为 %GeneratorFunction.prototype%(constructor 链解析到 // "GeneratorFunction"),且不像普通函数那样拥有 `prototype` 属性。 let is_generator = self.sub_modules.get(sub_idx as usize).map(|m| m.is_generator).unwrap_or(false); + let is_async = self.sub_modules.get(sub_idx as usize).map(|m| m.is_async).unwrap_or(false); let proto_val = if is_generator { JsValue::from_js_object(self.generator_function_proto.as_ptr() as *mut JsObject) + } else if is_async { + JsValue::from_js_object(self.async_function_proto.as_ptr() as *mut JsObject) } else { JsValue::from_js_object(self.session.builtin_world().function_proto.as_ptr() as *mut JsObject) }; diff --git a/crates/oxide_vm/tests/async_tests.rs b/crates/oxide_vm/tests/async_tests.rs new file mode 100644 index 00000000..7f3b2008 --- /dev/null +++ b/crates/oxide_vm/tests/async_tests.rs @@ -0,0 +1,118 @@ +//! async/await 运行时测试:异步函数调用返回 promise、await 恢复、reject 进 catch、 +//! 多 await 顺序、嵌套 async、微任务执行序。 + +use oxide_compiler::compiler::Compiler; +use oxide_parser::Allocator; +use oxide_vm::promise::promise_settled_value; +use oxide_vm::vm::Vm; + +/// 执行源码并格式化顶层结果;Promise 结果取其 drain 后的 settled 值。 +fn eval(source: &str) -> String { + let allocator = Allocator::default(); + let program = match oxide_parser::parse(&allocator, source) { + Ok(p) => p, + Err(e) => return format!("parse error: {}", e[0].message), + }; + let module = match Compiler::new().compile(&program) { + Ok(m) => m, + Err(e) => return format!("compile error: {e}"), + }; + let mut vm = Vm::new(); + match vm.run(&module) { + Ok(result) => format_value(&vm, result), + Err(e) => format!("vm error: {e}"), + } +} + +fn format_value(vm: &Vm, val: oxide_vm::JsValue) -> String { + if val.is_string() { + format!("\"{}\"", vm.lookup_str(val).unwrap_or_default()) + } else if val.is_object() { + let obj = unsafe { &*val.as_js_object_ptr() }; + if obj.is_promise_obj() { + match promise_settled_value(obj) { + Some((true, v)) => format_value(vm, v), + Some((false, v)) => format!("", format_value(vm, v)), + None => "".to_string(), + } + } else if obj.is_array() { + format!("[array]") + } else { + "[object]".to_string() + } + } else { + format!("{val}") + } +} + +#[test] +fn async_returns_immediate_value() { + assert_eq!(eval("async function f(){ return 42 } f()"), "42"); +} + +#[test] +fn async_await_primitive() { + assert_eq!(eval("async function f(){ var v = await 10; return v*2 } f()"), "20"); +} + +#[test] +fn async_await_resolved_promise() { + assert_eq!(eval("async function f(){ var v = await Promise.resolve(5); return v+1 } f()"), "6"); +} + +#[test] +fn async_await_reject_into_catch() { + assert_eq!( + eval("async function f(){ try { await Promise.reject('e') } catch(e) { return 'caught:'+e } } f()"), + "\"caught:e\"" + ); +} + +#[test] +fn async_multiple_awaits_in_order() { + assert_eq!(eval("async function f(){ var x = await 1; x += await 2; return x } f()"), "3"); +} + +#[test] +fn async_await_return_promise() { + assert_eq!(eval("async function f(){ return await Promise.resolve(7) } f()"), "7"); +} + +#[test] +fn async_nested_calls() { + assert_eq!(eval("async function g(){ return 2 } async function f(){ return await g() + 3 } f()"), "5"); +} + +#[test] +fn async_arrow_in_then() { + assert_eq!(eval("Promise.resolve().then(async ()=>{ return 9 }).then(v=>v)"), "9"); +} + +#[test] +fn async_execution_order_suspends_immediately() { + // await 挂起 body;当前同步代码先跑完,body 恢复在微任务 drain 阶段。 + assert_eq!( + eval("var order=[]; async function f(){ order.push(1); await 0; order.push(2) } f(); order.push(0); Promise.resolve().then(function(){ return order.join(',') })"), + "\"1,0,2\"" + ); +} + +#[test] +fn async_throw_rejects_promise() { + assert_eq!(eval("async function f(){ throw 'boom' } f()"), ""); +} + +#[test] +fn async_is_not_constructor() { + assert!(eval("new (async function(){})").starts_with("vm error") || eval("new (async function(){})").contains("not a constructor")); +} + +#[test] +fn async_constructor_name() { + assert_eq!(eval("async function f(){}; f.constructor.name"), "\"AsyncFunction\""); +} + +#[test] +fn async_class_method() { + assert_eq!(eval("class A { async m(){ return await 7 } } new A().m()"), "7"); +}