refactor: VM 统一 GC 遍历 for_each_value/rewrite_values(双子清单收敛三处手写清单)

This commit is contained in:
爱特每羊队
2026-08-10 13:57:13 +08:00
parent b808261135
commit 3947c5db85
2 changed files with 135 additions and 73 deletions
+48 -59
View File
@@ -7,7 +7,7 @@ use oxide_types::object::{JsObject, JsString, PropMetaEntry};
use oxide_types::value::JsValue;
use rustc_hash::FxBuildHasher;
use crate::vm::{Completion, Vm};
use crate::vm::Vm;
use oxide_builtins::{array_buffer, data_view, map, regexp, set, typed_array};
/// session 级 mark-sweep GC 的状态与统计。
@@ -553,63 +553,8 @@ fn rewrite_forwarded_value(
fn rewrite_vm_roots(vm: &mut Vm, forwarding: &HashMap<*mut JsObject, *mut JsObject, FxBuildHasher>) {
vm_debug!("[GC] rewrite_vm_roots: {} forwarded objects", forwarding.len());
for value in &mut vm.regs {
*value = rewrite_forwarded_value(*value, forwarding);
}
for value in &mut vm.save_stack {
*value = rewrite_forwarded_value(*value, forwarding);
}
for value in &mut vm.spill_stack {
*value = rewrite_forwarded_value(*value, forwarding);
}
for frame in &mut vm.frames {
frame.saved_this = rewrite_forwarded_value(frame.saved_this, forwarding);
frame.saved_new_target = rewrite_forwarded_value(frame.saved_new_target, forwarding);
frame.callee = rewrite_forwarded_value(frame.callee, forwarding);
frame.constructed_this = frame.constructed_this.map(|value| rewrite_forwarded_value(value, forwarding));
}
vm.exception_value = vm.exception_value.map(|value| rewrite_forwarded_value(value, forwarding));
vm.pending_exception = vm.pending_exception.map(|value| rewrite_forwarded_value(value, forwarding));
vm.last_uncaught_value = vm.last_uncaught_value.map(|value| rewrite_forwarded_value(value, forwarding));
vm.pending_completion = vm.pending_completion.map(|completion| match completion {
Completion::Return { value, remaining_finally } => Completion::Return {
value: rewrite_forwarded_value(value, forwarding),
remaining_finally,
},
other => other,
});
vm.generator_suspended = vm.generator_suspended.map(|value| rewrite_forwarded_value(value, forwarding));
vm.delegated_iterator = vm.delegated_iterator.map(|value| rewrite_forwarded_value(value, forwarding));
vm.async_context = vm.async_context.map(|value| rewrite_forwarded_value(value, forwarding));
vm.async_gen_context = vm.async_gen_context.map(|value| rewrite_forwarded_value(value, forwarding));
vm.inline_callee = vm.inline_callee.map(|value| rewrite_forwarded_value(value, forwarding));
for value in &mut vm.iters.for_of_iters {
*value = rewrite_forwarded_value(*value, forwarding);
}
vm.iters.last_for_of_result = rewrite_forwarded_value(vm.iters.last_for_of_result, forwarding);
// 微任务队列中的值随 sweep 重写。
for job in &mut vm.job_queue {
crate::promise::rewrite_job_values(job, |value| rewrite_forwarded_value(value, forwarding));
}
// 已转换的不可变常量不是 session 值(标量 + perm 字符串)——不重写。
for iter in &mut vm.iters.for_in_iters {
if iter.is_null() {
continue;
}
// SAFETY: for_in_iters 存放由当前 VM epoch 拥有的存活迭代器指针。
unsafe {
for (value, _si) in (*(*iter)).keys.iter_mut() {
*value = rewrite_forwarded_value(*value, forwarding);
}
}
}
let global_ptr = vm.session.global_object().as_ptr() as *mut JsObject;
if !global_ptr.is_null() {
// SAFETY: KernelSession 在 VM 生命周期内拥有 global_object。
unsafe {
(*global_ptr).rewrite_object_values(|value| rewrite_forwarded_value(value, forwarding));
}
}
// 统一遍历:与 for_each_value 共用同一字段清单。
vm.rewrite_values(|value| rewrite_forwarded_value(value, forwarding));
}
#[cfg(test)]
@@ -720,8 +665,52 @@ mod tests {
}
#[test]
fn mark_phase_reaches_cycles_and_unreachable_are_unmarked() {
fn rewrite_matches_roots_coverage() {
// 指针重写必须覆盖根收集访问的同一组执行核心字段:session→marker 映射后,
// 每个持有 session 的字段都应被改写为 marker(与 Step 1 的 for_each 覆盖测试
// 互补,共同构成孪生清单验证)。
let mut vm = Vm::new();
let obj = plain_object(&mut vm);
let session = vm.promote_object(obj);
let marker = plain_object(&mut vm);
let marker_session = vm.promote_object(marker);
vm.regs[0] = JsValue::from_js_object(session);
vm.last_uncaught_value = Some(JsValue::from_js_object(session));
vm.generator_suspended = Some(JsValue::from_js_object(session));
vm.delegated_iterator = Some(JsValue::from_js_object(session));
vm.async_context = Some(JsValue::from_js_object(session));
vm.async_gen_context = Some(JsValue::from_js_object(session));
vm.inline_callee = Some(JsValue::from_js_object(session));
vm.pending_completion = Some(crate::vm::Completion::Return {
value: JsValue::from_js_object(session),
remaining_finally: 0,
});
let mut forwarding = std::collections::HashMap::new();
forwarding.insert(session, marker_session);
vm.rewrite_values(|v| {
if v.is_object() {
if let Some(&m) = forwarding.get(&v.as_js_object_ptr()) {
return JsValue::from_js_object(m);
}
}
v
});
assert_eq!(vm.regs[0].as_js_object_ptr(), marker_session);
assert_eq!(vm.last_uncaught_value.unwrap().as_js_object_ptr(), marker_session);
assert_eq!(vm.generator_suspended.unwrap().as_js_object_ptr(), marker_session);
assert_eq!(vm.delegated_iterator.unwrap().as_js_object_ptr(), marker_session);
assert_eq!(vm.async_context.unwrap().as_js_object_ptr(), marker_session);
assert_eq!(vm.async_gen_context.unwrap().as_js_object_ptr(), marker_session);
assert_eq!(vm.inline_callee.unwrap().as_js_object_ptr(), marker_session);
match vm.pending_completion.unwrap() {
crate::vm::Completion::Return { value, .. } => assert_eq!(value.as_js_object_ptr(), marker_session),
_ => panic!("expected Return completion"),
}
}
#[test]
fn mark_phase_reaches_cycles_and_unreachable_are_unmarked() { let mut vm = Vm::new();
let root = plain_object(&mut vm);
let reachable = plain_object(&mut vm);
let unreachable = plain_object(&mut vm);
+87 -14
View File
@@ -520,11 +520,13 @@ impl Vm {
self.active_immutables = vec.as_slice() as *const [JsValue];
}
pub(crate) fn for_each_root(&self, mut f: impl FnMut(JsValue)) {
/// GC 根收集的统一遍历(对象与字符串都产出)。与 `rewrite_values` 字段一一对应。
/// 覆盖执行核心的全部 JsValue 持有点:regs/帧/各栈段/cell/在途异常与完成/
/// 挂起信号/迭代器/微任务/global。新增执行字段必须同时登记在此与
/// `rewrite_values`。
pub(crate) fn for_each_value(&self, mut f: impl FnMut(JsValue)) {
for value in &self.regs {
if value.is_object() || value.is_string() {
f(*value);
}
f(*value);
}
for frame in &self.frames {
f(frame.saved_this);
@@ -535,7 +537,7 @@ impl Vm {
for &v in &self.save_stack {
f(v);
}
// spill 栈是 session GC 根(漏根 → 溢出值被回收 → use-after-free)
// spill 栈是 session GC 根(漏根 → 溢出值被回收 → use-after-free)。
for &v in &self.spill_stack {
f(v);
}
@@ -544,21 +546,16 @@ impl Vm {
if cell_ptr.is_null() {
continue;
}
let cell = unsafe { &*cell_ptr };
if cell.value.is_object() || cell.value.is_string() {
f(cell.value);
}
// SAFETY: cell 由 session_epoch 分配,本 session 内指针有效。
f(unsafe { &*cell_ptr }.value);
}
}
f(JsValue::from_js_object(self.session.global_object().as_ptr() as *mut JsObject));
f(self.exception_value.unwrap_or(JsValue::undefined()));
f(self.pending_exception.unwrap_or(JsValue::undefined()));
f(self.last_uncaught_value.unwrap_or(JsValue::undefined()));
// 悬挂的 return 完成持有返回值,是 GC 根。
if let Some(Completion::Return { value, .. }) = self.pending_completion {
if value.is_object() || value.is_string() {
f(value);
}
f(value);
}
f(self.generator_suspended.unwrap_or(JsValue::undefined()));
f(self.delegated_iterator.unwrap_or(JsValue::undefined()));
@@ -573,17 +570,93 @@ impl Vm {
for job in &self.job_queue {
crate::promise::for_each_job_value(job, &mut f);
}
// 已转换的不可变常量(标量 + perm 字符串)不作为 session GC 根,不参与扫描。
for iter in &self.iters.for_in_iters {
if iter.is_null() {
continue;
}
// SAFETY: for_in_iters 存放由当前 VM epoch 拥有的存活迭代器指针。
unsafe {
for (v, _si) in (*(*iter)).keys.iter() {
f(*v);
}
}
}
f(JsValue::from_js_object(self.session.global_object().as_ptr() as *mut JsObject));
}
/// GC 指针重写(session 搬移后调用)。与 `for_each_value` 字段一一对应。
pub(crate) fn rewrite_values(&mut self, mut rewrite: impl FnMut(JsValue) -> JsValue) {
for value in &mut self.regs {
*value = rewrite(*value);
}
for frame in &mut self.frames {
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 self.save_stack {
*v = rewrite(*v);
}
for v in &mut self.spill_stack {
*v = rewrite(*v);
}
for cell_vec in &mut self.cell_stack {
for &mut cell_ptr in cell_vec.iter_mut() {
if cell_ptr.is_null() {
continue;
}
// SAFETY: cell 由 session_epoch 分配,本 session 内指针有效。
let cell = unsafe { &mut *cell_ptr };
cell.value = rewrite(cell.value);
}
}
self.exception_value = self.exception_value.map(&mut rewrite);
self.pending_exception = self.pending_exception.map(&mut rewrite);
self.last_uncaught_value = self.last_uncaught_value.map(&mut rewrite);
self.pending_completion = self.pending_completion.map(|completion| match completion {
Completion::Return { value, remaining_finally } => Completion::Return {
value: rewrite(value),
remaining_finally,
},
other => other,
});
self.generator_suspended = self.generator_suspended.map(&mut rewrite);
self.delegated_iterator = self.delegated_iterator.map(&mut rewrite);
self.async_context = self.async_context.map(&mut rewrite);
self.async_gen_context = self.async_gen_context.map(&mut rewrite);
self.inline_callee = self.inline_callee.map(&mut rewrite);
for v in &mut self.iters.for_of_iters {
*v = rewrite(*v);
}
self.iters.last_for_of_result = rewrite(self.iters.last_for_of_result);
// 微任务队列中的值随 sweep 重写。
for job in &mut self.job_queue {
crate::promise::rewrite_job_values(job, &mut rewrite);
}
for iter in &mut self.iters.for_in_iters {
if iter.is_null() {
continue;
}
// SAFETY: for_in_iters 存放由当前 VM epoch 拥有的存活迭代器指针。
unsafe {
for (v, _si) in (*(*iter)).keys.iter_mut() {
*v = rewrite(*v);
}
}
}
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject;
if !global_ptr.is_null() {
// SAFETY: KernelSession 在 VM 生命周期内拥有 global_object。
unsafe {
(*global_ptr).rewrite_object_values(|value| rewrite(value));
}
}
}
pub(crate) fn for_each_root(&self, f: impl FnMut(JsValue)) {
// 统一遍历:根收集与指针重写共用同一字段清单。
self.for_each_value(f);
}
pub(crate) fn maybe_collect_session_gc(&mut self) {