Skip to content

Commit ae367f5

Browse files
committed
fix: Mark builtin string memory, symbols, mark and descriptors
1 parent 011fec3 commit ae367f5

File tree

3 files changed

+491
-174
lines changed

3 files changed

+491
-174
lines changed

nova_vm/src/heap/element_array.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,3 +1763,69 @@ impl ElementArrays {
17631763
}
17641764
}
17651765
}
1766+
1767+
impl HeapMarkAndSweep for ElementDescriptor {
1768+
fn mark_values(&self, queues: &mut WorkQueues) {
1769+
match self {
1770+
ElementDescriptor::WritableEnumerableConfigurableData
1771+
| ElementDescriptor::WritableEnumerableUnconfigurableData
1772+
| ElementDescriptor::WritableUnenumerableConfigurableData
1773+
| ElementDescriptor::WritableUnenumerableUnconfigurableData
1774+
| ElementDescriptor::ReadOnlyEnumerableConfigurableData
1775+
| ElementDescriptor::ReadOnlyEnumerableUnconfigurableData
1776+
| ElementDescriptor::ReadOnlyUnenumerableConfigurableData
1777+
| ElementDescriptor::ReadOnlyUnenumerableUnconfigurableData => {}
1778+
ElementDescriptor::ReadOnlyEnumerableConfigurableAccessor { get }
1779+
| ElementDescriptor::ReadOnlyEnumerableUnconfigurableAccessor { get }
1780+
| ElementDescriptor::ReadOnlyUnenumerableConfigurableAccessor { get }
1781+
| ElementDescriptor::ReadOnlyUnenumerableUnconfigurableAccessor { get } => {
1782+
get.mark_values(queues)
1783+
}
1784+
ElementDescriptor::WriteOnlyEnumerableConfigurableAccessor { set }
1785+
| ElementDescriptor::WriteOnlyEnumerableUnconfigurableAccessor { set }
1786+
| ElementDescriptor::WriteOnlyUnenumerableConfigurableAccessor { set }
1787+
| ElementDescriptor::WriteOnlyUnenumerableUnconfigurableAccessor { set } => {
1788+
set.mark_values(queues)
1789+
}
1790+
ElementDescriptor::ReadWriteEnumerableConfigurableAccessor { get, set }
1791+
| ElementDescriptor::ReadWriteEnumerableUnconfigurableAccessor { get, set }
1792+
| ElementDescriptor::ReadWriteUnenumerableConfigurableAccessor { get, set }
1793+
| ElementDescriptor::ReadWriteUnenumerableUnconfigurableAccessor { get, set } => {
1794+
get.mark_values(queues);
1795+
set.mark_values(queues);
1796+
}
1797+
}
1798+
}
1799+
1800+
fn sweep_values(&mut self, compactions: &CompactionLists) {
1801+
match self {
1802+
ElementDescriptor::WritableEnumerableConfigurableData
1803+
| ElementDescriptor::WritableEnumerableUnconfigurableData
1804+
| ElementDescriptor::WritableUnenumerableConfigurableData
1805+
| ElementDescriptor::WritableUnenumerableUnconfigurableData
1806+
| ElementDescriptor::ReadOnlyEnumerableConfigurableData
1807+
| ElementDescriptor::ReadOnlyEnumerableUnconfigurableData
1808+
| ElementDescriptor::ReadOnlyUnenumerableConfigurableData
1809+
| ElementDescriptor::ReadOnlyUnenumerableUnconfigurableData => {}
1810+
ElementDescriptor::ReadOnlyEnumerableConfigurableAccessor { get }
1811+
| ElementDescriptor::ReadOnlyEnumerableUnconfigurableAccessor { get }
1812+
| ElementDescriptor::ReadOnlyUnenumerableConfigurableAccessor { get }
1813+
| ElementDescriptor::ReadOnlyUnenumerableUnconfigurableAccessor { get } => {
1814+
get.sweep_values(compactions)
1815+
}
1816+
ElementDescriptor::WriteOnlyEnumerableConfigurableAccessor { set }
1817+
| ElementDescriptor::WriteOnlyEnumerableUnconfigurableAccessor { set }
1818+
| ElementDescriptor::WriteOnlyUnenumerableConfigurableAccessor { set }
1819+
| ElementDescriptor::WriteOnlyUnenumerableUnconfigurableAccessor { set } => {
1820+
set.sweep_values(compactions)
1821+
}
1822+
ElementDescriptor::ReadWriteEnumerableConfigurableAccessor { get, set }
1823+
| ElementDescriptor::ReadWriteEnumerableUnconfigurableAccessor { get, set }
1824+
| ElementDescriptor::ReadWriteUnenumerableConfigurableAccessor { get, set }
1825+
| ElementDescriptor::ReadWriteUnenumerableUnconfigurableAccessor { get, set } => {
1826+
get.sweep_values(compactions);
1827+
set.sweep_values(compactions);
1828+
}
1829+
}
1830+
}
1831+
}

