Skip to content

proposal(vm): heap subspaces #798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
Draft
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
74 changes: 8 additions & 66 deletions nova_vm/src/ecmascript/builtins/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,25 @@ use crate::{
unwrap_try,
},
heap::{
CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep, HeapSweepWeakReference,
WellKnownSymbolIndexes, WorkQueues,
CompactionLists, CreateHeapData as _, Heap, HeapMarkAndSweep, HeapSweepWeakReference,
IsoSubspace, WellKnownSymbolIndexes, WorkQueues, declare_subspace_resident,
element_array::{
ElementArrays, ElementDescriptor, ElementStorageMut, ElementStorageRef, ElementsVector,
},
indexes::ArrayIndex,
indexes::BaseIndex,
},
};

use ahash::AHashMap;
pub use data::ArrayHeapData;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Array<'a>(ArrayIndex<'a>);
// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
// pub struct Array<'a>(ArrayIndex<'a>);
declare_subspace_resident!(iso = arrays; struct Array, ArrayHeapData);

pub(crate) static ARRAY_INDEX_RANGE: RangeInclusive<i64> = 0..=(i64::pow(2, 32) - 2);

impl<'a> Array<'a> {
/// # Do not use this
/// This is only for Value discriminant creation.
pub(crate) const fn _def() -> Self {
Self(ArrayIndex::from_u32_index(0))
}

/// Creates a new array with the given elements.
///
/// This is equal to the [CreateArrayFromList](https://tc39.es/ecma262/#sec-createarrayfromlist)
Expand All @@ -68,10 +63,6 @@ impl<'a> Array<'a> {
create_array_from_list(agent, elements, gc)
}

pub(crate) fn get_index(self) -> usize {
self.0.into_index()
}

pub fn len(&self, agent: &impl Index<Array<'a>, Output = ArrayHeapData<'static>>) -> u32 {
agent[*self].elements.len()
}
Expand Down Expand Up @@ -231,27 +222,6 @@ impl<'a> Array<'a> {
}
}

// SAFETY: Property implemented as a lifetime transmute.
unsafe impl Bindable for Array<'_> {
type Of<'a> = Array<'a>;

#[inline(always)]
fn unbind(self) -> Self::Of<'static> {
unsafe { core::mem::transmute::<Self, Self::Of<'static>>(self) }
}

#[inline(always)]
fn bind<'a>(self, _gc: NoGcScope<'a, '_>) -> Self::Of<'a> {
unsafe { core::mem::transmute::<Self, Self::Of<'a>>(self) }
}
}

impl<'a> From<ArrayIndex<'a>> for Array<'a> {
fn from(value: ArrayIndex<'a>) -> Self {
Array(value)
}
}

impl<'a> From<Array<'a>> for Object<'a> {
fn from(value: Array) -> Self {
Self::Array(value.unbind())
Expand Down Expand Up @@ -769,26 +739,6 @@ impl IndexMut<Array<'_>> for Agent {
}
}

impl Index<Array<'_>> for Vec<Option<ArrayHeapData<'static>>> {
type Output = ArrayHeapData<'static>;

fn index(&self, index: Array) -> &Self::Output {
self.get(index.get_index())
.expect("Array out of bounds")
.as_ref()
.expect("Array slot empty")
}
}

impl IndexMut<Array<'_>> for Vec<Option<ArrayHeapData<'static>>> {
fn index_mut(&mut self, index: Array) -> &mut Self::Output {
self.get_mut(index.get_index())
.expect("Array out of bounds")
.as_mut()
.expect("Array slot empty")
}
}

impl Rootable for Array<'_> {
type RootRepr = HeapRootRef;

Expand All @@ -812,14 +762,6 @@ impl Rootable for Array<'_> {
}
}

impl<'a> CreateHeapData<ArrayHeapData<'a>, Array<'a>> for Heap {
fn create(&mut self, data: ArrayHeapData<'a>) -> Array<'a> {
self.arrays.push(Some(data.unbind()));
self.alloc_counter += core::mem::size_of::<Option<ArrayHeapData<'static>>>();
Array::from(ArrayIndex::last(&self.arrays))
}
}

impl HeapMarkAndSweep for Array<'static> {
fn mark_values(&self, queues: &mut WorkQueues) {
queues.arrays.push(*self);
Expand Down Expand Up @@ -1127,13 +1069,13 @@ fn insert_element_descriptor(
/// A partial view to the Agent's Heap that allows accessing array heap data.
pub(crate) struct ArrayHeap<'a> {
elements: &'a ElementArrays,
arrays: &'a Vec<Option<ArrayHeapData<'static>>>,
arrays: &'a IsoSubspace<ArrayHeapData<'static>>,
}

impl ArrayHeap<'_> {
pub(crate) fn new<'a>(
elements: &'a ElementArrays,
arrays: &'a Vec<Option<ArrayHeapData<'static>>>,
arrays: &'a IsoSubspace<ArrayHeapData<'static>>,
) -> ArrayHeap<'a> {
ArrayHeap { elements, arrays }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{
context::{Bindable, GcScope, NoGcScope},
rootable::Scopable,
},
heap::{CreateHeapData, Heap, WellKnownSymbolIndexes},
heap::{CreateHeapData as _, Heap, WellKnownSymbolIndexes},
};

