nova_vm 1.0.0

Nova Virtual Machine
Documentation
// 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
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

mod data;

pub(crate) use data::*;

use crate::{
    ecmascript::{
        Agent, InternalMethods, InternalSlots, OrdinaryObject, ProtoIntrinsics, Value, WeakKey,
        object_handle,
    },
    engine::Bindable,
    heap::{
        ArenaAccess, ArenaAccessMut, BaseIndex, CompactionLists, CreateHeapData, Heap,
        HeapMarkAndSweep, HeapSweepWeakReference, WorkQueues, arena_vec_access,
    },
};

/// ## [24.3 WeakMap Objects](https://tc39.es/ecma262/#sec-weakmap-objects)
///
/// WeakMaps are collections of key/value pairs where the keys are objects
/// and/or symbols and values may be arbitrary ECMAScript language values. A
/// WeakMap may be queried to see if it contains a key/value pair with a
/// specific key, but no mechanism is provided for enumerating the values it
/// holds as keys. In certain conditions, values which are not live are removed
/// as WeakMap keys.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct WeakMap<'a>(BaseIndex<'a, WeakMapRecord<'static>>);
object_handle!(WeakMap);
arena_vec_access!(WeakMap, 'a, WeakMapRecord, weak_maps);

impl<'m> WeakMap<'m> {
    pub(crate) fn delete(self, agent: &mut Agent, key: WeakKey<'m>) -> bool {
        self.get_mut(agent).delete(key)
    }

    pub(crate) fn get_v(self, agent: &mut Agent, key: WeakKey<'m>) -> Option<Value<'m>> {
        self.get_mut(agent).get(key)
    }

    pub(crate) fn has(self, agent: &mut Agent, key: WeakKey<'m>) -> bool {
        self.get_mut(agent).has(key)
    }

    pub(crate) fn set(self, agent: &mut Agent, key: WeakKey<'m>, value: Value<'m>) {
        self.get_mut(agent).set(key, value)
    }
}

impl<'a> InternalSlots<'a> for WeakMap<'a> {
    const DEFAULT_PROTOTYPE: ProtoIntrinsics = ProtoIntrinsics::WeakMap;

    #[inline(always)]
    fn get_backing_object(self, agent: &Agent) -> Option<OrdinaryObject<'static>> {
        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<WeakMapRecord<'a>, 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::<WeakMapRecord<'static>>();
        WeakMap(BaseIndex::last(&self.weak_maps))
    }
}

impl HeapMarkAndSweep for WeakMap<'static> {
    fn mark_values(&self, queues: &mut WorkQueues) {
        queues.weak_maps.push(*self);
    }

    fn sweep_values(&mut self, compactions: &CompactionLists) {
        compactions.weak_maps.shift_index(&mut self.0);
    }
}

impl HeapSweepWeakReference for WeakMap<'static> {
    fn sweep_weak_reference(self, compactions: &CompactionLists) -> Option<Self> {
        compactions.weak_maps.shift_weak_index(self.0).map(Self)
    }
}