refactor: GeneratorState 收敛到 SuspendedFrame(save/restore/GC 遍历/string 边)

This commit is contained in:
2026-08-10 13:28:14 +08:00
parent 7318f8f2eb
commit 9d18eb2533
3 changed files with 73 additions and 219 deletions
+44 -214
View File
@@ -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<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,
/// `yield*` 委托中的内层迭代器:Some = 挂起在委托点,恢复时转发 next/return/throw。
pub delegated_iterator: Option<JsValue>,
pub saved_bytecode_stack: Vec<Vec<opcode::Instr>>,
pub saved_immutables_stack: Vec<*const [JsValue]>,
/// 在途异常/完成(throw 穿越 finally 挂起时保留,恢复后继续展开)。
pub exception_value: Option<JsValue>,
pub pending_exception: Option<JsValue>,
pub pending_error_kind: Option<&'static str>,
pub pending_completion: Option<crate::vm::Completion>,
/// 挂起时的执行上下文(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<JsValue> {
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::<GeneratorState>() 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.for_of_iters.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
+ state.suspended.heap_bytes()
+ state.args.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
}
+2 -4
View File
@@ -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() {
+27 -1
View File
@@ -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<JsValue, String> {