Skip to main content

nova_vm/ecmascript/builtins/
weak_set.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5mod data;
6
7pub(crate) use data::*;
8
9use crate::{
10    ecmascript::{
11        Agent, Behaviour, Function, InternalMethods, InternalSlots, OrdinaryObject,
12        ProtoIntrinsics, WeakSetPrototype, object_handle,
13    },
14    engine::Bindable,
15    heap::{
16        ArenaAccess, ArenaAccessMut, BaseIndex, CompactionLists, CreateHeapData, Heap,
17        HeapMarkAndSweep, HeapSweepWeakReference, WorkQueues, arena_vec_access,
18    },
19};
20
21/// ## [24.4 WeakSet Objects](https://tc39.es/ecma262/#sec-weakset-objects)
22//
23/// WeakSets are collections of objects and/or symbols. A distinct object or
24/// symbol may only occur once as an element of a WeakSet's collection. A
25/// WeakSet may be queried to see if it contains a specific value, but no
26/// mechanism is provided for enumerating the values it holds. In certain
27/// conditions, values which are not live are removed as WeakSet elements, as
28/// described in 9.9.3.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30#[repr(transparent)]
31pub struct WeakSet<'a>(BaseIndex<'a, WeakSetHeapData<'static>>);
32object_handle!(WeakSet);
33arena_vec_access!(WeakSet, 'a, WeakSetHeapData, weak_sets);
34
35impl WeakSet<'_> {
36    /// Returns true if the function is equal to %WeakSet.prototype.add%.
37    pub(crate) fn is_weak_set_prototype_add(agent: &Agent, function: Function) -> bool {
38        let Function::BuiltinFunction(function) = function else {
39            return false;
40        };
41        let Behaviour::Regular(behaviour) = function.get(agent).behaviour else {
42            return false;
43        };
44        // We allow a function address comparison here against best advice: it
45        // is exceedingly unlikely that the `add` function wouldn't be unique
46        // and even if it isn't, we don't care since we only care about its
47        // inner workings.
48        #[allow(unknown_lints, renamed_and_removed_lints)]
49        {
50            #[allow(
51                clippy::fn_address_comparisons,
52                unpredictable_function_pointer_comparisons
53            )]
54            {
55                behaviour == WeakSetPrototype::add
56            }
57        }
58    }
59}
60
61impl<'a> InternalSlots<'a> for WeakSet<'a> {
62    const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::WeakSet;
63
64    #[inline(always)]
65    fn get_backing_object(self, agent: &Agent) -> Option<OrdinaryObject<'static>> {
66        self.get(agent).object_index.unbind()
67    }
68
69    fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) {
70        assert!(
71            self.get_mut(agent)
72                .object_index
73                .replace(backing_object.unbind())
74                .is_none()
75        );
76    }
77}
78
79impl<'a> InternalMethods<'a> for WeakSet<'a> {}
80
81impl<'a> CreateHeapData<WeakSetHeapData<'a>, WeakSet<'a>> for Heap {
82    fn create(&mut self, data: WeakSetHeapData<'a>) -> WeakSet<'a> {
83        self.weak_sets.push(data.unbind());
84        self.alloc_counter += core::mem::size_of::<WeakSetHeapData<'static>>();
85        WeakSet(BaseIndex::last(&self.weak_sets))
86    }
87}
88
89impl HeapMarkAndSweep for WeakSet<'static> {
90    fn mark_values(&self, queues: &mut WorkQueues) {
91        queues.weak_sets.push(*self);
92    }
93
94    fn sweep_values(&mut self, compactions: &CompactionLists) {
95        compactions.weak_sets.shift_index(&mut self.0);
96    }
97}
98
99impl HeapSweepWeakReference for WeakSet<'static> {
100    fn sweep_weak_reference(self, compactions: &CompactionLists) -> Option<Self> {
101        compactions.weak_sets.shift_weak_index(self.0).map(Self)
102    }
103}