From abbabfc54e1c6f56301bf62f0f95fbe4e77ef855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Mon, 10 Aug 2026 13:28:14 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20GeneratorState=20=E6=94=B6=E6=95=9B?= =?UTF-8?q?=E5=88=B0=20SuspendedFrame=EF=BC=88save/restore/GC=20=E9=81=8D?= =?UTF-8?q?=E5=8E=86/string=20=E8=BE=B9=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_vm/src/generator.rs | 258 +++++------------------------- crates/oxide_vm/src/session_gc.rs | 6 +- crates/oxide_vm/src/vm_runtime.rs | 28 +++- 3 files changed, 73 insertions(+), 219 deletions(-) diff --git a/crates/oxide_vm/src/generator.rs b/crates/oxide_vm/src/generator.rs index d1fd7c1..3774318 100644 --- a/crates/oxide_vm/src/generator.rs +++ b/crates/oxide_vm/src/generator.rs @@ -9,14 +9,13 @@ use std::sync::Arc; use oxide_builtins::iterator::{is_callable, make_iter_result}; -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}; +use oxide_types::object::{JsObject, NativeFnPtr}; use oxide_types::value::JsValue; -use crate::vm::{CallFrame, ForInIter, FrameContinuation, TryHandler, Vm}; +use crate::vm::Vm; /// 生成器执行阶段。 #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -45,32 +44,8 @@ pub(crate) struct GeneratorState { pub this_value: JsValue, /// 完成后返回值。 pub result: 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, - /// `yield*` 委托中的内层迭代器:Some = 挂起在委托点,恢复时转发 next/return/throw。 - pub delegated_iterator: Option, - pub saved_bytecode_stack: Vec>, - pub saved_immutables_stack: Vec<*const [JsValue]>, - /// 在途异常/完成(throw 穿越 finally 挂起时保留,恢复后继续展开)。 - pub exception_value: Option, - pub pending_exception: Option, - pub pending_error_kind: Option<&'static str>, - pub pending_completion: Option, + /// 挂起时的执行上下文(regs/pc/bytecode/各栈段/迭代器/在途异常)。 + pub suspended: crate::suspended::SuspendedFrame, } /// `next()/return()/throw()` 的注入模式。 @@ -137,27 +112,7 @@ impl Vm { args: args.to_vec(), this_value, result: JsValue::undefined(), - 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(), - delegated_iterator: None, - saved_bytecode_stack: Vec::new(), - saved_immutables_stack: Vec::new(), - exception_value: None, - pending_exception: None, - pending_error_kind: None, - pending_completion: None, + suspended: crate::suspended::SuspendedFrame::new_empty(), }); obj_ref.set_native_data(Box::into_raw(state) as *mut u8); self.gc_state.track_epoch_object(obj); @@ -199,33 +154,10 @@ impl Vm { self.native_call_depth += 1; // 压入生成器帧(New)。 - 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, - ); + let push_res = self.prepare_execution_initial(callee, this_value, &args); unsafe { (*state_ptr).args = args }; if let Err(e) = push_res { self.restore_inline_state(saved); @@ -332,33 +264,10 @@ impl Vm { // 首次执行:压入生成器帧;挂起:恢复快照。 if was_new { - 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.delegated_iterator = None; - 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 args = unsafe { std::mem::take(&mut (*state_ptr).args) }; - let push_res = self.push_bytecode_frame( - callee, - JsValue::undefined(), - &args, - None, - None, - JsValue::undefined(), - FrameContinuation::None, - ); + let push_res = self.prepare_execution_initial(callee, JsValue::undefined(), &args); unsafe { (*state_ptr).args = args }; if let Err(e) = push_res { self.restore_inline_state(saved); @@ -367,38 +276,13 @@ impl Vm { unsafe { (*state_ptr).phase = GeneratorPhase::Running }; } else { 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 { + let restore_res = state.suspended.restore_into(self, &subs); + if restore_res.is_err() { // 挂起状态跨 run:sub_modules 已重建,无法恢复(与动态函数同限制)。 self.restore_inline_state(saved); return Err("generator 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.delegated_iterator = state.delegated_iterator.take(); - 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 = GeneratorPhase::Running; // `yield*` 委托恢复:把 next/return/throw 请求转发给内层迭代器,按内层 @@ -747,37 +631,10 @@ impl Vm { /// 把当前 VM 执行状态(生成器 body 刚在嵌套 dispatch 中让出)快照进状态盒。 /// - /// 生成器帧弹出存 `frame`,其余栈段整段搬入(嵌套循环期间这些栈只含生成器数据)。 + /// 生成器帧弹出存 `suspended.frame`,其余栈段整段搬入(嵌套循环期间这些栈 + /// 只含生成器数据)。 fn snapshot_generator(&mut self, state: &mut GeneratorState) -> Result<(), String> { - let frame = self - .frames - .pop() - .ok_or_else(|| "generator frame missing on yield".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.delegated_iterator = self.delegated_iterator.take(); - 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.suspended.save_from(self, state.callee)?; state.phase = GeneratorPhase::Suspended; Ok(()) } @@ -965,35 +822,40 @@ pub(crate) fn generator_native_edges(obj: &JsObject) -> Vec { push(state.callee, &mut edges); edges.extend(state.args.iter().copied().filter(|v| v.is_object())); push(state.result, &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); + state.suspended.for_each_value(|v| { + if v.is_object() { + edges.push(v); } - } - 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); - if let Some(iter) = state.delegated_iterator { - push(iter, &mut edges); - } + }); edges } +/// 生成器状态内所有 session 字符串的扁平列表(GC mark 字符串边)。 +/// 与 `generator_native_edges` 的对象收集互补,经同一字段清单(自身字段 + +/// `suspended.for_each_value`)产出字符串。 +pub(crate) fn generator_native_string_edges(obj: &JsObject) -> Vec<*mut oxide_types::object::JsString> { + let Some(state) = generator_state_mut(obj) else { + return Vec::new(); + }; + let mut out = Vec::new(); + let push_str = |v: JsValue, out: &mut Vec<*mut oxide_types::object::JsString>| { + if v.is_string() { + out.push(v.as_string_ptr_mut()); + } + }; + push_str(state.callee, &mut out); + for &v in &state.args { + push_str(v, &mut out); + } + push_str(state.result, &mut out); + state.suspended.for_each_value(|v| { + if v.is_string() { + out.push(v.as_string_ptr_mut()); + } + }); + out +} + /// 用转发函数重写状态快照中的所有 JsValue(session GC 移动式清扫 / promote 用)。 pub(crate) fn rewrite_generator_native(obj: &JsObject, mut rewrite: impl FnMut(JsValue) -> JsValue) { let Some(state) = generator_state_mut(obj) else { @@ -1004,36 +866,7 @@ pub(crate) fn rewrite_generator_native(obj: &JsObject, mut rewrite: impl FnMut(J *v = rewrite(*v); } state.result = rewrite(state.result); - 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); - state.delegated_iterator = state.delegated_iterator.map(&mut rewrite); + state.suspended.rewrite_values(rewrite); } /// 释放生成器状态盒(对象被 GC 回收时),返回释放字节数。 @@ -1048,9 +881,6 @@ pub(crate) fn drop_generator_native(obj: &JsObject) -> u64 { // SAFETY: 指针来自 create_generator_object 的 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.for_of_iters.capacity() as u64 * std::mem::size_of::() as u64 + + state.suspended.heap_bytes() + state.args.capacity() as u64 * std::mem::size_of::() as u64 } diff --git a/crates/oxide_vm/src/session_gc.rs b/crates/oxide_vm/src/session_gc.rs index 489baf6..f485348 100644 --- a/crates/oxide_vm/src/session_gc.rs +++ b/crates/oxide_vm/src/session_gc.rs @@ -157,10 +157,8 @@ impl SessionGc { } } if obj.is_generator_obj() { - for value in crate::generator::generator_native_edges(obj) { - if value.is_string() { - live.insert(value.as_string_ptr_mut()); - } + for ptr in crate::generator::generator_native_string_edges(obj) { + live.insert(ptr); } } if obj.is_promise_obj() { diff --git a/crates/oxide_vm/src/vm_runtime.rs b/crates/oxide_vm/src/vm_runtime.rs index 80d3dc3..acaf17b 100644 --- a/crates/oxide_vm/src/vm_runtime.rs +++ b/crates/oxide_vm/src/vm_runtime.rs @@ -2,7 +2,7 @@ use std::sync::{Arc, OnceLock}; use oxide_bytecode::module::CompiledModule; -use crate::vm::{CallFrame, InlineSyncState, Vm}; +use crate::vm::{CallFrame, FrameContinuation, InlineSyncState, Vm}; use crate::{vm_debug, vm_info, vm_trace, vm_warn}; use oxide_types::object::JsObject; use oxide_types::value::JsValue; @@ -84,6 +84,32 @@ impl Vm { self.inline_args_count = saved.inline_args_count; } + /// 首次执行的 VM 就绪:清空执行核心(regs/pc/bytecode/各栈段/迭代器/内联态), + /// 压入首帧。参数初始化步与 async/gen 调度标志由调用方管理。 + /// + /// # 边界 + /// callee 非函数 / sub_idx 越界 / 超调用深度时由 push_bytecode_frame 返回 Err。 + pub(crate) fn prepare_execution_initial( + &mut self, callee: JsValue, this_value: JsValue, args: &[JsValue], + ) -> Result<(), String> { + 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; + self.push_bytecode_frame(callee, this_value, args, None, None, JsValue::undefined(), FrameContinuation::None) + } + pub(crate) fn call_bytecode_function_inline( &mut self, callee: JsValue, callee_obj: &JsObject, receiver: JsValue, args: &[JsValue], ) -> Result {