Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down
73 changes: 31 additions & 42 deletions nova_vm/src/ecmascript/builtins/set/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<OrdinaryObject<'a>>,
set_data: SetData<'a>,
pub(crate) values: Vec<Option<Value<'a>>>,
/// Low-level hash table pointing to value indexes.
pub(crate) set_data: RefCell<HashTable<u32>>,
/// 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;
Expand All @@ -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<Value<'a>>] {
&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<Option<Value<'a>>>,
/// Low-level hash table pointing to value indexes.
pub(crate) set_data: RefCell<HashTable<u32>>,
/// 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);
}
Expand Down Expand Up @@ -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);

Expand Down
Loading