Skip to content

Commit f8ac3c9

Browse files
authored
chore(heap): Use SoAVec for Set storage (#901)
1 parent c4eb484 commit f8ac3c9

File tree

9 files changed

+115
-176
lines changed

9 files changed

+115
-176
lines changed

nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_constructor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ fn perform_promise_group<'gc>(
948948
#[cfg(feature = "set")]
949949
Object::Map(map) => agent[map].size(),
950950
#[cfg(feature = "set")]
951-
Object::Set(set) => agent[set].size(),
951+
Object::Set(set) => set.get(agent).set_data.borrow().len() as u32,
952952
_ => 0,
953953
};
954954

nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_constructor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ impl SetConstructor {
142142
let array_heap = ArrayHeap::new(elements, arrays);
143143
let primitive_heap = PrimitiveHeap::new(bigints, numbers, strings);
144144

145-
let set_heap_data = &mut sets[set].borrow_mut(&primitive_heap);
145+
let mut set_heap_data = set.get_direct_mut(sets);
146146
let values = &mut set_heap_data.values;
147147
let set_data = set_heap_data.set_data.get_mut();
148148

@@ -181,7 +181,7 @@ impl SetConstructor {
181181
}
182182
hashbrown::hash_table::Entry::Vacant(vacant) => {
183183
vacant.insert(next_index);
184-
values.push(Some(value.unbind()));
184+
values.push(Some(value));
185185
}
186186
}
187187
});

nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_iterator_objects/set_iterator_prototype.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ impl SetIteratorPrototype {
6060
// b. Let entries be set.[[SetData]].
6161
// c. Let numEntries be the number of elements in entries.
6262
// d. Repeat, while index < numEntries,
63-
while agent[iterator].next_index < agent[set].values(gc).len() {
63+
while agent[iterator].next_index < set.get(agent).values.len() {
6464
// i. Let e be entries[index].
6565
// ii. Set index to index + 1.
6666
let index = agent[iterator].next_index;
6767
agent[iterator].next_index += 1;
6868

6969
// iii. if e is not EMPTY, then
70-
let Some(e) = agent[set].values(gc)[index] else {
70+
let Some(e) = set.get(agent).values[index] else {
7171
continue;
7272
};
7373

@@ -91,7 +91,7 @@ impl SetIteratorPrototype {
9191
.map(|o| o.into_value());
9292
}
9393

94-
debug_assert_eq!(agent[iterator].next_index, agent[set].values(gc).len());
94+
debug_assert_eq!(agent[iterator].next_index, set.get(agent).values.len());
9595

9696
// e. Return undefined.
9797
agent[iterator].set = None;

nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_prototype.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ impl SetPrototype {
115115
// 3. Set value to CanonicalizeKeyedCollectionKey(value).
116116
let value = canonicalize_keyed_collection_key(numbers, value);
117117

118-
let set_heap_data = &mut sets[s].borrow_mut(&primitive_heap);
119-
let values = &mut set_heap_data.values;
118+
let set_heap_data = s.get_direct_mut(sets);
119+
let values = set_heap_data.values;
120120
let set_data = set_heap_data.set_data.get_mut();
121121
let hasher = |value: Value| {
122122
let mut hasher = AHasher::default();
@@ -140,7 +140,7 @@ impl SetPrototype {
140140
// 5. Append value to S.[[SetData]].
141141
let index = u32::try_from(values.len()).unwrap();
142142
entry.insert(index);
143-
values.push(Some(value.unbind()));
143+
values.push(Some(value));
144144
}
145145
// i. Return S.
146146
// 6. Return S.
@@ -166,7 +166,9 @@ impl SetPrototype {
166166
// 3. For each element e of S.[[SetData]], do
167167
// a. Replace the element of S.[[SetData]] whose value is e with an
168168
// element whose value is EMPTY.
169-
agent[s].clear();
169+
let data = s.get_mut(agent);
170+
data.set_data.borrow_mut().clear();
171+
data.values.clear();
170172
// 4. Return undefined.
171173
Ok(Value::Undefined)
172174
}
@@ -206,8 +208,8 @@ impl SetPrototype {
206208
value.hash(&primitive_heap, &mut hasher);
207209
hasher.finish()
208210
};
209-
let set_heap_data = &mut sets[s].borrow_mut(&primitive_heap);
210-
let values = &mut set_heap_data.values;
211+
let set_heap_data = s.get_direct_mut(sets);
212+
let values = set_heap_data.values;
211213
let set_data = set_heap_data.set_data.get_mut();
212214
// 4. For each element e of S.[[SetData]], do
213215
if let Ok(entry) = set_data.find_entry(value_hash, |hash_equal_index| {
@@ -309,7 +311,7 @@ impl SetPrototype {
309311
// 5. Let numEntries be the number of elements in entries.
310312
// Note: We must use the values vector length, not the size. The size
311313
// does not contain empty slots.
312-
let mut num_entries = agent[s].values(gc.nogc()).len() as u32;
314+
let mut num_entries = s.get(agent).values.len() as u32;
313315

314316
let callback_fn = callback_fn.scope(agent, nogc);
315317
let scoped_s = s.scope(agent, nogc);
@@ -320,7 +322,7 @@ impl SetPrototype {
320322
// 7. Repeat, while index < numEntries,
321323
while index < num_entries {
322324
// a. Let e be entries[index].
323-
let e = agent[s].values(gc.nogc())[index as usize];
325+
let e = s.get(agent).values[index as usize];
324326
// b. Set index to index + 1.
325327
index += 1;
326328
// c. If e is not EMPTY, then
@@ -341,7 +343,7 @@ impl SetPrototype {
341343
// ii. NOTE: The number of elements in entries may have increased during execution of callbackfn.
342344
// iii. Set numEntries to the number of elements in entries.
343345
s = scoped_s.get(agent).bind(gc.nogc());
344-
num_entries = agent[s].values(gc.nogc()).len() as u32;
346+
num_entries = s.get(agent).values.len() as u32;
345347
}
346348
}
347349
// 8. Return undefined.
@@ -370,8 +372,8 @@ impl SetPrototype {
370372
..
371373
} = &agent.heap;
372374
let primitive_heap = PrimitiveHeap::new(bigints, numbers, strings);
373-
let set_heap_data = &sets[s].borrow(&primitive_heap);
374-
let values = &set_heap_data.values;
375+
let set_heap_data = s.get_direct(sets);
376+
let values = set_heap_data.values;
375377
let set_data = set_heap_data.set_data.borrow();
376378

377379
// 3. Set value to CanonicalizeKeyedCollectionKey(value).
@@ -410,7 +412,7 @@ impl SetPrototype {
410412
// 2. Perform ? RequireInternalSlot(S, [[SetData]]).
411413
let s = require_set_data_internal_slot(agent, this_value, gc)?;
412414
// 3. Let size be SetDataSize(S.[[SetData]]).
413-
let size = agent[s].size();
415+
let size = s.get(agent).set_data.borrow().len() as u32;
414416
// 4. Return 𝔽(size).
415417
Ok(Number::from(size).into_value())
416418
}

nova_vm/src/ecmascript/builtins/set.rs

Lines changed: 85 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5-
use core::ops::{Index, IndexMut};
6-
75
use crate::{
86
Heap,
97
ecmascript::{
@@ -20,22 +18,57 @@ use crate::{
2018
},
2119
};
2220

23-
use self::data::SetHeapData;
21+
use self::data::{SetHeapData, SetHeapDataMut, SetHeapDataRef};
22+
use soavec::SoAVec;
2423

2524
pub mod data;
2625

2726
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2827
#[repr(transparent)]
2928
pub struct Set<'a>(BaseIndex<'a, SetHeapData<'static>>);
3029

31-
impl Set<'_> {
30+
impl<'gc> Set<'gc> {
3231
pub(crate) const fn _def() -> Self {
3332
Self(BaseIndex::from_u32_index(0))
3433
}
3534

3635
pub(crate) const fn get_index(self) -> usize {
3736
self.0.into_index()
3837
}
38+
39+
#[inline(always)]
40+
pub(crate) fn get<'a>(self, agent: &'a Agent) -> SetHeapDataRef<'a, 'gc> {
41+
self.get_direct(&agent.heap.sets)
42+
}
43+
44+
#[inline(always)]
45+
pub(crate) fn get_mut<'a>(self, agent: &'a mut Agent) -> SetHeapDataMut<'a, 'gc> {
46+
self.get_direct_mut(&mut agent.heap.sets)
47+
}
48+
49+
#[inline(always)]
50+
pub(crate) fn get_direct<'a>(
51+
self,
52+
sets: &'a SoAVec<SetHeapData<'static>>,
53+
) -> SetHeapDataRef<'a, 'gc> {
54+
sets.get(self.0.into_u32_index())
55+
.expect("Invalid Set reference")
56+
}
57+
58+
#[inline(always)]
59+
pub(crate) fn get_direct_mut<'a>(
60+
self,
61+
sets: &'a mut SoAVec<SetHeapData<'static>>,
62+
) -> SetHeapDataMut<'a, 'gc> {
63+
// SAFETY: Lifetime transmute to thread GC lifetime to temporary heap
64+
// reference.
65+
unsafe {
66+
core::mem::transmute::<SetHeapDataMut<'a, 'static>, SetHeapDataMut<'a, 'gc>>(
67+
sets.get_mut(self.0.into_u32_index())
68+
.expect("Invalid Set reference"),
69+
)
70+
}
71+
}
3972
}
4073

4174
bindable_handle!(Set);
@@ -81,12 +114,12 @@ impl<'a> InternalSlots<'a> for Set<'a> {
81114

82115
#[inline(always)]
83116
fn get_backing_object(self, agent: &Agent) -> Option<OrdinaryObject<'static>> {
84-
agent[self].object_index
117+
self.get(agent).object_index.unbind()
85118
}
86119

87120
fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) {
88121
assert!(
89-
agent[self]
122+
self.get_mut(agent)
90123
.object_index
91124
.replace(backing_object.unbind())
92125
.is_none()
@@ -112,34 +145,6 @@ impl HeapSweepWeakReference for Set<'static> {
112145
}
113146
}
114147

115-
impl Index<Set<'_>> for Agent {
116-
type Output = SetHeapData<'static>;
117-
118-
fn index(&self, index: Set) -> &Self::Output {
119-
&self.heap.sets[index]
120-
}
121-
}
122-
123-
impl IndexMut<Set<'_>> for Agent {
124-
fn index_mut(&mut self, index: Set) -> &mut Self::Output {
125-
&mut self.heap.sets[index]
126-
}
127-
}
128-
129-
impl Index<Set<'_>> for Vec<SetHeapData<'static>> {
130-
type Output = SetHeapData<'static>;
131-
132-
fn index(&self, index: Set) -> &Self::Output {
133-
self.get(index.get_index()).expect("Set out of bounds")
134-
}
135-
}
136-
137-
impl IndexMut<Set<'_>> for Vec<SetHeapData<'static>> {
138-
fn index_mut(&mut self, index: Set) -> &mut Self::Output {
139-
self.get_mut(index.get_index()).expect("Set out of bounds")
140-
}
141-
}
142-
143148
impl TryFrom<HeapRootData> for Set<'_> {
144149
type Error = ();
145150

@@ -155,8 +160,52 @@ impl TryFrom<HeapRootData> for Set<'_> {
155160

156161
impl<'a> CreateHeapData<SetHeapData<'a>, Set<'a>> for Heap {
157162
fn create(&mut self, data: SetHeapData<'a>) -> Set<'a> {
158-
self.sets.push(data.unbind());
163+
let i = self.sets.len();
164+
self.sets
165+
.push(data.unbind())
166+
.expect("Failed to allocate Set");
159167
self.alloc_counter += core::mem::size_of::<SetHeapData<'static>>();
160-
Set(BaseIndex::last(&self.sets))
168+
Set(BaseIndex::from_u32_index(i))
169+
}
170+
}
171+
172+
impl HeapMarkAndSweep for SetHeapDataRef<'_, 'static> {
173+
fn mark_values(&self, queues: &mut WorkQueues) {
174+
let Self {
175+
set_data: _,
176+
values,
177+
object_index,
178+
needs_primitive_rehashing: _,
179+
} = self;
180+
values.mark_values(queues);
181+
object_index.mark_values(queues);
182+
}
183+
184+
fn sweep_values(&mut self, _: &CompactionLists) {
185+
unreachable!()
186+
}
187+
}
188+
189+
impl HeapMarkAndSweep for SetHeapDataMut<'_, 'static> {
190+
fn mark_values(&self, queues: &mut WorkQueues) {
191+
let Self {
192+
set_data: _,
193+
values,
194+
object_index,
195+
needs_primitive_rehashing: _,
196+
} = self;
197+
values.mark_values(queues);
198+
object_index.mark_values(queues);
199+
}
200+
201+
fn sweep_values(&mut self, compactions: &CompactionLists) {
202+
let Self {
203+
set_data: _,
204+
values,
205+
object_index,
206+
needs_primitive_rehashing: _,
207+
} = self;
208+
values.sweep_values(compactions);
209+
object_index.sweep_values(compactions);
161210
}
162211
}

0 commit comments

Comments
 (0)