/// ### [10.4.2.2 ArrayCreate ( length \[ , proto \] )](https://tc39.es/ecma262/#sec-arraycreate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4204,9 +4204,9 @@ impl ArrayPrototype {
})
.build();

let slot = agent.heap.arrays.get_mut(this.get_index()).unwrap();
let slot = agent.heap.arrays.slot_mut(this);
assert!(slot.is_none());
*slot = Some(ArrayHeapData {
slot.replace(ArrayHeapData {
object_index: Some(this_base_object),
// has a "length" property whose initial value is +0𝔽 and whose
// attributes are { [[Writable]]: true, [[Enumerable]]: false,
Expand Down
5 changes: 4 additions & 1 deletion nova_vm/src/ecmascript/builtins/ordinary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1211,7 +1211,10 @@ pub(crate) fn ordinary_object_create_with_intrinsics<'a>(
};

let object = match proto_intrinsics {
ProtoIntrinsics::Array => agent.heap.create(ArrayHeapData::default()).into_object(),
ProtoIntrinsics::Array => agent
.heap
.create(ArrayHeapData::default())
.into_object(),
#[cfg(feature = "array-buffer")]
ProtoIntrinsics::ArrayBuffer => agent
.heap
Expand Down
5 changes: 2 additions & 3 deletions nova_vm/src/ecmascript/execution/realm/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ use crate::{
heap::{
CompactionLists, HeapMarkAndSweep, IntrinsicConstructorIndexes, IntrinsicFunctionIndexes,
IntrinsicObjectIndexes, IntrinsicPrimitiveObjectIndexes, WorkQueues,
indexes::{ArrayIndex, BuiltinFunctionIndex, ObjectIndex, PrimitiveObjectIndex},
indexes::{BuiltinFunctionIndex, ObjectIndex, PrimitiveObjectIndex},
intrinsic_function_count, intrinsic_object_count, intrinsic_primitive_object_count,
},
};
Expand Down Expand Up @@ -245,7 +245,6 @@ impl Intrinsics {
PrimitiveObjectIndex::from_index(agent.heap.primitive_objects.len());
let builtin_function_index_base =
BuiltinFunctionIndex::from_index(agent.heap.builtin_functions.len());
let array_prototype = Array::from(ArrayIndex::from_index(agent.heap.arrays.len()));

agent
.heap
Expand All @@ -259,7 +258,7 @@ impl Intrinsics {
.heap
.builtin_functions
.extend((0..intrinsic_function_count()).map(|_| None));
agent.heap.arrays.push(None);
let array_prototype = agent.heap.arrays.reserve_intrinsic();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't like this, it feels ad-hoc.


Self {
object_index_base,
Expand Down
2 changes: 1 addition & 1 deletion nova_vm/src/ecmascript/types/language/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use crate::ecmascript::{
use crate::{
ecmascript::builtins::{ArrayBuffer, data_view::DataView, typed_array::TypedArray},
engine::context::NoGcScope,
heap::indexes::TypedArrayIndex,
heap::{HeapIndexable, indexes::TypedArrayIndex},
};
use crate::{
ecmascript::{
Expand Down
4 changes: 2 additions & 2 deletions nova_vm/src/ecmascript/types/language/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use crate::{
small_bigint::SmallBigInt,
small_f64::SmallF64,
},
heap::{CompactionLists, HeapMarkAndSweep, WorkQueues},
heap::{CompactionLists, HeapIndexable as _, HeapMarkAndSweep, SubspaceIndex, WorkQueues},
};
#[cfg(feature = "array-buffer")]
use crate::{
Expand Down Expand Up @@ -258,7 +258,7 @@ pub(crate) const SMALL_BIGINT_DISCRIMINANT: u8 =
value_discriminant(Value::SmallBigInt(SmallBigInt::zero()));
pub(crate) const OBJECT_DISCRIMINANT: u8 =
value_discriminant(Value::Object(OrdinaryObject::_def()));
pub(crate) const ARRAY_DISCRIMINANT: u8 = value_discriminant(Value::Array(Array::_def()));
pub(crate) const ARRAY_DISCRIMINANT: u8 = value_discriminant(Value::Array(Array::_DEF));
#[cfg(feature = "array-buffer")]
pub(crate) const ARRAY_BUFFER_DISCRIMINANT: u8 =
value_discriminant(Value::ArrayBuffer(ArrayBuffer::_def()));
Expand Down
25 changes: 22 additions & 3 deletions nova_vm/src/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod heap_constants;
pub(crate) mod heap_gc;
pub mod indexes;
mod object_entry;
mod subspace;

use core::{cell::RefCell, ops::Index};
use std::ops::Deref;
Expand All @@ -27,7 +28,7 @@ use self::{
ElementArray2Pow8, ElementArray2Pow10, ElementArray2Pow12, ElementArray2Pow16,
ElementArray2Pow24, ElementArray2Pow32, ElementArrays,
},
indexes::NumberIndex,
indexes::{BaseIndex, NumberIndex},
};
#[cfg(feature = "date")]
use crate::ecmascript::builtins::date::data::DateHeapData;
Expand Down Expand Up @@ -112,6 +113,7 @@ pub(crate) use heap_bits::{
CompactionLists, HeapMarkAndSweep, HeapSweepWeakReference, WorkQueues, sweep_side_set,
};
use indexes::TypedArrayIndex;
pub(crate) use subspace::*;
use wtf8::{Wtf8, Wtf8Buf};

#[derive(Debug)]
Expand All @@ -120,7 +122,8 @@ pub struct Heap {
pub array_buffers: Vec<Option<ArrayBufferHeapData<'static>>>,
#[cfg(feature = "array-buffer")]
pub array_buffer_detach_keys: AHashMap<ArrayBuffer<'static>, DetachKey>,
pub arrays: Vec<Option<ArrayHeapData<'static>>>,
// pub arrays: Vec<Option<ArrayHeapData<'static>>>,
pub arrays: IsoSubspace<ArrayHeapData<'static>>,
pub array_iterators: Vec<Option<ArrayIteratorHeapData<'static>>>,
pub async_generators: Vec<Option<AsyncGeneratorHeapData<'static>>>,
pub(crate) await_reactions: Vec<Option<AwaitReactionRecord<'static>>>,
Expand Down Expand Up @@ -245,7 +248,7 @@ impl Heap {
array_buffers: Vec::with_capacity(1024),
#[cfg(feature = "array-buffer")]
array_buffer_detach_keys: AHashMap::with_capacity(0),
arrays: Vec::with_capacity(1024),
arrays: IsoSubspace::with_capacity(c"array", 1024),
array_iterators: Vec::with_capacity(256),
async_generators: Vec::with_capacity(0),
await_reactions: Vec::with_capacity(1024),
Expand Down Expand Up @@ -365,6 +368,14 @@ impl Heap {
Script::last(&self.scripts)
}

/// Allocate a value within the heap.
pub(crate) fn alloc<'a, T: SubspaceResident>(&mut self, value: T::Bound<'a>) -> T::Key<'a>
where
T::Key<'a>: WithSubspace<T>,
{
T::Key::subspace_for_mut(self).alloc(value)
}

/// Allocate a borrowed string onto the Agent heap
///
/// This method will hash the input and look for a matching string on the
Expand Down Expand Up @@ -621,6 +632,14 @@ pub(crate) trait PropertyKeyHeapIndexable:
impl PropertyKeyHeapIndexable for PropertyKeyHeap<'_> {}
impl PropertyKeyHeapIndexable for Agent {}

// impl<'a, T> CreateHeapData<T::Bound<'a>, T::Key<'a>> for T::Key<'a>
// where
// T: SubspaceResident,
// {
// fn create(&mut self, data: T::Bound<'a>) -> T::Key<'a> {
// self.alloc(data)
// }
// }
#[test]
fn init_heap() {
let heap = Heap::new();
Expand Down
16 changes: 2 additions & 14 deletions nova_vm/src/heap/heap_gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,17 +325,7 @@ pub fn heap_gc(agent: &mut Agent, root_realms: &mut [Option<Realm<'static>>], gc

let mut array_marks: Box<[Array]> = queues.arrays.drain(..).collect();
array_marks.sort();
array_marks.iter().for_each(|&idx| {
let index = idx.get_index();
if let Some(marked) = bits.arrays.get_mut(index) {
if *marked {
// Already marked, ignore
return;
}
*marked = true;
arrays.get(index).mark_values(&mut queues);
}
});
arrays.mark(array_marks, &mut bits.arrays, &mut queues);
#[cfg(feature = "array-buffer")]
{
let mut array_buffer_marks: Box<[ArrayBuffer]> =
Expand Down Expand Up @@ -1491,9 +1481,7 @@ fn sweep(
});
}
if !arrays.is_empty() {
s.spawn(|| {
sweep_heap_vector_values(arrays, &compactions, &bits.arrays);
});
s.spawn(|| arrays.sweep(&compactions, &bits.arrays));
}
if !array_iterators.is_empty() {
s.spawn(|| {
Expand Down
Loading
Loading