diff --git a/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_constructor.rs b/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_constructor.rs index 59b837348..c4b2bc7be 100644 --- a/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_constructor.rs +++ b/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_constructor.rs @@ -18,9 +18,7 @@ use crate::{ builders::builtin_function_builder::BuiltinFunctionBuilder, builtins::{ ArgumentsList, Behaviour, Builtin, BuiltinGetter, BuiltinIntrinsicConstructor, - array::ArrayHeap, - ordinary::ordinary_create_from_constructor, - set::{Set, data::SetData}, + array::ArrayHeap, ordinary::ordinary_create_from_constructor, set::Set, }, execution::{Agent, JsResult, ProtoIntrinsics, Realm, agent::ExceptionType}, types::{ @@ -144,10 +142,9 @@ impl SetConstructor { let array_heap = ArrayHeap::new(elements, arrays); let primitive_heap = PrimitiveHeap::new(bigints, numbers, strings); - let SetData { - values, set_data, .. - } = &mut sets[set].borrow_mut(&primitive_heap); - let set_data = set_data.get_mut(); + let set_heap_data = &mut sets[set].borrow_mut(&primitive_heap); + let values = &mut set_heap_data.values; + let set_data = set_heap_data.set_data.get_mut(); let hasher = |value: Value| { let mut hasher = AHasher::default(); diff --git a/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_prototype.rs b/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_prototype.rs index 91be01919..6507ce952 100644 --- a/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_prototype.rs +++ b/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_prototype.rs @@ -20,7 +20,7 @@ use crate::{ map_objects::map_prototype::canonicalize_keyed_collection_key, set_objects::set_iterator_objects::set_iterator::SetIterator, }, - set::{Set, data::SetData}, + set::Set, }, execution::{Agent, JsResult, Realm, agent::ExceptionType}, types::{BUILTIN_STRING_MEMORY, IntoValue, Number, PropertyKey, String, Value}, @@ -115,10 +115,9 @@ impl SetPrototype { // 3. Set value to CanonicalizeKeyedCollectionKey(value). let value = canonicalize_keyed_collection_key(numbers, value); - let SetData { - values, set_data, .. - } = &mut sets[s].borrow_mut(&primitive_heap); - let set_data = set_data.get_mut(); + let set_heap_data = &mut sets[s].borrow_mut(&primitive_heap); + let values = &mut set_heap_data.values; + let set_data = set_heap_data.set_data.get_mut(); let hasher = |value: Value| { let mut hasher = AHasher::default(); value.hash(&primitive_heap, &mut hasher); @@ -207,10 +206,9 @@ impl SetPrototype { value.hash(&primitive_heap, &mut hasher); hasher.finish() }; - let SetData { - values, set_data, .. - } = &mut sets[s].borrow_mut(&primitive_heap); - let set_data = set_data.get_mut(); + let set_heap_data = &mut sets[s].borrow_mut(&primitive_heap); + let values = &mut set_heap_data.values; + let set_data = set_heap_data.set_data.get_mut(); // 4. For each element e of S.[[SetData]], do if let Ok(entry) = set_data.find_entry(value_hash, |hash_equal_index| { let found_value = values[*hash_equal_index as usize].unwrap(); @@ -372,10 +370,9 @@ impl SetPrototype { .. } = &agent.heap; let primitive_heap = PrimitiveHeap::new(bigints, numbers, strings); - let SetData { - values, set_data, .. - } = &sets[s].borrow(&primitive_heap); - let set_data = set_data.borrow(); + let set_heap_data = &sets[s].borrow(&primitive_heap); + let values = &set_heap_data.values; + let set_data = set_heap_data.set_data.borrow(); // 3. Set value to CanonicalizeKeyedCollectionKey(value). let value = canonicalize_keyed_collection_key(&primitive_heap, value); diff --git a/nova_vm/src/ecmascript/builtins/set/data.rs b/nova_vm/src/ecmascript/builtins/set/data.rs index ba9f5cd50..dfc53908e 100644 --- a/nova_vm/src/ecmascript/builtins/set/data.rs +++ b/nova_vm/src/ecmascript/builtins/set/data.rs @@ -17,11 +17,22 @@ use core::{ sync::atomic::{AtomicBool, Ordering}, }; use hashbrown::{HashTable, hash_table::Entry}; +use soavec_derive::SoAble; -#[derive(Debug, Default)] +#[derive(Debug, Default, SoAble)] pub struct SetHeapData<'a> { pub(crate) object_index: Option>, - set_data: SetData<'a>, + pub(crate) values: Vec>>, + /// Low-level hash table pointing to value indexes. + pub(crate) set_data: RefCell>, + /// Flag that lets the Set know if it needs to rehash its primitive keys. + /// + /// This happens when an object key needs to be moved in the set_data + /// during garbage collection, and the move results in a primitive key + /// moving as well. The primitive key's hash cannot be calculated during + /// garbage collection due to the heap data being concurrently sweeped on + /// another thread. + pub(crate) needs_primitive_rehashing: AtomicBool, // TODO: When an non-terminal (start or end) iterator exists for the Set, // the items in the set cannot be compacted. // pub(crate) observed: bool; @@ -38,58 +49,40 @@ impl<'a> SetHeapData<'a> { // 2. For each element e of setData, do // a. If e is not EMPTY, set count to count + 1. // 3. Return count. - self.set_data.set_data.borrow().len() as u32 + self.set_data.borrow().len() as u32 } pub fn values(&self, _gc: NoGcScope<'a, '_>) -> &[Option>] { - &self.set_data.values + &self.values } pub fn clear(&mut self) { // 3. For each element e of S.[[SetData]], do // a. Replace the element of S.[[SetData]] whose value is e with an // element whose value is EMPTY. - self.set_data.set_data.get_mut().clear(); - self.set_data.values.fill(None); + self.set_data.get_mut().clear(); + self.values.fill(None); } - pub(crate) fn borrow(&self, arena: &impl PrimitiveHeapIndexable) -> &SetData<'a> { - self.set_data.rehash_if_needed(arena); - &self.set_data + pub(crate) fn borrow(&self, arena: &impl PrimitiveHeapIndexable) -> &Self { + self.rehash_if_needed(arena); + self } - pub(crate) fn borrow_mut(&mut self, arena: &impl PrimitiveHeapIndexable) -> &mut SetData<'a> { - self.set_data.rehash_if_needed(arena); - &mut self.set_data + pub(crate) fn borrow_mut(&mut self, arena: &impl PrimitiveHeapIndexable) -> &mut Self { + self.rehash_if_needed(arena); + self } } -#[derive(Debug, Default)] -pub(crate) struct SetData<'a> { - pub(crate) values: Vec>>, - /// Low-level hash table pointing to value indexes. - pub(crate) set_data: RefCell>, - /// Flag that lets the Set know if it needs to rehash its primitive keys. - /// - /// This happens when an object key needs to be moved in the set_data - /// during garbage collection, and the move results in a primitive key - /// moving as well. The primitive key's hash cannot be calculated during - /// garbage collection due to the heap data being concurrently sweeped on - /// another thread. - pub(crate) needs_primitive_rehashing: AtomicBool, -} - -impl SetData<'_> { +impl SetHeapData<'_> { fn rehash_if_needed(&self, arena: &impl PrimitiveHeapIndexable) { if !self.needs_primitive_rehashing.load(Ordering::Relaxed) { return; } - let SetData { - values, set_data, .. - } = self; - let mut set_data = set_data.borrow_mut(); + let mut set_data = self.set_data.borrow_mut(); - rehash_set_data(values, &mut set_data, arena); + rehash_set_data(&self.values, &mut set_data, arena); self.needs_primitive_rehashing .store(false, Ordering::Relaxed); } @@ -160,25 +153,21 @@ impl HeapMarkAndSweep for SetHeapData<'static> { fn mark_values(&self, queues: &mut WorkQueues) { let Self { object_index, - set_data, + values, + .. } = self; object_index.mark_values(queues); - set_data - .values - .iter() - .for_each(|value| value.mark_values(queues)); + values.iter().for_each(|value| value.mark_values(queues)); } fn sweep_values(&mut self, compactions: &CompactionLists) { let Self { object_index, - set_data, - } = self; - let SetData { values, set_data, needs_primitive_rehashing, - } = set_data; + .. + } = self; let set_data = set_data.get_mut(); object_index.sweep_values(compactions);