feat: async/await 语法支持(AWAIT 帧快照挂起/恢复 + 微任务驱动 + AsyncFunction intrinsics)
This commit is contained in:
@@ -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<JsValue>,
|
||||
/// 首次调用时的方法接收者(`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<opcode::Instr>,
|
||||
/// 异步模块 flat_id(恢复时重激活 immutables)。
|
||||
pub sub_idx: u32,
|
||||
pub active_reg_limit: u8,
|
||||
pub root_reg_limit: u8,
|
||||
/// 异步帧(压入时由 push_bytecode_frame 构造,挂起时弹出存此)。
|
||||
pub frame: Option<CallFrame>,
|
||||
pub spill_stack: Vec<JsValue>,
|
||||
pub save_stack: Vec<JsValue>,
|
||||
pub cell_stack: Vec<Vec<*mut Cell>>,
|
||||
pub try_stack: Vec<TryHandler>,
|
||||
pub for_in_iters: Vec<*mut ForInIter<'static>>,
|
||||
pub for_of_iters: Vec<JsValue>,
|
||||
pub last_for_of_result: JsValue,
|
||||
pub saved_bytecode_stack: Vec<Vec<opcode::Instr>>,
|
||||
pub saved_immutables_stack: Vec<*const [JsValue]>,
|
||||
/// 在途异常/完成(异常展开穿越 await 挂起时保留,恢复后继续展开)。
|
||||
pub exception_value: Option<JsValue>,
|
||||
pub pending_exception: Option<JsValue>,
|
||||
pub pending_error_kind: Option<&'static str>,
|
||||
pub pending_completion: Option<Completion>,
|
||||
}
|
||||
|
||||
/// 一次 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<JsValue, String> {
|
||||
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<JsValue, JsValue>) -> 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<JsValue> {
|
||||
let Some(state) = async_state_mut(obj) else {
|
||||
return Vec::new();
|
||||
};
|
||||
let mut edges = Vec::new();
|
||||
let push = |v: JsValue, edges: &mut Vec<JsValue>| {
|
||||
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::<AsyncState>() as u64
|
||||
+ state.bytecode.len() as u64 * std::mem::size_of::<u32>() as u64
|
||||
+ state.spill_stack.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
|
||||
+ state.save_stack.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
|
||||
+ state.args.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
/// 内置对象绑定模块:向 session 的 global 对象安装 Object/Array/... 及各原型。
|
||||
pub mod bindings;
|
||||
mod async_func;
|
||||
mod dispatch;
|
||||
mod generator;
|
||||
mod ic_helper;
|
||||
|
||||
@@ -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<JsValue, JsValue> {
|
||||
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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,6 +138,7 @@ pub struct ForInIter<'bump> {
|
||||
}
|
||||
|
||||
/// try/catch/finally 处理记录,异常展开时用于定位跳转目标与清理范围。
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TryHandler {
|
||||
pub catch_pc: Option<usize>,
|
||||
pub finally_pc: Option<usize>,
|
||||
@@ -249,6 +250,8 @@ pub struct Vm {
|
||||
pub promise_constructor: P<JsObject>,
|
||||
/// `%Promise.prototype%`:Promise 实例的原型(then/catch/finally 方法挂此)。
|
||||
pub promise_proto: P<JsObject>,
|
||||
/// `%AsyncFunction.prototype%`:异步函数对象的原型(`constructor` 指向 `%AsyncFunction%`)。
|
||||
pub async_function_proto: P<JsObject>,
|
||||
/// 微任务队列(Promise reactions / thenable 委托),`run()` 末尾 FIFO drain。
|
||||
pub(crate) job_queue: VecDeque<crate::promise::Microtask>,
|
||||
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<JsValue>,
|
||||
/// 异步体 `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"));
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
|
||||
@@ -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!("<rejected {}>", format_value(vm, v)),
|
||||
None => "<pending>".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()"), "<rejected \"boom\">");
|
||||
}
|
||||
|
||||
#[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");
|
||||
}
|
||||
Reference in New Issue
Block a user