nova_vm/src/heap/heap_bits.rs

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use std::borrow::Borrow;
1+
use std::collections::HashMap;
22

33
use super::{
4-
element_array::{ElementArrayKey, ElementsVector},
4+
element_array::{ElementArrayKey, ElementDescriptor, ElementsVector},
55
indexes::{BaseIndex, ElementIndex, TypedArrayIndex},
66
Heap,
77
};
@@ -36,7 +36,10 @@ use crate::ecmascript::{
3636
GlobalEnvironmentIndex, ObjectEnvironmentIndex, RealmIdentifier,
3737
},
3838
scripts_and_modules::script::ScriptIdentifier,
39-
types::{bigint::HeapBigInt, HeapNumber, HeapString, OrdinaryObject, Symbol, Value},
39+
types::{
40+
bigint::HeapBigInt, HeapNumber, HeapString, OrdinaryObject, Symbol, Value,
41+
BUILTIN_STRINGS_LIST,
42+
},
4043
};
4144

4245
#[derive(Debug)]
@@ -273,8 +276,8 @@ impl WorkQueues {
273276
scripts: Vec::with_capacity(heap.scripts.len() / 4),
274277
sets: Vec::with_capacity(heap.sets.len() / 4),
275278
shared_array_buffers: Vec::with_capacity(heap.shared_array_buffers.len() / 4),
276-
strings: Vec::with_capacity(heap.strings.len() / 4),
277-
symbols: Vec::with_capacity(heap.symbols.len() / 4),
279+
strings: Vec::with_capacity((heap.strings.len() / 4).max(BUILTIN_STRINGS_LIST.len())),
280+
symbols: Vec::with_capacity((heap.symbols.len() / 4).max(13)),
278281
typed_arrays: Vec::with_capacity(heap.typed_arrays.len() / 4),
279282
weak_maps: Vec::with_capacity(heap.weak_maps.len() / 4),
280283
weak_refs: Vec::with_capacity(heap.weak_refs.len() / 4),
@@ -416,7 +419,7 @@ impl CompactionList {
416419
.unwrap_or(0)
417420
}
418421

419-
pub(crate) fn shift_index<T>(&self, index: &mut BaseIndex<T>) {
422+
pub(crate) fn shift_index<T: ?Sized>(&self, index: &mut BaseIndex<T>) {
420423
let base_index = index.into_u32_index();
421424
*index = BaseIndex::from_u32_index(base_index - self.get_shift_for_index(base_index));
422425
}
@@ -711,26 +714,32 @@ where
711714
}
712715
}
713716

