diff --git a/crates/oxide_vm/src/session_arena.rs b/crates/oxide_vm/src/session_arena.rs index 2c5e931..dbe6bf4 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()); + } }