diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb3190a49..d742839c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@nightly with: - toolchain: nightly-2025-05-14 + toolchain: nightly-2025-10-31 components: rustfmt, clippy, llvm-tools-preview, rustc-dev - name: Cache on ${{ github.ref_name }} uses: Swatinem/rust-cache@v2 @@ -52,7 +52,7 @@ jobs: - name: Clippy run: | cargo +stable clippy --all-targets -- -D warnings - cargo +nightly-2025-05-14 clippy --all-targets --all-features -- -D warnings + cargo +nightly-2025-10-31 clippy --all-targets --all-features -- -D warnings - name: Dylint tests working-directory: nova_lint run: cargo test diff --git a/nova_lint/Cargo.toml b/nova_lint/Cargo.toml index 8826497c1..5fd93e285 100644 --- a/nova_lint/Cargo.toml +++ b/nova_lint/Cargo.toml @@ -25,11 +25,11 @@ name = "gc_scope_is_only_passed_by_value" path = "ui/gc_scope_is_only_passed_by_value.rs" [dependencies] -clippy_utils = { git = "https://github.com/rust-lang/rust-clippy", rev = "0450db33a5d8587f7c1d4b6d233dac963605766b" } -dylint_linting = { version = "4.1.0", features = ["constituent"] } +clippy_utils = { git = "https://github.com/rust-lang/rust-clippy", rev = "c936595d17413c1f08e162e117e504fb4ed126e4" } +dylint_linting = { version = "5.0.0", features = ["constituent"] } [dev-dependencies] -dylint_testing = "4.1.0" +dylint_testing = "5.0.0" nova_vm = { path = "../nova_vm" } [package.metadata.rust-analyzer] diff --git a/nova_lint/rust-toolchain.toml b/nova_lint/rust-toolchain similarity index 66% rename from nova_lint/rust-toolchain.toml rename to nova_lint/rust-toolchain index 0f53877b3..4e5ce19b2 100644 --- a/nova_lint/rust-toolchain.toml +++ b/nova_lint/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-05-14" +channel = "nightly-2025-10-31" components = ["llvm-tools-preview", "rustc-dev"] diff --git a/nova_vm/src/ecmascript/abstract_operations/operations_on_objects.rs b/nova_vm/src/ecmascript/abstract_operations/operations_on_objects.rs index 89a8226b7..bba360235 100644 --- a/nova_vm/src/ecmascript/abstract_operations/operations_on_objects.rs +++ b/nova_vm/src/ecmascript/abstract_operations/operations_on_objects.rs @@ -895,7 +895,6 @@ pub(crate) fn set_integrity_level<'a, T: Level>( // 3. Perform ? DefinePropertyOrThrow(O, k, desc). define_property_or_throw(agent, o, k.get(agent), desc, gc.reborrow()).unbind()?; } - i += 1; } } // 6. Return true. diff --git a/nova_vm/src/ecmascript/builtins/array.rs b/nova_vm/src/ecmascript/builtins/array.rs index dcfda4265..48d1176f9 100644 --- a/nova_vm/src/ecmascript/builtins/array.rs +++ b/nova_vm/src/ecmascript/builtins/array.rs @@ -183,7 +183,7 @@ impl<'a> Array<'a> { create_array_from_list(agent, elements, gc) } - pub(crate) fn get_index(self) -> usize { + pub(crate) const fn get_index(self) -> usize { self.0.into_index() } diff --git a/nova_vm/src/ecmascript/builtins/array/data.rs b/nova_vm/src/ecmascript/builtins/array/data.rs index f63db6c2e..872b2bd48 100644 --- a/nova_vm/src/ecmascript/builtins/array/data.rs +++ b/nova_vm/src/ecmascript/builtins/array/data.rs @@ -56,23 +56,3 @@ impl HeapMarkAndSweep for ArrayHeapDataMut<'_, 'static> { object_index.sweep_values(compactions); } } - -impl HeapMarkAndSweep for ArrayHeapData<'static> { - fn mark_values(&self, queues: &mut WorkQueues) { - let Self { - object_index, - elements, - } = self; - object_index.mark_values(queues); - elements.mark_values(queues); - } - - fn sweep_values(&mut self, compactions: &CompactionLists) { - let Self { - object_index, - elements, - } = self; - object_index.sweep_values(compactions); - elements.sweep_values(compactions); - } -} diff --git a/nova_vm/src/ecmascript/builtins/data_view/data.rs b/nova_vm/src/ecmascript/builtins/data_view/data.rs index ffc301174..eed9c4715 100644 --- a/nova_vm/src/ecmascript/builtins/data_view/data.rs +++ b/nova_vm/src/ecmascript/builtins/data_view/data.rs @@ -16,6 +16,7 @@ use crate::{ heap::{CompactionLists, HeapMarkAndSweep, WorkQueues}, }; +#[derive(Debug)] pub struct DataViewRecord<'a> { pub(crate) object_index: Option>, // TODO: Add a helper function for a u32::MAX value which signifies an a under-construction value: @@ -41,6 +42,7 @@ impl Default for DataViewRecord<'_> { } #[cfg(feature = "shared-array-buffer")] +#[derive(Debug)] pub struct SharedDataViewRecord<'a> { pub(crate) object_index: Option>, // TODO: Add a helper function for a u32::MAX value which signifies an a under-construction value: diff --git a/nova_vm/src/ecmascript/builtins/indexed_collections/array_objects/array_iterator_objects/array_iterator.rs b/nova_vm/src/ecmascript/builtins/indexed_collections/array_objects/array_iterator_objects/array_iterator.rs index c94739330..7ebf5a09d 100644 --- a/nova_vm/src/ecmascript/builtins/indexed_collections/array_objects/array_iterator_objects/array_iterator.rs +++ b/nova_vm/src/ecmascript/builtins/indexed_collections/array_objects/array_iterator_objects/array_iterator.rs @@ -30,7 +30,7 @@ impl<'a> ArrayIterator<'a> { Self(BaseIndex::from_u32_index(0)) } - pub(crate) fn get_index(self) -> usize { + pub(crate) const fn get_index(self) -> usize { self.0.into_index() } diff --git a/nova_vm/src/ecmascript/builtins/keyed_collections/map_objects/map_constructor.rs b/nova_vm/src/ecmascript/builtins/keyed_collections/map_objects/map_constructor.rs index a2c3b90f7..b0bc1ad06 100644 --- a/nova_vm/src/ecmascript/builtins/keyed_collections/map_objects/map_constructor.rs +++ b/nova_vm/src/ecmascript/builtins/keyed_collections/map_objects/map_constructor.rs @@ -440,14 +440,15 @@ pub fn add_entries_from_iterable_map_constructor<'a>( /// > element array-like object whose first element is a value that will be used /// > as a Map key and whose second element is the value to associate with that /// > key. -pub(crate) fn add_entries_from_iterable<'a>( +pub(crate) fn add_entries_from_iterable<'a, T: Into> + TryFrom>>( agent: &mut Agent, - target: Map, + target: T, iterable: Value, adder: Function, mut gc: GcScope<'a, '_>, -) -> JsResult<'a, Map<'a>> { +) -> JsResult<'a, T> { let nogc = gc.nogc(); + let target: Object = target.into(); let target = target.scope(agent, nogc); let iterable = iterable.bind(nogc); let adder = adder.scope(agent, nogc); @@ -482,7 +483,11 @@ pub(crate) fn add_entries_from_iterable<'a>( .bind(gc.nogc()); // b. If next is DONE, return target. let Some(next) = next else { - return Ok(target.get(agent).bind(gc.into_nogc())); + // SAFETY: not shared. + let target = unsafe { target.take(agent).bind(gc.into_nogc()) }; + // SAFETY: passed in type is still the same type. + let target = unsafe { T::try_from(target).unwrap_unchecked() }; + return Ok(target); }; // c. If next is not an Object, then let Ok(next) = Object::try_from(next) else { diff --git a/nova_vm/src/ecmascript/builtins/keyed_collections/map_objects/map_iterator_objects/map_iterator.rs b/nova_vm/src/ecmascript/builtins/keyed_collections/map_objects/map_iterator_objects/map_iterator.rs index 48bea2335..765828167 100644 --- a/nova_vm/src/ecmascript/builtins/keyed_collections/map_objects/map_iterator_objects/map_iterator.rs +++ b/nova_vm/src/ecmascript/builtins/keyed_collections/map_objects/map_iterator_objects/map_iterator.rs @@ -34,7 +34,7 @@ impl MapIterator<'_> { Self(BaseIndex::from_u32_index(0)) } - pub(crate) fn get_index(self) -> usize { + pub(crate) const fn get_index(self) -> usize { self.0.into_index() } diff --git a/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_iterator_objects/set_iterator.rs b/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_iterator_objects/set_iterator.rs index 067d06944..65c7ebbfe 100644 --- a/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_iterator_objects/set_iterator.rs +++ b/nova_vm/src/ecmascript/builtins/keyed_collections/set_objects/set_iterator_objects/set_iterator.rs @@ -34,7 +34,7 @@ impl SetIterator<'_> { Self(BaseIndex::from_u32_index(0)) } - pub(crate) fn get_index(self) -> usize { + pub(crate) const fn get_index(self) -> usize { self.0.into_index() } diff --git a/nova_vm/src/ecmascript/builtins/keyed_collections/weak_map_objects/weak_map_constructor.rs b/nova_vm/src/ecmascript/builtins/keyed_collections/weak_map_objects/weak_map_constructor.rs index e10dd5137..a8c0785e3 100644 --- a/nova_vm/src/ecmascript/builtins/keyed_collections/weak_map_objects/weak_map_constructor.rs +++ b/nova_vm/src/ecmascript/builtins/keyed_collections/weak_map_objects/weak_map_constructor.rs @@ -2,14 +2,24 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +use std::hint::unreachable_unchecked; + use crate::{ ecmascript::{ + abstract_operations::{operations_on_objects::get, testing_and_comparison::is_callable}, builders::builtin_function_builder::BuiltinFunctionBuilder, - builtins::{ArgumentsList, Behaviour, Builtin, BuiltinIntrinsicConstructor}, - execution::{Agent, JsResult, Realm}, - types::{BUILTIN_STRING_MEMORY, IntoObject, Object, String, Value}, + builtins::{ + ArgumentsList, Behaviour, Builtin, BuiltinIntrinsicConstructor, + keyed_collections::map_objects::map_constructor::add_entries_from_iterable, + ordinary::ordinary_create_from_constructor, + }, + execution::{Agent, JsResult, ProtoIntrinsics, Realm, agent::ExceptionType}, + types::{BUILTIN_STRING_MEMORY, Function, IntoObject, IntoValue, Object, String, Value}, + }, + engine::{ + context::{Bindable, GcScope}, + rootable::Scopable, }, - engine::context::GcScope, heap::IntrinsicConstructorIndexes, }; @@ -36,18 +46,74 @@ impl WeakMapConstructor { fn constructor<'gc>( agent: &mut Agent, _this_value: Value, - _arguments: ArgumentsList, - _new_target: Option, - gc: GcScope<'gc, '_>, + arguments: ArgumentsList, + new_target: Option, + mut gc: GcScope<'gc, '_>, ) -> JsResult<'gc, Value<'gc>> { + let iterable = arguments.get(0).bind(gc.nogc()); // 1. If NewTarget is undefined, throw a TypeError exception. + let Some(new_target) = new_target else { + return Err(agent.throw_exception_with_static_message( + ExceptionType::TypeError, + "WeakMap Constructor requires 'new'", + gc.into_nogc(), + )); + }; + let Ok(new_target) = Function::try_from(new_target) else { + return Err(agent.throw_exception_with_static_message( + ExceptionType::TypeError, + "Function Proxies not yet supported", + gc.into_nogc(), + )); + }; + let iterable_is_undefined_or_null = iterable.is_undefined() || iterable.is_null(); + let iterable = iterable.scope(agent, gc.nogc()); // 2. Let map be ? OrdinaryCreateFromConstructor(NewTarget, "%WeakMap.prototype%", « [[WeakMapData]] »). + let Object::WeakMap(map) = ordinary_create_from_constructor( + agent, + new_target, + ProtoIntrinsics::WeakMap, + gc.reborrow(), + ) + .unbind()? + else { + // SAFETY: ProtoIntrinsics guarded. + unsafe { unreachable_unchecked() } + }; // 3. Set map.[[WeakMapData]] to a new empty List. // 4. If iterable is either undefined or null, return map. + if iterable_is_undefined_or_null { + return Ok(map.into_value()); + } + let scoped_map = map.scope(agent, gc.nogc()); // 5. Let adder be ? Get(map, "set"). + let adder = get( + agent, + map.unbind(), + BUILTIN_STRING_MEMORY.set.to_property_key(), + gc.reborrow(), + ) + .unbind()? + .bind(gc.nogc()); // 6. If IsCallable(adder) is false, throw a TypeError exception. + let Some(adder) = is_callable(adder, gc.nogc()) else { + return Err(agent.throw_exception_with_static_message( + ExceptionType::TypeError, + "expected 'add' to be a function", + gc.into_nogc(), + )); + }; // 7. Return ? AddEntriesFromIterable(map, iterable, adder). - Err(agent.todo("WeakMap", gc.into_nogc())) + add_entries_from_iterable( + agent, + // SAFETY: not shared. + unsafe { scoped_map.take(agent) }, + // SAFETY: not shared. + unsafe { iterable.take(agent) }, + adder.unbind(), + gc, + ) + .map(|m| m.into_value()) } pub(crate) fn create_intrinsic(agent: &mut Agent, realm: Realm<'static>) { diff --git a/nova_vm/src/ecmascript/builtins/keyed_collections/weak_map_objects/weak_map_prototype.rs b/nova_vm/src/ecmascript/builtins/keyed_collections/weak_map_objects/weak_map_prototype.rs index 52f21a675..624631949 100644 --- a/nova_vm/src/ecmascript/builtins/keyed_collections/weak_map_objects/weak_map_prototype.rs +++ b/nova_vm/src/ecmascript/builtins/keyed_collections/weak_map_objects/weak_map_prototype.rs @@ -5,11 +5,14 @@ use crate::{ ecmascript::{ builders::ordinary_object_builder::OrdinaryObjectBuilder, - builtins::{ArgumentsList, Behaviour, Builtin}, - execution::{Agent, JsResult, Realm}, + builtins::{ArgumentsList, Behaviour, Builtin, weak_map::WeakMap}, + execution::{ + Agent, JsResult, Realm, agent::ExceptionType, can_be_held_weakly, + throw_not_weak_key_error, + }, types::{BUILTIN_STRING_MEMORY, IntoValue, String, Value}, }, - engine::context::GcScope, + engine::context::{Bindable, GcScope, NoGcScope}, heap::WellKnownSymbolIndexes, }; @@ -33,7 +36,7 @@ impl Builtin for WeakMapPrototypeHas { const LENGTH: u8 = 1; const BEHAVIOUR: Behaviour = Behaviour::Regular(WeakMapPrototype::has); } -struct WeakMapPrototypeSet; +pub(super) struct WeakMapPrototypeSet; impl Builtin for WeakMapPrototypeSet { const NAME: String<'static> = BUILTIN_STRING_MEMORY.set; const LENGTH: u8 = 2; @@ -49,72 +52,105 @@ impl WeakMapPrototype { /// > structures. fn delete<'gc>( agent: &mut Agent, - _this_value: Value, - _: ArgumentsList, + this_value: Value, + arguments: ArgumentsList, gc: GcScope<'gc, '_>, ) -> JsResult<'gc, Value<'gc>> { + let gc = gc.into_nogc(); + let key = arguments.get(0).bind(gc); // 1. Let M be the this value. + let m = this_value.bind(gc); // 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). - // 3. If CanBeHeldWeakly(key) is false, return false. + let m = require_internal_slot_weak_map_data(agent, m, gc)?; + // 3. If CanBeHeldWeakly(key) is false, + let Some(key) = can_be_held_weakly(agent, key) else { + // return false. + return Ok(false.into_value()); + }; // 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do - // a. If p.[[Key]] is not EMPTY and SameValue(p.[[Key]], key) is true, then - // i. Set p.[[Key]] to EMPTY. - // ii. Set p.[[Value]] to EMPTY. - // iii. Return true. + // a. If p.[[Key]] is not EMPTY and SameValue(p.[[Key]], key) is true, then + // i. Set p.[[Key]] to EMPTY. + // ii. Set p.[[Value]] to EMPTY. + // iii. Return true. // 5. Return false. - Err(agent.todo("WeakMap.prototype.delete", gc.into_nogc())) + Ok(m.delete(agent, key).into_value()) } /// ### [24.3.3.3 WeakMap.prototype.get ( key )](https://tc39.es/ecma262/#sec-weakmap.prototype.get) fn get<'gc>( agent: &mut Agent, - _this_value: Value, - _: ArgumentsList, + this_value: Value, + arguments: ArgumentsList, gc: GcScope<'gc, '_>, ) -> JsResult<'gc, Value<'gc>> { + let gc = gc.into_nogc(); + let key = arguments.get(0).bind(gc); // 1. Let M be the this value. + let m = this_value.bind(gc); // 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). - // 3. If CanBeHeldWeakly(key) is false, return false. + let m = require_internal_slot_weak_map_data(agent, m, gc)?; + // 3. If CanBeHeldWeakly(key) is false, + let Some(key) = can_be_held_weakly(agent, key) else { + // return undefined. + return Ok(Value::Undefined); + }; // 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do - // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return true. - // 5. Return false. - Err(agent.todo("WeakMap.prototype.get", gc.into_nogc())) + // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + // 5. Return undefined. + Ok(m.get_v(agent, key).unwrap_or(Value::Undefined)) } /// ### [24.3.3.4 WeakMap.prototype.has ( key )](https://tc39.es/ecma262/#sec-weakmap.prototype.has) fn has<'gc>( agent: &mut Agent, - _this_value: Value, - _: ArgumentsList, + this_value: Value, + arguments: ArgumentsList, gc: GcScope<'gc, '_>, ) -> JsResult<'gc, Value<'gc>> { + let gc = gc.into_nogc(); + let key = arguments.get(0).bind(gc); // 1. Let M be the this value. + let m = this_value.bind(gc); // 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). - // 3. If CanBeHeldWeakly(key) is false, return false. + let m = require_internal_slot_weak_map_data(agent, m, gc)?; + // 3. If CanBeHeldWeakly(key) is false, + let Some(key) = can_be_held_weakly(agent, key) else { + // return false. + return Ok(false.into_value()); + }; // 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do - // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return true. + // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return true. // 5. Return false. - Err(agent.todo("WeakMap.prototype.has", gc.into_nogc())) + Ok(m.has(agent, key).into_value()) } /// ### [24.3.3.5 WeakMap.prototype.set ( key, value )](https://tc39.es/ecma262/#sec-weakmap.prototype.set) fn set<'gc>( agent: &mut Agent, - _this_value: Value, - _: ArgumentsList, + this_value: Value, + arguments: ArgumentsList, gc: GcScope<'gc, '_>, ) -> JsResult<'gc, Value<'gc>> { + let gc = gc.into_nogc(); + let key = arguments.get(0).bind(gc); + let value = arguments.get(1).bind(gc); // 1. Let M be the this value. + let m = this_value.bind(gc); // 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). + let m = require_internal_slot_weak_map_data(agent, m, gc)?; // 3. If CanBeHeldWeakly(key) is false, throw a TypeError exception. + let Some(key) = can_be_held_weakly(agent, key) else { + return Err(throw_not_weak_key_error(agent, key, gc)); + }; // 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do - // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, then - // i. Set p.[[Value]] to value. - // ii. Return M. + // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, then + // i. Set p.[[Value]] to value. + // ii. Return M. // 5. Let p be the Record { [[Key]]: key, [[Value]]: value }. // 6. Append p to M.[[WeakMapData]]. + m.set(agent, key, value); // 7. Return M. - Err(agent.todo("WeakMap.prototype.set", gc.into_nogc())) + Ok(m.into_value()) } pub(crate) fn create_intrinsic(agent: &mut Agent, realm: Realm<'static>) { @@ -142,3 +178,19 @@ impl WeakMapPrototype { .build(); } } + +#[inline(always)] +fn require_internal_slot_weak_map_data<'a>( + agent: &mut Agent, + value: Value, + gc: NoGcScope<'a, '_>, +) -> JsResult<'a, WeakMap<'a>> { + match value { + Value::WeakMap(map) => Ok(map.bind(gc)), + _ => Err(agent.throw_exception_with_static_message( + ExceptionType::TypeError, + "Object is not a WeakMap", + gc, + )), + } +} diff --git a/nova_vm/src/ecmascript/builtins/map.rs b/nova_vm/src/ecmascript/builtins/map.rs index 8c0f4c007..826f00f8f 100644 --- a/nova_vm/src/ecmascript/builtins/map.rs +++ b/nova_vm/src/ecmascript/builtins/map.rs @@ -12,7 +12,7 @@ use crate::{ }, engine::{ context::{Bindable, bindable_handle}, - rootable::{HeapRootData, HeapRootRef, Rootable}, + rootable::HeapRootData, }, heap::{ CompactionLists, CreateHeapData, HeapMarkAndSweep, HeapSweepWeakReference, WorkQueues, @@ -52,6 +52,12 @@ impl<'a> From> for Object<'a> { } } +impl From> for HeapRootData { + fn from(value: Map) -> Self { + HeapRootData::Map(value.unbind()) + } +} + impl<'a> TryFrom> for Map<'a> { type Error = (); @@ -63,6 +69,28 @@ impl<'a> TryFrom> for Map<'a> { } } +impl<'a> TryFrom> for Map<'a> { + type Error = (); + + fn try_from(value: Value<'a>) -> Result { + match value { + Value::Map(data) => Ok(data), + _ => Err(()), + } + } +} + +impl TryFrom for Map<'_> { + type Error = (); + + fn try_from(value: HeapRootData) -> Result { + match value { + HeapRootData::Map(data) => Ok(data), + _ => Err(()), + } + } +} + impl<'a> InternalSlots<'a> for Map<'a> { const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::Map; @@ -127,29 +155,6 @@ impl IndexMut> for Vec> { } } -impl Rootable for Map<'_> { - type RootRepr = HeapRootRef; - - fn to_root_repr(value: Self) -> Result { - Err(HeapRootData::Map(value.unbind())) - } - - fn from_root_repr(value: &Self::RootRepr) -> Result { - Err(*value) - } - - fn from_heap_ref(heap_ref: HeapRootRef) -> Self::RootRepr { - heap_ref - } - - fn from_heap_data(heap_data: HeapRootData) -> Option { - match heap_data { - HeapRootData::Map(object) => Some(object), - _ => None, - } - } -} - impl<'a> CreateHeapData, Map<'a>> for Heap { fn create(&mut self, data: MapHeapData<'a>) -> Map<'a> { self.maps.push(data.unbind()); diff --git a/nova_vm/src/ecmascript/builtins/ordinary.rs b/nova_vm/src/ecmascript/builtins/ordinary.rs index 4abaef773..ab6da9c06 100644 --- a/nova_vm/src/ecmascript/builtins/ordinary.rs +++ b/nova_vm/src/ecmascript/builtins/ordinary.rs @@ -81,8 +81,7 @@ use super::{ }; #[cfg(feature = "weak-refs")] use super::{ - weak_map::data::WeakMapHeapData, weak_ref::data::WeakRefHeapData, - weak_set::data::WeakSetHeapData, + weak_map::data::WeakMapRecord, weak_ref::data::WeakRefHeapData, weak_set::data::WeakSetHeapData, }; /// ### [10.1 Ordinary Object Internal Methods and Internal Slots](https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots) @@ -1808,7 +1807,7 @@ pub(crate) fn ordinary_object_create_with_intrinsics<'a>( Object::Uint8ClampedArray(agent.heap.create(TypedArrayRecord::default())) } #[cfg(feature = "weak-refs")] - ProtoIntrinsics::WeakMap => agent.heap.create(WeakMapHeapData::default()).into_object(), + ProtoIntrinsics::WeakMap => agent.heap.create(WeakMapRecord::default()).into_object(), #[cfg(feature = "weak-refs")] ProtoIntrinsics::WeakRef => agent.heap.create(WeakRefHeapData::default()).into_object(), #[cfg(feature = "weak-refs")] diff --git a/nova_vm/src/ecmascript/builtins/ordinary/caches.rs b/nova_vm/src/ecmascript/builtins/ordinary/caches.rs index a6da7e888..4ab4fbcb9 100644 --- a/nova_vm/src/ecmascript/builtins/ordinary/caches.rs +++ b/nova_vm/src/ecmascript/builtins/ordinary/caches.rs @@ -16,8 +16,8 @@ use crate::{ rootable::{HeapRootData, HeapRootRef, Rootable}, }, heap::{ - CompactionLists, HeapMarkAndSweep, HeapSweepWeakReference, PropertyKeyHeap, WeakReference, - WorkQueues, sweep_heap_vector_values, + AtomicBits, BitRange, CompactionLists, HeapMarkAndSweep, HeapSweepWeakReference, + PropertyKeyHeap, WeakReference, WorkQueues, sweep_heap_vector_values, }, }; @@ -428,11 +428,17 @@ impl Caches<'static> { self.property_lookup_cache_prototypes[index].mark_values(queues); } - pub(crate) fn sweep_cache(&mut self, compactions: &CompactionLists, bits: &[bool]) { - sweep_heap_vector_values(&mut self.property_lookup_caches, compactions, bits); + pub(crate) fn sweep_cache( + &mut self, + compactions: &CompactionLists, + range: &BitRange, + bits: &[AtomicBits], + ) { + sweep_heap_vector_values(&mut self.property_lookup_caches, compactions, range, bits); sweep_heap_vector_values( &mut self.property_lookup_cache_prototypes, compactions, + range, bits, ); } diff --git a/nova_vm/src/ecmascript/builtins/ordinary/shape.rs b/nova_vm/src/ecmascript/builtins/ordinary/shape.rs index 56f39779d..2deb601fb 100644 --- a/nova_vm/src/ecmascript/builtins/ordinary/shape.rs +++ b/nova_vm/src/ecmascript/builtins/ordinary/shape.rs @@ -1162,7 +1162,7 @@ impl HeapMarkAndSweep for ObjectShapeRecord<'static> { prototype, keys, keys_cap, - len, + len: _, // Note: values capacity is only used for marking and sweeping // objects, not object shapes themselves. values_cap: _, @@ -1170,17 +1170,17 @@ impl HeapMarkAndSweep for ObjectShapeRecord<'static> { prototype.mark_values(queues); match keys_cap { ElementArrayKey::Empty | ElementArrayKey::EmptyIntrinsic => {} - ElementArrayKey::E1 => queues.k_2_1.push((*keys, *len)), - ElementArrayKey::E2 => queues.k_2_2.push((*keys, *len)), - ElementArrayKey::E3 => queues.k_2_3.push((*keys, *len)), - ElementArrayKey::E4 => queues.k_2_4.push((*keys, *len)), - ElementArrayKey::E6 => queues.k_2_6.push((*keys, *len)), - ElementArrayKey::E8 => queues.k_2_8.push((*keys, *len)), - ElementArrayKey::E10 => queues.k_2_10.push((*keys, *len)), - ElementArrayKey::E12 => queues.k_2_12.push((*keys, *len)), - ElementArrayKey::E16 => queues.k_2_16.push((*keys, *len)), - ElementArrayKey::E24 => queues.k_2_24.push((*keys, *len)), - ElementArrayKey::E32 => queues.k_2_32.push((*keys, *len)), + ElementArrayKey::E1 => queues.k_2_1.push(*keys), + ElementArrayKey::E2 => queues.k_2_2.push(*keys), + ElementArrayKey::E3 => queues.k_2_3.push(*keys), + ElementArrayKey::E4 => queues.k_2_4.push(*keys), + ElementArrayKey::E6 => queues.k_2_6.push(*keys), + ElementArrayKey::E8 => queues.k_2_8.push(*keys), + ElementArrayKey::E10 => queues.k_2_10.push(*keys), + ElementArrayKey::E12 => queues.k_2_12.push(*keys), + ElementArrayKey::E16 => queues.k_2_16.push(*keys), + ElementArrayKey::E24 => queues.k_2_24.push(*keys), + ElementArrayKey::E32 => queues.k_2_32.push(*keys), } } diff --git a/nova_vm/src/ecmascript/builtins/typed_array/normal_typed_array.rs b/nova_vm/src/ecmascript/builtins/typed_array/normal_typed_array.rs index 64412ae4c..cdd3789ee 100644 --- a/nova_vm/src/ecmascript/builtins/typed_array/normal_typed_array.rs +++ b/nova_vm/src/ecmascript/builtins/typed_array/normal_typed_array.rs @@ -88,6 +88,11 @@ impl<'ta, T: Viewable> GenericTypedArray<'ta, T> { GenericTypedArray(self.0, PhantomData) } + #[inline(always)] + pub(crate) const fn get_index(self) -> usize { + self.0.into_index() + } + fn check_not_void_array() { if core::any::TypeId::of::() == core::any::TypeId::of::<()>() { panic!("Invalid GenericTypedArray invocation using void type"); @@ -325,11 +330,6 @@ impl<'gc> VoidArray<'gc> { GenericTypedArray(self.0, PhantomData) } - #[inline(always)] - pub(crate) fn get_index(self) -> usize { - self.0.into_index() - } - #[inline(always)] fn get<'a>(self, agent: &'a Agent) -> &'a TypedArrayRecord<'gc> { self.get_direct(&agent.heap.typed_arrays) diff --git a/nova_vm/src/ecmascript/builtins/typed_array/shared_typed_array.rs b/nova_vm/src/ecmascript/builtins/typed_array/shared_typed_array.rs index 518b4457d..6fcf28aac 100644 --- a/nova_vm/src/ecmascript/builtins/typed_array/shared_typed_array.rs +++ b/nova_vm/src/ecmascript/builtins/typed_array/shared_typed_array.rs @@ -97,6 +97,11 @@ impl<'ta, T: Viewable> GenericSharedTypedArray<'ta, T> { GenericSharedTypedArray(self.0, PhantomData) } + #[inline(always)] + pub(crate) const fn get_index(self) -> usize { + self.0.into_index() + } + fn check_not_void_array() { if core::any::TypeId::of::() == core::any::TypeId::of::<()>() { panic!("Invalid GenericSharedTypedArray invocation using void type"); @@ -290,11 +295,6 @@ impl<'ta, T: Viewable> GenericSharedTypedArray<'ta, T> { pub(crate) type SharedVoidArray<'a> = GenericSharedTypedArray<'a, ()>; impl<'gc> SharedVoidArray<'gc> { - #[inline(always)] - pub(crate) fn get_index(self) -> usize { - self.0.into_index() - } - #[inline(always)] fn get<'a>(self, agent: &'a Agent) -> &'a SharedTypedArrayRecord<'gc> { self.get_direct(&agent.heap.shared_typed_arrays) @@ -896,6 +896,7 @@ impl<'a> SharedTypedArray<'a> { } } +#[cfg(feature = "shared-array-buffer")] macro_rules! for_shared_typed_array { ($value: ident, $ta: ident, $expr: expr) => { for_shared_typed_array($value, $ta, $expr, TA) @@ -954,6 +955,7 @@ macro_rules! for_shared_typed_array { } }; } +#[cfg(feature = "shared-array-buffer")] pub(crate) use for_shared_typed_array; impl<'a> From> for Value<'a> { @@ -2221,9 +2223,7 @@ impl<'a, T: Viewable> TypedArrayAbstractOperations<'a> for GenericSharedTypedArr } #[cfg(feature = "shared-array-buffer")] AnyArrayBuffer::SharedArrayBuffer(source_buffer) => { - use crate::ecmascript::builtins::typed_array::{ - SharedTypedArray, for_shared_typed_array, - }; + use crate::ecmascript::builtins::typed_array::SharedTypedArray; let Ok(source) = SharedTypedArray::try_from(source) else { // SAFETY: Cannot get SharedArrayBuffer from TypedArray. @@ -2343,9 +2343,7 @@ impl<'a, T: Viewable> TypedArrayAbstractOperations<'a> for GenericSharedTypedArr } #[cfg(feature = "shared-array-buffer")] AnyArrayBuffer::SharedArrayBuffer(source_buffer) => { - use crate::ecmascript::builtins::typed_array::{ - SharedTypedArray, for_shared_typed_array, - }; + use crate::ecmascript::builtins::typed_array::SharedTypedArray; let Ok(source) = SharedTypedArray::try_from(source) else { // SAFETY: Cannot get SharedArrayBuffer from TypedArray. diff --git a/nova_vm/src/ecmascript/builtins/weak_map.rs b/nova_vm/src/ecmascript/builtins/weak_map.rs index 9e3e6ce62..5a9d9ba91 100644 --- a/nova_vm/src/ecmascript/builtins/weak_map.rs +++ b/nova_vm/src/ecmascript/builtins/weak_map.rs @@ -2,12 +2,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use core::ops::{Index, IndexMut}; - use crate::{ Heap, ecmascript::{ - execution::{Agent, ProtoIntrinsics}, + execution::{Agent, ProtoIntrinsics, WeakKey}, types::{InternalMethods, InternalSlots, Object, OrdinaryObject, Value}, }, engine::{ @@ -20,84 +18,116 @@ use crate::{ }, }; -use self::data::WeakMapHeapData; +use self::data::WeakMapRecord; pub mod data; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] -pub struct WeakMap<'a>(BaseIndex<'a, WeakMapHeapData<'static>>); +pub struct WeakMap<'a>(BaseIndex<'a, WeakMapRecord<'static>>); +bindable_handle!(WeakMap); -impl WeakMap<'_> { - pub(crate) const fn _def() -> Self { - Self(BaseIndex::from_u32_index(0)) +impl<'m> WeakMap<'m> { + pub(crate) fn delete(self, agent: &mut Agent, key: WeakKey<'m>) -> bool { + self.get_mut(agent).delete(key) } - pub(crate) const fn get_index(self) -> usize { - self.0.into_index() + pub(crate) fn get_v(self, agent: &mut Agent, key: WeakKey<'m>) -> Option> { + self.get_mut(agent).get(key) } -} -bindable_handle!(WeakMap); + pub(crate) fn has(self, agent: &mut Agent, key: WeakKey<'m>) -> bool { + self.get_mut(agent).has(key) + } -impl<'a> From> for Value<'a> { - fn from(value: WeakMap<'a>) -> Self { - Value::WeakMap(value) + pub(crate) fn set(self, agent: &mut Agent, key: WeakKey<'m>, value: Value<'m>) { + self.get_mut(agent).set(key, value) } -} -impl<'a> From> for Object<'a> { - fn from(value: WeakMap<'a>) -> Self { - Object::WeakMap(value) + pub(crate) const _DEF: Self = Self(BaseIndex::from_u32_index(u32::MAX - 1)); + + pub(crate) const fn get_index(self) -> usize { + self.0.into_index() } -} -impl<'a> InternalSlots<'a> for WeakMap<'a> { - const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::WeakMap; + #[inline(always)] + pub(crate) fn get<'a>(self, agent: &'a Agent) -> &'a WeakMapRecord<'m> { + self.get_direct(&agent.heap.weak_maps) + } #[inline(always)] - fn get_backing_object(self, agent: &Agent) -> Option> { - agent[self].object_index + pub(crate) fn get_mut<'a>(self, agent: &'a mut Agent) -> &'a mut WeakMapRecord<'m> { + self.get_direct_mut(&mut agent.heap.weak_maps) } - fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) { - assert!( - agent[self] - .object_index - .replace(backing_object.unbind()) - .is_none() - ); + #[inline(always)] + pub(crate) fn get_direct<'a>( + self, + weak_maps: &'a [WeakMapRecord<'static>], + ) -> &'a WeakMapRecord<'m> { + weak_maps + .get(self.get_index()) + .expect("Invalid WeakMap reference") } -} -impl<'a> InternalMethods<'a> for WeakMap<'a> {} + #[inline(always)] + pub(crate) fn get_direct_mut<'a>( + self, + weak_maps: &'a mut [WeakMapRecord<'static>], + ) -> &'a mut WeakMapRecord<'m> { + // SAFETY: Lifetime transmute to thread GC lifetime to temporary heap + // reference. + unsafe { + core::mem::transmute::<&'a mut WeakMapRecord<'static>, &'a mut WeakMapRecord<'m>>( + weak_maps + .get_mut(self.get_index()) + .expect("Invalid WeakMap reference"), + ) + } + } +} -impl Index> for Agent { - type Output = WeakMapHeapData<'static>; +impl<'a> From> for Value<'a> { + fn from(value: WeakMap<'a>) -> Self { + Value::WeakMap(value) + } +} - fn index(&self, index: WeakMap) -> &Self::Output { - &self.heap.weak_maps[index] +impl<'a> From> for Object<'a> { + fn from(value: WeakMap<'a>) -> Self { + Object::WeakMap(value) } } -impl IndexMut> for Agent { - fn index_mut(&mut self, index: WeakMap) -> &mut Self::Output { - &mut self.heap.weak_maps[index] +impl<'a> From> for HeapRootData { + fn from(value: WeakMap<'a>) -> Self { + HeapRootData::WeakMap(value.unbind()) } } -impl Index> for Vec> { - type Output = WeakMapHeapData<'static>; +impl<'a> TryFrom> for WeakMap<'a> { + type Error = (); - fn index(&self, index: WeakMap) -> &Self::Output { - self.get(index.get_index()).expect("WeakMap out of bounds") + #[inline] + fn try_from(value: Value<'a>) -> Result { + if let Value::WeakMap(value) = value { + Ok(value) + } else { + Err(()) + } } } -impl IndexMut> for Vec> { - fn index_mut(&mut self, index: WeakMap) -> &mut Self::Output { - self.get_mut(index.get_index()) - .expect("WeakMap out of bounds") +impl<'a> TryFrom> for WeakMap<'a> { + type Error = (); + + #[inline] + fn try_from(value: Object<'a>) -> Result { + if let Object::WeakMap(value) = value { + Ok(value) + } else { + Err(()) + } } } @@ -114,10 +144,30 @@ impl TryFrom for WeakMap<'_> { } } -impl<'a> CreateHeapData, WeakMap<'a>> for Heap { - fn create(&mut self, data: WeakMapHeapData<'a>) -> WeakMap<'a> { +impl<'a> InternalSlots<'a> for WeakMap<'a> { + const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::WeakMap; + + #[inline(always)] + fn get_backing_object(self, agent: &Agent) -> Option> { + self.get(agent).object_index.unbind() + } + + fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) { + assert!( + self.get_mut(agent) + .object_index + .replace(backing_object.unbind()) + .is_none() + ); + } +} + +impl<'a> InternalMethods<'a> for WeakMap<'a> {} + +impl<'a> CreateHeapData, WeakMap<'a>> for Heap { + fn create(&mut self, data: WeakMapRecord<'a>) -> WeakMap<'a> { self.weak_maps.push(data.unbind()); - self.alloc_counter += core::mem::size_of::>(); + self.alloc_counter += core::mem::size_of::>(); WeakMap(BaseIndex::last(&self.weak_maps)) } } diff --git a/nova_vm/src/ecmascript/builtins/weak_map/data.rs b/nova_vm/src/ecmascript/builtins/weak_map/data.rs index c3766ad84..508d70412 100644 --- a/nova_vm/src/ecmascript/builtins/weak_map/data.rs +++ b/nova_vm/src/ecmascript/builtins/weak_map/data.rs @@ -2,60 +2,88 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +use ahash::AHashMap; + use crate::{ - ecmascript::types::{OrdinaryObject, Value}, + ecmascript::{ + execution::WeakKey, + types::{OrdinaryObject, Value}, + }, engine::context::bindable_handle, - heap::{CompactionLists, HeapMarkAndSweep, WorkQueues}, + heap::{CompactionLists, HeapMarkAndSweep, HeapSweepWeakReference, WorkQueues}, }; -#[derive(Debug, Clone, Default)] -pub struct WeakMapHeapData<'a> { - pub(crate) object_index: Option>, - // TODO: This isn't even close to a hashmap; HashMap won't allow inserting - // Value as key; f32 isn't hashable. And our f64s are found on the Heap and - // require fetching; What we actually should do is more like: - // pub(crate) map: HashMap - // pub(crate) key_values: ParallelVec, Option> - // ValueHash is created using a Value.hash(agent) function and connects to - // an index; the index points to a key and value in parallel vector / Vec2. - // Note that empty slots are deleted values in the ParallelVec. - pub(crate) keys: Vec>, - pub(crate) values: Vec>, - // TODO: When an non-terminal (start or end) iterator exists for the Map, - // the items in the map cannot be compacted. - // pub(crate) observed: bool; +#[derive(Debug, Default)] +pub struct WeakMapRecord<'a> { + pub(crate) weak_map_data: AHashMap, Value<'a>>, + pub(super) object_index: Option>, } +bindable_handle!(WeakMapRecord); + +impl<'a> WeakMapRecord<'a> { + pub(super) fn delete(&mut self, key: WeakKey<'a>) -> bool { + // 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + // a. If p.[[Key]] is not EMPTY and SameValue(p.[[Key]], key) is true, then + // i. Set p.[[Key]] to EMPTY. + // ii. Set p.[[Value]] to EMPTY. + // iii. Return true. + // 5. Return false. + self.weak_map_data.remove(&key).is_some() + } + + pub(super) fn get(&mut self, key: WeakKey<'a>) -> Option> { + // 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + // 5. Return undefined. + self.weak_map_data.get(&key).cloned() + } -bindable_handle!(WeakMapHeapData); + pub(super) fn has(&mut self, key: WeakKey<'a>) -> bool { + // 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return true. + // 5. Return false. + self.weak_map_data.contains_key(&key) + } -impl HeapMarkAndSweep for WeakMapHeapData<'static> { + pub(super) fn set(&mut self, key: WeakKey<'a>, value: Value<'a>) { + // 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + // a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, then + // i. Set p.[[Value]] to value. + // ii. Return M. + // 5. Let p be the Record { [[Key]]: key, [[Value]]: value }. + // 6. Append p to M.[[WeakMapData]]. + self.weak_map_data.insert(key, value); + } +} + +impl HeapMarkAndSweep for WeakMapRecord<'static> { fn mark_values(&self, queues: &mut WorkQueues) { let Self { + weak_map_data: map, object_index, - keys, - values, } = self; - object_index.mark_values(queues); - for ele in keys { - ele.mark_values(queues); - } - for ele in values { - ele.mark_values(queues); + for (key, value) in map.iter() { + if queues.bits.is_marked(key) { + value.mark_values(queues); + } else { + queues.pending_ephemerons.push((*key, *value)); + } } + object_index.mark_values(queues); } fn sweep_values(&mut self, compactions: &CompactionLists) { let Self { + weak_map_data: map, object_index, - keys, - values, } = self; - object_index.sweep_values(compactions); - for ele in keys { - ele.sweep_values(compactions); - } - for ele in values { - ele.sweep_values(compactions); + let old_map = core::mem::replace(map, AHashMap::with_capacity(map.len())); + for (key, mut value) in old_map { + if let Some(key) = key.sweep_weak_reference(compactions) { + value.sweep_values(compactions); + map.insert(key, value); + } } + object_index.sweep_values(compactions); } } diff --git a/nova_vm/src/ecmascript/execution/weak_key.rs b/nova_vm/src/ecmascript/execution/weak_key.rs index a9863df29..051ab68ef 100644 --- a/nova_vm/src/ecmascript/execution/weak_key.rs +++ b/nova_vm/src/ecmascript/execution/weak_key.rs @@ -120,7 +120,7 @@ use crate::{ }; /// ### [6.1 ECMAScript Language Types](https://tc39.es/ecma262/#sec-ecmascript-language-types) -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(u8)] pub(crate) enum WeakKey<'a> { Symbol(Symbol<'a>) = SYMBOL_DISCRIMINANT, @@ -219,6 +219,7 @@ pub(crate) enum WeakKey<'a> { ArrayIterator(ArrayIterator<'a>) = ARRAY_ITERATOR_DISCRIMINANT, #[cfg(feature = "set")] SetIterator(SetIterator<'a>) = SET_ITERATOR_DISCRIMINANT, + #[cfg(feature = "set")] MapIterator(MapIterator<'a>) = MAP_ITERATOR_DISCRIMINANT, StringIterator(StringIterator<'a>) = STRING_ITERATOR_DISCRIMINANT, #[cfg(feature = "regexp")] diff --git a/nova_vm/src/ecmascript/types/language/object.rs b/nova_vm/src/ecmascript/types/language/object.rs index 67daa602f..002444d9b 100644 --- a/nova_vm/src/ecmascript/types/language/object.rs +++ b/nova_vm/src/ecmascript/types/language/object.rs @@ -267,6 +267,7 @@ pub enum Object<'a> { ArrayIterator(ArrayIterator<'a>) = ARRAY_ITERATOR_DISCRIMINANT, #[cfg(feature = "set")] SetIterator(SetIterator<'a>) = SET_ITERATOR_DISCRIMINANT, + #[cfg(feature = "set")] MapIterator(MapIterator<'a>) = MAP_ITERATOR_DISCRIMINANT, StringIterator(StringIterator<'a>) = STRING_ITERATOR_DISCRIMINANT, #[cfg(feature = "regexp")] diff --git a/nova_vm/src/ecmascript/types/language/object/data.rs b/nova_vm/src/ecmascript/types/language/object/data.rs index 9de2b0319..231ea506d 100644 --- a/nova_vm/src/ecmascript/types/language/object/data.rs +++ b/nova_vm/src/ecmascript/types/language/object/data.rs @@ -15,8 +15,8 @@ use crate::{ #[derive(Debug, PartialEq, Eq)] pub(crate) struct ObjectRecord<'a> { - shape: ObjectShape<'a>, - values: ElementIndex<'a>, + pub(crate) shape: ObjectShape<'a>, + pub(crate) values: ElementIndex<'a>, } impl<'a> ObjectRecord<'a> { @@ -98,20 +98,19 @@ impl ObjectRecord<'static> { ) { let Self { shape, values } = self; shape.mark_values(queues); - let len = shape.len(&shapes); match shape.values_capacity(&shapes) { ElementArrayKey::Empty | ElementArrayKey::EmptyIntrinsic => {} - ElementArrayKey::E1 => queues.e_2_1.push((*values, len)), - ElementArrayKey::E2 => queues.e_2_2.push((*values, len)), - ElementArrayKey::E3 => queues.e_2_3.push((*values, len)), - ElementArrayKey::E4 => queues.e_2_4.push((*values, len)), - ElementArrayKey::E6 => queues.e_2_6.push((*values, len)), - ElementArrayKey::E8 => queues.e_2_8.push((*values, len)), - ElementArrayKey::E10 => queues.e_2_10.push((*values, len)), - ElementArrayKey::E12 => queues.e_2_12.push((*values, len)), - ElementArrayKey::E16 => queues.e_2_16.push((*values, len)), - ElementArrayKey::E24 => queues.e_2_24.push((*values, len)), - ElementArrayKey::E32 => queues.e_2_32.push((*values, len)), + ElementArrayKey::E1 => queues.e_2_1.push(*values), + ElementArrayKey::E2 => queues.e_2_2.push(*values), + ElementArrayKey::E3 => queues.e_2_3.push(*values), + ElementArrayKey::E4 => queues.e_2_4.push(*values), + ElementArrayKey::E6 => queues.e_2_6.push(*values), + ElementArrayKey::E8 => queues.e_2_8.push(*values), + ElementArrayKey::E10 => queues.e_2_10.push(*values), + ElementArrayKey::E12 => queues.e_2_12.push(*values), + ElementArrayKey::E16 => queues.e_2_16.push(*values), + ElementArrayKey::E24 => queues.e_2_24.push(*values), + ElementArrayKey::E32 => queues.e_2_32.push(*values), } } diff --git a/nova_vm/src/ecmascript/types/language/value.rs b/nova_vm/src/ecmascript/types/language/value.rs index 9105bd6ee..9e7480c1b 100644 --- a/nova_vm/src/ecmascript/types/language/value.rs +++ b/nova_vm/src/ecmascript/types/language/value.rs @@ -267,6 +267,7 @@ pub enum Value<'a> { ArrayIterator(ArrayIterator<'a>), #[cfg(feature = "set")] SetIterator(SetIterator<'a>), + #[cfg(feature = "set")] MapIterator(MapIterator<'a>), StringIterator(StringIterator<'a>), #[cfg(feature = "regexp")] @@ -348,7 +349,7 @@ pub(crate) const PROXY_DISCRIMINANT: u8 = value_discriminant(Value::Proxy(Proxy: #[cfg(feature = "set")] pub(crate) const SET_DISCRIMINANT: u8 = value_discriminant(Value::Set(Set::_def())); #[cfg(feature = "weak-refs")] -pub(crate) const WEAK_MAP_DISCRIMINANT: u8 = value_discriminant(Value::WeakMap(WeakMap::_def())); +pub(crate) const WEAK_MAP_DISCRIMINANT: u8 = value_discriminant(Value::WeakMap(WeakMap::_DEF)); #[cfg(feature = "weak-refs")] pub(crate) const WEAK_REF_DISCRIMINANT: u8 = value_discriminant(Value::WeakRef(WeakRef::_def())); #[cfg(feature = "weak-refs")] @@ -447,6 +448,7 @@ pub(crate) const ARRAY_ITERATOR_DISCRIMINANT: u8 = #[cfg(feature = "set")] pub(crate) const SET_ITERATOR_DISCRIMINANT: u8 = value_discriminant(Value::SetIterator(SetIterator::_def())); +#[cfg(feature = "set")] pub(crate) const MAP_ITERATOR_DISCRIMINANT: u8 = value_discriminant(Value::MapIterator(MapIterator::_def())); pub(crate) const STRING_ITERATOR_DISCRIMINANT: u8 = diff --git a/nova_vm/src/engine/bytecode/bytecode_compiler.rs b/nova_vm/src/engine/bytecode/bytecode_compiler.rs index 8eddf3268..22942fee5 100644 --- a/nova_vm/src/engine/bytecode/bytecode_compiler.rs +++ b/nova_vm/src/engine/bytecode/bytecode_compiler.rs @@ -3613,7 +3613,6 @@ impl<'a, 's, 'gc, 'scope> CompileEvaluation<'a, 's, 'gc, 'scope> for ast::TSEnum ); // 2. Analyze enum properties to determine if we can use ObjectCreateWithShape - let mut current_numeric_value = 0f64; let mut is_numeric_enum = true; let mut has_computed_members = false; @@ -3624,9 +3623,7 @@ impl<'a, 's, 'gc, 'scope> CompileEvaluation<'a, 's, 'gc, 'scope> for ast::TSEnum ast::Expression::StringLiteral(_) => { is_numeric_enum = false; } - ast::Expression::NumericLiteral(num_lit) => { - current_numeric_value = num_lit.value + 1.0; - } + ast::Expression::NumericLiteral(_) => {} _ => { // Computed expression is_numeric_enum = false; @@ -3634,8 +3631,6 @@ impl<'a, 's, 'gc, 'scope> CompileEvaluation<'a, 's, 'gc, 'scope> for ast::TSEnum break; } } - } else { - current_numeric_value += 1.0; } } @@ -3669,7 +3664,7 @@ impl<'a, 's, 'gc, 'scope> CompileEvaluation<'a, 's, 'gc, 'scope> for ast::TSEnum // Add reverse mapping keys for numeric enums if is_numeric_enum { - current_numeric_value = 0f64; + let mut current_numeric_value = 0f64; for member in self.body.members.iter() { let reverse_key_value = if let Some(ast::Expression::NumericLiteral(num_lit)) = &member.initializer { @@ -3709,7 +3704,7 @@ impl<'a, 's, 'gc, 'scope> CompileEvaluation<'a, 's, 'gc, 'scope> for ast::TSEnum )); // 4. Compile values in correct order (matching the shape) - current_numeric_value = 0f64; + let mut current_numeric_value = 0f64; // Compile forward mapping values for member in self.body.members.iter() { diff --git a/nova_vm/src/engine/rootable.rs b/nova_vm/src/engine/rootable.rs index e6b43e95e..3bf1bfa3b 100644 --- a/nova_vm/src/engine/rootable.rs +++ b/nova_vm/src/engine/rootable.rs @@ -622,6 +622,7 @@ pub enum HeapRootData { ArrayIterator(ArrayIterator<'static>) = ARRAY_ITERATOR_DISCRIMINANT, #[cfg(feature = "set")] SetIterator(SetIterator<'static>) = SET_ITERATOR_DISCRIMINANT, + #[cfg(feature = "set")] MapIterator(MapIterator<'static>) = MAP_ITERATOR_DISCRIMINANT, Generator(Generator<'static>) = GENERATOR_DISCRIMINANT, StringIterator(StringIterator<'static>) = STRING_ITERATOR_DISCRIMINANT, diff --git a/nova_vm/src/heap.rs b/nova_vm/src/heap.rs index 02bfa0a1a..102abb0f6 100644 --- a/nova_vm/src/heap.rs +++ b/nova_vm/src/heap.rs @@ -55,8 +55,7 @@ use crate::ecmascript::builtins::{ }; #[cfg(feature = "weak-refs")] use crate::ecmascript::builtins::{ - weak_map::data::WeakMapHeapData, weak_ref::data::WeakRefHeapData, - weak_set::data::WeakSetHeapData, + weak_map::data::WeakMapRecord, weak_ref::data::WeakRefHeapData, weak_set::data::WeakSetHeapData, }; use crate::{ ecmascript::{ @@ -124,8 +123,8 @@ use hashbrown::HashTable; #[cfg(feature = "weak-refs")] pub(crate) use heap_bits::sweep_side_set; pub(crate) use heap_bits::{ - CompactionLists, HeapMarkAndSweep, HeapSweepWeakReference, WeakReference, WorkQueues, - sweep_heap_vector_values, + AtomicBits, BitRange, CompactionLists, HeapMarkAndSweep, HeapSweepWeakReference, WeakReference, + WorkQueues, sweep_heap_vector_values, }; use soavec::SoAVec; use wtf8::{Wtf8, Wtf8Buf}; @@ -214,7 +213,7 @@ pub(crate) struct Heap { #[cfg(feature = "shared-array-buffer")] pub(crate) shared_data_view_byte_offsets: AHashMap, usize>, #[cfg(feature = "weak-refs")] - pub(crate) weak_maps: Vec>, + pub(crate) weak_maps: Vec>, #[cfg(feature = "weak-refs")] pub(crate) weak_refs: Vec>, #[cfg(feature = "weak-refs")] diff --git a/nova_vm/src/heap/element_array.rs b/nova_vm/src/heap/element_array.rs index 09f75818f..0104a6a53 100644 --- a/nova_vm/src/heap/element_array.rs +++ b/nova_vm/src/heap/element_array.rs @@ -392,22 +392,22 @@ impl HeapMarkAndSweep for ElementsVector<'static> { let Self { elements_index, cap, - len, + len: _, len_writable: _, } = self; match cap { ElementArrayKey::Empty | ElementArrayKey::EmptyIntrinsic => {} - ElementArrayKey::E1 => queues.e_2_1.push((*elements_index, *len)), - ElementArrayKey::E2 => queues.e_2_2.push((*elements_index, *len)), - ElementArrayKey::E3 => queues.e_2_3.push((*elements_index, *len)), - ElementArrayKey::E4 => queues.e_2_4.push((*elements_index, *len)), - ElementArrayKey::E6 => queues.e_2_6.push((*elements_index, *len)), - ElementArrayKey::E8 => queues.e_2_8.push((*elements_index, *len)), - ElementArrayKey::E10 => queues.e_2_10.push((*elements_index, *len)), - ElementArrayKey::E12 => queues.e_2_12.push((*elements_index, *len)), - ElementArrayKey::E16 => queues.e_2_16.push((*elements_index, *len)), - ElementArrayKey::E24 => queues.e_2_24.push((*elements_index, *len)), - ElementArrayKey::E32 => queues.e_2_32.push((*elements_index, *len)), + ElementArrayKey::E1 => queues.e_2_1.push(*elements_index), + ElementArrayKey::E2 => queues.e_2_2.push(*elements_index), + ElementArrayKey::E3 => queues.e_2_3.push(*elements_index), + ElementArrayKey::E4 => queues.e_2_4.push(*elements_index), + ElementArrayKey::E6 => queues.e_2_6.push(*elements_index), + ElementArrayKey::E8 => queues.e_2_8.push(*elements_index), + ElementArrayKey::E10 => queues.e_2_10.push(*elements_index), + ElementArrayKey::E12 => queues.e_2_12.push(*elements_index), + ElementArrayKey::E16 => queues.e_2_16.push(*elements_index), + ElementArrayKey::E24 => queues.e_2_24.push(*elements_index), + ElementArrayKey::E32 => queues.e_2_32.push(*elements_index), } } diff --git a/nova_vm/src/heap/heap_bits.rs b/nova_vm/src/heap/heap_bits.rs index 6b623cb1f..7bd339d5f 100644 --- a/nova_vm/src/heap/heap_bits.rs +++ b/nova_vm/src/heap/heap_bits.rs @@ -1,10 +1,19 @@ use core::{hash::Hash, num::NonZeroU32}; +#[cfg(feature = "weak-refs")] +use std::ops::Range; +use std::{ + cell::UnsafeCell, + hint::assert_unchecked, + mem::MaybeUninit, + sync::atomic::{AtomicU8, Ordering}, +}; use ahash::AHashMap; #[cfg(feature = "weak-refs")] use ahash::AHashSet; use hashbrown::HashTable; use soavec::{SoAVec, SoAble}; +use soavec_derive::SoAble; // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -65,7 +74,7 @@ use crate::ecmascript::{ }, execution::{ DeclarativeEnvironment, FunctionEnvironment, GlobalEnvironment, ModuleEnvironment, - ObjectEnvironment, PrivateEnvironment, Realm, + ObjectEnvironment, PrivateEnvironment, Realm, WeakKey, }, scripts_and_modules::{ module::module_semantics::{ModuleRequest, source_text_module_records::SourceTextModule}, @@ -73,398 +82,941 @@ use crate::ecmascript::{ source_code::SourceCode, }, types::{ - BUILTIN_STRINGS_LIST, HeapNumber, HeapString, OrdinaryObject, PropertyKey, Symbol, Value, + BUILTIN_STRINGS_LIST, HeapNumber, HeapString, OrdinaryObject, Symbol, Value, bigint::HeapBigInt, }, }; use crate::engine::Executable; +#[derive(Debug, Clone, Default)] +pub(crate) struct BitRange(Range); + +impl BitRange { + const fn from_bit_count_and_len(bit_count: &mut usize, len: usize) -> Self { + if len == 0 { + Self(Range { start: 0, end: 0 }) + } else { + let start = *bit_count; + *bit_count += len; + Self(Range { + start, + end: *bit_count, + }) + } + } + + #[inline] + pub(crate) const fn from_range(range: Range) -> Self { + Self(range) + } + + #[inline] + pub(crate) fn len(&self) -> usize { + self.0.len() + } + + #[inline] + pub(crate) fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Set a bit and return true if it was not already set. + pub(crate) fn get_bit(&self, index: usize, bits: &[AtomicBits]) -> bool { + let index = self.0.start + index; + let byte_index = index / 8; + let bit_index = (index % 8) as u8; + let bits = &bits[byte_index]; + bits.get_bit(BitOffset::new(bit_index)) + } + + /// Set a bit and return true if it was not already set. + pub(crate) fn set_bit(&self, index: usize, bits: &[AtomicBits]) -> bool { + let index = self.0.start + index; + let byte_index = index / 8; + let bit_index = (index % 8) as u8; + let bits = &bits[byte_index]; + bits.set_bit(BitOffset::new(bit_index)) + } + + pub(crate) fn mark_range(&self, range_to_mark: Range, bits: &mut [AtomicBits]) { + let start = self.0.start + range_to_mark.start as usize; + let end = self.0.start + range_to_mark.end as usize; + + let range = BitRange::from_range(start..end); + + range.for_each_byte_mut(bits, |mark_byte, bit_iterator| { + if let Some(bit_iterator) = bit_iterator { + *mark_byte = + bit_iterator.fold(*mark_byte, |acc, bitmask| acc | bitmask.as_bitmask()); + } else { + *mark_byte = 0xFF; + } + }); + } + + pub(crate) fn iter<'a>(&self, bits: &'a [AtomicBits]) -> BitRangeIterator<'a> { + let (byte_range, bit_range) = BitOffset::from_range(&self.0); + let bits = &bits[byte_range.start..byte_range.end]; + BitRangeIterator { bits, bit_range } + } + + #[inline] + pub(crate) fn for_each_byte( + &self, + marks: &[AtomicBits], + mut cb: impl FnMut(&AtomicBits, Option), + ) { + let (byte_range, bit_range) = BitOffset::from_range(&self.0); + let mut marks = &marks[byte_range.start..byte_range.end]; + debug_assert!(!marks.is_empty()); + if marks.len() == 1 && !bit_range.start.is_zero() && !bit_range.end.is_zero() { + cb(&marks[0], Some(BitIterator::from_range(bit_range))); + return; + } + if !bit_range.start.is_zero() { + let (first, m) = marks.split_first().unwrap(); + marks = m; + cb(first, Some(BitIterator::from_offset(bit_range.start))); + } + let mut end = None; + if !bit_range.end.is_zero() + && let Some((last, m)) = marks.split_last() + { + marks = m; + end = Some(last); + } + for mark_byte in marks { + cb(mark_byte, None); + } + if let Some(end) = end { + cb(end, Some(BitIterator::until_offset(bit_range.end))); + } + } + + #[inline] + pub(crate) fn for_each_byte_mut( + &self, + marks: &mut [AtomicBits], + mut cb: impl FnMut(&mut u8, Option), + ) { + let (byte_range, bit_range) = BitOffset::from_range(&self.0); + let mut marks = &mut marks[byte_range.start..byte_range.end]; + debug_assert!(!marks.is_empty()); + if marks.len() == 1 && !bit_range.start.is_zero() && !bit_range.end.is_zero() { + cb(marks[0].get_mut(), Some(BitIterator::from_range(bit_range))); + return; + } + if !bit_range.start.is_zero() { + let (first, m) = marks.split_first_mut().unwrap(); + marks = m; + cb( + first.get_mut(), + Some(BitIterator::from_offset(bit_range.start)), + ); + } + let mut end = None; + if !bit_range.end.is_zero() { + let (last, m) = marks.split_last_mut().unwrap(); + marks = m; + end = Some(last.get_mut()); + } + for mark_byte in marks.iter_mut() { + cb(mark_byte.get_mut(), None); + } + if let Some(end) = end { + cb(end, Some(BitIterator::until_offset(bit_range.end))); + } + } +} + +pub(crate) struct BitRangeIterator<'a> { + bits: &'a [AtomicBits], + bit_range: Range, +} + +impl<'a> Iterator for BitRangeIterator<'a> { + type Item = bool; + + fn size_hint(&self) -> (usize, Option) { + let mut hint = self.bits.len() * 8; + if !self.bit_range.start.is_zero() { + // Reduce before-start bits. + hint -= self.bit_range.start.0 as usize; + } + if !self.bit_range.end.is_zero() { + // Reduce after-end bits. + hint -= (8 - self.bit_range.end.0) as usize; + } + (hint, Some(hint)) + } + + fn next(&mut self) -> Option { + let byte = self.bits.first()?; + let value = byte.get_bit(self.bit_range.start.advance()); + if self.bits.len() == 1 && self.bit_range.start == self.bit_range.end { + // We've reached the end of our bit range. + self.bits = &[]; + } else if self.bit_range.start.is_zero() { + // We've passed the last bit of the current byte and need to + // advance further. + self.bits = self.bits.split_first().unwrap().1; + } + Some(value) + } +} + +impl ExactSizeIterator for BitRangeIterator<'_> {} + +impl core::fmt::Debug for BitRangeIterator<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let clone = Self { + bits: self.bits, + bit_range: self.bit_range.clone(), + }; + let result = clone.fold(String::with_capacity(self.bits.len()), |a, b| { + a + if b { "1" } else { "0" } + }); + f.debug_struct("BitRangeIterator") + .field("bits", &result) + .finish() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub(crate) struct BitOffset(u8); + +impl BitOffset { + const fn new(value: u8) -> Self { + unsafe { assert_unchecked(value < 8) }; + Self(value) + } + + const fn advance(&mut self) -> BitOffset { + let offset = *self; + self.0 = (self.0 + 1) % 8; + offset + } + + #[inline] + pub(crate) const fn is_zero(&self) -> bool { + self.0 == 0 + } + + /// Creates a byte with only this offset bit set. + pub(crate) const fn as_bitmask(&self) -> u8 { + 1u8 << self.0 + } + + pub(crate) const fn from_range(range: &Range) -> (Range, Range) { + let start_byte_offset = range.start / 8; + let start_bit_offset = range.start % 8; + // SAFETY: rem should always return < 8. + unsafe { assert_unchecked(start_bit_offset < 8) }; + let start_bit_offset = start_bit_offset as u8; + let end_byte_offset = range.end.div_ceil(8); + let end_bit_offset = range.end % 8; + // SAFETY: rem should always return < 8. + unsafe { assert_unchecked(end_bit_offset < 8) }; + let end_bit_offset = end_bit_offset as u8; + ( + Range { + start: start_byte_offset, + end: end_byte_offset, + }, + Range { + start: BitOffset(start_bit_offset), + end: BitOffset(end_bit_offset), + }, + ) + } +} + #[derive(Debug)] -pub struct HeapBits { +pub(crate) struct BitIterator { + start: BitOffset, + end: BitOffset, +} + +impl BitIterator { + fn from_range(range: Range) -> Self { + debug_assert!( + !range.start.is_zero() || !range.end.is_zero(), + "Full byte should not need a bitmask iterator" + ); + BitIterator { + start: range.start, + end: range.end, + } + } + + fn from_offset(start: BitOffset) -> Self { + debug_assert!( + !start.is_zero(), + "Full byte should not need a bitmask iterator" + ); + BitIterator { + start, + end: BitOffset(0), + } + } + + fn until_offset(end: BitOffset) -> Self { + debug_assert!( + !end.is_zero(), + "Full byte should not need a bitmask iterator" + ); + BitIterator { + start: BitOffset(0), + end, + } + } +} + +impl Iterator for BitIterator { + type Item = BitOffset; + + fn next(&mut self) -> Option { + if self.start == self.end { + // We've reached the end of our bit range. + None + } else { + let bitmask = self.start.advance(); + Some(bitmask) + } + } +} + +#[derive(Debug, Default)] +#[repr(transparent)] +pub(crate) struct AtomicBits(AtomicU8); + +impl AtomicBits { + #[inline] + fn get_mut(&mut self) -> &mut u8 { + self.0.get_mut() + } + + /// Get the nth bit atomically. Returns true if the bit is set. + #[inline] + fn get_bit(&self, offset: BitOffset) -> bool { + (self.0.load(Ordering::Relaxed) & offset.as_bitmask()) > 0 + } + + /// Set the nth bit atomically. Returns true if the bit was previously + /// unset. + #[inline] + fn set_bit(&self, offset: BitOffset) -> bool { + let bitmask = offset.as_bitmask(); + let old_value = self.0.fetch_or(bitmask, Ordering::Relaxed); + (old_value & bitmask) == 0 + } +} + +#[derive(Debug)] +pub(crate) struct HeapBits { + pub(super) bits: Box<[AtomicBits]>, + pub(super) e_2_1: BitRange, + pub(super) e_2_2: BitRange, + pub(super) e_2_3: BitRange, + pub(super) e_2_4: BitRange, + pub(super) e_2_6: BitRange, + pub(super) e_2_8: BitRange, + pub(super) e_2_10: BitRange, + pub(super) e_2_12: BitRange, + pub(super) e_2_16: BitRange, + pub(super) e_2_24: BitRange, + pub(super) e_2_32: BitRange, + pub(super) k_2_1: BitRange, + pub(super) k_2_2: BitRange, + pub(super) k_2_3: BitRange, + pub(super) k_2_4: BitRange, + pub(super) k_2_6: BitRange, + pub(super) k_2_8: BitRange, + pub(super) k_2_10: BitRange, + pub(super) k_2_12: BitRange, + pub(super) k_2_16: BitRange, + pub(super) k_2_24: BitRange, + pub(super) k_2_32: BitRange, #[cfg(feature = "array-buffer")] - pub array_buffers: Box<[bool]>, - pub arrays: Box<[bool]>, - pub array_iterators: Box<[bool]>, - pub async_generators: Box<[bool]>, - pub await_reactions: Box<[bool]>, - pub bigints: Box<[bool]>, - pub bound_functions: Box<[bool]>, - pub builtin_constructors: Box<[bool]>, - pub builtin_functions: Box<[bool]>, - pub caches: Box<[bool]>, + pub(super) array_buffers: BitRange, + pub(super) arrays: BitRange, + pub(super) array_iterators: BitRange, + pub(super) async_generators: BitRange, + pub(super) await_reactions: BitRange, + pub(super) bigints: BitRange, + pub(super) bound_functions: BitRange, + pub(super) builtin_constructors: BitRange, + pub(super) builtin_functions: BitRange, + pub(super) caches: BitRange, #[cfg(feature = "array-buffer")] - pub data_views: Box<[bool]>, + pub(super) data_views: BitRange, #[cfg(feature = "date")] - pub dates: Box<[bool]>, - pub declarative_environments: Box<[bool]>, - pub e_2_1: Box<[(bool, u8)]>, - pub e_2_2: Box<[(bool, u8)]>, - pub e_2_3: Box<[(bool, u8)]>, - pub e_2_4: Box<[(bool, u8)]>, - pub e_2_6: Box<[(bool, u8)]>, - pub e_2_8: Box<[(bool, u8)]>, - pub e_2_10: Box<[(bool, u16)]>, - pub e_2_12: Box<[(bool, u16)]>, - pub e_2_16: Box<[(bool, u16)]>, - pub e_2_24: Box<[(bool, u32)]>, - pub e_2_32: Box<[(bool, u32)]>, - pub k_2_1: Box<[(bool, u8)]>, - pub k_2_2: Box<[(bool, u8)]>, - pub k_2_3: Box<[(bool, u8)]>, - pub k_2_4: Box<[(bool, u8)]>, - pub k_2_6: Box<[(bool, u8)]>, - pub k_2_8: Box<[(bool, u8)]>, - pub k_2_10: Box<[(bool, u16)]>, - pub k_2_12: Box<[(bool, u16)]>, - pub k_2_16: Box<[(bool, u16)]>, - pub k_2_24: Box<[(bool, u32)]>, - pub k_2_32: Box<[(bool, u32)]>, - pub ecmascript_functions: Box<[bool]>, - pub embedder_objects: Box<[bool]>, - pub errors: Box<[bool]>, - pub executables: Box<[bool]>, - pub source_codes: Box<[bool]>, - pub finalization_registrys: Box<[bool]>, - pub function_environments: Box<[bool]>, - pub generators: Box<[bool]>, - pub global_environments: Box<[bool]>, - pub maps: Box<[bool]>, - pub map_iterators: Box<[bool]>, - pub module_environments: Box<[bool]>, - pub modules: Box<[bool]>, - pub module_request_records: Box<[bool]>, - pub numbers: Box<[bool]>, - pub object_environments: Box<[bool]>, - pub object_shapes: Box<[bool]>, - pub objects: Box<[bool]>, - pub primitive_objects: Box<[bool]>, - pub private_environments: Box<[bool]>, - pub promise_reaction_records: Box<[bool]>, - pub promise_resolving_functions: Box<[bool]>, - pub promise_finally_functions: Box<[bool]>, - pub promises: Box<[bool]>, - pub promise_group_records: Box<[bool]>, - pub proxies: Box<[bool]>, - pub realms: Box<[bool]>, + pub(super) dates: BitRange, + pub(super) declarative_environments: BitRange, + pub(super) ecmascript_functions: BitRange, + pub(super) embedder_objects: BitRange, + pub(super) errors: BitRange, + pub(super) executables: BitRange, + pub(super) source_codes: BitRange, + pub(super) finalization_registrys: BitRange, + pub(super) function_environments: BitRange, + pub(super) generators: BitRange, + pub(super) global_environments: BitRange, + pub(super) maps: BitRange, + pub(super) map_iterators: BitRange, + pub(super) module_environments: BitRange, + pub(super) modules: BitRange, + pub(super) module_request_records: BitRange, + pub(super) numbers: BitRange, + pub(super) object_environments: BitRange, + pub(super) object_shapes: BitRange, + pub(super) objects: BitRange, + pub(super) primitive_objects: BitRange, + pub(super) private_environments: BitRange, + pub(super) promise_reaction_records: BitRange, + pub(super) promise_resolving_functions: BitRange, + pub(super) promise_finally_functions: BitRange, + pub(super) promises: BitRange, + pub(super) promise_group_records: BitRange, + pub(super) proxies: BitRange, + pub(super) realms: BitRange, #[cfg(feature = "regexp")] - pub regexps: Box<[bool]>, + pub(super) regexps: BitRange, #[cfg(feature = "regexp")] - pub regexp_string_iterators: Box<[bool]>, - pub scripts: Box<[bool]>, + pub(super) regexp_string_iterators: BitRange, + pub(super) scripts: BitRange, #[cfg(feature = "set")] - pub sets: Box<[bool]>, + pub(super) sets: BitRange, #[cfg(feature = "set")] - pub set_iterators: Box<[bool]>, + pub(super) set_iterators: BitRange, #[cfg(feature = "shared-array-buffer")] - pub shared_array_buffers: Box<[bool]>, + pub(super) shared_array_buffers: BitRange, #[cfg(feature = "shared-array-buffer")] - pub shared_data_views: Box<[bool]>, + pub(super) shared_data_views: BitRange, #[cfg(feature = "shared-array-buffer")] - pub shared_typed_arrays: Box<[bool]>, - pub source_text_module_records: Box<[bool]>, - pub string_iterators: Box<[bool]>, - pub strings: Box<[bool]>, - pub symbols: Box<[bool]>, + pub(super) shared_typed_arrays: BitRange, + pub(super) source_text_module_records: BitRange, + pub(super) string_iterators: BitRange, + pub(super) strings: BitRange, + pub(super) symbols: BitRange, #[cfg(feature = "array-buffer")] - pub typed_arrays: Box<[bool]>, + pub(super) typed_arrays: BitRange, #[cfg(feature = "weak-refs")] - pub weak_maps: Box<[bool]>, + pub(super) weak_maps: BitRange, #[cfg(feature = "weak-refs")] - pub weak_refs: Box<[bool]>, + pub(super) weak_refs: BitRange, #[cfg(feature = "weak-refs")] - pub weak_sets: Box<[bool]>, + pub(super) weak_sets: BitRange, } #[derive(Debug)] -pub(crate) struct WorkQueues { +pub(crate) struct WorkQueues<'a> { + pub(crate) bits: &'a HeapBits, + pub(crate) pending_ephemerons: Vec<(WeakKey<'static>, Value<'static>)>, #[cfg(feature = "array-buffer")] - pub array_buffers: Vec>, - pub arrays: Vec>, - pub array_iterators: Vec>, - pub async_generators: Vec>, - pub await_reactions: Vec>, - pub bigints: Vec>, - pub bound_functions: Vec>, - pub builtin_constructors: Vec>, - pub builtin_functions: Vec>, - pub caches: Vec>, + pub(crate) array_buffers: Vec>, + pub(crate) arrays: Vec>, + pub(crate) array_iterators: Vec>, + pub(crate) async_generators: Vec>, + pub(crate) await_reactions: Vec>, + pub(crate) bigints: Vec>, + pub(crate) bound_functions: Vec>, + pub(crate) builtin_constructors: Vec>, + pub(crate) builtin_functions: Vec>, + pub(crate) caches: Vec>, #[cfg(feature = "array-buffer")] - pub data_views: Vec>, + pub(crate) data_views: Vec>, #[cfg(feature = "date")] - pub dates: Vec>, - pub declarative_environments: Vec>, - pub e_2_1: Vec<(ElementIndex<'static>, u32)>, - pub e_2_2: Vec<(ElementIndex<'static>, u32)>, - pub e_2_3: Vec<(ElementIndex<'static>, u32)>, - pub e_2_4: Vec<(ElementIndex<'static>, u32)>, - pub e_2_6: Vec<(ElementIndex<'static>, u32)>, - pub e_2_8: Vec<(ElementIndex<'static>, u32)>, - pub e_2_10: Vec<(ElementIndex<'static>, u32)>, - pub e_2_12: Vec<(ElementIndex<'static>, u32)>, - pub e_2_16: Vec<(ElementIndex<'static>, u32)>, - pub e_2_24: Vec<(ElementIndex<'static>, u32)>, - pub e_2_32: Vec<(ElementIndex<'static>, u32)>, - pub k_2_1: Vec<(PropertyKeyIndex<'static>, u32)>, - pub k_2_2: Vec<(PropertyKeyIndex<'static>, u32)>, - pub k_2_3: Vec<(PropertyKeyIndex<'static>, u32)>, - pub k_2_4: Vec<(PropertyKeyIndex<'static>, u32)>, - pub k_2_6: Vec<(PropertyKeyIndex<'static>, u32)>, - pub k_2_8: Vec<(PropertyKeyIndex<'static>, u32)>, - pub k_2_10: Vec<(PropertyKeyIndex<'static>, u32)>, - pub k_2_12: Vec<(PropertyKeyIndex<'static>, u32)>, - pub k_2_16: Vec<(PropertyKeyIndex<'static>, u32)>, - pub k_2_24: Vec<(PropertyKeyIndex<'static>, u32)>, - pub k_2_32: Vec<(PropertyKeyIndex<'static>, u32)>, - pub ecmascript_functions: Vec>, - pub embedder_objects: Vec>, - pub source_codes: Vec>, - pub errors: Vec>, - pub executables: Vec>, - pub finalization_registrys: Vec>, - pub function_environments: Vec>, - pub generators: Vec>, - pub global_environments: Vec>, - pub maps: Vec>, - pub map_iterators: Vec>, - pub module_environments: Vec>, - pub modules: Vec>, - pub module_request_records: Vec>, - pub numbers: Vec>, - pub object_environments: Vec>, - pub objects: Vec>, - pub object_shapes: Vec>, - pub primitive_objects: Vec>, - pub private_environments: Vec>, - pub promises: Vec>, - pub promise_reaction_records: Vec>, - pub promise_resolving_functions: Vec>, - pub promise_finally_functions: Vec>, - pub promise_group_records: Vec>, - pub proxies: Vec>, - pub realms: Vec>, + pub(crate) dates: Vec>, + pub(crate) declarative_environments: Vec>, + pub(crate) e_2_1: Vec>, + pub(crate) e_2_2: Vec>, + pub(crate) e_2_3: Vec>, + pub(crate) e_2_4: Vec>, + pub(crate) e_2_6: Vec>, + pub(crate) e_2_8: Vec>, + pub(crate) e_2_10: Vec>, + pub(crate) e_2_12: Vec>, + pub(crate) e_2_16: Vec>, + pub(crate) e_2_24: Vec>, + pub(crate) e_2_32: Vec>, + pub(crate) k_2_1: Vec>, + pub(crate) k_2_2: Vec>, + pub(crate) k_2_3: Vec>, + pub(crate) k_2_4: Vec>, + pub(crate) k_2_6: Vec>, + pub(crate) k_2_8: Vec>, + pub(crate) k_2_10: Vec>, + pub(crate) k_2_12: Vec>, + pub(crate) k_2_16: Vec>, + pub(crate) k_2_24: Vec>, + pub(crate) k_2_32: Vec>, + pub(crate) ecmascript_functions: Vec>, + pub(crate) embedder_objects: Vec>, + pub(crate) source_codes: Vec>, + pub(crate) errors: Vec>, + pub(crate) executables: Vec>, + pub(crate) finalization_registrys: Vec>, + pub(crate) function_environments: Vec>, + pub(crate) generators: Vec>, + pub(crate) global_environments: Vec>, + pub(crate) maps: Vec>, + pub(crate) map_iterators: Vec>, + pub(crate) module_environments: Vec>, + pub(crate) modules: Vec>, + pub(crate) module_request_records: Vec>, + pub(crate) numbers: Vec>, + pub(crate) object_environments: Vec>, + pub(crate) objects: Vec>, + pub(crate) object_shapes: Vec>, + pub(crate) primitive_objects: Vec>, + pub(crate) private_environments: Vec>, + pub(crate) promises: Vec>, + pub(crate) promise_reaction_records: Vec>, + pub(crate) promise_resolving_functions: Vec>, + pub(crate) promise_finally_functions: Vec>, + pub(crate) promise_group_records: Vec>, + pub(crate) proxies: Vec>, + pub(crate) realms: Vec>, #[cfg(feature = "regexp")] - pub regexps: Vec>, + pub(crate) regexps: Vec>, #[cfg(feature = "regexp")] - pub regexp_string_iterators: Vec>, - pub scripts: Vec>, + pub(crate) regexp_string_iterators: Vec>, + pub(crate) scripts: Vec>, #[cfg(feature = "set")] - pub sets: Vec>, + pub(crate) sets: Vec>, #[cfg(feature = "set")] - pub set_iterators: Vec>, + pub(crate) set_iterators: Vec>, #[cfg(feature = "shared-array-buffer")] - pub shared_array_buffers: Vec>, + pub(crate) shared_array_buffers: Vec>, #[cfg(feature = "shared-array-buffer")] - pub shared_data_views: Vec>, + pub(crate) shared_data_views: Vec>, #[cfg(feature = "shared-array-buffer")] - pub shared_typed_arrays: Vec>, - pub source_text_module_records: Vec>, - pub string_iterators: Vec>, - pub strings: Vec>, - pub symbols: Vec>, + pub(crate) shared_typed_arrays: Vec>, + pub(crate) source_text_module_records: Vec>, + pub(crate) string_iterators: Vec>, + pub(crate) strings: Vec>, + pub(crate) symbols: Vec>, #[cfg(feature = "array-buffer")] - pub typed_arrays: Vec>, + pub(crate) typed_arrays: Vec>, #[cfg(feature = "weak-refs")] - pub weak_maps: Vec>, + pub(crate) weak_maps: Vec>, #[cfg(feature = "weak-refs")] - pub weak_refs: Vec>, + pub(crate) weak_refs: Vec>, #[cfg(feature = "weak-refs")] - pub weak_sets: Vec>, + pub(crate) weak_sets: Vec>, } impl HeapBits { - pub fn new(heap: &Heap) -> Self { + pub(crate) fn new(heap: &Heap) -> Self { + let mut bit_count = 0; + + let e_2_1 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.e2pow1.values.len()); + let e_2_2 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.e2pow2.values.len()); + let e_2_3 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.e2pow3.values.len()); + let e_2_4 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.e2pow4.values.len()); + let e_2_6 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.e2pow6.values.len()); + let e_2_8 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.e2pow8.values.len()); + let k_2_1 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.k2pow1.keys.len()); + let k_2_2 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.k2pow2.keys.len()); + let k_2_3 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.k2pow3.keys.len()); + let k_2_4 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.k2pow4.keys.len()); + let k_2_6 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.k2pow6.keys.len()); + let k_2_8 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.k2pow8.keys.len()); + let e_2_10 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.e2pow10.values.len()); + let e_2_12 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.e2pow12.values.len()); + let e_2_16 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.e2pow16.values.len()); + let k_2_10 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.k2pow10.keys.len()); + let k_2_12 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.k2pow12.keys.len()); + let k_2_16 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.k2pow16.keys.len()); + let e_2_24 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.e2pow24.values.len()); + let e_2_32 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.e2pow32.values.len()); + let k_2_24 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.k2pow24.keys.len()); + let k_2_32 = + BitRange::from_bit_count_and_len(&mut bit_count, heap.elements.k2pow32.keys.len()); #[cfg(feature = "array-buffer")] - let array_buffers = vec![false; heap.array_buffers.len()]; - let arrays = vec![false; heap.arrays.len() as usize]; - let array_iterators = vec![false; heap.array_iterators.len()]; - let async_generators = vec![false; heap.async_generators.len()]; - let await_reactions = vec![false; heap.await_reactions.len()]; - let bigints = vec![false; heap.bigints.len()]; - let bound_functions = vec![false; heap.bound_functions.len()]; - let builtin_constructors = vec![false; heap.builtin_constructors.len()]; - let builtin_functions = vec![false; heap.builtin_functions.len()]; - let caches = vec![false; heap.caches.len()]; + let array_buffers = + BitRange::from_bit_count_and_len(&mut bit_count, heap.array_buffers.len()); + let arrays = BitRange::from_bit_count_and_len(&mut bit_count, heap.arrays.len() as usize); + let array_iterators = + BitRange::from_bit_count_and_len(&mut bit_count, heap.array_iterators.len()); + let async_generators = + BitRange::from_bit_count_and_len(&mut bit_count, heap.async_generators.len()); + let await_reactions = + BitRange::from_bit_count_and_len(&mut bit_count, heap.await_reactions.len()); + let bigints = BitRange::from_bit_count_and_len(&mut bit_count, heap.bigints.len()); + let bound_functions = + BitRange::from_bit_count_and_len(&mut bit_count, heap.bound_functions.len()); + let builtin_constructors = + BitRange::from_bit_count_and_len(&mut bit_count, heap.builtin_constructors.len()); + let builtin_functions = + BitRange::from_bit_count_and_len(&mut bit_count, heap.builtin_functions.len()); + let caches = BitRange::from_bit_count_and_len(&mut bit_count, heap.caches.len()); #[cfg(feature = "array-buffer")] - let data_views = vec![false; heap.data_views.len()]; + let data_views = BitRange::from_bit_count_and_len(&mut bit_count, heap.data_views.len()); #[cfg(feature = "date")] - let dates = vec![false; heap.dates.len()]; - let declarative_environments = vec![false; heap.environments.declarative.len()]; - let e_2_1 = vec![(false, 0u8); heap.elements.e2pow1.values.len()]; - let e_2_2 = vec![(false, 0u8); heap.elements.e2pow2.values.len()]; - let e_2_3 = vec![(false, 0u8); heap.elements.e2pow3.values.len()]; - let e_2_4 = vec![(false, 0u8); heap.elements.e2pow4.values.len()]; - let e_2_6 = vec![(false, 0u8); heap.elements.e2pow6.values.len()]; - let e_2_8 = vec![(false, 0u8); heap.elements.e2pow8.values.len()]; - let e_2_10 = vec![(false, 0u16); heap.elements.e2pow10.values.len()]; - let e_2_12 = vec![(false, 0u16); heap.elements.e2pow12.values.len()]; - let e_2_16 = vec![(false, 0u16); heap.elements.e2pow16.values.len()]; - let e_2_24 = vec![(false, 0u32); heap.elements.e2pow24.values.len()]; - let e_2_32 = vec![(false, 0u32); heap.elements.e2pow32.values.len()]; - let k_2_1 = vec![(false, 0u8); heap.elements.k2pow1.keys.len()]; - let k_2_2 = vec![(false, 0u8); heap.elements.k2pow2.keys.len()]; - let k_2_3 = vec![(false, 0u8); heap.elements.k2pow3.keys.len()]; - let k_2_4 = vec![(false, 0u8); heap.elements.k2pow4.keys.len()]; - let k_2_6 = vec![(false, 0u8); heap.elements.k2pow6.keys.len()]; - let k_2_8 = vec![(false, 0u8); heap.elements.k2pow8.keys.len()]; - let k_2_10 = vec![(false, 0u16); heap.elements.k2pow10.keys.len()]; - let k_2_12 = vec![(false, 0u16); heap.elements.k2pow12.keys.len()]; - let k_2_16 = vec![(false, 0u16); heap.elements.k2pow16.keys.len()]; - let k_2_24 = vec![(false, 0u32); heap.elements.k2pow24.keys.len()]; - let k_2_32 = vec![(false, 0u32); heap.elements.k2pow32.keys.len()]; - let ecmascript_functions = vec![false; heap.ecmascript_functions.len()]; - let embedder_objects = vec![false; heap.embedder_objects.len()]; - let errors = vec![false; heap.errors.len()]; - let executables = vec![false; heap.executables.len()]; - let source_codes = vec![false; heap.source_codes.len()]; - let finalization_registrys = vec![false; heap.finalization_registrys.len() as usize]; - let function_environments = vec![false; heap.environments.function.len()]; - let generators = vec![false; heap.generators.len()]; - let global_environments = vec![false; heap.environments.global.len()]; - let maps = vec![false; heap.maps.len()]; - let map_iterators = vec![false; heap.map_iterators.len()]; - let module_environments = vec![false; heap.environments.module.len()]; - let modules = vec![false; heap.modules.len()]; - let module_request_records = vec![false; heap.module_request_records.len()]; - let numbers = vec![false; heap.numbers.len()]; - let object_environments = vec![false; heap.environments.object.len()]; - let object_shapes = vec![false; heap.object_shapes.len()]; - let objects = vec![false; heap.objects.len()]; - let primitive_objects = vec![false; heap.primitive_objects.len()]; - let promise_reaction_records = vec![false; heap.promise_reaction_records.len()]; - let promise_resolving_functions = vec![false; heap.promise_resolving_functions.len()]; - let promise_finally_functions = vec![false; heap.promise_finally_functions.len()]; - let private_environments = vec![false; heap.environments.private.len()]; - let promises = vec![false; heap.promises.len()]; - let promise_group_records = vec![false; heap.promise_group_records.len()]; - let proxies = vec![false; heap.proxies.len()]; - let realms = vec![false; heap.realms.len()]; + let dates = BitRange::from_bit_count_and_len(&mut bit_count, heap.dates.len()); + let declarative_environments = + BitRange::from_bit_count_and_len(&mut bit_count, heap.environments.declarative.len()); + let ecmascript_functions = + BitRange::from_bit_count_and_len(&mut bit_count, heap.ecmascript_functions.len()); + let embedder_objects = + BitRange::from_bit_count_and_len(&mut bit_count, heap.embedder_objects.len()); + let errors = BitRange::from_bit_count_and_len(&mut bit_count, heap.errors.len()); + let executables = BitRange::from_bit_count_and_len(&mut bit_count, heap.executables.len()); + let source_codes = + BitRange::from_bit_count_and_len(&mut bit_count, heap.source_codes.len()); + let finalization_registrys = BitRange::from_bit_count_and_len( + &mut bit_count, + heap.finalization_registrys.len() as usize, + ); + let function_environments = + BitRange::from_bit_count_and_len(&mut bit_count, heap.environments.function.len()); + let generators = BitRange::from_bit_count_and_len(&mut bit_count, heap.generators.len()); + let global_environments = + BitRange::from_bit_count_and_len(&mut bit_count, heap.environments.global.len()); + let maps = BitRange::from_bit_count_and_len(&mut bit_count, heap.maps.len()); + let map_iterators = + BitRange::from_bit_count_and_len(&mut bit_count, heap.map_iterators.len()); + let module_environments = + BitRange::from_bit_count_and_len(&mut bit_count, heap.environments.module.len()); + let modules = BitRange::from_bit_count_and_len(&mut bit_count, heap.modules.len()); + let module_request_records = + BitRange::from_bit_count_and_len(&mut bit_count, heap.module_request_records.len()); + let numbers = BitRange::from_bit_count_and_len(&mut bit_count, heap.numbers.len()); + let object_environments = + BitRange::from_bit_count_and_len(&mut bit_count, heap.environments.object.len()); + let object_shapes = + BitRange::from_bit_count_and_len(&mut bit_count, heap.object_shapes.len()); + let objects = BitRange::from_bit_count_and_len(&mut bit_count, heap.objects.len()); + let primitive_objects = + BitRange::from_bit_count_and_len(&mut bit_count, heap.primitive_objects.len()); + let promise_reaction_records = + BitRange::from_bit_count_and_len(&mut bit_count, heap.promise_reaction_records.len()); + let promise_resolving_functions = BitRange::from_bit_count_and_len( + &mut bit_count, + heap.promise_resolving_functions.len(), + ); + let promise_finally_functions = + BitRange::from_bit_count_and_len(&mut bit_count, heap.promise_finally_functions.len()); + let private_environments = + BitRange::from_bit_count_and_len(&mut bit_count, heap.environments.private.len()); + let promises = BitRange::from_bit_count_and_len(&mut bit_count, heap.promises.len()); + let promise_group_records = + BitRange::from_bit_count_and_len(&mut bit_count, heap.promise_group_records.len()); + let proxies = BitRange::from_bit_count_and_len(&mut bit_count, heap.proxies.len()); + let realms = BitRange::from_bit_count_and_len(&mut bit_count, heap.realms.len()); #[cfg(feature = "regexp")] - let regexps = vec![false; heap.regexps.len()]; + let regexps = BitRange::from_bit_count_and_len(&mut bit_count, heap.regexps.len()); #[cfg(feature = "regexp")] - let regexp_string_iterators = vec![false; heap.regexp_string_iterators.len()]; - let scripts = vec![false; heap.scripts.len()]; + let regexp_string_iterators = + BitRange::from_bit_count_and_len(&mut bit_count, heap.regexp_string_iterators.len()); + let scripts = BitRange::from_bit_count_and_len(&mut bit_count, heap.scripts.len()); #[cfg(feature = "set")] - let sets = vec![false; heap.sets.len()]; + let sets = BitRange::from_bit_count_and_len(&mut bit_count, heap.sets.len()); #[cfg(feature = "set")] - let set_iterators = vec![false; heap.set_iterators.len()]; + let set_iterators = + BitRange::from_bit_count_and_len(&mut bit_count, heap.set_iterators.len()); #[cfg(feature = "shared-array-buffer")] - let shared_array_buffers = vec![false; heap.shared_array_buffers.len()]; + let shared_array_buffers = + BitRange::from_bit_count_and_len(&mut bit_count, heap.shared_array_buffers.len()); #[cfg(feature = "shared-array-buffer")] - let shared_data_views = vec![false; heap.shared_data_views.len()]; + let shared_data_views = + BitRange::from_bit_count_and_len(&mut bit_count, heap.shared_data_views.len()); #[cfg(feature = "shared-array-buffer")] - let shared_typed_arrays = vec![false; heap.shared_typed_arrays.len()]; - let source_text_module_records = vec![false; heap.source_text_module_records.len()]; - let string_iterators = vec![false; heap.string_iterators.len()]; - let strings = vec![false; heap.strings.len()]; - let symbols = vec![false; heap.symbols.len()]; + let shared_typed_arrays = + BitRange::from_bit_count_and_len(&mut bit_count, heap.shared_typed_arrays.len()); + let source_text_module_records = + BitRange::from_bit_count_and_len(&mut bit_count, heap.source_text_module_records.len()); + let string_iterators = + BitRange::from_bit_count_and_len(&mut bit_count, heap.string_iterators.len()); + let strings = BitRange::from_bit_count_and_len(&mut bit_count, heap.strings.len()); + let symbols = BitRange::from_bit_count_and_len(&mut bit_count, heap.symbols.len()); #[cfg(feature = "array-buffer")] - let typed_arrays = vec![false; heap.typed_arrays.len()]; + let typed_arrays = + BitRange::from_bit_count_and_len(&mut bit_count, heap.typed_arrays.len()); #[cfg(feature = "weak-refs")] - let weak_maps = vec![false; heap.weak_maps.len()]; + let weak_maps = BitRange::from_bit_count_and_len(&mut bit_count, heap.weak_maps.len()); #[cfg(feature = "weak-refs")] - let weak_refs = vec![false; heap.weak_refs.len()]; + let weak_refs = BitRange::from_bit_count_and_len(&mut bit_count, heap.weak_refs.len()); #[cfg(feature = "weak-refs")] - let weak_sets = vec![false; heap.weak_sets.len()]; + let weak_sets = BitRange::from_bit_count_and_len(&mut bit_count, heap.weak_sets.len()); + let byte_count = bit_count.div_ceil(8); + let mut bits = Box::<[AtomicBits]>::new_uninit_slice(byte_count); + bits.fill_with(|| MaybeUninit::new(Default::default())); + // SAFETY: filled in. + let bits = unsafe { bits.assume_init() }; Self { + bits, #[cfg(feature = "array-buffer")] - array_buffers: array_buffers.into_boxed_slice(), - arrays: arrays.into_boxed_slice(), - array_iterators: array_iterators.into_boxed_slice(), - async_generators: async_generators.into_boxed_slice(), - await_reactions: await_reactions.into_boxed_slice(), - bigints: bigints.into_boxed_slice(), - bound_functions: bound_functions.into_boxed_slice(), - builtin_constructors: builtin_constructors.into_boxed_slice(), - builtin_functions: builtin_functions.into_boxed_slice(), - caches: caches.into_boxed_slice(), + array_buffers, + arrays, + array_iterators, + async_generators, + await_reactions, + bigints, + bound_functions, + builtin_constructors, + builtin_functions, + caches, #[cfg(feature = "array-buffer")] - data_views: data_views.into_boxed_slice(), + data_views, #[cfg(feature = "date")] - dates: dates.into_boxed_slice(), - declarative_environments: declarative_environments.into_boxed_slice(), - e_2_1: e_2_1.into_boxed_slice(), - e_2_2: e_2_2.into_boxed_slice(), - e_2_3: e_2_3.into_boxed_slice(), - e_2_4: e_2_4.into_boxed_slice(), - e_2_6: e_2_6.into_boxed_slice(), - e_2_8: e_2_8.into_boxed_slice(), - e_2_10: e_2_10.into_boxed_slice(), - e_2_12: e_2_12.into_boxed_slice(), - e_2_16: e_2_16.into_boxed_slice(), - e_2_24: e_2_24.into_boxed_slice(), - e_2_32: e_2_32.into_boxed_slice(), - k_2_1: k_2_1.into_boxed_slice(), - k_2_2: k_2_2.into_boxed_slice(), - k_2_3: k_2_3.into_boxed_slice(), - k_2_4: k_2_4.into_boxed_slice(), - k_2_6: k_2_6.into_boxed_slice(), - k_2_8: k_2_8.into_boxed_slice(), - k_2_10: k_2_10.into_boxed_slice(), - k_2_12: k_2_12.into_boxed_slice(), - k_2_16: k_2_16.into_boxed_slice(), - k_2_24: k_2_24.into_boxed_slice(), - k_2_32: k_2_32.into_boxed_slice(), - ecmascript_functions: ecmascript_functions.into_boxed_slice(), - embedder_objects: embedder_objects.into_boxed_slice(), - errors: errors.into_boxed_slice(), - executables: executables.into_boxed_slice(), - source_codes: source_codes.into_boxed_slice(), - finalization_registrys: finalization_registrys.into_boxed_slice(), - function_environments: function_environments.into_boxed_slice(), - generators: generators.into_boxed_slice(), - global_environments: global_environments.into_boxed_slice(), - maps: maps.into_boxed_slice(), - map_iterators: map_iterators.into_boxed_slice(), - module_environments: module_environments.into_boxed_slice(), - modules: modules.into_boxed_slice(), - module_request_records: module_request_records.into_boxed_slice(), - numbers: numbers.into_boxed_slice(), - object_environments: object_environments.into_boxed_slice(), - object_shapes: object_shapes.into_boxed_slice(), - objects: objects.into_boxed_slice(), - primitive_objects: primitive_objects.into_boxed_slice(), - promise_reaction_records: promise_reaction_records.into_boxed_slice(), - promise_resolving_functions: promise_resolving_functions.into_boxed_slice(), - promise_finally_functions: promise_finally_functions.into_boxed_slice(), - private_environments: private_environments.into_boxed_slice(), - promises: promises.into_boxed_slice(), - promise_group_records: promise_group_records.into_boxed_slice(), - proxies: proxies.into_boxed_slice(), - realms: realms.into_boxed_slice(), + dates, + declarative_environments, + e_2_1, + e_2_2, + e_2_3, + e_2_4, + e_2_6, + e_2_8, + e_2_10, + e_2_12, + e_2_16, + e_2_24, + e_2_32, + k_2_1, + k_2_2, + k_2_3, + k_2_4, + k_2_6, + k_2_8, + k_2_10, + k_2_12, + k_2_16, + k_2_24, + k_2_32, + ecmascript_functions, + embedder_objects, + errors, + executables, + source_codes, + finalization_registrys, + function_environments, + generators, + global_environments, + maps, + map_iterators, + module_environments, + modules, + module_request_records, + numbers, + object_environments, + object_shapes, + objects, + primitive_objects, + promise_reaction_records, + promise_resolving_functions, + promise_finally_functions, + private_environments, + promises, + promise_group_records, + proxies, + realms, #[cfg(feature = "regexp")] - regexps: regexps.into_boxed_slice(), + regexps, #[cfg(feature = "regexp")] - regexp_string_iterators: regexp_string_iterators.into_boxed_slice(), - scripts: scripts.into_boxed_slice(), + regexp_string_iterators, + scripts, #[cfg(feature = "set")] - sets: sets.into_boxed_slice(), + sets, #[cfg(feature = "set")] - set_iterators: set_iterators.into_boxed_slice(), + set_iterators, #[cfg(feature = "shared-array-buffer")] - shared_array_buffers: shared_array_buffers.into_boxed_slice(), + shared_array_buffers, #[cfg(feature = "shared-array-buffer")] - shared_data_views: shared_data_views.into_boxed_slice(), + shared_data_views, #[cfg(feature = "shared-array-buffer")] - shared_typed_arrays: shared_typed_arrays.into_boxed_slice(), - source_text_module_records: source_text_module_records.into_boxed_slice(), - string_iterators: string_iterators.into_boxed_slice(), - strings: strings.into_boxed_slice(), - symbols: symbols.into_boxed_slice(), + shared_typed_arrays, + source_text_module_records, + string_iterators, + strings, + symbols, #[cfg(feature = "array-buffer")] - typed_arrays: typed_arrays.into_boxed_slice(), + typed_arrays, #[cfg(feature = "weak-refs")] - weak_maps: weak_maps.into_boxed_slice(), + weak_maps, #[cfg(feature = "weak-refs")] - weak_refs: weak_refs.into_boxed_slice(), + weak_refs, #[cfg(feature = "weak-refs")] - weak_sets: weak_sets.into_boxed_slice(), + weak_sets, + } + } + + pub(crate) fn is_marked(&self, key: &WeakKey) -> bool { + match key { + WeakKey::Symbol(d) => self.symbols.get_bit(d.get_index(), &self.bits), + WeakKey::Object(d) => self.objects.get_bit(d.get_index(), &self.bits), + WeakKey::BoundFunction(d) => self.bound_functions.get_bit(d.get_index(), &self.bits), + WeakKey::BuiltinFunction(d) => { + self.builtin_functions.get_bit(d.get_index(), &self.bits) + } + WeakKey::ECMAScriptFunction(d) => { + self.ecmascript_functions.get_bit(d.get_index(), &self.bits) + } + WeakKey::BuiltinConstructorFunction(d) => { + self.builtin_constructors.get_bit(d.get_index(), &self.bits) + } + WeakKey::BuiltinPromiseResolvingFunction(d) => self + .promise_resolving_functions + .get_bit(d.get_index(), &self.bits), + WeakKey::BuiltinPromiseFinallyFunction(d) => self + .promise_finally_functions + .get_bit(d.get_index(), &self.bits), + WeakKey::BuiltinPromiseCollectorFunction | WeakKey::BuiltinProxyRevokerFunction => { + unreachable!() + } + WeakKey::PrimitiveObject(d) => { + self.primitive_objects.get_bit(d.get_index(), &self.bits) + } + WeakKey::Arguments(d) => self.objects.get_bit(d.get_index(), &self.bits), + WeakKey::Array(d) => self.arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "date")] + WeakKey::Date(d) => self.dates.get_bit(d.get_index(), &self.bits), + WeakKey::Error(d) => self.errors.get_bit(d.get_index(), &self.bits), + WeakKey::FinalizationRegistry(d) => self + .finalization_registrys + .get_bit(d.get_index(), &self.bits), + WeakKey::Map(d) => self.maps.get_bit(d.get_index(), &self.bits), + WeakKey::Promise(d) => self.promises.get_bit(d.get_index(), &self.bits), + WeakKey::Proxy(d) => self.proxies.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "regexp")] + WeakKey::RegExp(d) => self.regexps.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "set")] + WeakKey::Set(d) => self.sets.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "weak-refs")] + WeakKey::WeakMap(d) => self.weak_maps.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "weak-refs")] + WeakKey::WeakRef(d) => self.weak_refs.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "weak-refs")] + WeakKey::WeakSet(d) => self.weak_sets.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::ArrayBuffer(d) => self.array_buffers.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::DataView(d) => self.data_views.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::Int8Array(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::Uint8Array(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::Uint8ClampedArray(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::Int16Array(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::Uint16Array(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::Int32Array(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::Uint32Array(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::BigInt64Array(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::BigUint64Array(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "proposal-float16array")] + WeakKey::Float16Array(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::Float32Array(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "array-buffer")] + WeakKey::Float64Array(d) => self.typed_arrays.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedArrayBuffer(d) => { + self.shared_array_buffers.get_bit(d.get_index(), &self.bits) + } + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedDataView(d) => self.shared_data_views.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedInt8Array(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedUint8Array(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedUint8ClampedArray(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedInt16Array(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedUint16Array(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedInt32Array(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedUint32Array(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedBigInt64Array(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedBigUint64Array(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + #[cfg(all(feature = "proposal-float16array", feature = "shared-array-buffer"))] + WeakKey::SharedFloat16Array(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedFloat32Array(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + #[cfg(feature = "shared-array-buffer")] + WeakKey::SharedFloat64Array(d) => { + self.shared_typed_arrays.get_bit(d.get_index(), &self.bits) + } + WeakKey::AsyncGenerator(d) => self.async_generators.get_bit(d.get_index(), &self.bits), + WeakKey::ArrayIterator(d) => self.array_iterators.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "set")] + WeakKey::SetIterator(d) => self.set_iterators.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "set")] + WeakKey::MapIterator(d) => self.map_iterators.get_bit(d.get_index(), &self.bits), + WeakKey::StringIterator(d) => self.string_iterators.get_bit(d.get_index(), &self.bits), + #[cfg(feature = "regexp")] + WeakKey::RegExpStringIterator(d) => self + .regexp_string_iterators + .get_bit(d.get_index(), &self.bits), + WeakKey::Generator(d) => self.generators.get_bit(d.get_index(), &self.bits), + WeakKey::Module(d) => self.modules.get_bit(d.get_index(), &self.bits), + WeakKey::EmbedderObject(d) => self.embedder_objects.get_bit(d.get_index(), &self.bits), } } } -impl WorkQueues { - pub fn new(heap: &Heap) -> Self { +impl<'a> WorkQueues<'a> { + pub(crate) fn new(heap: &Heap, bits: &'a HeapBits) -> Self { Self { + bits, + pending_ephemerons: vec![], #[cfg(feature = "array-buffer")] array_buffers: Vec::with_capacity(heap.array_buffers.len() / 4), arrays: Vec::with_capacity(heap.arrays.len() as usize / 4), @@ -566,8 +1118,11 @@ impl WorkQueues { } } - pub fn is_empty(&self) -> bool { + pub(crate) fn is_empty(&self) -> bool { let Self { + bits: _, + // Note: we can have pending ephemerons that will never resolve. + pending_ephemerons: _, #[cfg(feature = "array-buffer")] array_buffers, arrays, @@ -771,33 +1326,52 @@ impl WorkQueues { } } -#[derive(Debug)] +#[repr(transparent)] pub(crate) struct CompactionList { - indexes: Box<[u32]>, - shifts: Box<[u32]>, + shifts: SoAVec, +} + +impl core::fmt::Debug for CompactionList { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let slices = self.shifts.as_slice(); + + f.debug_list() + .entries( + slices + .index + .iter() + .as_slice() + .iter() + .zip(slices.shift.iter()), + ) + .finish() + } } impl CompactionList { /// Perform a shift on a strongly held reference index. Returns a shifted /// index. fn shift_strong_u32_index(&self, index: u32) -> u32 { - assert!(self.indexes.len() == self.shifts.len()); - if self.indexes.is_empty() { + if self.shifts.is_empty() { // If there are no shifts, then all items stay where they are. return index; } - match self.indexes.binary_search(&index) { + let ShiftDataSlice { + index: indexes, + shift: shifts, + } = self.shifts.as_slice(); + match indexes.binary_search(&index) { Ok(exact_index) => { // An exact match means we have the exact correct index to get // our shift from. - index - self.shifts[exact_index] + index - shifts[exact_index] } Err(upper_bound_index) => { // Otherwise we find an upper-bound index; it can be zero. let own_location = upper_bound_index.checked_sub(1); // If the upper-bound index is zero, then our shift amount is // zero as well. - index - own_location.map(|i| self.shifts[i]).unwrap_or(0) + index - own_location.map(|i| shifts[i]).unwrap_or(0) } } } @@ -805,34 +1379,37 @@ impl CompactionList { /// Shift a weakly held bare u32 reference index. Returns a new index if /// the reference target is live, otherwise returns None. pub(crate) fn shift_weak_u32_index(&self, index: u32) -> Option { - assert!(self.indexes.len() == self.shifts.len()); // If there are no shift indexes, then all values are live. - if self.indexes.is_empty() { + if self.shifts.is_empty() { return Some(index); } + let ShiftDataSlice { + index: indexes, + shift: shifts, + } = self.shifts.as_slice(); // Find the place in the indexes list where our index is or should be // placed to maintain order. - let found_index = self.indexes.binary_search(&index); + let found_index = indexes.binary_search(&index); let insertion_index = match found_index { Ok(exact_index) => { // If we found an exact index then it means that our index is // necessarily live and we just need to shift it down by the // appropriate amount. - let shift_amount = self.shifts[exact_index]; + let shift_amount = shifts[exact_index]; return Some(index - shift_amount); } Err(i) => i, }; // It's possible that our index is at the "top shift" position. // In that case our index is necessarily alive. - if insertion_index == self.indexes.len() { - let own_shift_amount = *self.shifts.last().unwrap(); + if insertion_index == indexes.len() { + let own_shift_amount = *shifts.last().unwrap(); return Some(index - own_shift_amount); } // This is the lowest index that could overwrite our index... - let upper_bound = self.indexes[insertion_index]; + let upper_bound = indexes[insertion_index]; // ... and this is how much it shifts down. - let upper_bound_shift_amount = self.shifts[insertion_index]; + let upper_bound_shift_amount = shifts[insertion_index]; // After the shift, it ends up at this index. let post_shift_upper_bound = upper_bound - upper_bound_shift_amount; // Our own shift amount is found in the next slot below the insertion @@ -840,7 +1417,7 @@ impl CompactionList { let own_location = insertion_index.checked_sub(1); // If insertion index is zero then our index does not shift but can // still be overwritten. - let own_shift_amount = own_location.map(|i| self.shifts[i]).unwrap_or(0); + let own_shift_amount = own_location.map(|i| shifts[i]).unwrap_or(0); let post_shift_index = index - own_shift_amount; // If the post-shift upper bound shifts to be less or equal than our @@ -906,83 +1483,65 @@ impl CompactionList { Some(unsafe { NonZeroU32::new_unchecked(base_index) }) } - fn build(indexes: Vec, shifts: Vec) -> Self { - assert_eq!(indexes.len(), shifts.len()); - Self { - indexes: indexes.into_boxed_slice(), - shifts: shifts.into_boxed_slice(), - } - } - - pub(crate) fn from_mark_bits(marks: &[bool]) -> Self { - let mut builder = CompactionListBuilder::with_bits_length(marks.len()); - marks.iter().for_each(|bit| { - if *bit { - builder.mark_used(); - } else { - builder.mark_unused(); - } - }); - builder.done() - } - - pub(crate) fn from_mark_u8s(marks: &[(bool, u8)]) -> Self { - let mut builder = CompactionListBuilder::with_bits_length(marks.len()); - marks.iter().for_each(|mark| { - if mark.0 { - builder.mark_used(); - } else { - builder.mark_unused(); - } - }); - builder.done() + fn build(shifts: SoAVec) -> Self { + Self { shifts } } - pub(crate) fn from_mark_u16s(marks: &[(bool, u16)]) -> Self { - let mut builder = CompactionListBuilder::with_bits_length(marks.len()); - marks.iter().for_each(|mark| { - if mark.0 { - builder.mark_used(); + pub(crate) fn from_mark_bits(range: &BitRange, marks: &[AtomicBits]) -> Self { + let builder = CompactionListBuilder::with_bits_length(range.len() as u32); + if range.is_empty() { + return builder.done(); + } + let builder = UnsafeCell::new(builder); + range.for_each_byte(marks, |mark_byte, bit_iterator| { + // SAFETY: synchronous calls. + let builder = unsafe { builder.get().as_mut().unwrap() }; + if let Some(bit_iterator) = bit_iterator { + for bit_offset in bit_iterator { + if mark_byte.get_bit(bit_offset) { + builder.mark_used(); + } else { + builder.mark_unused(); + } + } } else { - builder.mark_unused(); + for bit_offset in 0..8 { + if mark_byte.get_bit(BitOffset::new(bit_offset)) { + builder.mark_used(); + } else { + builder.mark_unused(); + } + } } }); - builder.done() + builder.into_inner().done() } +} - pub(crate) fn from_mark_u32s(marks: &[(bool, u32)]) -> Self { - let mut builder = CompactionListBuilder::with_bits_length(marks.len()); - marks.iter().for_each(|mark| { - if mark.0 { - builder.mark_used(); - } else { - builder.mark_unused(); - } - }); - builder.done() - } +#[derive(Debug, Clone, Copy, SoAble)] +pub(crate) struct ShiftData { + /// Starting from this index... + pub(crate) index: u32, + /// ...shift reference values down by this much. + pub(crate) shift: u32, } -#[derive(Debug)] pub(crate) struct CompactionListBuilder { - // TODO: Use a combined Box<[MaybeUninit]> and separate `len: u32`. - indexes: Vec, - shifts: Vec, + shifts: SoAVec, current_index: u32, current_shift: u32, current_used: bool, } impl CompactionListBuilder { - fn with_bits_length(bits_length: usize) -> Self { + fn with_bits_length(bits_length: u32) -> Self { // Note: the maximum possible size of the indexes and shifts vectors is // half the bits length; this happens if every other bit is 1. // It's unlikely that we find this case, so we halve that for a fairly // conservative guess. let capacity = bits_length / 4; Self { - indexes: Vec::with_capacity(capacity), - shifts: Vec::with_capacity(capacity), + shifts: SoAVec::with_capacity(capacity).unwrap(), current_index: 0, current_shift: 0, current_used: true, @@ -993,11 +1552,12 @@ impl CompactionListBuilder { fn add_current_index(&mut self) { let index = self.current_index; let shift = self.current_shift; - assert_eq!(self.shifts.len(), self.indexes.len()); - assert!(self.indexes.is_empty() || *self.indexes.last().unwrap() < index); - assert!(self.shifts.is_empty() || *self.shifts.last().unwrap() < shift); - self.shifts.push(shift); - self.indexes.push(index); + assert!( + self.shifts.is_empty() + || *self.shifts.get(self.shifts.len() - 1).unwrap().index < index + && *self.shifts.get(self.shifts.len() - 1).unwrap().shift < shift + ); + self.shifts.push(ShiftData { index, shift }).unwrap(); } fn mark_used(&mut self) { @@ -1025,15 +1585,14 @@ impl CompactionListBuilder { if !self.current_used { self.add_current_index(); } - CompactionList::build(self.indexes, self.shifts) + CompactionList::build(self.shifts) } } impl Default for CompactionListBuilder { fn default() -> Self { Self { - indexes: Vec::with_capacity(16), - shifts: Vec::with_capacity(16), + shifts: SoAVec::with_capacity(16).unwrap(), current_index: 0, current_shift: 0, current_used: true, @@ -1043,101 +1602,101 @@ impl Default for CompactionListBuilder { pub(crate) struct CompactionLists { #[cfg(feature = "array-buffer")] - pub array_buffers: CompactionList, - pub arrays: CompactionList, - pub array_iterators: CompactionList, - pub async_generators: CompactionList, - pub await_reactions: CompactionList, - pub bigints: CompactionList, - pub bound_functions: CompactionList, - pub builtin_constructors: CompactionList, - pub builtin_functions: CompactionList, - pub caches: CompactionList, + pub(crate) array_buffers: CompactionList, + pub(crate) arrays: CompactionList, + pub(crate) array_iterators: CompactionList, + pub(crate) async_generators: CompactionList, + pub(crate) await_reactions: CompactionList, + pub(crate) bigints: CompactionList, + pub(crate) bound_functions: CompactionList, + pub(crate) builtin_constructors: CompactionList, + pub(crate) builtin_functions: CompactionList, + pub(crate) caches: CompactionList, #[cfg(feature = "array-buffer")] - pub data_views: CompactionList, + pub(crate) data_views: CompactionList, #[cfg(feature = "date")] - pub dates: CompactionList, - pub declarative_environments: CompactionList, - pub e_2_1: CompactionList, - pub e_2_2: CompactionList, - pub e_2_3: CompactionList, - pub e_2_4: CompactionList, - pub e_2_6: CompactionList, - pub e_2_8: CompactionList, - pub e_2_10: CompactionList, - pub e_2_12: CompactionList, - pub e_2_16: CompactionList, - pub e_2_24: CompactionList, - pub e_2_32: CompactionList, - pub k_2_1: CompactionList, - pub k_2_2: CompactionList, - pub k_2_3: CompactionList, - pub k_2_4: CompactionList, - pub k_2_6: CompactionList, - pub k_2_8: CompactionList, - pub k_2_10: CompactionList, - pub k_2_12: CompactionList, - pub k_2_16: CompactionList, - pub k_2_24: CompactionList, - pub k_2_32: CompactionList, - pub ecmascript_functions: CompactionList, - pub embedder_objects: CompactionList, - pub source_codes: CompactionList, - pub source_text_module_records: CompactionList, - pub errors: CompactionList, - pub executables: CompactionList, - pub finalization_registrys: CompactionList, - pub function_environments: CompactionList, - pub generators: CompactionList, - pub global_environments: CompactionList, - pub maps: CompactionList, - pub map_iterators: CompactionList, - pub modules: CompactionList, - pub module_environments: CompactionList, - pub module_request_records: CompactionList, - pub numbers: CompactionList, - pub object_environments: CompactionList, - pub object_shapes: CompactionList, - pub objects: CompactionList, - pub primitive_objects: CompactionList, - pub private_environments: CompactionList, - pub promise_reaction_records: CompactionList, - pub promise_resolving_functions: CompactionList, - pub promise_finally_functions: CompactionList, - pub promises: CompactionList, - pub promise_group_records: CompactionList, - pub proxies: CompactionList, - pub realms: CompactionList, + pub(crate) dates: CompactionList, + pub(crate) declarative_environments: CompactionList, + pub(crate) e_2_1: CompactionList, + pub(crate) e_2_2: CompactionList, + pub(crate) e_2_3: CompactionList, + pub(crate) e_2_4: CompactionList, + pub(crate) e_2_6: CompactionList, + pub(crate) e_2_8: CompactionList, + pub(crate) e_2_10: CompactionList, + pub(crate) e_2_12: CompactionList, + pub(crate) e_2_16: CompactionList, + pub(crate) e_2_24: CompactionList, + pub(crate) e_2_32: CompactionList, + pub(crate) k_2_1: CompactionList, + pub(crate) k_2_2: CompactionList, + pub(crate) k_2_3: CompactionList, + pub(crate) k_2_4: CompactionList, + pub(crate) k_2_6: CompactionList, + pub(crate) k_2_8: CompactionList, + pub(crate) k_2_10: CompactionList, + pub(crate) k_2_12: CompactionList, + pub(crate) k_2_16: CompactionList, + pub(crate) k_2_24: CompactionList, + pub(crate) k_2_32: CompactionList, + pub(crate) ecmascript_functions: CompactionList, + pub(crate) embedder_objects: CompactionList, + pub(crate) source_codes: CompactionList, + pub(crate) source_text_module_records: CompactionList, + pub(crate) errors: CompactionList, + pub(crate) executables: CompactionList, + pub(crate) finalization_registrys: CompactionList, + pub(crate) function_environments: CompactionList, + pub(crate) generators: CompactionList, + pub(crate) global_environments: CompactionList, + pub(crate) maps: CompactionList, + pub(crate) map_iterators: CompactionList, + pub(crate) modules: CompactionList, + pub(crate) module_environments: CompactionList, + pub(crate) module_request_records: CompactionList, + pub(crate) numbers: CompactionList, + pub(crate) object_environments: CompactionList, + pub(crate) object_shapes: CompactionList, + pub(crate) objects: CompactionList, + pub(crate) primitive_objects: CompactionList, + pub(crate) private_environments: CompactionList, + pub(crate) promise_reaction_records: CompactionList, + pub(crate) promise_resolving_functions: CompactionList, + pub(crate) promise_finally_functions: CompactionList, + pub(crate) promises: CompactionList, + pub(crate) promise_group_records: CompactionList, + pub(crate) proxies: CompactionList, + pub(crate) realms: CompactionList, #[cfg(feature = "regexp")] - pub regexps: CompactionList, + pub(crate) regexps: CompactionList, #[cfg(feature = "regexp")] - pub regexp_string_iterators: CompactionList, - pub scripts: CompactionList, + pub(crate) regexp_string_iterators: CompactionList, + pub(crate) scripts: CompactionList, #[cfg(feature = "set")] - pub sets: CompactionList, + pub(crate) sets: CompactionList, #[cfg(feature = "set")] - pub set_iterators: CompactionList, + pub(crate) set_iterators: CompactionList, #[cfg(feature = "shared-array-buffer")] - pub shared_array_buffers: CompactionList, + pub(crate) shared_array_buffers: CompactionList, #[cfg(feature = "shared-array-buffer")] - pub shared_data_views: CompactionList, + pub(crate) shared_data_views: CompactionList, #[cfg(feature = "shared-array-buffer")] - pub shared_typed_arrays: CompactionList, - pub string_iterators: CompactionList, - pub strings: CompactionList, - pub symbols: CompactionList, + pub(crate) shared_typed_arrays: CompactionList, + pub(crate) string_iterators: CompactionList, + pub(crate) strings: CompactionList, + pub(crate) symbols: CompactionList, #[cfg(feature = "array-buffer")] - pub typed_arrays: CompactionList, + pub(crate) typed_arrays: CompactionList, #[cfg(feature = "weak-refs")] - pub weak_maps: CompactionList, + pub(crate) weak_maps: CompactionList, #[cfg(feature = "weak-refs")] - pub weak_refs: CompactionList, + pub(crate) weak_refs: CompactionList, #[cfg(feature = "weak-refs")] - pub weak_sets: CompactionList, + pub(crate) weak_sets: CompactionList, } impl CompactionLists { - pub fn create_from_bits(bits: &HeapBits) -> Self { + pub(crate) fn create_from_bits(bits: &HeapBits) -> Self { // TODO: Instead of each list creating its own Vecs, this // could instead be a singular Vec segmented into slices. // The total number of vector items needed for compactions can @@ -1148,108 +1707,152 @@ impl CompactionLists { // areas can exist. We can use this mathematical bound to estimate a good // vector allocation. Self { - modules: CompactionList::from_mark_bits(&bits.modules), - scripts: CompactionList::from_mark_bits(&bits.scripts), - realms: CompactionList::from_mark_bits(&bits.realms), + modules: CompactionList::from_mark_bits(&bits.modules, &bits.bits), + scripts: CompactionList::from_mark_bits(&bits.scripts, &bits.bits), + realms: CompactionList::from_mark_bits(&bits.realms, &bits.bits), declarative_environments: CompactionList::from_mark_bits( &bits.declarative_environments, + &bits.bits, + ), + function_environments: CompactionList::from_mark_bits( + &bits.function_environments, + &bits.bits, + ), + global_environments: CompactionList::from_mark_bits( + &bits.global_environments, + &bits.bits, ), - function_environments: CompactionList::from_mark_bits(&bits.function_environments), - global_environments: CompactionList::from_mark_bits(&bits.global_environments), - object_environments: CompactionList::from_mark_bits(&bits.object_environments), - e_2_1: CompactionList::from_mark_u8s(&bits.e_2_1), - e_2_2: CompactionList::from_mark_u8s(&bits.e_2_2), - e_2_3: CompactionList::from_mark_u8s(&bits.e_2_3), - e_2_4: CompactionList::from_mark_u8s(&bits.e_2_4), - e_2_6: CompactionList::from_mark_u8s(&bits.e_2_6), - e_2_8: CompactionList::from_mark_u8s(&bits.e_2_8), - e_2_10: CompactionList::from_mark_u16s(&bits.e_2_10), - e_2_12: CompactionList::from_mark_u16s(&bits.e_2_12), - e_2_16: CompactionList::from_mark_u16s(&bits.e_2_16), - e_2_24: CompactionList::from_mark_u32s(&bits.e_2_24), - e_2_32: CompactionList::from_mark_u32s(&bits.e_2_32), - k_2_1: CompactionList::from_mark_u8s(&bits.k_2_1), - k_2_2: CompactionList::from_mark_u8s(&bits.k_2_2), - k_2_3: CompactionList::from_mark_u8s(&bits.k_2_3), - k_2_4: CompactionList::from_mark_u8s(&bits.k_2_4), - k_2_6: CompactionList::from_mark_u8s(&bits.k_2_6), - k_2_8: CompactionList::from_mark_u8s(&bits.k_2_8), - k_2_10: CompactionList::from_mark_u16s(&bits.k_2_10), - k_2_12: CompactionList::from_mark_u16s(&bits.k_2_12), - k_2_16: CompactionList::from_mark_u16s(&bits.k_2_16), - k_2_24: CompactionList::from_mark_u32s(&bits.k_2_24), - k_2_32: CompactionList::from_mark_u32s(&bits.k_2_32), - arrays: CompactionList::from_mark_bits(&bits.arrays), + object_environments: CompactionList::from_mark_bits( + &bits.object_environments, + &bits.bits, + ), + e_2_1: CompactionList::from_mark_bits(&bits.e_2_1, &bits.bits), + e_2_2: CompactionList::from_mark_bits(&bits.e_2_2, &bits.bits), + e_2_3: CompactionList::from_mark_bits(&bits.e_2_3, &bits.bits), + e_2_4: CompactionList::from_mark_bits(&bits.e_2_4, &bits.bits), + e_2_6: CompactionList::from_mark_bits(&bits.e_2_6, &bits.bits), + e_2_8: CompactionList::from_mark_bits(&bits.e_2_8, &bits.bits), + e_2_10: CompactionList::from_mark_bits(&bits.e_2_10, &bits.bits), + e_2_12: CompactionList::from_mark_bits(&bits.e_2_12, &bits.bits), + e_2_16: CompactionList::from_mark_bits(&bits.e_2_16, &bits.bits), + e_2_24: CompactionList::from_mark_bits(&bits.e_2_24, &bits.bits), + e_2_32: CompactionList::from_mark_bits(&bits.e_2_32, &bits.bits), + k_2_1: CompactionList::from_mark_bits(&bits.k_2_1, &bits.bits), + k_2_2: CompactionList::from_mark_bits(&bits.k_2_2, &bits.bits), + k_2_3: CompactionList::from_mark_bits(&bits.k_2_3, &bits.bits), + k_2_4: CompactionList::from_mark_bits(&bits.k_2_4, &bits.bits), + k_2_6: CompactionList::from_mark_bits(&bits.k_2_6, &bits.bits), + k_2_8: CompactionList::from_mark_bits(&bits.k_2_8, &bits.bits), + k_2_10: CompactionList::from_mark_bits(&bits.k_2_10, &bits.bits), + k_2_12: CompactionList::from_mark_bits(&bits.k_2_12, &bits.bits), + k_2_16: CompactionList::from_mark_bits(&bits.k_2_16, &bits.bits), + k_2_24: CompactionList::from_mark_bits(&bits.k_2_24, &bits.bits), + k_2_32: CompactionList::from_mark_bits(&bits.k_2_32, &bits.bits), + arrays: CompactionList::from_mark_bits(&bits.arrays, &bits.bits), #[cfg(feature = "array-buffer")] - array_buffers: CompactionList::from_mark_bits(&bits.array_buffers), - array_iterators: CompactionList::from_mark_bits(&bits.array_iterators), - async_generators: CompactionList::from_mark_bits(&bits.async_generators), - await_reactions: CompactionList::from_mark_bits(&bits.await_reactions), - bigints: CompactionList::from_mark_bits(&bits.bigints), - bound_functions: CompactionList::from_mark_bits(&bits.bound_functions), - builtin_constructors: CompactionList::from_mark_bits(&bits.builtin_constructors), - builtin_functions: CompactionList::from_mark_bits(&bits.builtin_functions), - caches: CompactionList::from_mark_bits(&bits.caches), - ecmascript_functions: CompactionList::from_mark_bits(&bits.ecmascript_functions), - embedder_objects: CompactionList::from_mark_bits(&bits.embedder_objects), - generators: CompactionList::from_mark_bits(&bits.generators), - source_codes: CompactionList::from_mark_bits(&bits.source_codes), + array_buffers: CompactionList::from_mark_bits(&bits.array_buffers, &bits.bits), + array_iterators: CompactionList::from_mark_bits(&bits.array_iterators, &bits.bits), + async_generators: CompactionList::from_mark_bits(&bits.async_generators, &bits.bits), + await_reactions: CompactionList::from_mark_bits(&bits.await_reactions, &bits.bits), + bigints: CompactionList::from_mark_bits(&bits.bigints, &bits.bits), + bound_functions: CompactionList::from_mark_bits(&bits.bound_functions, &bits.bits), + builtin_constructors: CompactionList::from_mark_bits( + &bits.builtin_constructors, + &bits.bits, + ), + builtin_functions: CompactionList::from_mark_bits(&bits.builtin_functions, &bits.bits), + caches: CompactionList::from_mark_bits(&bits.caches, &bits.bits), + ecmascript_functions: CompactionList::from_mark_bits( + &bits.ecmascript_functions, + &bits.bits, + ), + embedder_objects: CompactionList::from_mark_bits(&bits.embedder_objects, &bits.bits), + generators: CompactionList::from_mark_bits(&bits.generators, &bits.bits), + source_codes: CompactionList::from_mark_bits(&bits.source_codes, &bits.bits), #[cfg(feature = "date")] - dates: CompactionList::from_mark_bits(&bits.dates), - errors: CompactionList::from_mark_bits(&bits.errors), - executables: CompactionList::from_mark_bits(&bits.executables), - maps: CompactionList::from_mark_bits(&bits.maps), - map_iterators: CompactionList::from_mark_bits(&bits.map_iterators), - module_environments: CompactionList::from_mark_bits(&bits.module_environments), - module_request_records: CompactionList::from_mark_bits(&bits.module_request_records), - numbers: CompactionList::from_mark_bits(&bits.numbers), - object_shapes: CompactionList::from_mark_bits(&bits.object_shapes), - objects: CompactionList::from_mark_bits(&bits.objects), - primitive_objects: CompactionList::from_mark_bits(&bits.primitive_objects), - private_environments: CompactionList::from_mark_bits(&bits.private_environments), + dates: CompactionList::from_mark_bits(&bits.dates, &bits.bits), + errors: CompactionList::from_mark_bits(&bits.errors, &bits.bits), + executables: CompactionList::from_mark_bits(&bits.executables, &bits.bits), + maps: CompactionList::from_mark_bits(&bits.maps, &bits.bits), + map_iterators: CompactionList::from_mark_bits(&bits.map_iterators, &bits.bits), + module_environments: CompactionList::from_mark_bits( + &bits.module_environments, + &bits.bits, + ), + module_request_records: CompactionList::from_mark_bits( + &bits.module_request_records, + &bits.bits, + ), + numbers: CompactionList::from_mark_bits(&bits.numbers, &bits.bits), + object_shapes: CompactionList::from_mark_bits(&bits.object_shapes, &bits.bits), + objects: CompactionList::from_mark_bits(&bits.objects, &bits.bits), + primitive_objects: CompactionList::from_mark_bits(&bits.primitive_objects, &bits.bits), + private_environments: CompactionList::from_mark_bits( + &bits.private_environments, + &bits.bits, + ), promise_reaction_records: CompactionList::from_mark_bits( &bits.promise_reaction_records, + &bits.bits, ), promise_resolving_functions: CompactionList::from_mark_bits( &bits.promise_resolving_functions, + &bits.bits, ), promise_finally_functions: CompactionList::from_mark_bits( &bits.promise_finally_functions, + &bits.bits, + ), + promises: CompactionList::from_mark_bits(&bits.promises, &bits.bits), + promise_group_records: CompactionList::from_mark_bits( + &bits.promise_group_records, + &bits.bits, ), - promises: CompactionList::from_mark_bits(&bits.promises), - promise_group_records: CompactionList::from_mark_bits(&bits.promise_group_records), #[cfg(feature = "regexp")] - regexps: CompactionList::from_mark_bits(&bits.regexps), + regexps: CompactionList::from_mark_bits(&bits.regexps, &bits.bits), #[cfg(feature = "regexp")] - regexp_string_iterators: CompactionList::from_mark_bits(&bits.regexp_string_iterators), + regexp_string_iterators: CompactionList::from_mark_bits( + &bits.regexp_string_iterators, + &bits.bits, + ), #[cfg(feature = "set")] - sets: CompactionList::from_mark_bits(&bits.sets), + sets: CompactionList::from_mark_bits(&bits.sets, &bits.bits), #[cfg(feature = "set")] - set_iterators: CompactionList::from_mark_bits(&bits.set_iterators), - string_iterators: CompactionList::from_mark_bits(&bits.string_iterators), - strings: CompactionList::from_mark_bits(&bits.strings), + set_iterators: CompactionList::from_mark_bits(&bits.set_iterators, &bits.bits), + string_iterators: CompactionList::from_mark_bits(&bits.string_iterators, &bits.bits), + strings: CompactionList::from_mark_bits(&bits.strings, &bits.bits), #[cfg(feature = "shared-array-buffer")] - shared_array_buffers: CompactionList::from_mark_bits(&bits.shared_array_buffers), + shared_array_buffers: CompactionList::from_mark_bits( + &bits.shared_array_buffers, + &bits.bits, + ), #[cfg(feature = "shared-array-buffer")] - shared_data_views: CompactionList::from_mark_bits(&bits.shared_data_views), + shared_data_views: CompactionList::from_mark_bits(&bits.shared_data_views, &bits.bits), #[cfg(feature = "shared-array-buffer")] - shared_typed_arrays: CompactionList::from_mark_bits(&bits.shared_typed_arrays), + shared_typed_arrays: CompactionList::from_mark_bits( + &bits.shared_typed_arrays, + &bits.bits, + ), source_text_module_records: CompactionList::from_mark_bits( &bits.source_text_module_records, + &bits.bits, ), - symbols: CompactionList::from_mark_bits(&bits.symbols), + symbols: CompactionList::from_mark_bits(&bits.symbols, &bits.bits), #[cfg(feature = "array-buffer")] - data_views: CompactionList::from_mark_bits(&bits.data_views), - finalization_registrys: CompactionList::from_mark_bits(&bits.finalization_registrys), - proxies: CompactionList::from_mark_bits(&bits.proxies), + data_views: CompactionList::from_mark_bits(&bits.data_views, &bits.bits), + finalization_registrys: CompactionList::from_mark_bits( + &bits.finalization_registrys, + &bits.bits, + ), + proxies: CompactionList::from_mark_bits(&bits.proxies, &bits.bits), #[cfg(feature = "weak-refs")] - weak_maps: CompactionList::from_mark_bits(&bits.weak_maps), + weak_maps: CompactionList::from_mark_bits(&bits.weak_maps, &bits.bits), #[cfg(feature = "weak-refs")] - weak_refs: CompactionList::from_mark_bits(&bits.weak_refs), + weak_refs: CompactionList::from_mark_bits(&bits.weak_refs, &bits.bits), #[cfg(feature = "weak-refs")] - weak_sets: CompactionList::from_mark_bits(&bits.weak_sets), + weak_sets: CompactionList::from_mark_bits(&bits.weak_sets, &bits.bits), #[cfg(feature = "array-buffer")] - typed_arrays: CompactionList::from_mark_bits(&bits.typed_arrays), + typed_arrays: CompactionList::from_mark_bits(&bits.typed_arrays, &bits.bits), } } } @@ -1322,6 +1925,25 @@ where } } +impl HeapMarkAndSweep for [T; N] +where + T: HeapMarkAndSweep, +{ + #[inline] + fn mark_values(&self, queues: &mut WorkQueues) { + for elem in self { + elem.mark_values(queues); + } + } + + #[inline] + fn sweep_values(&mut self, compactions: &CompactionLists) { + for elem in self { + elem.sweep_values(compactions); + } + } +} + macro_rules! trivially_sweepable { ($self:ty) => { impl crate::heap::heap_bits::HeapMarkAndSweep for $self { @@ -1333,7 +1955,6 @@ macro_rules! trivially_sweepable { } }; } -pub(crate) use trivially_sweepable; trivially_sweepable!(()); trivially_sweepable!(bool); @@ -1683,16 +2304,6 @@ impl( - array: &[T; N], - queues: &mut WorkQueues, - length: u32, -) { - array.as_ref()[..length as usize].iter().for_each(|value| { - value.mark_values(queues); - }); -} - pub(crate) fn mark_descriptors( descriptors: &AHashMap>, queues: &mut WorkQueues, @@ -1702,31 +2313,17 @@ pub(crate) fn mark_descriptors( } } -fn sweep_array_with_u32_length( - array: &mut [T; N], - compactions: &CompactionLists, - length: u32, -) { - if length == 0 { - return; - } - array.as_mut()[..length as usize] - .iter_mut() - .for_each(|value| { - value.sweep_values(compactions); - }); -} - pub(crate) fn sweep_heap_vector_values( vec: &mut Vec, compactions: &CompactionLists, - bits: &[bool], + range: &BitRange, + bits: &[AtomicBits], ) { - assert_eq!(vec.len(), bits.len()); - let mut iter = bits.iter(); + assert_eq!(vec.len(), range.len()); + let mut iter = range.iter(bits); vec.retain_mut(|item| { let do_retain = iter.next().unwrap(); - if *do_retain { + if do_retain { item.sweep_values(compactions); true } else { @@ -1738,15 +2335,16 @@ pub(crate) fn sweep_heap_vector_values( pub(crate) fn sweep_heap_soa_vector_values( vec: &mut SoAVec, compactions: &CompactionLists, - bits: &[bool], + range: &BitRange, + bits: &[AtomicBits], ) where for<'a> T::Mut<'a>: HeapMarkAndSweep, { - assert_eq!(vec.len() as usize, bits.len()); - let mut iter = bits.iter(); + assert_eq!(vec.len() as usize, range.len()); + let mut iter = range.iter(bits); vec.retain_mut(|mut item| { let do_retain = iter.next().unwrap(); - if *do_retain { + if do_retain { item.sweep_values(compactions); true } else { @@ -1755,125 +2353,18 @@ pub(crate) fn sweep_heap_soa_vector_values( }); } -pub(crate) fn sweep_heap_u8_property_key_vector( - vec: &mut Vec<[Option>; N]>, - compactions: &CompactionLists, - u8s: &[(bool, u8)], -) { - assert_eq!(vec.len(), u8s.len()); - let mut iter = u8s.iter(); - vec.retain_mut(|item| { - let (mark, length) = iter.next().unwrap(); - if *mark { - sweep_array_with_u32_length(item, compactions, *length as u32); - true - } else { - false - } - }); -} - -pub(crate) fn sweep_heap_u16_property_key_vector( - vec: &mut Vec<[Option>; N]>, - compactions: &CompactionLists, - u16s: &[(bool, u16)], -) { - assert_eq!(vec.len(), u16s.len()); - let mut iter = u16s.iter(); - vec.retain_mut(|item| { - let (mark, length) = iter.next().unwrap(); - if *mark { - sweep_array_with_u32_length(item, compactions, *length as u32); - true - } else { - false - } - }); -} - -pub(crate) fn sweep_heap_u32_property_key_vector( - vec: &mut Vec<[Option>; N]>, - compactions: &CompactionLists, - u32s: &[(bool, u32)], -) { - assert_eq!(vec.len(), u32s.len()); - let mut iter = u32s.iter(); - vec.retain_mut(|item| { - let (mark, length) = iter.next().unwrap(); - if *mark { - sweep_array_with_u32_length(item, compactions, *length); - true - } else { - false - } - }); -} - -pub(crate) fn sweep_heap_u8_elements_vector_values( - vec: &mut Vec<[Option>; N]>, - compactions: &CompactionLists, - u8s: &[(bool, u8)], -) { - assert_eq!(vec.len(), u8s.len()); - let mut iter = u8s.iter(); - vec.retain_mut(|item| { - let (mark, length) = iter.next().unwrap(); - if *mark { - sweep_array_with_u32_length(item, compactions, *length as u32); - true - } else { - false - } - }); -} - -pub(crate) fn sweep_heap_u16_elements_vector_values( - vec: &mut Vec<[Option>; N]>, - compactions: &CompactionLists, - u16s: &[(bool, u16)], -) { - assert_eq!(vec.len(), u16s.len()); - let mut iter = u16s.iter(); - vec.retain_mut(|item| { - let (mark, length) = iter.next().unwrap(); - if *mark { - sweep_array_with_u32_length(item, compactions, *length as u32); - true - } else { - false - } - }); -} - -pub(crate) fn sweep_heap_u32_elements_vector_values( - vec: &mut Vec<[Option>; N]>, - compactions: &CompactionLists, - u32s: &[(bool, u32)], -) { - assert_eq!(vec.len(), u32s.len()); - let mut iter = u32s.iter(); - vec.retain_mut(|item| { - let (mark, length) = iter.next().unwrap(); - if *mark { - sweep_array_with_u32_length(item, compactions, *length); - true - } else { - false - } - }); -} - -pub(crate) fn sweep_heap_elements_vector_descriptors( +pub(crate) fn sweep_heap_elements_vector_descriptors( descriptors: &mut AHashMap, AHashMap>>, compactions: &CompactionLists, self_compactions: &CompactionList, - marks: &[(bool, T)], + range: &BitRange, + bits: &[AtomicBits], ) { - let mut keys_to_remove = Vec::with_capacity(marks.len() / 4); - let mut keys_to_reassign = Vec::with_capacity(marks.len() / 4); + let mut keys_to_remove = Vec::with_capacity(range.len() / 4); + let mut keys_to_reassign = Vec::with_capacity(range.len() / 4); for (key, descriptor) in descriptors.iter_mut() { let old_key = *key; - if !marks.get(key.into_index()).unwrap().0 { + if !range.get_bit(old_key.into_index(), bits) { keys_to_remove.push(old_key); } else { for descriptor in descriptor.values_mut() { diff --git a/nova_vm/src/heap/heap_gc.rs b/nova_vm/src/heap/heap_gc.rs index b2c258261..ae4d79203 100644 --- a/nova_vm/src/heap/heap_gc.rs +++ b/nova_vm/src/heap/heap_gc.rs @@ -10,11 +10,8 @@ use super::{ Heap, WellKnownSymbolIndexes, element_array::ElementArrays, heap_bits::{ - CompactionLists, HeapBits, HeapMarkAndSweep, WorkQueues, mark_array_with_u32_length, - mark_descriptors, sweep_heap_elements_vector_descriptors, sweep_heap_soa_vector_values, - sweep_heap_u8_elements_vector_values, sweep_heap_u8_property_key_vector, - sweep_heap_u16_elements_vector_values, sweep_heap_u16_property_key_vector, - sweep_heap_u32_elements_vector_values, sweep_heap_u32_property_key_vector, + CompactionLists, HeapBits, HeapMarkAndSweep, WorkQueues, mark_descriptors, + sweep_heap_elements_vector_descriptors, sweep_heap_soa_vector_values, sweep_heap_vector_values, sweep_lookup_table, }, indexes::{ElementIndex, PropertyKeyIndex}, @@ -96,19 +93,24 @@ pub fn heap_gc(agent: &mut Agent, root_realms: &mut [Option>], gc ndt::gc_start!(|| ()); let mut bits = HeapBits::new(&agent.heap); - let mut queues = WorkQueues::new(&agent.heap); - + bits.strings + .mark_range(0..(BUILTIN_STRINGS_LIST.len() as u32), &mut bits.bits); + bits.symbols.mark_range( + 0..(WellKnownSymbolIndexes::Unscopables as u32), + &mut bits.bits, + ); + let mut queues = WorkQueues::new(&agent.heap, &bits); root_realms.iter().for_each(|realm| { if let Some(realm) = realm { queues.realms.push(realm.unbind()); } }); - - bits.strings[0..BUILTIN_STRINGS_LIST.len()].fill(true); - bits.symbols[0..WellKnownSymbolIndexes::Unscopables as usize].fill(true); queues.object_shapes.push(ObjectShape::NULL); + agent.heap.prototype_shapes.mark_values(&mut queues); + agent.heap.caches.mark_values(&mut queues); agent.mark_values(&mut queues); let mut has_finalization_registrys = false; + while !queues.is_empty() { let Heap { #[cfg(feature = "array-buffer")] @@ -143,7 +145,7 @@ pub fn heap_gc(agent: &mut Agent, root_realms: &mut [Option>], gc numbers, object_shapes, object_shape_transitions, - prototype_shapes, + prototype_shapes: _, objects, primitive_objects, promise_reaction_records, @@ -239,1211 +241,977 @@ pub fn heap_gc(agent: &mut Agent, root_realms: &mut [Option>], gc k2pow32, } = elements; - prototype_shapes.mark_values(&mut queues); - caches.mark_values(&mut queues); + if !queues.modules.is_empty() { + let mut module_marks: Box<[Module]> = queues.modules.drain(..).collect(); + module_marks.sort(); + module_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.modules.set_bit(index, &bits.bits) { + // Did mark. + modules.get(index).mark_values(&mut queues); + } + }); + } + if !queues.scripts.is_empty() { + let mut script_marks: Box<[Script]> = queues.scripts.drain(..).collect(); + script_marks.sort(); + script_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.scripts.set_bit(index, &bits.bits) { + // Did mark. + scripts.get(index).mark_values(&mut queues); + } + }); + } + if !queues.realms.is_empty() { + let mut realm_marks: Box<[Realm]> = queues.realms.drain(..).collect(); + realm_marks.sort(); + realm_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.realms.set_bit(index, &bits.bits) { + // Did mark. + realms.get(index).mark_values(&mut queues); + } + }); + } - let mut module_marks: Box<[Module]> = queues.modules.drain(..).collect(); - module_marks.sort(); - module_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.modules.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - modules.get(index).mark_values(&mut queues); - } - }); - let mut script_marks: Box<[Script]> = queues.scripts.drain(..).collect(); - script_marks.sort(); - script_marks.iter().for_each(|&idx| { - let index = idx.into_index(); - if let Some(marked) = bits.scripts.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - scripts.get(index).mark_values(&mut queues); - } - }); - let mut realm_marks: Box<[Realm]> = queues.realms.drain(..).collect(); - realm_marks.sort(); - realm_marks.iter().for_each(|&idx| { - let index = idx.into_index(); - if let Some(marked) = bits.realms.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - realms.get(index).mark_values(&mut queues); - } - }); + if !queues.declarative_environments.is_empty() { + let mut declarative_environment_marks: Box<[DeclarativeEnvironment]> = + queues.declarative_environments.drain(..).collect(); + declarative_environment_marks.sort(); + declarative_environment_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.declarative_environments.set_bit(index, &bits.bits) { + // Did mark. + declarative_environments.get(index).mark_values(&mut queues); + } + }); + } - let mut declarative_environment_marks: Box<[DeclarativeEnvironment]> = - queues.declarative_environments.drain(..).collect(); - declarative_environment_marks.sort(); - declarative_environment_marks.iter().for_each(|&idx| { - let index = idx.into_index(); - if let Some(marked) = bits.declarative_environments.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - declarative_environments.get(index).mark_values(&mut queues); - } - }); - let mut function_environment_marks: Box<[FunctionEnvironment]> = - queues.function_environments.drain(..).collect(); - function_environment_marks.sort(); - function_environment_marks.iter().for_each(|&idx| { - let index = idx.into_index(); - if let Some(marked) = bits.function_environments.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - function_environments.get(index).mark_values(&mut queues); - } - }); - let mut global_environment_marks: Box<[GlobalEnvironment]> = - queues.global_environments.drain(..).collect(); - global_environment_marks.sort(); - global_environment_marks.iter().for_each(|&idx| { - let index = idx.into_index(); - if let Some(marked) = bits.global_environments.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - global_environments.get(index).mark_values(&mut queues); - } - }); - let mut module_environment_marks: Box<[ModuleEnvironment]> = - queues.module_environments.drain(..).collect(); - module_environment_marks.sort(); - module_environment_marks.iter().for_each(|&idx| { - let index = idx.into_index(); - if let Some(marked) = bits.module_environments.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - module_environments.get(index).mark_values(&mut queues); - } - }); - let mut object_environment_marks: Box<[ObjectEnvironment]> = - queues.object_environments.drain(..).collect(); - object_environment_marks.sort(); - object_environment_marks.iter().for_each(|&idx| { - let index = idx.into_index(); - if let Some(marked) = bits.object_environments.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - object_environments.get(index).mark_values(&mut queues); - } - }); + if !queues.function_environments.is_empty() { + let mut function_environment_marks: Box<[FunctionEnvironment]> = + queues.function_environments.drain(..).collect(); + function_environment_marks.sort(); + function_environment_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.function_environments.set_bit(index, &bits.bits) { + // Did mark. + function_environments.get(index).mark_values(&mut queues); + } + }); + } + + if !queues.global_environments.is_empty() { + let mut global_environment_marks: Box<[GlobalEnvironment]> = + queues.global_environments.drain(..).collect(); + global_environment_marks.sort(); + global_environment_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.global_environments.set_bit(index, &bits.bits) { + // Did mark. + global_environments.get(index).mark_values(&mut queues); + } + }); + } + + if !queues.module_environments.is_empty() { + let mut module_environment_marks: Box<[ModuleEnvironment]> = + queues.module_environments.drain(..).collect(); + module_environment_marks.sort(); + module_environment_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.module_environments.set_bit(index, &bits.bits) { + // Did mark. + module_environments.get(index).mark_values(&mut queues); + } + }); + } + + if !queues.object_environments.is_empty() { + let mut object_environment_marks: Box<[ObjectEnvironment]> = + queues.object_environments.drain(..).collect(); + object_environment_marks.sort(); + object_environment_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.object_environments.set_bit(index, &bits.bits) { + // Did mark. + object_environments.get(index).mark_values(&mut queues); + } + }); + } - 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 as u32).mark_values(&mut queues); + if !queues.pending_ephemerons.is_empty() { + queues.pending_ephemerons.sort_by_key(|(key, _)| *key); + let new_values_to_mark = queues + .pending_ephemerons + .extract_if(.., |(key, _)| queues.bits.is_marked(key)) + .map(|(_, value)| value) + .collect::>(); + for value in new_values_to_mark { + value.mark_values(&mut queues); } - }); + } + + if !queues.arrays.is_empty() { + 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 bits.arrays.set_bit(index, &bits.bits) { + // Did mark. + arrays.get(index as u32).mark_values(&mut queues); + } + }); + } + #[cfg(feature = "array-buffer")] { - let mut array_buffer_marks: Box<[ArrayBuffer]> = - queues.array_buffers.drain(..).collect(); - array_buffer_marks.sort(); - array_buffer_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.array_buffers.get_mut(index) { - if *marked { - // Already marked, ignore - return; + if !queues.array_buffers.is_empty() { + let mut array_buffer_marks: Box<[ArrayBuffer]> = + queues.array_buffers.drain(..).collect(); + array_buffer_marks.sort(); + array_buffer_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.array_buffers.set_bit(index, &bits.bits) { + // Did mark. + array_buffers.get(index).mark_values(&mut queues); } - *marked = true; - array_buffers.get(index).mark_values(&mut queues); + }); + } + } + + if !queues.array_iterators.is_empty() { + let mut array_iterator_marks: Box<[ArrayIterator]> = + queues.array_iterators.drain(..).collect(); + array_iterator_marks.sort(); + array_iterator_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.array_iterators.set_bit(index, &bits.bits) { + // Did mark. + array_iterators.get(index).mark_values(&mut queues); } }); } - let mut array_iterator_marks: Box<[ArrayIterator]> = - queues.array_iterators.drain(..).collect(); - array_iterator_marks.sort(); - array_iterator_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.array_iterators.get_mut(index) { - if *marked { - // Already marked, ignore - return; + + if !queues.async_generators.is_empty() { + let mut async_generator_marks: Box<[AsyncGenerator]> = + queues.async_generators.drain(..).collect(); + async_generator_marks.sort(); + async_generator_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.async_generators.set_bit(index, &bits.bits) { + // Did mark. + async_generators.get(index).mark_values(&mut queues); } - *marked = true; - array_iterators.get(index).mark_values(&mut queues); - } - }); - let mut async_generator_marks: Box<[AsyncGenerator]> = - queues.async_generators.drain(..).collect(); - async_generator_marks.sort(); - async_generator_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.async_generators.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - async_generators.get(index).mark_values(&mut queues); - } - }); - let mut await_reaction_marks: Box<[AwaitReaction]> = - queues.await_reactions.drain(..).collect(); - await_reaction_marks.sort(); - await_reaction_marks.iter().for_each(|&idx| { - let index = idx.into_index(); - if let Some(marked) = bits.await_reactions.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - await_reactions.get(index).mark_values(&mut queues); - } - }); - let mut bigint_marks: Box<[HeapBigInt]> = queues.bigints.drain(..).collect(); - bigint_marks.sort(); - bigint_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.bigints.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - bigints.get(index).mark_values(&mut queues); - } - }); - let mut bound_function_marks: Box<[BoundFunction]> = - queues.bound_functions.drain(..).collect(); - bound_function_marks.sort(); - bound_function_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.bound_functions.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - bound_functions.get(index).mark_values(&mut queues); - } - }); - let mut ecmascript_function_marks: Box<[ECMAScriptFunction]> = - queues.ecmascript_functions.drain(..).collect(); - ecmascript_function_marks.sort(); - ecmascript_function_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.ecmascript_functions.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - ecmascript_functions.get(index).mark_values(&mut queues); - } - }); - let mut error_marks: Box<[Error]> = queues.errors.drain(..).collect(); - error_marks.sort(); - error_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.errors.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - errors.get(index).mark_values(&mut queues); - } - }); - let mut executable_marks: Box<[Executable]> = queues.executables.drain(..).collect(); - executable_marks.sort(); - executable_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.executables.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - executables.get(index).mark_values(&mut queues); - } - }); - let mut source_code_marks: Box<[SourceCode]> = queues.source_codes.drain(..).collect(); - source_code_marks.sort(); - source_code_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.source_codes.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - source_codes.get(index).mark_values(&mut queues); - } - }); - let mut builtin_constructors_marks: Box<[BuiltinConstructorFunction]> = - queues.builtin_constructors.drain(..).collect(); - builtin_constructors_marks.sort(); - builtin_constructors_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.builtin_constructors.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - builtin_constructors.get(index).mark_values(&mut queues); - } - }); - let mut builtin_functions_marks: Box<[BuiltinFunction]> = - queues.builtin_functions.drain(..).collect(); - builtin_functions_marks.sort(); - builtin_functions_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.builtin_functions.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - builtin_functions.get(index).mark_values(&mut queues); - } - }); - let mut caches_marks: Box<[PropertyLookupCache]> = queues.caches.drain(..).collect(); - caches_marks.sort(); - caches_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.caches.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - caches.mark_cache(index, &mut queues); - } - }); + }); + } + + if !queues.await_reactions.is_empty() { + let mut await_reaction_marks: Box<[AwaitReaction]> = + queues.await_reactions.drain(..).collect(); + await_reaction_marks.sort(); + await_reaction_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.await_reactions.set_bit(index, &bits.bits) { + // Did mark. + await_reactions.get(index).mark_values(&mut queues); + } + }); + } + + if !queues.bigints.is_empty() { + let mut bigint_marks: Box<[HeapBigInt]> = queues.bigints.drain(..).collect(); + bigint_marks.sort(); + bigint_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.bigints.set_bit(index, &bits.bits) { + // Did mark. + bigints.get(index).mark_values(&mut queues); + } + }); + } + + if !queues.bound_functions.is_empty() { + let mut bound_function_marks: Box<[BoundFunction]> = + queues.bound_functions.drain(..).collect(); + bound_function_marks.sort(); + bound_function_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.bound_functions.set_bit(index, &bits.bits) { + // Did mark. + bound_functions.get(index).mark_values(&mut queues); + } + }); + } + if !queues.ecmascript_functions.is_empty() { + let mut ecmascript_function_marks: Box<[ECMAScriptFunction]> = + queues.ecmascript_functions.drain(..).collect(); + ecmascript_function_marks.sort(); + ecmascript_function_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.ecmascript_functions.set_bit(index, &bits.bits) { + // Did mark. + ecmascript_functions.get(index).mark_values(&mut queues); + } + }); + } + if !queues.errors.is_empty() { + let mut error_marks: Box<[Error]> = queues.errors.drain(..).collect(); + error_marks.sort(); + error_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.errors.set_bit(index, &bits.bits) { + // Did mark. + errors.get(index).mark_values(&mut queues); + } + }); + } + if !queues.executables.is_empty() { + let mut executable_marks: Box<[Executable]> = queues.executables.drain(..).collect(); + executable_marks.sort(); + executable_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.executables.set_bit(index, &bits.bits) { + // Did mark. + executables.get(index).mark_values(&mut queues); + } + }); + } + if !queues.source_codes.is_empty() { + let mut source_code_marks: Box<[SourceCode]> = queues.source_codes.drain(..).collect(); + source_code_marks.sort(); + source_code_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.source_codes.set_bit(index, &bits.bits) { + // Did mark. + source_codes.get(index).mark_values(&mut queues); + } + }); + } + if !queues.builtin_constructors.is_empty() { + let mut builtin_constructors_marks: Box<[BuiltinConstructorFunction]> = + queues.builtin_constructors.drain(..).collect(); + builtin_constructors_marks.sort(); + builtin_constructors_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.builtin_constructors.set_bit(index, &bits.bits) { + // Did mark. + builtin_constructors.get(index).mark_values(&mut queues); + } + }); + } + if !queues.builtin_functions.is_empty() { + let mut builtin_functions_marks: Box<[BuiltinFunction]> = + queues.builtin_functions.drain(..).collect(); + builtin_functions_marks.sort(); + builtin_functions_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.builtin_functions.set_bit(index, &bits.bits) { + // Did mark. + builtin_functions.get(index).mark_values(&mut queues); + } + }); + } + if !queues.caches.is_empty() { + let mut caches_marks: Box<[PropertyLookupCache]> = queues.caches.drain(..).collect(); + caches_marks.sort(); + caches_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.caches.set_bit(index, &bits.bits) { + // Did mark. + caches.mark_cache(index, &mut queues); + } + }); + } #[cfg(feature = "array-buffer")] - { + if !queues.data_views.is_empty() { let mut data_view_marks: Box<[DataView]> = queues.data_views.drain(..).collect(); data_view_marks.sort(); data_view_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.data_views.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; + if bits.data_views.set_bit(index, &bits.bits) { + // Did mark. data_views.get(index).mark_values(&mut queues); } }); } + #[cfg(feature = "date")] - { + if !queues.dates.is_empty() { let mut date_marks: Box<[Date]> = queues.dates.drain(..).collect(); date_marks.sort(); date_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.dates.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; + if bits.dates.set_bit(index, &bits.bits) { + // Did mark. dates.get(index).mark_values(&mut queues); } }); } - let mut embedder_object_marks: Box<[EmbedderObject]> = - queues.embedder_objects.drain(..).collect(); - embedder_object_marks.sort(); - embedder_object_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.embedder_objects.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - embedder_objects.get(index).mark_values(&mut queues); - } - }); - let mut finalization_registry_marks: Box<[FinalizationRegistry]> = - queues.finalization_registrys.drain(..).collect(); - finalization_registry_marks.sort(); - if !finalization_registry_marks.is_empty() { - has_finalization_registrys = true; - } - finalization_registry_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.finalization_registrys.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - finalization_registrys - .get(index as u32) - .mark_values(&mut queues); - } - }); - let mut generator_marks: Box<[Generator]> = queues.generators.drain(..).collect(); - generator_marks.sort(); - generator_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.generators.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - generators.get(index).mark_values(&mut queues); - } - }); - let mut object_marks: Box<[ObjectShape]> = queues.object_shapes.drain(..).collect(); - object_marks.sort(); - object_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.object_shapes.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - object_shapes.get(index).mark_values(&mut queues); - object_shape_transitions.get(index).mark_values(&mut queues); - } - }); - let mut object_marks: Box<[OrdinaryObject]> = queues.objects.drain(..).collect(); - object_marks.sort(); - object_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.objects.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - if let Some(rec) = objects.get(index) { - rec.mark_values(&mut queues, &agent.heap.object_shapes); + + if !queues.embedder_objects.is_empty() { + let mut embedder_object_marks: Box<[EmbedderObject]> = + queues.embedder_objects.drain(..).collect(); + embedder_object_marks.sort(); + embedder_object_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.embedder_objects.set_bit(index, &bits.bits) { + // Did mark. + embedder_objects.get(index).mark_values(&mut queues); } + }); + } + if !queues.finalization_registrys.is_empty() { + let mut finalization_registry_marks: Box<[FinalizationRegistry]> = + queues.finalization_registrys.drain(..).collect(); + finalization_registry_marks.sort(); + if !finalization_registry_marks.is_empty() { + has_finalization_registrys = true; } - }); - let mut promise_marks: Box<[Promise]> = queues.promises.drain(..).collect(); - promise_marks.sort(); - promise_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.promises.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - promises.get(index).mark_values(&mut queues); - } - }); - let mut promise_reaction_record_marks: Box<[PromiseReaction]> = - queues.promise_reaction_records.drain(..).collect(); - promise_reaction_record_marks.sort(); - promise_reaction_record_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.promise_reaction_records.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - promise_reaction_records.get(index).mark_values(&mut queues); - } - }); - let mut promise_group_record_marks: Box<[PromiseGroup]> = - queues.promise_group_records.drain(..).collect(); - promise_group_record_marks.sort(); - promise_group_record_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.promise_group_records.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - promise_group_records.get(index).mark_values(&mut queues); - } - }); - let mut promise_resolving_function_marks: Box<[BuiltinPromiseResolvingFunction]> = - queues.promise_resolving_functions.drain(..).collect(); - promise_resolving_function_marks.sort(); - promise_resolving_function_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.promise_resolving_functions.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - promise_resolving_functions - .get(index) - .mark_values(&mut queues); - } - }); - let mut promise_finally_function_marks: Box<[BuiltinPromiseFinallyFunction]> = - queues.promise_finally_functions.drain(..).collect(); - promise_finally_function_marks.sort(); - promise_finally_function_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.promise_finally_functions.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - promise_finally_functions - .get(index) - .mark_values(&mut queues); - } - }); - let mut proxy_marks: Box<[Proxy]> = queues.proxies.drain(..).collect(); - proxy_marks.sort(); - proxy_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.proxies.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - proxies.get(index).mark_values(&mut queues); - } - }); - let mut map_marks: Box<[Map]> = queues.maps.drain(..).collect(); - map_marks.sort(); - map_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.maps.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - maps.get(index).mark_values(&mut queues); - } - }); - let mut map_iterator_marks: Box<[MapIterator]> = queues.map_iterators.drain(..).collect(); - map_iterator_marks.sort(); - map_iterator_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.map_iterators.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - map_iterators.get(index).mark_values(&mut queues); - } - }); - let mut module_request_record_marks: Box<[ModuleRequest]> = - queues.module_request_records.drain(..).collect(); - module_request_record_marks.sort(); - module_request_record_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.module_request_records.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - module_request_records.get(index).mark_values(&mut queues); - } - }); - let mut number_marks: Box<[HeapNumber]> = queues.numbers.drain(..).collect(); - number_marks.sort(); - number_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.numbers.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - numbers.get(index).mark_values(&mut queues); - } - }); - let mut primitive_object_marks: Box<[PrimitiveObject]> = - queues.primitive_objects.drain(..).collect(); - primitive_object_marks.sort(); - primitive_object_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.primitive_objects.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - primitive_objects.get(index).mark_values(&mut queues); - } - }); - #[cfg(feature = "regexp")] - { - let mut regexp_marks: Box<[RegExp]> = queues.regexps.drain(..).collect(); - regexp_marks.sort(); - regexp_marks.iter().for_each(|&idx| { + finalization_registry_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.regexps.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - regexps.get(index).mark_values(&mut queues); + if bits.finalization_registrys.set_bit(index, &bits.bits) { + // Did mark. + + finalization_registrys + .get(index as u32) + .mark_values(&mut queues); } }); } - #[cfg(feature = "regexp")] - { - let mut regexp_string_iterator_marks: Box<[RegExpStringIterator]> = - queues.regexp_string_iterators.drain(..).collect(); - regexp_string_iterator_marks.sort(); - regexp_string_iterator_marks.iter().for_each(|&idx| { + if !queues.generators.is_empty() { + let mut generator_marks: Box<[Generator]> = queues.generators.drain(..).collect(); + generator_marks.sort(); + generator_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.regexp_string_iterators.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - regexp_string_iterators.get(index).mark_values(&mut queues); + if bits.generators.set_bit(index, &bits.bits) { + // Did mark. + generators.get(index).mark_values(&mut queues); } }); } - #[cfg(feature = "set")] - { - let mut set_marks: Box<[Set]> = queues.sets.drain(..).collect(); - set_marks.sort(); - set_marks.iter().for_each(|&idx| { + if !queues.object_shapes.is_empty() { + let mut object_marks: Box<[ObjectShape]> = queues.object_shapes.drain(..).collect(); + object_marks.sort(); + object_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.sets.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - sets.get(index).mark_values(&mut queues); + if bits.object_shapes.set_bit(index, &bits.bits) { + // Did mark. + object_shapes.get(index).mark_values(&mut queues); + object_shape_transitions.get(index).mark_values(&mut queues); } }); - - let mut set_iterator_marks: Box<[SetIterator]> = - queues.set_iterators.drain(..).collect(); - set_iterator_marks.sort(); - set_iterator_marks.iter().for_each(|&idx| { + } + if !queues.objects.is_empty() { + let mut object_marks: Box<[OrdinaryObject]> = queues.objects.drain(..).collect(); + object_marks.sort(); + object_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.set_iterators.get_mut(index) { - if *marked { - // Already marked, ignore - return; + if bits.objects.set_bit(index, &bits.bits) { + // Did mark. + if let Some(rec) = objects.get(index) { + rec.mark_values(&mut queues, &agent.heap.object_shapes); } - *marked = true; - set_iterators.get(index).mark_values(&mut queues); } }); } - #[cfg(feature = "shared-array-buffer")] - { - let mut shared_array_buffer_marks: Box<[SharedArrayBuffer]> = - queues.shared_array_buffers.drain(..).collect(); - shared_array_buffer_marks.sort(); - shared_array_buffer_marks.iter().for_each(|&idx| { + if !queues.promises.is_empty() { + let mut promise_marks: Box<[Promise]> = queues.promises.drain(..).collect(); + promise_marks.sort(); + promise_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.shared_array_buffers.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - shared_array_buffers.get(index).mark_values(&mut queues); + if bits.promises.set_bit(index, &bits.bits) { + // Did mark. + promises.get(index).mark_values(&mut queues); } }); } - #[cfg(feature = "shared-array-buffer")] - { - let mut shared_data_view_marks: Box<[SharedDataView]> = - queues.shared_data_views.drain(..).collect(); - shared_data_view_marks.sort(); - shared_data_view_marks.iter().for_each(|&idx| { + if !queues.promise_reaction_records.is_empty() { + let mut promise_reaction_record_marks: Box<[PromiseReaction]> = + queues.promise_reaction_records.drain(..).collect(); + promise_reaction_record_marks.sort(); + promise_reaction_record_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.shared_data_views.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - shared_data_views.get(index).mark_values(&mut queues); + if bits.promise_reaction_records.set_bit(index, &bits.bits) { + // Did mark. + promise_reaction_records.get(index).mark_values(&mut queues); } }); } - #[cfg(feature = "shared-array-buffer")] - { - let mut shared_typed_array_marks: Box<[SharedVoidArray]> = - queues.shared_typed_arrays.drain(..).collect(); - shared_typed_array_marks.sort(); - shared_typed_array_marks.iter().for_each(|&idx| { + if !queues.promise_group_records.is_empty() { + let mut promise_group_record_marks: Box<[PromiseGroup]> = + queues.promise_group_records.drain(..).collect(); + promise_group_record_marks.sort(); + promise_group_record_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.shared_typed_arrays.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - shared_typed_arrays.get(index).mark_values(&mut queues); + if bits.promise_group_records.set_bit(index, &bits.bits) { + // Did mark. + promise_group_records.get(index).mark_values(&mut queues); } }); } - let mut source_text_module_record_marks: Box<[SourceTextModule]> = - queues.source_text_module_records.drain(..).collect(); - source_text_module_record_marks.sort(); - source_text_module_record_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.source_text_module_records.get_mut(index) { - if *marked { - // Already marked, ignore - return; + if !queues.promise_resolving_functions.is_empty() { + let mut promise_resolving_function_marks: Box<[BuiltinPromiseResolvingFunction]> = + queues.promise_resolving_functions.drain(..).collect(); + promise_resolving_function_marks.sort(); + promise_resolving_function_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.promise_resolving_functions.set_bit(index, &bits.bits) { + // Did mark. + promise_resolving_functions + .get(index) + .mark_values(&mut queues); } - *marked = true; - source_text_module_records - .get(index) - .mark_values(&mut queues); - } - }); - let mut string_generator_marks: Box<[StringIterator]> = - queues.string_iterators.drain(..).collect(); - string_generator_marks.sort(); - string_generator_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.string_iterators.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - string_iterators.get(index).mark_values(&mut queues); - } - }); - let mut string_marks: Box<[HeapString]> = queues.strings.drain(..).collect(); - string_marks.sort(); - string_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.strings.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - strings.get(index).mark_values(&mut queues); - } - }); - let mut symbol_marks: Box<[Symbol]> = queues.symbols.drain(..).collect(); - symbol_marks.sort(); - symbol_marks.iter().for_each(|&idx| { - let index = idx.get_index(); - if let Some(marked) = bits.symbols.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - symbols.get(index).mark_values(&mut queues); - } - }); - #[cfg(feature = "array-buffer")] - { - let mut typed_arrays_marks: Box<[VoidArray]> = queues.typed_arrays.drain(..).collect(); - typed_arrays_marks.sort(); - typed_arrays_marks.iter().for_each(|&idx| { + }); + } + if !queues.promise_finally_functions.is_empty() { + let mut promise_finally_function_marks: Box<[BuiltinPromiseFinallyFunction]> = + queues.promise_finally_functions.drain(..).collect(); + promise_finally_function_marks.sort(); + promise_finally_function_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.typed_arrays.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - typed_arrays.get(index).mark_values(&mut queues); + if bits.promise_finally_functions.set_bit(index, &bits.bits) { + // Did mark. + promise_finally_functions + .get(index) + .mark_values(&mut queues); } }); } - #[cfg(feature = "weak-refs")] - { - let mut weak_map_marks: Box<[WeakMap]> = queues.weak_maps.drain(..).collect(); - weak_map_marks.sort(); - weak_map_marks.iter().for_each(|&idx| { + if !queues.proxies.is_empty() { + let mut proxy_marks: Box<[Proxy]> = queues.proxies.drain(..).collect(); + proxy_marks.sort(); + proxy_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.weak_maps.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - weak_maps.get(index).mark_values(&mut queues); + if bits.proxies.set_bit(index, &bits.bits) { + // Did mark. + proxies.get(index).mark_values(&mut queues); } }); - let mut weak_ref_marks: Box<[WeakRef]> = queues.weak_refs.drain(..).collect(); - weak_ref_marks.sort(); - weak_ref_marks.iter().for_each(|&idx| { + } + if !queues.maps.is_empty() { + let mut map_marks: Box<[Map]> = queues.maps.drain(..).collect(); + map_marks.sort(); + map_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.weak_refs.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - weak_refs.get(index).mark_values(&mut queues); + if bits.maps.set_bit(index, &bits.bits) { + // Did mark. + maps.get(index).mark_values(&mut queues); } }); - let mut weak_set_marks: Box<[WeakSet]> = queues.weak_sets.drain(..).collect(); - weak_set_marks.sort(); - weak_set_marks.iter().for_each(|&idx| { + } + if !queues.map_iterators.is_empty() { + let mut map_iterator_marks: Box<[MapIterator]> = + queues.map_iterators.drain(..).collect(); + map_iterator_marks.sort(); + map_iterator_marks.iter().for_each(|&idx| { let index = idx.get_index(); - if let Some(marked) = bits.weak_sets.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - weak_sets.get(index).mark_values(&mut queues); + if bits.map_iterators.set_bit(index, &bits.bits) { + // Did mark. + map_iterators.get(index).mark_values(&mut queues); } }); } - - let mut e_2_1_marks: Box<[(ElementIndex, u32)]> = queues.e_2_1.drain(..).collect(); - e_2_1_marks.sort(); - e_2_1_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.e_2_1.get_mut(index) { - if *marked { - // Already marked, panic: Elements are uniquely owned - // and any other reference existing to this entry is a sign of - // a GC algorithm bug. - panic!("ElementsVector was not unique"); + if !queues.module_request_records.is_empty() { + let mut module_request_record_marks: Box<[ModuleRequest]> = + queues.module_request_records.drain(..).collect(); + module_request_record_marks.sort(); + module_request_record_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.module_request_records.set_bit(index, &bits.bits) { + // Did mark. + module_request_records.get(index).mark_values(&mut queues); } - *marked = true; - *length = len as u8; - if let Some(descriptors) = e2pow1.descriptors.get(&idx) { - mark_descriptors(descriptors, &mut queues); + }); + } + if !queues.numbers.is_empty() { + let mut number_marks: Box<[HeapNumber]> = queues.numbers.drain(..).collect(); + number_marks.sort(); + number_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.numbers.set_bit(index, &bits.bits) { + // Did mark. + numbers.get(index).mark_values(&mut queues); } - if let Some(array) = e2pow1.values.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.primitive_objects.is_empty() { + let mut primitive_object_marks: Box<[PrimitiveObject]> = + queues.primitive_objects.drain(..).collect(); + primitive_object_marks.sort(); + primitive_object_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.primitive_objects.set_bit(index, &bits.bits) { + // Did mark. + primitive_objects.get(index).mark_values(&mut queues); } + }); + } + #[cfg(feature = "regexp")] + { + if !queues.regexps.is_empty() { + let mut regexp_marks: Box<[RegExp]> = queues.regexps.drain(..).collect(); + regexp_marks.sort(); + regexp_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.regexps.set_bit(index, &bits.bits) { + // Did mark. + regexps.get(index).mark_values(&mut queues); + } + }); } - }); - let mut e_2_2_marks: Box<[(ElementIndex, u32)]> = queues.e_2_2.drain(..).collect(); - e_2_2_marks.sort(); - e_2_2_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.e_2_2.get_mut(index) { - if *marked { - // Already marked, panic: Elements are uniquely owned - // and any other reference existing to this entry is a sign of - // a GC algorithm bug. - panic!("ElementsVector was not unique"); - } - *marked = true; - *length = len as u8; - if let Some(descriptors) = e2pow2.descriptors.get(&idx) { - mark_descriptors(descriptors, &mut queues); - } - if let Some(array) = e2pow2.values.get(index) { - mark_array_with_u32_length(array, &mut queues, len); - } + if !queues.regexp_string_iterators.is_empty() { + let mut regexp_string_iterator_marks: Box<[RegExpStringIterator]> = + queues.regexp_string_iterators.drain(..).collect(); + regexp_string_iterator_marks.sort(); + regexp_string_iterator_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.regexp_string_iterators.set_bit(index, &bits.bits) { + // Did mark. + regexp_string_iterators.get(index).mark_values(&mut queues); + } + }); } - }); - let mut e_2_3_marks: Box<[(ElementIndex, u32)]> = queues.e_2_3.drain(..).collect(); - e_2_3_marks.sort(); - e_2_3_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.e_2_3.get_mut(index) { - if *marked { - // Already marked, panic: Elements are uniquely owned - // and any other reference existing to this entry is a sign of - // a GC algorithm bug. - panic!("ElementsVector was not unique"); - } - *marked = true; - *length = len as u8; - if let Some(descriptors) = e2pow3.descriptors.get(&idx) { - mark_descriptors(descriptors, &mut queues); - } - if let Some(array) = e2pow3.values.get(index) { - mark_array_with_u32_length(array, &mut queues, len); - } + } + #[cfg(feature = "set")] + { + if !queues.sets.is_empty() { + let mut set_marks: Box<[Set]> = queues.sets.drain(..).collect(); + set_marks.sort(); + set_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.sets.set_bit(index, &bits.bits) { + // Did mark. + sets.get(index).mark_values(&mut queues); + } + }); } - }); - let mut e_2_4_marks: Box<[(ElementIndex, u32)]> = queues.e_2_4.drain(..).collect(); - e_2_4_marks.sort(); - e_2_4_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.e_2_4.get_mut(index) { - if *marked { - // Already marked, panic: Elements are uniquely owned - // and any other reference existing to this entry is a sign of - // a GC algorithm bug. - panic!("ElementsVector was not unique"); - } - *marked = true; - *length = len as u8; - if let Some(descriptors) = e2pow4.descriptors.get(&idx) { - mark_descriptors(descriptors, &mut queues); - } - if let Some(array) = e2pow4.values.get(index) { - mark_array_with_u32_length(array, &mut queues, len); - } + + if !queues.set_iterators.is_empty() { + let mut set_iterator_marks: Box<[SetIterator]> = + queues.set_iterators.drain(..).collect(); + set_iterator_marks.sort(); + set_iterator_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.set_iterators.set_bit(index, &bits.bits) { + // Did mark. + set_iterators.get(index).mark_values(&mut queues); + } + }); } - }); - let mut e_2_6_marks: Box<[(ElementIndex, u32)]> = queues.e_2_6.drain(..).collect(); - e_2_6_marks.sort(); - e_2_6_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.e_2_6.get_mut(index) { - if *marked { - // Already marked, panic: Elements are uniquely owned - // and any other reference existing to this entry is a sign of - // a GC algorithm bug. - panic!("ElementsVector was not unique"); - } - *marked = true; - *length = len as u8; - if let Some(descriptors) = e2pow6.descriptors.get(&idx) { - mark_descriptors(descriptors, &mut queues); - } - if let Some(array) = e2pow6.values.get(index) { - mark_array_with_u32_length(array, &mut queues, len); - } + } + #[cfg(feature = "shared-array-buffer")] + { + if !queues.shared_array_buffers.is_empty() { + let mut shared_array_buffer_marks: Box<[SharedArrayBuffer]> = + queues.shared_array_buffers.drain(..).collect(); + shared_array_buffer_marks.sort(); + shared_array_buffer_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.shared_array_buffers.set_bit(index, &bits.bits) { + // Did mark. + shared_array_buffers.get(index).mark_values(&mut queues); + } + }); } - }); - let mut e_2_8_marks: Box<[(ElementIndex, u32)]> = queues.e_2_8.drain(..).collect(); - e_2_8_marks.sort(); - e_2_8_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.e_2_8.get_mut(index) { - if *marked { - // Already marked, panic: Elements are uniquely owned - // and any other reference existing to this entry is a sign of - // a GC algorithm bug. - panic!("ElementsVector was not unique"); - } - *marked = true; - *length = len as u8; - if let Some(descriptors) = e2pow8.descriptors.get(&idx) { - mark_descriptors(descriptors, &mut queues); + if !queues.shared_data_views.is_empty() { + let mut shared_data_view_marks: Box<[SharedDataView]> = + queues.shared_data_views.drain(..).collect(); + shared_data_view_marks.sort(); + shared_data_view_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.shared_data_views.set_bit(index, &bits.bits) { + // Did mark. + shared_data_views.get(index).mark_values(&mut queues); + } + }); + } + if !queues.shared_typed_arrays.is_empty() { + let mut shared_typed_array_marks: Box<[SharedVoidArray]> = + queues.shared_typed_arrays.drain(..).collect(); + shared_typed_array_marks.sort(); + shared_typed_array_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.shared_typed_arrays.set_bit(index, &bits.bits) { + // Did mark. + shared_typed_arrays.get(index).mark_values(&mut queues); + } + }); + } + } + if !queues.source_text_module_records.is_empty() { + let mut source_text_module_record_marks: Box<[SourceTextModule]> = + queues.source_text_module_records.drain(..).collect(); + source_text_module_record_marks.sort(); + source_text_module_record_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.source_text_module_records.set_bit(index, &bits.bits) { + // Did mark. + source_text_module_records + .get(index) + .mark_values(&mut queues); } - if let Some(array) = e2pow8.values.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.string_iterators.is_empty() { + let mut string_generator_marks: Box<[StringIterator]> = + queues.string_iterators.drain(..).collect(); + string_generator_marks.sort(); + string_generator_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.string_iterators.set_bit(index, &bits.bits) { + // Did mark. + string_iterators.get(index).mark_values(&mut queues); } - } - }); - let mut e_2_10_marks: Box<[(ElementIndex, u32)]> = queues.e_2_10.drain(..).collect(); - e_2_10_marks.sort(); - e_2_10_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.e_2_10.get_mut(index) { - if *marked { - // Already marked, panic: Elements are uniquely owned - // and any other reference existing to this entry is a sign of - // a GC algorithm bug. - panic!("ElementsVector was not unique"); + }); + } + if !queues.strings.is_empty() { + let mut string_marks: Box<[HeapString]> = queues.strings.drain(..).collect(); + string_marks.sort(); + string_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.strings.set_bit(index, &bits.bits) { + // Did mark. + strings.get(index).mark_values(&mut queues); } - *marked = true; - *length = len as u16; - if let Some(descriptors) = e2pow10.descriptors.get(&idx) { - mark_descriptors(descriptors, &mut queues); + }); + } + if !queues.symbols.is_empty() { + let mut symbol_marks: Box<[Symbol]> = queues.symbols.drain(..).collect(); + symbol_marks.sort(); + symbol_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.symbols.set_bit(index, &bits.bits) { + // Did mark. + symbols.get(index).mark_values(&mut queues); } - if let Some(array) = e2pow10.values.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + #[cfg(feature = "array-buffer")] + if !queues.typed_arrays.is_empty() { + let mut typed_arrays_marks: Box<[VoidArray]> = queues.typed_arrays.drain(..).collect(); + typed_arrays_marks.sort(); + typed_arrays_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.typed_arrays.set_bit(index, &bits.bits) { + // Did mark. + typed_arrays.get(index).mark_values(&mut queues); } + }); + } + #[cfg(feature = "weak-refs")] + { + if !queues.weak_maps.is_empty() { + let mut weak_map_marks: Box<[WeakMap]> = queues.weak_maps.drain(..).collect(); + weak_map_marks.sort(); + weak_map_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.weak_maps.set_bit(index, &bits.bits) { + // Did mark. + weak_maps.get(index).mark_values(&mut queues); + } + }); } - }); - let mut e_2_12_marks: Box<[(ElementIndex, u32)]> = queues.e_2_12.drain(..).collect(); - e_2_12_marks.sort(); - e_2_12_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.e_2_12.get_mut(index) { - if *marked { - // Already marked, panic: Elements are uniquely owned - // and any other reference existing to this entry is a sign of - // a GC algorithm bug. + if !queues.weak_refs.is_empty() { + let mut weak_ref_marks: Box<[WeakRef]> = queues.weak_refs.drain(..).collect(); + weak_ref_marks.sort(); + weak_ref_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.weak_refs.set_bit(index, &bits.bits) { + // Did mark. + weak_refs.get(index).mark_values(&mut queues); + } + }); + } + if !queues.weak_sets.is_empty() { + let mut weak_set_marks: Box<[WeakSet]> = queues.weak_sets.drain(..).collect(); + weak_set_marks.sort(); + weak_set_marks.iter().for_each(|&idx| { + let index = idx.get_index(); + if bits.weak_sets.set_bit(index, &bits.bits) { + // Did mark. + weak_sets.get(index).mark_values(&mut queues); + } + }); + } + } + + if !queues.e_2_1.is_empty() { + let mut e_2_1_marks: Box<[ElementIndex]> = queues.e_2_1.drain(..).collect(); + e_2_1_marks.sort(); + e_2_1_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.e_2_1.set_bit(index, &bits.bits) { + if let Some(descriptors) = e2pow1.descriptors.get(&idx) { + mark_descriptors(descriptors, &mut queues); + } + e2pow1.values.get(index).mark_values(&mut queues); + } else { panic!("ElementsVector was not unique"); } - *marked = true; - *length = len as u16; - if let Some(descriptors) = e2pow12.descriptors.get(&idx) { - mark_descriptors(descriptors, &mut queues); - } - if let Some(array) = e2pow12.values.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.e_2_2.is_empty() { + let mut e_2_2_marks: Box<[ElementIndex]> = queues.e_2_2.drain(..).collect(); + e_2_2_marks.sort(); + e_2_2_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.e_2_2.set_bit(index, &bits.bits) { + if let Some(descriptors) = e2pow2.descriptors.get(&idx) { + mark_descriptors(descriptors, &mut queues); + } + e2pow2.values.get(index).mark_values(&mut queues); + } else { + panic!("ElementsVector was not unique"); } - } - }); - let mut e_2_16_marks: Box<[(ElementIndex, u32)]> = queues.e_2_16.drain(..).collect(); - e_2_16_marks.sort(); - e_2_16_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.e_2_16.get_mut(index) { - if *marked { - // Already marked, panic: Elements are uniquely owned - // and any other reference existing to this entry is a sign of - // a GC algorithm bug. + }); + } + if !queues.e_2_3.is_empty() { + let mut e_2_3_marks: Box<[ElementIndex]> = queues.e_2_3.drain(..).collect(); + e_2_3_marks.sort(); + e_2_3_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.e_2_3.set_bit(index, &bits.bits) { + if let Some(descriptors) = e2pow3.descriptors.get(&idx) { + mark_descriptors(descriptors, &mut queues); + } + e2pow3.values.get(index).mark_values(&mut queues); + } else { panic!("ElementsVector was not unique"); } - *marked = true; - *length = len as u16; - if let Some(descriptors) = e2pow16.descriptors.get(&idx) { - mark_descriptors(descriptors, &mut queues); + }); + } + if !queues.e_2_4.is_empty() { + let mut e_2_4_marks: Box<[ElementIndex]> = queues.e_2_4.drain(..).collect(); + e_2_4_marks.sort(); + e_2_4_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.e_2_4.set_bit(index, &bits.bits) { + if let Some(descriptors) = e2pow4.descriptors.get(&idx) { + mark_descriptors(descriptors, &mut queues); + } + e2pow4.values.get(index).mark_values(&mut queues); + } else { + panic!("ElementsVector was not unique"); } - if let Some(array) = e2pow16.values.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.e_2_6.is_empty() { + let mut e_2_6_marks: Box<[ElementIndex]> = queues.e_2_6.drain(..).collect(); + e_2_6_marks.sort(); + e_2_6_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.e_2_6.set_bit(index, &bits.bits) { + if let Some(descriptors) = e2pow6.descriptors.get(&idx) { + mark_descriptors(descriptors, &mut queues); + } + e2pow6.values.get(index).mark_values(&mut queues); + } else { + panic!("ElementsVector was not unique"); } - } - }); - let mut e_2_24_marks: Box<[(ElementIndex, u32)]> = queues.e_2_24.drain(..).collect(); - e_2_24_marks.sort(); - e_2_24_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.e_2_24.get_mut(index) { - if *marked { - // Already marked, panic: Elements are uniquely owned - // and any other reference existing to this entry is a sign of - // a GC algorithm bug. + }); + } + if !queues.e_2_8.is_empty() { + let mut e_2_8_marks: Box<[ElementIndex]> = queues.e_2_8.drain(..).collect(); + e_2_8_marks.sort(); + e_2_8_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.e_2_8.set_bit(index, &bits.bits) { + if let Some(descriptors) = e2pow8.descriptors.get(&idx) { + mark_descriptors(descriptors, &mut queues); + } + e2pow8.values.get(index).mark_values(&mut queues); + } else { panic!("ElementsVector was not unique"); } - *marked = true; - *length = len; - if let Some(descriptors) = e2pow24.descriptors.get(&idx) { - mark_descriptors(descriptors, &mut queues); + }); + } + if !queues.e_2_10.is_empty() { + let mut e_2_10_marks: Box<[ElementIndex]> = queues.e_2_10.drain(..).collect(); + e_2_10_marks.sort(); + e_2_10_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.e_2_10.set_bit(index, &bits.bits) { + if let Some(descriptors) = e2pow10.descriptors.get(&idx) { + mark_descriptors(descriptors, &mut queues); + } + e2pow10.values.get(index).mark_values(&mut queues); + } else { + panic!("ElementsVector was not unique"); } - if let Some(array) = e2pow24.values.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.e_2_12.is_empty() { + let mut e_2_12_marks: Box<[ElementIndex]> = queues.e_2_12.drain(..).collect(); + e_2_12_marks.sort(); + e_2_12_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.e_2_12.set_bit(index, &bits.bits) { + if let Some(descriptors) = e2pow12.descriptors.get(&idx) { + mark_descriptors(descriptors, &mut queues); + } + e2pow12.values.get(index).mark_values(&mut queues); + } else { + panic!("ElementsVector was not unique"); } - } - }); - let mut e_2_32_marks: Box<[(ElementIndex, u32)]> = queues.e_2_32.drain(..).collect(); - e_2_32_marks.sort(); - e_2_32_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.e_2_32.get_mut(index) { - if *marked { - // Already marked, panic: Elements are uniquely owned - // and any other reference existing to this entry is a sign of - // a GC algorithm bug. + }); + } + if !queues.e_2_16.is_empty() { + let mut e_2_16_marks: Box<[ElementIndex]> = queues.e_2_16.drain(..).collect(); + e_2_16_marks.sort(); + e_2_16_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.e_2_16.set_bit(index, &bits.bits) { + if let Some(descriptors) = e2pow16.descriptors.get(&idx) { + mark_descriptors(descriptors, &mut queues); + } + e2pow16.values.get(index).mark_values(&mut queues); + } else { panic!("ElementsVector was not unique"); } - *marked = true; - *length = len; - if let Some(descriptors) = e2pow32.descriptors.get(&idx) { - mark_descriptors(descriptors, &mut queues); + }); + } + if !queues.e_2_24.is_empty() { + let mut e_2_24_marks: Box<[ElementIndex]> = queues.e_2_24.drain(..).collect(); + e_2_24_marks.sort(); + e_2_24_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.e_2_24.set_bit(index, &bits.bits) { + if let Some(descriptors) = e2pow24.descriptors.get(&idx) { + mark_descriptors(descriptors, &mut queues); + } + e2pow24.values.get(index).mark_values(&mut queues); + } else { + panic!("ElementsVector was not unique"); } - if let Some(array) = e2pow32.values.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.e_2_32.is_empty() { + let mut e_2_32_marks: Box<[ElementIndex]> = queues.e_2_32.drain(..).collect(); + e_2_32_marks.sort(); + e_2_32_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.e_2_32.set_bit(index, &bits.bits) { + if let Some(descriptors) = e2pow32.descriptors.get(&idx) { + mark_descriptors(descriptors, &mut queues); + } + e2pow32.values.get(index).mark_values(&mut queues); + } else { + panic!("ElementsVector was not unique"); } - } - }); + }); + } - let mut k_2_4_marks: Box<[(PropertyKeyIndex, u32)]> = queues.k_2_4.drain(..).collect(); - k_2_4_marks.sort(); - k_2_4_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.k_2_4.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - *length = len as u8; - if let Some(array) = k2pow4.keys.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + if !queues.k_2_4.is_empty() { + let mut k_2_4_marks: Box<[PropertyKeyIndex]> = queues.k_2_4.drain(..).collect(); + k_2_4_marks.sort(); + k_2_4_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.k_2_4.set_bit(index, &bits.bits) { + k2pow4.keys.get(index).mark_values(&mut queues) } - } - }); - let mut k_2_1_marks: Box<[(PropertyKeyIndex, u32)]> = queues.k_2_1.drain(..).collect(); - k_2_1_marks.sort(); - k_2_1_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.k_2_1.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - *length = len as u8; - if let Some(array) = k2pow1.keys.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.k_2_1.is_empty() { + let mut k_2_1_marks: Box<[PropertyKeyIndex]> = queues.k_2_1.drain(..).collect(); + k_2_1_marks.sort(); + k_2_1_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.k_2_1.set_bit(index, &bits.bits) { + k2pow1.keys.get(index).mark_values(&mut queues) } - } - }); - let mut k_2_2_marks: Box<[(PropertyKeyIndex, u32)]> = queues.k_2_2.drain(..).collect(); - k_2_2_marks.sort(); - k_2_2_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.k_2_2.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - *length = len as u8; - if let Some(array) = k2pow2.keys.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.k_2_2.is_empty() { + let mut k_2_2_marks: Box<[PropertyKeyIndex]> = queues.k_2_2.drain(..).collect(); + k_2_2_marks.sort(); + k_2_2_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.k_2_2.set_bit(index, &bits.bits) { + k2pow2.keys.get(index).mark_values(&mut queues) } - } - }); - let mut k_2_3_marks: Box<[(PropertyKeyIndex, u32)]> = queues.k_2_3.drain(..).collect(); - k_2_3_marks.sort(); - k_2_3_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.k_2_3.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - *length = len as u8; - if let Some(array) = k2pow3.keys.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.k_2_3.is_empty() { + let mut k_2_3_marks: Box<[PropertyKeyIndex]> = queues.k_2_3.drain(..).collect(); + k_2_3_marks.sort(); + k_2_3_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.k_2_3.set_bit(index, &bits.bits) { + k2pow3.keys.get(index).mark_values(&mut queues) } - } - }); - let mut k_2_6_marks: Box<[(PropertyKeyIndex, u32)]> = queues.k_2_6.drain(..).collect(); - k_2_6_marks.sort(); - k_2_6_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.k_2_6.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - *length = len as u8; - if let Some(array) = k2pow6.keys.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.k_2_6.is_empty() { + let mut k_2_6_marks: Box<[PropertyKeyIndex]> = queues.k_2_6.drain(..).collect(); + k_2_6_marks.sort(); + k_2_6_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.k_2_6.set_bit(index, &bits.bits) { + k2pow6.keys.get(index).mark_values(&mut queues) } - } - }); - let mut k_2_8_marks: Box<[(PropertyKeyIndex, u32)]> = queues.k_2_8.drain(..).collect(); - k_2_8_marks.sort(); - k_2_8_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.k_2_8.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - *length = len as u8; - if let Some(array) = k2pow8.keys.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.k_2_8.is_empty() { + let mut k_2_8_marks: Box<[PropertyKeyIndex]> = queues.k_2_8.drain(..).collect(); + k_2_8_marks.sort(); + k_2_8_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.k_2_8.set_bit(index, &bits.bits) { + k2pow8.keys.get(index).mark_values(&mut queues) } - } - }); - let mut k_2_10_marks: Box<[(PropertyKeyIndex, u32)]> = queues.k_2_10.drain(..).collect(); - k_2_10_marks.sort(); - k_2_10_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.k_2_10.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - *length = len as u16; - if let Some(array) = k2pow10.keys.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.k_2_10.is_empty() { + let mut k_2_10_marks: Box<[PropertyKeyIndex]> = queues.k_2_10.drain(..).collect(); + k_2_10_marks.sort(); + k_2_10_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.k_2_10.set_bit(index, &bits.bits) { + k2pow10.keys.get(index).mark_values(&mut queues) } - } - }); - let mut k_2_12_marks: Box<[(PropertyKeyIndex, u32)]> = queues.k_2_12.drain(..).collect(); - k_2_12_marks.sort(); - k_2_12_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.k_2_12.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - *length = len as u16; - if let Some(array) = k2pow12.keys.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.k_2_12.is_empty() { + let mut k_2_12_marks: Box<[PropertyKeyIndex]> = queues.k_2_12.drain(..).collect(); + k_2_12_marks.sort(); + k_2_12_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.k_2_12.set_bit(index, &bits.bits) { + k2pow12.keys.get(index).mark_values(&mut queues) } - } - }); - let mut k_2_16_marks: Box<[(PropertyKeyIndex, u32)]> = queues.k_2_16.drain(..).collect(); - k_2_16_marks.sort(); - k_2_16_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.k_2_16.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - *length = len as u16; - if let Some(array) = k2pow16.keys.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.k_2_16.is_empty() { + let mut k_2_16_marks: Box<[PropertyKeyIndex]> = queues.k_2_16.drain(..).collect(); + k_2_16_marks.sort(); + k_2_16_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.k_2_16.set_bit(index, &bits.bits) { + k2pow16.keys.get(index).mark_values(&mut queues) } - } - }); - let mut k_2_24_marks: Box<[(PropertyKeyIndex, u32)]> = queues.k_2_24.drain(..).collect(); - k_2_24_marks.sort(); - k_2_24_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.k_2_24.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - *length = len; - if let Some(array) = k2pow24.keys.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.k_2_24.is_empty() { + let mut k_2_24_marks: Box<[PropertyKeyIndex]> = queues.k_2_24.drain(..).collect(); + k_2_24_marks.sort(); + k_2_24_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.k_2_24.set_bit(index, &bits.bits) { + k2pow24.keys.get(index).mark_values(&mut queues) } - } - }); - let mut k_2_32_marks: Box<[(PropertyKeyIndex, u32)]> = queues.k_2_32.drain(..).collect(); - k_2_32_marks.sort(); - k_2_32_marks.iter().for_each(|&(idx, len)| { - let index = idx.into_index(); - if let Some((marked, length)) = bits.k_2_32.get_mut(index) { - if *marked { - // Already marked, ignore - return; - } - *marked = true; - *length = len; - if let Some(array) = k2pow32.keys.get(index) { - mark_array_with_u32_length(array, &mut queues, len); + }); + } + if !queues.k_2_32.is_empty() { + let mut k_2_32_marks: Box<[PropertyKeyIndex]> = queues.k_2_32.drain(..).collect(); + k_2_32_marks.sort(); + k_2_32_marks.iter().for_each(|&idx| { + let index = idx.into_index(); + if bits.k_2_32.set_bit(index, &bits.bits) { + k2pow32.keys.get(index).mark_values(&mut queues) } - } - }); + }); + } } sweep(agent, &bits, root_realms, gc); @@ -1606,7 +1374,7 @@ fn sweep( }); s.spawn(|| { - caches.sweep_cache(&compactions, &bits.caches); + caches.sweep_cache(&compactions, &bits.caches, &bits.bits); caches.sweep_values(&compactions); }); @@ -1622,8 +1390,9 @@ fn sweep( &compactions, &compactions.e_2_1, &bits.e_2_1, + &bits.bits, ); - sweep_heap_u8_elements_vector_values(&mut e2pow1.values, &compactions, &bits.e_2_1); + sweep_heap_vector_values(&mut e2pow1.values, &compactions, &bits.e_2_1, &bits.bits); }); } if !e2pow2.values.is_empty() { @@ -1633,8 +1402,9 @@ fn sweep( &compactions, &compactions.e_2_2, &bits.e_2_2, + &bits.bits, ); - sweep_heap_u8_elements_vector_values(&mut e2pow2.values, &compactions, &bits.e_2_2); + sweep_heap_vector_values(&mut e2pow2.values, &compactions, &bits.e_2_2, &bits.bits); }); } if !e2pow3.values.is_empty() { @@ -1644,8 +1414,9 @@ fn sweep( &compactions, &compactions.e_2_3, &bits.e_2_3, + &bits.bits, ); - sweep_heap_u8_elements_vector_values(&mut e2pow3.values, &compactions, &bits.e_2_3); + sweep_heap_vector_values(&mut e2pow3.values, &compactions, &bits.e_2_3, &bits.bits); }); } if !e2pow4.values.is_empty() { @@ -1655,8 +1426,9 @@ fn sweep( &compactions, &compactions.e_2_4, &bits.e_2_4, + &bits.bits, ); - sweep_heap_u8_elements_vector_values(&mut e2pow4.values, &compactions, &bits.e_2_4); + sweep_heap_vector_values(&mut e2pow4.values, &compactions, &bits.e_2_4, &bits.bits); }); } if !e2pow6.values.is_empty() { @@ -1666,8 +1438,9 @@ fn sweep( &compactions, &compactions.e_2_6, &bits.e_2_6, + &bits.bits, ); - sweep_heap_u8_elements_vector_values(&mut e2pow6.values, &compactions, &bits.e_2_6); + sweep_heap_vector_values(&mut e2pow6.values, &compactions, &bits.e_2_6, &bits.bits); }); } if !e2pow8.values.is_empty() { @@ -1677,8 +1450,9 @@ fn sweep( &compactions, &compactions.e_2_8, &bits.e_2_8, + &bits.bits, ); - sweep_heap_u8_elements_vector_values(&mut e2pow8.values, &compactions, &bits.e_2_8); + sweep_heap_vector_values(&mut e2pow8.values, &compactions, &bits.e_2_8, &bits.bits); }); } if !e2pow10.values.is_empty() { @@ -1688,11 +1462,13 @@ fn sweep( &compactions, &compactions.e_2_10, &bits.e_2_10, + &bits.bits, ); - sweep_heap_u16_elements_vector_values( + sweep_heap_vector_values( &mut e2pow10.values, &compactions, &bits.e_2_10, + &bits.bits, ); }); } @@ -1703,11 +1479,13 @@ fn sweep( &compactions, &compactions.e_2_12, &bits.e_2_12, + &bits.bits, ); - sweep_heap_u16_elements_vector_values( + sweep_heap_vector_values( &mut e2pow12.values, &compactions, &bits.e_2_12, + &bits.bits, ); }); } @@ -1718,11 +1496,13 @@ fn sweep( &compactions, &compactions.e_2_16, &bits.e_2_16, + &bits.bits, ); - sweep_heap_u16_elements_vector_values( + sweep_heap_vector_values( &mut e2pow16.values, &compactions, &bits.e_2_16, + &bits.bits, ); }); } @@ -1733,11 +1513,13 @@ fn sweep( &compactions, &compactions.e_2_24, &bits.e_2_24, + &bits.bits, ); - sweep_heap_u32_elements_vector_values( + sweep_heap_vector_values( &mut e2pow24.values, &compactions, &bits.e_2_24, + &bits.bits, ); }); } @@ -1748,104 +1530,131 @@ fn sweep( &compactions, &compactions.e_2_32, &bits.e_2_32, + &bits.bits, ); - sweep_heap_u32_elements_vector_values( + sweep_heap_vector_values( &mut e2pow32.values, &compactions, &bits.e_2_32, + &bits.bits, ); }); } if !k2pow1.keys.is_empty() { s.spawn(|| { - sweep_heap_u8_property_key_vector(&mut k2pow1.keys, &compactions, &bits.k_2_1); + sweep_heap_vector_values(&mut k2pow1.keys, &compactions, &bits.k_2_1, &bits.bits); }); } if !k2pow2.keys.is_empty() { s.spawn(|| { - sweep_heap_u8_property_key_vector(&mut k2pow2.keys, &compactions, &bits.k_2_2); + sweep_heap_vector_values(&mut k2pow2.keys, &compactions, &bits.k_2_2, &bits.bits); }); } if !k2pow3.keys.is_empty() { s.spawn(|| { - sweep_heap_u8_property_key_vector(&mut k2pow3.keys, &compactions, &bits.k_2_3); + sweep_heap_vector_values(&mut k2pow3.keys, &compactions, &bits.k_2_3, &bits.bits); }); } if !k2pow4.keys.is_empty() { s.spawn(|| { - sweep_heap_u8_property_key_vector(&mut k2pow4.keys, &compactions, &bits.k_2_4); + sweep_heap_vector_values(&mut k2pow4.keys, &compactions, &bits.k_2_4, &bits.bits); }); } if !k2pow6.keys.is_empty() { s.spawn(|| { - sweep_heap_u8_property_key_vector(&mut k2pow6.keys, &compactions, &bits.k_2_6); + sweep_heap_vector_values(&mut k2pow6.keys, &compactions, &bits.k_2_6, &bits.bits); }); } if !k2pow8.keys.is_empty() { s.spawn(|| { - sweep_heap_u8_property_key_vector(&mut k2pow8.keys, &compactions, &bits.k_2_8); + sweep_heap_vector_values(&mut k2pow8.keys, &compactions, &bits.k_2_8, &bits.bits); }); } if !k2pow10.keys.is_empty() { s.spawn(|| { - sweep_heap_u16_property_key_vector(&mut k2pow10.keys, &compactions, &bits.k_2_10); + sweep_heap_vector_values(&mut k2pow10.keys, &compactions, &bits.k_2_10, &bits.bits); }); } if !k2pow12.keys.is_empty() { s.spawn(|| { - sweep_heap_u16_property_key_vector(&mut k2pow12.keys, &compactions, &bits.k_2_12); + sweep_heap_vector_values(&mut k2pow12.keys, &compactions, &bits.k_2_12, &bits.bits); }); } if !k2pow16.keys.is_empty() { s.spawn(|| { - sweep_heap_u16_property_key_vector(&mut k2pow16.keys, &compactions, &bits.k_2_16); + sweep_heap_vector_values(&mut k2pow16.keys, &compactions, &bits.k_2_16, &bits.bits); }); } if !k2pow24.keys.is_empty() { s.spawn(|| { - sweep_heap_u32_property_key_vector(&mut k2pow24.keys, &compactions, &bits.k_2_24); + sweep_heap_vector_values(&mut k2pow24.keys, &compactions, &bits.k_2_24, &bits.bits); }); } if !k2pow32.keys.is_empty() { s.spawn(|| { - sweep_heap_u32_property_key_vector(&mut k2pow32.keys, &compactions, &bits.k_2_32); + sweep_heap_vector_values(&mut k2pow32.keys, &compactions, &bits.k_2_32, &bits.bits); }); } #[cfg(feature = "array-buffer")] if !array_buffers.is_empty() { s.spawn(|| { - sweep_heap_vector_values(array_buffers, &compactions, &bits.array_buffers); + sweep_heap_vector_values( + array_buffers, + &compactions, + &bits.array_buffers, + &bits.bits, + ); sweep_side_table_values(array_buffer_detach_keys, &compactions); }); } if !arrays.is_empty() { s.spawn(|| { - sweep_heap_soa_vector_values(arrays, &compactions, &bits.arrays); + sweep_heap_soa_vector_values(arrays, &compactions, &bits.arrays, &bits.bits); }); } if !array_iterators.is_empty() { s.spawn(|| { - sweep_heap_vector_values(array_iterators, &compactions, &bits.array_iterators); + sweep_heap_vector_values( + array_iterators, + &compactions, + &bits.array_iterators, + &bits.bits, + ); }); } if !async_generators.is_empty() { s.spawn(|| { - sweep_heap_vector_values(async_generators, &compactions, &bits.async_generators); + sweep_heap_vector_values( + async_generators, + &compactions, + &bits.async_generators, + &bits.bits, + ); }); } if !await_reactions.is_empty() { s.spawn(|| { - sweep_heap_vector_values(await_reactions, &compactions, &bits.await_reactions); + sweep_heap_vector_values( + await_reactions, + &compactions, + &bits.await_reactions, + &bits.bits, + ); }); } if !bigints.is_empty() { s.spawn(|| { - sweep_heap_vector_values(bigints, &compactions, &bits.bigints); + sweep_heap_vector_values(bigints, &compactions, &bits.bigints, &bits.bits); }); } if !bound_functions.is_empty() { s.spawn(|| { - sweep_heap_vector_values(bound_functions, &compactions, &bits.bound_functions); + sweep_heap_vector_values( + bound_functions, + &compactions, + &bits.bound_functions, + &bits.bits, + ); }); } if !builtin_constructors.is_empty() { @@ -1854,18 +1663,24 @@ fn sweep( builtin_constructors, &compactions, &bits.builtin_constructors, + &bits.bits, ); }); } if !builtin_functions.is_empty() { s.spawn(|| { - sweep_heap_vector_values(builtin_functions, &compactions, &bits.builtin_functions); + sweep_heap_vector_values( + builtin_functions, + &compactions, + &bits.builtin_functions, + &bits.bits, + ); }); } #[cfg(feature = "array-buffer")] if !data_views.is_empty() { s.spawn(|| { - sweep_heap_vector_values(data_views, &compactions, &bits.data_views); + sweep_heap_vector_values(data_views, &compactions, &bits.data_views, &bits.bits); sweep_side_table_values(data_view_byte_lengths, &compactions); sweep_side_table_values(data_view_byte_offsets, &compactions); }); @@ -1873,7 +1688,12 @@ fn sweep( #[cfg(feature = "shared-array-buffer")] if !shared_data_views.is_empty() { s.spawn(|| { - sweep_heap_vector_values(shared_data_views, &compactions, &bits.shared_data_views); + sweep_heap_vector_values( + shared_data_views, + &compactions, + &bits.shared_data_views, + &bits.bits, + ); sweep_side_table_values(shared_data_view_byte_lengths, &compactions); sweep_side_table_values(shared_data_view_byte_offsets, &compactions); }); @@ -1881,12 +1701,17 @@ fn sweep( #[cfg(feature = "date")] if !dates.is_empty() { s.spawn(|| { - sweep_heap_vector_values(dates, &compactions, &bits.dates); + sweep_heap_vector_values(dates, &compactions, &bits.dates, &bits.bits); }); } if !declarative.is_empty() { s.spawn(|| { - sweep_heap_vector_values(declarative, &compactions, &bits.declarative_environments); + sweep_heap_vector_values( + declarative, + &compactions, + &bits.declarative_environments, + &bits.bits, + ); }); } if !ecmascript_functions.is_empty() { @@ -1895,22 +1720,28 @@ fn sweep( ecmascript_functions, &compactions, &bits.ecmascript_functions, + &bits.bits, ); }); } if !embedder_objects.is_empty() { s.spawn(|| { - sweep_heap_vector_values(embedder_objects, &compactions, &bits.embedder_objects); + sweep_heap_vector_values( + embedder_objects, + &compactions, + &bits.embedder_objects, + &bits.bits, + ); }); } if !errors.is_empty() { s.spawn(|| { - sweep_heap_vector_values(errors, &compactions, &bits.errors); + sweep_heap_vector_values(errors, &compactions, &bits.errors, &bits.bits); }); } if !executables.is_empty() { s.spawn(|| { - sweep_heap_vector_values(executables, &compactions, &bits.executables); + sweep_heap_vector_values(executables, &compactions, &bits.executables, &bits.bits); }); } if !finalization_registrys.is_empty() { @@ -1919,42 +1750,63 @@ fn sweep( finalization_registrys, &compactions, &bits.finalization_registrys, + &bits.bits, ); }); } if !function.is_empty() { s.spawn(|| { - sweep_heap_vector_values(function, &compactions, &bits.function_environments); + sweep_heap_vector_values( + function, + &compactions, + &bits.function_environments, + &bits.bits, + ); }); } if !generators.is_empty() { s.spawn(|| { - sweep_heap_vector_values(generators, &compactions, &bits.generators); + sweep_heap_vector_values(generators, &compactions, &bits.generators, &bits.bits); }); } if !global.is_empty() { s.spawn(|| { - sweep_heap_vector_values(global, &compactions, &bits.global_environments); + sweep_heap_vector_values( + global, + &compactions, + &bits.global_environments, + &bits.bits, + ); }); } if !module.is_empty() { s.spawn(|| { - sweep_heap_vector_values(module, &compactions, &bits.module_environments); + sweep_heap_vector_values( + module, + &compactions, + &bits.module_environments, + &bits.bits, + ); }); } if !maps.is_empty() { s.spawn(|| { - sweep_heap_vector_values(maps, &compactions, &bits.maps); + sweep_heap_vector_values(maps, &compactions, &bits.maps, &bits.bits); }); } if !map_iterators.is_empty() { s.spawn(|| { - sweep_heap_vector_values(map_iterators, &compactions, &bits.map_iterators); + sweep_heap_vector_values( + map_iterators, + &compactions, + &bits.map_iterators, + &bits.bits, + ); }); } if !modules.is_empty() { s.spawn(|| { - sweep_heap_vector_values(modules, &compactions, &bits.modules); + sweep_heap_vector_values(modules, &compactions, &bits.modules, &bits.bits); }); } if !module_request_records.is_empty() { @@ -1963,17 +1815,23 @@ fn sweep( module_request_records, &compactions, &bits.module_request_records, + &bits.bits, ); }); } if !numbers.is_empty() { s.spawn(|| { - sweep_heap_vector_values(numbers, &compactions, &bits.numbers); + sweep_heap_vector_values(numbers, &compactions, &bits.numbers, &bits.bits); }); } if !object.is_empty() { s.spawn(|| { - sweep_heap_vector_values(object, &compactions, &bits.object_environments); + sweep_heap_vector_values( + object, + &compactions, + &bits.object_environments, + &bits.bits, + ); }); } if !object_shapes.is_empty() { @@ -1982,17 +1840,23 @@ fn sweep( object_shape_transitions, &compactions, &bits.object_shapes, + &bits.bits, ); }); } if !object_shapes.is_empty() || !objects.is_empty() { s.spawn(|| { - sweep_heap_vector_values(object_shapes, &compactions, &bits.object_shapes); + sweep_heap_vector_values( + object_shapes, + &compactions, + &bits.object_shapes, + &bits.bits, + ); assert_eq!(objects.len(), bits.objects.len()); - let mut iter = bits.objects.iter(); + let mut iter = bits.objects.iter(&bits.bits); objects.retain_mut(|item| { let do_retain = iter.next().unwrap(); - if *do_retain { + if do_retain { item.sweep_values(&compactions, object_shapes); true } else { @@ -2003,7 +1867,12 @@ fn sweep( } if !primitive_objects.is_empty() { s.spawn(|| { - sweep_heap_vector_values(primitive_objects, &compactions, &bits.primitive_objects); + sweep_heap_vector_values( + primitive_objects, + &compactions, + &bits.primitive_objects, + &bits.bits, + ); }); } if !promise_reaction_records.is_empty() { @@ -2012,6 +1881,7 @@ fn sweep( promise_reaction_records, &compactions, &bits.promise_reaction_records, + &bits.bits, ); }); } @@ -2021,6 +1891,7 @@ fn sweep( promise_resolving_functions, &compactions, &bits.promise_resolving_functions, + &bits.bits, ); }); } @@ -2030,12 +1901,13 @@ fn sweep( promise_finally_functions, &compactions, &bits.promise_finally_functions, + &bits.bits, ); }); } if !promises.is_empty() { s.spawn(|| { - sweep_heap_vector_values(promises, &compactions, &bits.promises); + sweep_heap_vector_values(promises, &compactions, &bits.promises, &bits.bits); }); } if !promise_group_records.is_empty() { @@ -2044,23 +1916,24 @@ fn sweep( promise_group_records, &compactions, &bits.promise_group_records, + &bits.bits, ); }); } if !proxies.is_empty() { s.spawn(|| { - sweep_heap_vector_values(proxies, &compactions, &bits.proxies); + sweep_heap_vector_values(proxies, &compactions, &bits.proxies, &bits.bits); }); } if !realms.is_empty() { s.spawn(|| { - sweep_heap_vector_values(realms, &compactions, &bits.realms); + sweep_heap_vector_values(realms, &compactions, &bits.realms, &bits.bits); }); } #[cfg(feature = "regexp")] if !regexps.is_empty() { s.spawn(|| { - sweep_heap_vector_values(regexps, &compactions, &bits.regexps); + sweep_heap_vector_values(regexps, &compactions, &bits.regexps, &bits.bits); }); } #[cfg(feature = "regexp")] @@ -2070,24 +1943,30 @@ fn sweep( regexp_string_iterators, &compactions, &bits.regexp_string_iterators, + &bits.bits, ); }); } if !scripts.is_empty() { s.spawn(|| { - sweep_heap_vector_values(scripts, &compactions, &bits.scripts); + sweep_heap_vector_values(scripts, &compactions, &bits.scripts, &bits.bits); }); } #[cfg(feature = "set")] if !sets.is_empty() { s.spawn(|| { - sweep_heap_vector_values(sets, &compactions, &bits.sets); + sweep_heap_vector_values(sets, &compactions, &bits.sets, &bits.bits); }); } #[cfg(feature = "set")] if !set_iterators.is_empty() { s.spawn(|| { - sweep_heap_vector_values(set_iterators, &compactions, &bits.set_iterators); + sweep_heap_vector_values( + set_iterators, + &compactions, + &bits.set_iterators, + &bits.bits, + ); }); } #[cfg(feature = "shared-array-buffer")] @@ -2097,6 +1976,7 @@ fn sweep( shared_array_buffers, &compactions, &bits.shared_array_buffers, + &bits.bits, ); }); } @@ -2106,34 +1986,50 @@ fn sweep( source_text_module_records, &compactions, &bits.source_text_module_records, + &bits.bits, ); }); } if !source_codes.is_empty() { s.spawn(|| { - sweep_heap_vector_values(source_codes, &compactions, &bits.source_codes); + sweep_heap_vector_values( + source_codes, + &compactions, + &bits.source_codes, + &bits.bits, + ); }); } if !string_iterators.is_empty() { s.spawn(|| { - sweep_heap_vector_values(string_iterators, &compactions, &bits.string_iterators); + sweep_heap_vector_values( + string_iterators, + &compactions, + &bits.string_iterators, + &bits.bits, + ); }); } if !strings.is_empty() { s.spawn(|| { - sweep_heap_vector_values(strings, &compactions, &bits.strings); + sweep_heap_vector_values(strings, &compactions, &bits.strings, &bits.bits); sweep_lookup_table(string_lookup_table, &compactions); }); } if !symbols.is_empty() { s.spawn(|| { - sweep_heap_vector_values(symbols, &compactions, &bits.symbols); + sweep_heap_vector_values(symbols, &compactions, &bits.symbols, &bits.bits); }); } #[cfg(feature = "array-buffer")] if !typed_arrays.is_empty() { s.spawn(|| { - sweep_heap_vector_values(typed_arrays, &compactions, &bits.typed_arrays); + sweep_heap_vector_values( + typed_arrays, + &compactions, + &bits.typed_arrays, + &bits.bits, + ); sweep_side_table_values(typed_array_byte_lengths, &compactions); sweep_side_table_values(typed_array_byte_offsets, &compactions); sweep_side_table_values(typed_array_array_lengths, &compactions); @@ -2146,6 +2042,7 @@ fn sweep( shared_typed_arrays, &compactions, &bits.shared_typed_arrays, + &bits.bits, ); sweep_side_table_values(shared_typed_array_byte_lengths, &compactions); sweep_side_table_values(shared_typed_array_byte_offsets, &compactions); @@ -2155,19 +2052,19 @@ fn sweep( #[cfg(feature = "weak-refs")] if !weak_maps.is_empty() { s.spawn(|| { - sweep_heap_vector_values(weak_maps, &compactions, &bits.weak_maps); + sweep_heap_vector_values(weak_maps, &compactions, &bits.weak_maps, &bits.bits); }); } #[cfg(feature = "weak-refs")] if !weak_refs.is_empty() { s.spawn(|| { - sweep_heap_vector_values(weak_refs, &compactions, &bits.weak_refs); + sweep_heap_vector_values(weak_refs, &compactions, &bits.weak_refs, &bits.bits); }); } #[cfg(feature = "weak-refs")] if !weak_sets.is_empty() { s.spawn(|| { - sweep_heap_vector_values(weak_sets, &compactions, &bits.weak_sets); + sweep_heap_vector_values(weak_sets, &compactions, &bits.weak_sets, &bits.bits); }); } }); diff --git a/nova_vm/src/heap/indexes.rs b/nova_vm/src/heap/indexes.rs index 8632754b7..46b2ebade 100644 --- a/nova_vm/src/heap/indexes.rs +++ b/nova_vm/src/heap/indexes.rs @@ -169,7 +169,7 @@ impl Default for ElementIndex<'static> { #[inline(always)] fn default() -> Self { Self( - unsafe { NonZeroU32::new_unchecked(1) }, + const { NonZeroU32::new(1).unwrap() }, PhantomData, PhantomData, ) @@ -203,7 +203,7 @@ impl IndexMut> for Vec<[Option>; impl Default for PropertyKeyIndex<'static> { fn default() -> Self { Self( - unsafe { NonZeroU32::new_unchecked(1) }, + const { NonZeroU32::new(1).unwrap() }, PhantomData, PhantomData, ) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 43e5784a1..cdeba7a2b 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.90.0" +channel = "1.91.0" components = ["rustfmt", "clippy"] diff --git a/tests/expectations.json b/tests/expectations.json index 63b0f23af..2081d38d4 100644 --- a/tests/expectations.json +++ b/tests/expectations.json @@ -415,8 +415,6 @@ "built-ins/Error/isError/symbols.js": "FAIL", "built-ins/Error/proto-from-ctor-realm.js": "FAIL", "built-ins/FinalizationRegistry/proto-from-ctor-realm.js": "FAIL", - "built-ins/FinalizationRegistry/prototype/register/this-does-not-have-internal-target-throws.js": "FAIL", - "built-ins/FinalizationRegistry/prototype/unregister/this-does-not-have-internal-cells-throws.js": "FAIL", "built-ins/Function/15.3.5.4_2-12gs.js": "FAIL", "built-ins/Function/15.3.5.4_2-14gs.js": "FAIL", "built-ins/Function/15.3.5.4_2-75gs.js": "FAIL", @@ -756,11 +754,6 @@ "built-ins/JSON/stringify/value-bigint-cross-realm.js": "FAIL", "built-ins/JSON/stringify/value-object-proxy-revoked.js": "FAIL", "built-ins/Map/proto-from-ctor-realm.js": "FAIL", - "built-ins/Map/prototype/clear/context-is-weakmap-object-throws.js": "FAIL", - "built-ins/Map/prototype/delete/context-is-weakmap-object-throws.js": "FAIL", - "built-ins/Map/prototype/entries/does-not-have-mapdata-internal-slot-weakmap.js": "FAIL", - "built-ins/Map/prototype/forEach/does-not-have-mapdata-internal-slot-weakmap.js": "FAIL", - "built-ins/Map/prototype/get/does-not-have-mapdata-internal-slot-weakmap.js": "FAIL", "built-ins/Map/prototype/getOrInsert/append-new-values-normalizes-zero-key.js": "FAIL", "built-ins/Map/prototype/getOrInsert/append-new-values.js": "FAIL", "built-ins/Map/prototype/getOrInsert/append-value-if-key-is-not-present-different-key-types.js": "FAIL", @@ -780,19 +773,12 @@ "built-ins/Map/prototype/getOrInsertComputed/check-state-after-callback-fn-throws.js": "FAIL", "built-ins/Map/prototype/getOrInsertComputed/different-types-function-callbackfn-does-not-throw.js": "FAIL", "built-ins/Map/prototype/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js": "FAIL", - "built-ins/Map/prototype/getOrInsertComputed/does-not-have-mapdata-internal-slot-weakmap.js": "FAIL", "built-ins/Map/prototype/getOrInsertComputed/getOrInsertComputed.js": "FAIL", "built-ins/Map/prototype/getOrInsertComputed/not-a-constructor.js": "FAIL", "built-ins/Map/prototype/getOrInsertComputed/overwrites-mutation-from-callbackfn.js": "FAIL", "built-ins/Map/prototype/getOrInsertComputed/returns-value-if-key-is-not-present-different-key-types.js": "FAIL", "built-ins/Map/prototype/getOrInsertComputed/returns-value-if-key-is-present-different-key-types.js": "FAIL", "built-ins/Map/prototype/getOrInsertComputed/returns-value-normalized-zero-key.js": "FAIL", - "built-ins/Map/prototype/has/does-not-have-mapdata-internal-slot-weakmap.js": "FAIL", - "built-ins/Map/prototype/keys/does-not-have-mapdata-internal-slot-weakmap.js": "FAIL", - "built-ins/Map/prototype/set/does-not-have-mapdata-internal-slot-weakmap.js": "FAIL", - "built-ins/Map/prototype/size/does-not-have-mapdata-internal-slot-weakmap.js": "FAIL", - "built-ins/Map/prototype/values/does-not-have-mapdata-internal-slot-weakmap.js": "FAIL", - "built-ins/Map/valid-keys.js": "FAIL", "built-ins/Math/f16round/length.js": "FAIL", "built-ins/Math/f16round/name.js": "FAIL", "built-ins/Math/f16round/not-a-constructor.js": "FAIL", @@ -901,8 +887,6 @@ "built-ins/Object/prototype/setPrototypeOf-with-non-circular-values.js": "FAIL", "built-ins/Object/prototype/toString/proxy-revoked-during-get-call.js": "FAIL", "built-ins/Object/prototype/toString/proxy-revoked.js": "FAIL", - "built-ins/Object/prototype/toString/symbol-tag-weakmap-builtin.js": "FAIL", - "built-ins/Object/seal/seal-weakmap.js": "FAIL", "built-ins/Promise/all/S25.4.4.1_A4.1_T1.js": "FAIL", "built-ins/Promise/all/call-resolve-element-after-return.js": "FAIL", "built-ins/Promise/all/call-resolve-element-items.js": "FAIL", @@ -6090,59 +6074,9 @@ "built-ins/Uint8Array/prototype/toHex/name.js": "FAIL", "built-ins/Uint8Array/prototype/toHex/nonconstructor.js": "FAIL", "built-ins/Uint8Array/prototype/toHex/results.js": "FAIL", - "built-ins/WeakMap/empty-iterable.js": "FAIL", - "built-ins/WeakMap/get-set-method-failure.js": "FAIL", - "built-ins/WeakMap/is-a-constructor.js": "FAIL", - "built-ins/WeakMap/iterable-failure.js": "FAIL", - "built-ins/WeakMap/iterable-with-object-keys.js": "FAIL", - "built-ins/WeakMap/iterable-with-symbol-keys.js": "FAIL", - "built-ins/WeakMap/iterator-close-after-set-failure.js": "FAIL", - "built-ins/WeakMap/iterator-item-first-entry-returns-abrupt.js": "FAIL", - "built-ins/WeakMap/iterator-item-second-entry-returns-abrupt.js": "FAIL", - "built-ins/WeakMap/iterator-items-are-not-object-close-iterator.js": "FAIL", - "built-ins/WeakMap/iterator-items-keys-cannot-be-held-weakly.js": "FAIL", - "built-ins/WeakMap/iterator-next-failure.js": "FAIL", - "built-ins/WeakMap/iterator-value-failure.js": "FAIL", - "built-ins/WeakMap/no-iterable.js": "FAIL", - "built-ins/WeakMap/properties-of-map-instances.js": "FAIL", "built-ins/WeakMap/proto-from-ctor-realm.js": "FAIL", - "built-ins/WeakMap/prototype/constructor.js": "FAIL", - "built-ins/WeakMap/prototype/delete/delete-entry-with-object-key-initial-iterable.js": "FAIL", - "built-ins/WeakMap/prototype/delete/delete-entry-with-object-key.js": "FAIL", - "built-ins/WeakMap/prototype/delete/delete-entry-with-symbol-key-initial-iterable.js": "FAIL", - "built-ins/WeakMap/prototype/delete/delete-entry-with-symbol-key.js": "FAIL", - "built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-array.js": "FAIL", - "built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-map.js": "FAIL", - "built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-object.js": "FAIL", - "built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-set.js": "FAIL", - "built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js": "FAIL", - "built-ins/WeakMap/prototype/delete/not-a-constructor.js": "FAIL", - "built-ins/WeakMap/prototype/delete/returns-false-if-key-cannot-be-held-weakly.js": "FAIL", - "built-ins/WeakMap/prototype/delete/returns-false-when-object-key-not-present.js": "FAIL", - "built-ins/WeakMap/prototype/delete/returns-false-when-symbol-key-not-present.js": "FAIL", - "built-ins/WeakMap/prototype/delete/this-not-object-throw-boolean.js": "FAIL", - "built-ins/WeakMap/prototype/delete/this-not-object-throw-null.js": "FAIL", - "built-ins/WeakMap/prototype/delete/this-not-object-throw-number.js": "FAIL", - "built-ins/WeakMap/prototype/delete/this-not-object-throw-string.js": "FAIL", - "built-ins/WeakMap/prototype/delete/this-not-object-throw-symbol.js": "FAIL", - "built-ins/WeakMap/prototype/delete/this-not-object-throw-undefined.js": "FAIL", - "built-ins/WeakMap/prototype/get/does-not-have-weakmapdata-internal-slot-map.js": "FAIL", - "built-ins/WeakMap/prototype/get/does-not-have-weakmapdata-internal-slot-set.js": "FAIL", - "built-ins/WeakMap/prototype/get/does-not-have-weakmapdata-internal-slot.js": "FAIL", - "built-ins/WeakMap/prototype/get/not-a-constructor.js": "FAIL", - "built-ins/WeakMap/prototype/get/returns-undefined-if-key-cannot-be-held-weakly.js": "FAIL", - "built-ins/WeakMap/prototype/get/returns-undefined-with-object-key.js": "FAIL", - "built-ins/WeakMap/prototype/get/returns-undefined-with-symbol-key.js": "FAIL", - "built-ins/WeakMap/prototype/get/returns-value-with-object-key.js": "FAIL", - "built-ins/WeakMap/prototype/get/returns-value-with-symbol-key.js": "FAIL", - "built-ins/WeakMap/prototype/get/this-not-object-throw.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsert/adds-object-element.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsert/adds-symbol-element.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsert/does-not-have-weakmapdata-internal-slot-array.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsert/does-not-have-weakmapdata-internal-slot-map.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsert/does-not-have-weakmapdata-internal-slot-object.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsert/does-not-have-weakmapdata-internal-slot-set.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsert/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsert/getOrInsert.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsert/length.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsert/name.js": "FAIL", @@ -6151,8 +6085,6 @@ "built-ins/WeakMap/prototype/getOrInsert/returns-value-if-key-is-not-present-symbol-key.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsert/returns-value-if-key-is-present-object-key.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsert/returns-value-if-key-is-present-symbol-key.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsert/this-not-object-throw.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsert/throw-if-key-cannot-be-held-weakly.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/adds-object-element.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/adds-symbol-element.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/adds-value-different-callbackfn.js": "FAIL", @@ -6160,59 +6092,14 @@ "built-ins/WeakMap/prototype/getOrInsertComputed/check-callback-fn-args.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/check-state-after-callback-fn-throws.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-array.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-map.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-object.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-set.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/getOrInsertComputed.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/not-a-constructor.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsertComputed/not-a-function-callbackfn-throws.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/overwrites-mutation-from-callbackfn.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-not-present-object-key.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-not-present-symbol-key.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-present-object-key.js": "FAIL", "built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-present-symbol-key.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsertComputed/this-not-object-throw.js": "FAIL", - "built-ins/WeakMap/prototype/getOrInsertComputed/throw-if-key-cannot-be-held-weakly.js": "FAIL", - "built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-array.js": "FAIL", - "built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-map.js": "FAIL", - "built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-object.js": "FAIL", - "built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-set.js": "FAIL", - "built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js": "FAIL", - "built-ins/WeakMap/prototype/has/not-a-constructor.js": "FAIL", - "built-ins/WeakMap/prototype/has/returns-false-when-key-cannot-be-held-weakly.js": "FAIL", - "built-ins/WeakMap/prototype/has/returns-false-when-object-key-not-present.js": "FAIL", - "built-ins/WeakMap/prototype/has/returns-false-when-symbol-key-not-present.js": "FAIL", - "built-ins/WeakMap/prototype/has/returns-true-when-object-key-present.js": "FAIL", - "built-ins/WeakMap/prototype/has/returns-true-when-symbol-key-present.js": "FAIL", - "built-ins/WeakMap/prototype/has/this-not-object-throw-boolean.js": "FAIL", - "built-ins/WeakMap/prototype/has/this-not-object-throw-null.js": "FAIL", - "built-ins/WeakMap/prototype/has/this-not-object-throw-number.js": "FAIL", - "built-ins/WeakMap/prototype/has/this-not-object-throw-string.js": "FAIL", - "built-ins/WeakMap/prototype/has/this-not-object-throw-symbol.js": "FAIL", - "built-ins/WeakMap/prototype/has/this-not-object-throw-undefined.js": "FAIL", - "built-ins/WeakMap/prototype/set/adds-object-element.js": "FAIL", - "built-ins/WeakMap/prototype/set/adds-symbol-element.js": "FAIL", - "built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-array.js": "FAIL", - "built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-map.js": "FAIL", - "built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-object.js": "FAIL", - "built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-set.js": "FAIL", - "built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js": "FAIL", - "built-ins/WeakMap/prototype/set/not-a-constructor.js": "FAIL", - "built-ins/WeakMap/prototype/set/returns-this-when-ignoring-duplicate.js": "FAIL", - "built-ins/WeakMap/prototype/set/returns-this.js": "FAIL", - "built-ins/WeakMap/prototype/set/this-not-object-throw-boolean.js": "FAIL", - "built-ins/WeakMap/prototype/set/this-not-object-throw-null.js": "FAIL", - "built-ins/WeakMap/prototype/set/this-not-object-throw-number.js": "FAIL", - "built-ins/WeakMap/prototype/set/this-not-object-throw-string.js": "FAIL", - "built-ins/WeakMap/prototype/set/this-not-object-throw-symbol.js": "FAIL", - "built-ins/WeakMap/prototype/set/this-not-object-throw-undefined.js": "FAIL", - "built-ins/WeakMap/prototype/set/throw-if-key-cannot-be-held-weakly.js": "FAIL", - "built-ins/WeakMap/set-not-callable-throws.js": "FAIL", - "built-ins/WeakMap/undefined-newtarget.js": "FAIL", "built-ins/WeakRef/proto-from-ctor-realm.js": "FAIL", - "built-ins/WeakRef/prototype/deref/this-does-not-have-internal-target-throws.js": "FAIL", "built-ins/WeakSet/proto-from-ctor-realm.js": "FAIL", "built-ins/global/property-descriptor.js": "FAIL", "harness/assert-throws-same-realm.js": "FAIL", @@ -6332,7 +6219,6 @@ "language/expressions/class/private-static-setter-multiple-evaluations-of-class-realm.js": "FAIL", "language/expressions/class/static-init-await-reference.js": "FAIL", "language/expressions/class/subclass-builtins/subclass-Promise.js": "FAIL", - "language/expressions/class/subclass-builtins/subclass-WeakMap.js": "FAIL", "language/expressions/coalesce/tco-pos-null.js": "FAIL", "language/expressions/coalesce/tco-pos-undefined.js": "FAIL", "language/expressions/comma/tco-final.js": "FAIL", @@ -6986,7 +6872,6 @@ "language/statements/class/static-init-await-binding-valid.js": "FAIL", "language/statements/class/static-init-super-property.js": "CRASH", "language/statements/class/subclass-builtins/subclass-Promise.js": "FAIL", - "language/statements/class/subclass-builtins/subclass-WeakMap.js": "FAIL", "language/statements/class/subclass/builtin-objects/Error/message-property-assignment.js": "FAIL", "language/statements/class/subclass/builtin-objects/Error/regular-subclassing.js": "FAIL", "language/statements/class/subclass/builtin-objects/Function/instance-length.js": "FAIL", @@ -7001,8 +6886,6 @@ "language/statements/class/subclass/builtin-objects/NativeError/URIError-message.js": "FAIL", "language/statements/class/subclass/builtin-objects/Promise/regular-subclassing.js": "FAIL", "language/statements/class/subclass/builtin-objects/Promise/super-must-be-called.js": "FAIL", - "language/statements/class/subclass/builtin-objects/WeakMap/regular-subclassing.js": "FAIL", - "language/statements/class/subclass/builtin-objects/WeakMap/super-must-be-called.js": "FAIL", "language/statements/class/super/in-constructor-superproperty-evaluation.js": "FAIL", "language/statements/const/cptn-value.js": "FAIL", "language/statements/const/static-init-await-binding-valid.js": "FAIL", @@ -7419,8 +7302,6 @@ "staging/sm/Iterator/prototype/toArray/create-in-current-realm.js": "FAIL", "staging/sm/JSON/parse-with-source.js": "FAIL", "staging/sm/JSON/stringify-gap.js": "FAIL", - "staging/sm/Map/constructor-iterator-close.js": "FAIL", - "staging/sm/Map/constructor-iterator-primitive.js": "FAIL", "staging/sm/Math/acosh-approx.js": "FAIL", "staging/sm/Math/acosh-exact.js": "FAIL", "staging/sm/Math/asinh-approx.js": "FAIL", @@ -7547,66 +7428,35 @@ "staging/sm/Temporal/PlainMonthDay/from-coptic.js": "FAIL", "staging/sm/Temporal/PlainMonthDay/from-gregory.js": "FAIL", "staging/sm/Temporal/ZonedDateTime/zones-and-links.js": "FAIL", - "staging/sm/TypedArray/Tconstructor-fromTypedArray-byteLength.js": "FAIL", "staging/sm/TypedArray/at.js": "FAIL", - "staging/sm/TypedArray/bug1526838.js": "FAIL", - "staging/sm/TypedArray/constructor-ArrayBuffer-species-wrap.js": "FAIL", - "staging/sm/TypedArray/constructor-ArrayBuffer-species.js": "FAIL", - "staging/sm/TypedArray/constructor-byteoffsets-bounds.js": "FAIL", - "staging/sm/TypedArray/constructor-iterator-primitive.js": "FAIL", - "staging/sm/TypedArray/constructor-non-detached.js": "FAIL", - "staging/sm/TypedArray/constructor-not-callable.js": "FAIL", "staging/sm/TypedArray/constructor-typedarray-species-other-global.js": "FAIL", - "staging/sm/TypedArray/element-setting-converts-using-ToNumber.js": "FAIL", "staging/sm/TypedArray/entries.js": "FAIL", "staging/sm/TypedArray/every-and-some.js": "FAIL", "staging/sm/TypedArray/fill.js": "FAIL", "staging/sm/TypedArray/filter-species.js": "FAIL", - "staging/sm/TypedArray/find-and-findIndex.js": "FAIL", - "staging/sm/TypedArray/findLast-and-findLastIndex.js": "FAIL", "staging/sm/TypedArray/forEach.js": "FAIL", "staging/sm/TypedArray/from_basics.js": "FAIL", - "staging/sm/TypedArray/from_constructor.js": "FAIL", "staging/sm/TypedArray/from_errors.js": "FAIL", - "staging/sm/TypedArray/from_iterable.js": "FAIL", - "staging/sm/TypedArray/from_mapping.js": "FAIL", - "staging/sm/TypedArray/from_realms.js": "FAIL", "staging/sm/TypedArray/from_surfaces.js": "FAIL", - "staging/sm/TypedArray/from_this.js": "FAIL", "staging/sm/TypedArray/has-property-op.js": "FAIL", "staging/sm/TypedArray/includes.js": "FAIL", "staging/sm/TypedArray/indexOf-and-lastIndexOf.js": "FAIL", - "staging/sm/TypedArray/iterator-next-with-detached.js": "FAIL", "staging/sm/TypedArray/join.js": "FAIL", "staging/sm/TypedArray/keys.js": "FAIL", "staging/sm/TypedArray/map-and-filter.js": "FAIL", - "staging/sm/TypedArray/object-defineproperty.js": "FAIL", "staging/sm/TypedArray/of.js": "FAIL", "staging/sm/TypedArray/prototype-constructor-identity.js": "FAIL", - "staging/sm/TypedArray/reduce-and-reduceRight.js": "FAIL", "staging/sm/TypedArray/reverse.js": "FAIL", - "staging/sm/TypedArray/set-with-receiver.js": "FAIL", - "staging/sm/TypedArray/set-wrapped.js": "FAIL", - "staging/sm/TypedArray/set.js": "FAIL", - "staging/sm/TypedArray/slice-bitwise-same.js": "FAIL", "staging/sm/TypedArray/slice-conversion.js": "FAIL", - "staging/sm/TypedArray/slice-memcpy.js": "FAIL", - "staging/sm/TypedArray/slice-species.js": "FAIL", "staging/sm/TypedArray/slice.js": "FAIL", "staging/sm/TypedArray/sort-negative-nan.js": "FAIL", "staging/sm/TypedArray/sort-non-function.js": "FAIL", - "staging/sm/TypedArray/sort_byteoffset.js": "FAIL", - "staging/sm/TypedArray/sort_large_countingsort.js": "FAIL", - "staging/sm/TypedArray/sorting_buffer_access.js": "FAIL", - "staging/sm/TypedArray/subarray.js": "FAIL", + "staging/sm/TypedArray/sort_large_countingsort.js": "TIMEOUT", "staging/sm/TypedArray/test-integrity-level-detached.js": "FAIL", "staging/sm/TypedArray/toLocaleString-detached.js": "FAIL", - "staging/sm/TypedArray/toLocaleString-nointl.js": "FAIL", "staging/sm/TypedArray/toLocaleString.js": "FAIL", "staging/sm/TypedArray/toString.js": "FAIL", - "staging/sm/TypedArray/toStringTag-cross-compartment.js": "FAIL", "staging/sm/TypedArray/values.js": "FAIL", - "staging/sm/WeakMap/symbols.js": "FAIL", "staging/sm/async-functions/async-contains-unicode-escape.js": "FAIL", "staging/sm/async-functions/await-error.js": "CRASH", "staging/sm/async-functions/await-in-arrow-parameters.js": "FAIL", @@ -7663,14 +7513,11 @@ "staging/sm/extensions/proxy-strict.js": "FAIL", "staging/sm/extensions/regress-469625-01.js": "FAIL", "staging/sm/extensions/regress-645160.js": "FAIL", - "staging/sm/extensions/regress-650753.js": "FAIL", "staging/sm/extensions/shareddataview.js": "FAIL", "staging/sm/extensions/string-literal-getter-setter-decompilation.js": "FAIL", - "staging/sm/extensions/weakmap.js": "FAIL", "staging/sm/fields/await-identifier-script.js": "FAIL", "staging/sm/fields/bug1587574.js": "FAIL", "staging/sm/generators/iteration.js": "FAIL", - "staging/sm/generators/iterator-next-non-object.js": "FAIL", "staging/sm/generators/return-finally.js": "FAIL", "staging/sm/generators/runtime.js": "FAIL", "staging/sm/generators/yield-star-throw-htmldda.js": "FAIL", @@ -7700,7 +7547,7 @@ "staging/sm/object/getter-name.js": "FAIL", "staging/sm/object/setPrototypeOf-cross-realm-cycle.js": "FAIL", "staging/sm/object/toPrimitive-callers.js": "FAIL", - "staging/sm/regress/regress-1507322-deep-weakmap.js": "FAIL", + "staging/sm/regress/regress-1507322-deep-weakmap.js": "TIMEOUT", "staging/sm/regress/regress-325925.js": "FAIL", "staging/sm/regress/regress-428366.js": "FAIL", "staging/sm/regress/regress-452189.js": "FAIL", diff --git a/tests/metrics.json b/tests/metrics.json index 806ee5daf..51a31dc61 100644 --- a/tests/metrics.json +++ b/tests/metrics.json @@ -1,10 +1,10 @@ { "results": { "crash": 72, - "fail": 7613, - "pass": 39669, + "fail": 7458, + "pass": 39822, "skip": 3325, - "timeout": 17, + "timeout": 19, "unresolved": 37 }, "total": 50733