714-
pub(crate) fn mark_array_with_u32_length<T: HeapMarkAndSweep + std::fmt::Debug, const N: usize>(
717+
pub(crate) fn mark_array_with_u32_length<T: HeapMarkAndSweep, const N: usize>(
715718
array: &Option<[T; N]>,
716719
queues: &mut WorkQueues,
717720
length: u32,
718721
) {
719-
let length: u32 = *length.borrow();
720-
721722
array.as_ref().unwrap()[..length as usize]
722723
.iter()
723724
.for_each(|value| {
724725
value.mark_values(queues);
725726
});
726727
}
727728

729+
pub(crate) fn mark_descriptors(
730+
descriptors: &HashMap<u32, ElementDescriptor>,
731+
queues: &mut WorkQueues,
732+
) {
733+
for descriptor in descriptors.values() {
734+
descriptor.mark_values(queues);
735+
}
736+
}
737+
728738
fn sweep_array_with_u32_length<T: HeapMarkAndSweep, const N: usize>(
729739
array: &mut Option<[T; N]>,
730740
compactions: &CompactionLists,
731741
length: u32,
732742
) {
733-
let length: u32 = *length.borrow();
734743
if length == 0 {
735744
return;
736745
}
@@ -741,15 +750,16 @@ fn sweep_array_with_u32_length<T: HeapMarkAndSweep, const N: usize>(
741750
});
742751
}
743752

744-
pub(crate) fn sweep_heap_vector_values<T: HeapMarkAndSweep>(
753+
pub(crate) fn sweep_heap_vector_values<T: HeapMarkAndSweep + std::fmt::Debug>(
745754
vec: &mut Vec<T>,
746755
compactions: &CompactionLists,
747756
bits: &[bool],
748757
) {
749758
assert_eq!(vec.len(), bits.len());
750759
let mut iter = bits.iter();
751760
vec.retain_mut(|item| {
752-
if *iter.next().unwrap() {
761+
let do_retain = iter.next().unwrap();
762+
if *do_retain {
753763
item.sweep_values(compactions);
754764
true
755765
} else {
@@ -811,3 +821,41 @@ pub(crate) fn sweep_heap_u32_elements_vector_values<const N: usize>(
811821
}
812822
});
813823
}
824+
825+
pub(crate) fn sweep_heap_elements_vector_descriptors<T>(
826+
descriptors: &mut HashMap<ElementIndex, HashMap<u32, ElementDescriptor>>,
827+
compactions: &CompactionLists,
828+
self_compactions: &CompactionList,
829+
marks: &[(bool, T)],
830+
) {
831+
let mut keys_to_remove = Vec::with_capacity(marks.len() / 4);
832+
let mut keys_to_reassign = Vec::with_capacity(marks.len() / 4);
833+
for (key, descriptor) in descriptors.iter_mut() {
834+
let old_key = *key;
835+
if !marks.get(key.into_index()).unwrap().0 {
836+
keys_to_remove.push(old_key);
837+
} else {
838+
for descriptor in descriptor.values_mut() {
839+
descriptor.sweep_values(compactions);
840+
}
841+
let mut new_key = old_key;
842+
self_compactions.shift_index(&mut new_key);
843+
if new_key != old_key {
844+
keys_to_reassign.push((old_key, new_key));
845+
}
846+
}
847+
}
848+
keys_to_remove.sort();
849+
keys_to_reassign.sort();
850+
for old_key in keys_to_remove.iter() {
851+
// println!("Dropping descriptors at key {:?}: {:?}", old_key, descriptors.get(old_key).unwrap());
852+
descriptors.remove(old_key);
853+
}
854+
for (old_key, new_key) in keys_to_reassign {
855+
// SAFETY: The old key came from iterating descriptors, and the same
856+
// key cannot appear in both keys to remove and keys to reassign. Thus
857+
// the key must necessarily exist in the descriptors hash map.
858+
let descriptor = unsafe { descriptors.remove(&old_key).unwrap_unchecked() };
859+
descriptors.insert(new_key, descriptor);
860+
}
861+
}

0 commit comments

Comments
 (0)