Skip to content

Commit e0eedd6

Browse files
committed
chore(heap): Use SoAVec for Set storage
1 parent 5f43606 commit e0eedd6

File tree

9 files changed

+106
-173
lines changed

9 files changed

+106
-173
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: 1 addition & 1 deletion
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

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: 13 additions & 11 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();
@@ -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: 78 additions & 35 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,7 +18,8 @@ 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

@@ -36,6 +35,34 @@ impl Set<'_> {
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, 'static> {
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, 'static> {
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, 'static> {
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, 'static> {
63+
sets.get_mut(self.0.into_u32_index())
64+
.expect("Invalid Set reference")
65+
}
3966
}
4067

4168
bindable_handle!(Set);
@@ -81,12 +108,12 @@ impl<'a> InternalSlots<'a> for Set<'a> {
81108

82109
#[inline(always)]
83110
fn get_backing_object(self, agent: &Agent) -> Option<OrdinaryObject<'static>> {
84-
agent[self].object_index
111+
*self.get(agent).object_index
85112
}
86113

87114
fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) {
88115
assert!(
89-
agent[self]
116+
self.get_mut(agent)
90117
.object_index
91118
.replace(backing_object.unbind())
92119
.is_none()
@@ -112,34 +139,6 @@ impl HeapSweepWeakReference for Set<'static> {
112139
}
113140
}
114141

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-
143142
impl TryFrom<HeapRootData> for Set<'_> {
144143
type Error = ();
145144

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

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

0 commit comments

Comments
 (0)