From f118903ad3d982f53f96086ccc21491a330878a2 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:00:15 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20GC=20=E6=A0=B9=E6=B8=85=E5=8D=95?= =?UTF-8?q?=E8=A1=A5=E9=BD=90=E4=BF=A1=E5=8F=B7=E5=AD=97=E6=AE=B5=E4=B8=8E?= =?UTF-8?q?=20pending=5Fcompletion=20=E9=87=8D=E5=86=99=EF=BC=88=E6=94=B6?= =?UTF-8?q?=E6=95=9B=E5=89=8D=E7=BD=AE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_vm/src/session_gc.rs | 46 +++++++++++++++++++++++++++++-- crates/oxide_vm/src/vm.rs | 6 ++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/crates/oxide_vm/src/session_gc.rs b/crates/oxide_vm/src/session_gc.rs index a2c19b6..489baf6 100644 --- a/crates/oxide_vm/src/session_gc.rs +++ b/crates/oxide_vm/src/session_gc.rs @@ -7,7 +7,7 @@ use oxide_types::object::{JsObject, JsString, PropMetaEntry}; use oxide_types::value::JsValue; use rustc_hash::FxBuildHasher; -use crate::vm::Vm; +use crate::vm::{Completion, Vm}; use oxide_builtins::{array_buffer, data_view, map, regexp, set, typed_array}; /// session 级 mark-sweep GC 的状态与统计。 @@ -576,6 +576,19 @@ fn rewrite_vm_roots(vm: &mut Vm, forwarding: &HashMap<*mut JsObject, *mut JsObje } 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); } @@ -630,8 +643,37 @@ mod tests { } #[test] - fn gc_roots_contains_registers_frames_and_root_roots() { + fn uncaught_value_is_gc_root() { let mut vm = Vm::new(); + let obj = plain_object(&mut vm); + let session = vm.promote_object(obj); + vm.last_uncaught_value = Some(JsValue::from_js_object(session)); + let mut roots = Vec::new(); + vm.for_each_root(|v| roots.push(v)); + assert!(has_ptr(&roots, session)); + } + + #[test] + fn suspended_signal_fields_are_roots() { + let mut vm = Vm::new(); + let a = plain_object(&mut vm); + let b = plain_object(&mut vm); + let c = plain_object(&mut vm); + let a_s = vm.promote_object(a); + let b_s = vm.promote_object(b); + let c_s = vm.promote_object(c); + vm.generator_suspended = Some(JsValue::from_js_object(a_s)); + vm.async_context = Some(JsValue::from_js_object(b_s)); + vm.async_gen_context = Some(JsValue::from_js_object(c_s)); + let mut roots = Vec::new(); + vm.for_each_root(|v| roots.push(v)); + assert!(has_ptr(&roots, a_s)); + assert!(has_ptr(&roots, b_s)); + assert!(has_ptr(&roots, c_s)); + } + + #[test] + fn gc_roots_contains_registers_frames_and_root_roots() { let mut vm = Vm::new(); let root = plain_object(&mut vm); let frame_obj = plain_object(&mut vm); let saved_this = plain_object(&mut vm); diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index 5fd6a57..f43385c 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -553,12 +553,18 @@ impl Vm { 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(self.generator_suspended.unwrap_or(JsValue::undefined())); + f(self.delegated_iterator.unwrap_or(JsValue::undefined())); + f(self.async_context.unwrap_or(JsValue::undefined())); + f(self.async_gen_context.unwrap_or(JsValue::undefined())); + f(self.inline_callee.unwrap_or(JsValue::undefined())); for &v in &self.iters.for_of_iters { f(v); }