From c0f16dc76443065bccf5989d69637902819358be Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Wed, 24 Jun 2026 16:08:17 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20promote=20=E5=A4=8D=E7=94=A8=20Vm.forwar?= =?UTF-8?q?ding=EF=BC=8C=E6=B6=88=E9=99=A4=20promote=20=E7=9A=84=20HashMap?= =?UTF-8?q?=20=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_vm/src/session_arena.rs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/crates/oxide_vm/src/session_arena.rs b/crates/oxide_vm/src/session_arena.rs index 2c5e9313..dbe6bf44 100644 --- a/crates/oxide_vm/src/session_arena.rs +++ b/crates/oxide_vm/src/session_arena.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use oxide_types::object::JsObject; use oxide_types::value::JsValue; +use rustc_hash::FxBuildHasher; use crate::builtins::{data_view, map, set, typed_array}; use crate::vm::Vm; @@ -16,12 +17,15 @@ impl Vm { } pub(crate) fn promote_object(&mut self, src: *mut JsObject) -> *mut JsObject { - let mut forwarding = HashMap::new(); - self.promote_object_inner(src, &mut forwarding) + let mut forwarding = std::mem::take(&mut self.forwarding); + let result = self.promote_object_inner(src, &mut forwarding); + forwarding.clear(); + self.forwarding = forwarding; + result } pub(crate) fn promote_object_inner( - &mut self, src: *mut JsObject, forwarding: &mut HashMap<*mut JsObject, *mut JsObject>, + &mut self, src: *mut JsObject, forwarding: &mut HashMap<*mut JsObject, *mut JsObject, FxBuildHasher>, ) -> *mut JsObject { if src.is_null() { return src; @@ -63,7 +67,7 @@ impl Vm { } pub(crate) fn promote_value_if_epoch_object( - &mut self, value: JsValue, forwarding: &mut HashMap<*mut JsObject, *mut JsObject>, + &mut self, value: JsValue, forwarding: &mut HashMap<*mut JsObject, *mut JsObject, FxBuildHasher>, ) -> JsValue { if !value.is_object() { return value; @@ -230,4 +234,20 @@ mod tests { assert!(!is_epoch_object(&vm, meta.get)); assert!(!is_epoch_object(&vm, meta.set)); } + + #[test] + fn promote_clears_forwarding_map() { + let mut vm = Vm::new(); + let first = plain_object(&mut vm); + let promoted = vm.promote_object(first); + assert!(!promoted.is_null()); + // The shared forwarding map must be cleared after each promote so a + // later promote (or GC sweep) never observes stale old->new mappings. + assert!(vm.forwarding.is_empty()); + + let second = plain_object(&mut vm); + let promoted2 = vm.promote_object(second); + assert!(!promoted2.is_null()); + assert!(vm.forwarding.is_empty()); + } }