Skip to main content

nova_vm/ecmascript/builtins/
primitive_objects.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
5use crate::{
6    ecmascript::{
7        Agent, BIGINT_DISCRIMINANT, BOOLEAN_DISCRIMINANT, BUILTIN_STRING_MEMORY, BigInt,
8        FLOAT_DISCRIMINANT, HeapBigInt, HeapNumber, HeapString, INTEGER_DISCRIMINANT,
9        InternalMethods, InternalSlots, JsResult, NUMBER_DISCRIMINANT, Number, Object,
10        OrdinaryObject, Primitive, PropertyDescriptor, PropertyKey, ProtoIntrinsics,
11        SMALL_BIGINT_DISCRIMINANT, SMALL_STRING_DISCRIMINANT, STRING_DISCRIMINANT,
12        SYMBOL_DISCRIMINANT, SetResult, SmallBigInt, SmallF64, SmallInteger, String, Symbol,
13        TryError, TryGetResult, TryHasResult, TryResult, Value, is_compatible_property_descriptor,
14        js_result_into_try, object_handle, ordinary_define_own_property, ordinary_delete,
15        ordinary_get, ordinary_get_own_property, ordinary_has_property, ordinary_set, unwrap_try,
16    },
17    engine::{Bindable, GcScope, NoGcScope, bindable_handle},
18    heap::{
19        ArenaAccess, ArenaAccessMut, BaseIndex, CompactionLists, CreateHeapData, Heap,
20        HeapMarkAndSweep, HeapSweepWeakReference, IntrinsicPrimitiveObjectIndexes, WorkQueues,
21        arena_vec_access,
22    },
23};
24use small_string::SmallString;
25
26use super::{
27    ObjectShape, PropertyLookupCache, ordinary_own_property_keys, ordinary_try_get,
28    ordinary_try_has_property, ordinary_try_set,
29};
30
31/// Primitive objects are special objects that hold a primitive value in their
32/// internal data.
33///
34/// # Examples
35///
36/// ```javascript
37/// new Number(0);
38/// new String("");
39/// new Boolean(true);
40/// new Object(0);
41/// new Object("");
42/// new Object(true);
43/// new Object(0n);
44/// new Object(Symbol());
45/// ```
46#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
47#[repr(transparent)]
48pub struct PrimitiveObject<'a>(BaseIndex<'a, PrimitiveObjectRecord<'static>>);
49object_handle!(PrimitiveObject);
50arena_vec_access!(PrimitiveObject, 'a, PrimitiveObjectRecord, primitive_objects);
51
52impl IntrinsicPrimitiveObjectIndexes {
53    pub(crate) const fn get_primitive_object<'a>(
54        self,
55        base: BaseIndex<'a, PrimitiveObjectRecord<'static>>,
56    ) -> PrimitiveObject<'a> {
57        PrimitiveObject(BaseIndex::from_index_u32_const(
58            self as u32 + base.get_index_u32_const() + Self::PRIMITIVE_OBJECT_INDEX_OFFSET,
59        ))
60    }
61}
62
63impl PrimitiveObject<'_> {
64    /// Returns `true` if the primitive object is a BigInt object.
65    ///
66    /// ## Examples
67    ///
68    /// ```javascript
69    /// new Object(0n);
70    /// ```
71    pub fn is_bigint_object(self, agent: &Agent) -> bool {
72        matches!(
73            self.get(agent).data,
74            PrimitiveObjectData::BigInt(_) | PrimitiveObjectData::SmallBigInt(_)
75        )
76    }
77
78    /// Returns `true` if the primitive object is a Number object.
79    ///
80    /// ## Examples
81    ///
82    /// ```javascript
83    /// new Number(0);
84    /// new Object(0);
85    /// ```
86    pub fn is_number_object(self, agent: &Agent) -> bool {
87        matches!(
88            self.get(agent).data,
89            PrimitiveObjectData::SmallF64(_)
90                | PrimitiveObjectData::Integer(_)
91                | PrimitiveObjectData::Number(_)
92        )
93    }
94
95    /// Returns `true` if the primitive object is a String object.
96    ///
97    /// ## Examples
98    ///
99    /// ```javascript
100    /// new String("");
101    /// new Object("");
102    /// ```
103    pub fn is_string_object(self, agent: &Agent) -> bool {
104        matches!(
105            self.get(agent).data,
106            PrimitiveObjectData::String(_) | PrimitiveObjectData::SmallString(_)
107        )
108    }
109
110    /// Returns `true` if the primitive object is a Symbol object.
111    ///
112    /// ## Examples
113    ///
114    /// ```javascript
115    /// new Object(Symbol())
116    /// ```
117    pub fn is_symbol_object(self, agent: &Agent) -> bool {
118        matches!(self.get(agent).data, PrimitiveObjectData::Symbol(_))
119    }
120}
121
122impl<'a> InternalSlots<'a> for PrimitiveObject<'a> {
123    #[inline(always)]
124    fn get_backing_object(self, agent: &Agent) -> Option<OrdinaryObject<'static>> {
125        self.get(agent).object_index.unbind()
126    }
127
128    fn set_backing_object(self, agent: &mut Agent, backing_object: OrdinaryObject<'static>) {
129        assert!(
130            self.get_mut(agent)
131                .object_index
132                .replace(backing_object.unbind())
133                .is_none()
134        );
135    }
136
137    fn object_shape(self, agent: &mut Agent) -> ObjectShape<'static> {
138        if let Some(bo) = self.get_backing_object(agent) {
139            bo.object_shape(agent)
140        } else {
141            let primitive: Primitive = self.get(agent).data.into();
142            primitive.object_shape(agent).unwrap()
143        }
144    }
145
146    fn internal_prototype(self, agent: &Agent) -> Option<Object<'static>> {
147        match self.get_backing_object(agent) {
148            Some(obj) => obj.internal_prototype(agent),
149            None => {
150                let intrinsic_default_proto = match self.get(agent).data {
151                    PrimitiveObjectData::Boolean(_) => ProtoIntrinsics::Boolean,
152                    PrimitiveObjectData::String(_) | PrimitiveObjectData::SmallString(_) => {
153                        ProtoIntrinsics::String
154                    }
155                    PrimitiveObjectData::Symbol(_) => ProtoIntrinsics::Symbol,
156                    PrimitiveObjectData::Number(_)
157                    | PrimitiveObjectData::Integer(_)
158                    | PrimitiveObjectData::SmallF64(_) => ProtoIntrinsics::Number,
159                    PrimitiveObjectData::BigInt(_) | PrimitiveObjectData::SmallBigInt(_) => {
160                        ProtoIntrinsics::BigInt
161                    }
162                };
163                // TODO: Should take realm from "backing object"'s Realm/None
164                // variant
165                Some(
166                    agent
167                        .current_realm_record()
168                        .intrinsics()
169                        .get_intrinsic_default_proto(intrinsic_default_proto),
170                )
171            }
172        }
173    }
174}
175
176impl<'a> InternalMethods<'a> for PrimitiveObject<'a> {
177    fn try_get_own_property<'gc>(
178        self,
179        agent: &mut Agent,
180        property_key: PropertyKey,
181        cache: Option<PropertyLookupCache>,
182        gc: NoGcScope<'gc, '_>,
183    ) -> TryResult<'gc, Option<PropertyDescriptor<'gc>>> {
184        let o = self.bind(gc);
185        // For non-string primitive objects:
186        // 1. Return OrdinaryGetOwnProperty(O, P).
187        // For string exotic objects:
188        // 1. Let desc be OrdinaryGetOwnProperty(S, P).
189        // 2. If desc is not undefined, return desc.
190        if let Some(backing_object) = o.get_backing_object(agent)
191            && let Some(property_descriptor) =
192                ordinary_get_own_property(agent, o.into(), backing_object, property_key, cache, gc)
193        {
194            return TryResult::Continue(Some(property_descriptor));
195        }
196
197        if let Ok(string) = String::try_from(self.get(agent).data) {
198            // 3. Return StringGetOwnProperty(S, P).
199            TryResult::Continue(string.get_property_descriptor(agent, property_key))
200        } else {
201            TryResult::Continue(None)
202        }
203    }
204
205    fn try_define_own_property<'gc>(
206        self,
207        agent: &mut Agent,
208        property_key: PropertyKey,
209        property_descriptor: PropertyDescriptor,
210        cache: Option<PropertyLookupCache>,
211        gc: NoGcScope<'gc, '_>,
212    ) -> TryResult<'gc, bool> {
213        if let Ok(string) = String::try_from(self.get(agent).data) {
214            // For string exotic objects:
215            // 1. Let stringDesc be StringGetOwnProperty(S, P).
216            // 2. If stringDesc is not undefined, then
217            if let Some(string_desc) = string.get_property_descriptor(agent, property_key) {
218                // a. Let extensible be S.[[Extensible]].
219                // b. Return IsCompatiblePropertyDescriptor(extensible, Desc, stringDesc).
220                return match is_compatible_property_descriptor(
221                    agent,
222                    self.internal_extensible(agent),
223                    property_descriptor,
224                    Some(string_desc),
225                    gc,
226                ) {
227                    Ok(b) => TryResult::Continue(b),
228                    Err(_) => TryError::GcError.into(),
229                };
230            }
231            // 3. Return ! OrdinaryDefineOwnProperty(S, P, Desc).
232        }
233
234        let backing_object = self
235            .get_backing_object(agent)
236            .unwrap_or_else(|| self.create_backing_object(agent));
237        js_result_into_try(ordinary_define_own_property(
238            agent,
239            self.into(),
240            backing_object,
241            property_key,
242            property_descriptor,
243            cache,
244            gc,
245        ))
246    }
247
248    fn try_has_property<'gc>(
249        self,
250        agent: &mut Agent,
251        property_key: PropertyKey,
252        cache: Option<PropertyLookupCache>,
253        gc: NoGcScope<'gc, '_>,
254    ) -> TryResult<'gc, TryHasResult<'gc>> {
255        if let Ok(string) = String::try_from(self.get(agent).data)
256            && string.get_property_value(agent, property_key).is_some()
257        {
258            return TryHasResult::Custom(0, self.bind(gc).into()).into();
259        }
260
261        // 1. Return ? OrdinaryHasProperty(O, P).
262        ordinary_try_has_property(
263            agent,
264            self.into(),
265            self.get_backing_object(agent),
266            property_key,
267            cache,
268            gc,
269        )
270    }
271
272    fn internal_has_property<'gc>(
273        self,
274        agent: &mut Agent,
275        property_key: PropertyKey,
276        gc: GcScope<'gc, '_>,
277    ) -> JsResult<'gc, bool> {
278        let property_key = property_key.bind(gc.nogc());
279        if let Ok(string) = String::try_from(self.get(agent).data)
280            && string.get_property_value(agent, property_key).is_some()
281        {
282            return Ok(true);
283        }
284
285        // 1. Return ? OrdinaryHasProperty(O, P).
286        match self.get_backing_object(agent) {
287            Some(backing_object) => ordinary_has_property(
288                agent,
289                self.into(),
290                backing_object,
291                property_key.unbind(),
292                gc,
293            ),
294            None => {
295                // 3. Let parent be ? O.[[GetPrototypeOf]]().
296                // Note: Primitive objects never call into JS from GetPrototypeOf.
297                let parent = unwrap_try(self.try_get_prototype_of(agent, gc.nogc()));
298
299                // 4. If parent is not null, then
300                if let Some(parent) = parent {
301                    // a. Return ? parent.[[HasProperty]](P).
302                    parent
303                        .unbind()
304                        .internal_has_property(agent, property_key.unbind(), gc)
305                } else {
306                    // 5. Return false.
307                    Ok(false)
308                }
309            }
310        }
311    }
312
313    fn try_get<'gc>(
314        self,
315        agent: &mut Agent,
316        property_key: PropertyKey,
317        receiver: Value,
318        cache: Option<PropertyLookupCache>,
319        gc: NoGcScope<'gc, '_>,
320    ) -> TryResult<'gc, TryGetResult<'gc>> {
321        if let Ok(string) = String::try_from(self.get(agent).data)
322            && let Some(value) = string.get_property_value(agent, property_key)
323        {
324            return TryGetResult::Value(value.bind(gc)).into();
325        }
326        // 1. Return ? OrdinaryGet(O, P, Receiver).
327        ordinary_try_get(
328            agent,
329            self.into(),
330            self.get_backing_object(agent),
331            property_key,
332            receiver,
333            cache,
334            gc,
335        )
336    }
337
338    fn internal_get<'gc>(
339        self,
340        agent: &mut Agent,
341        property_key: PropertyKey,
342        receiver: Value,
343        gc: GcScope<'gc, '_>,
344    ) -> JsResult<'gc, Value<'gc>> {
345        let property_key = property_key.bind(gc.nogc());
346        if let Ok(string) = String::try_from(self.get(agent).data)
347            && let Some(value) = string.get_property_value(agent, property_key)
348        {
349            return Ok(value.bind(gc.into_nogc()));
350        }
351
352        // 1. Return ? OrdinaryGet(O, P, Receiver).
353        match self.get_backing_object(agent) {
354            Some(backing_object) => {
355                ordinary_get(agent, backing_object, property_key.unbind(), receiver, gc)
356            }
357            None => {
358                // a. Let parent be ? O.[[GetPrototypeOf]]().
359                let Some(parent) = unwrap_try(self.try_get_prototype_of(agent, gc.nogc())) else {
360                    // b. If parent is null, return undefined.
361                    return Ok(Value::Undefined);
362                };
363
364                // c. Return ? parent.[[Get]](P, Receiver).
365                parent
366                    .unbind()
367                    .internal_get(agent, property_key.unbind(), receiver, gc)
368            }
369        }
370    }
371
372    fn try_set<'gc>(
373        self,
374        agent: &mut Agent,
375        property_key: PropertyKey,
376        value: Value,
377        receiver: Value,
378        cache: Option<PropertyLookupCache>,
379        gc: NoGcScope<'gc, '_>,
380    ) -> TryResult<'gc, SetResult<'gc>> {
381        if let Ok(string) = String::try_from(self.get(agent).data)
382            && string.get_property_value(agent, property_key).is_some()
383        {
384            return SetResult::Unwritable.into();
385        }
386
387        // 1. Return ? OrdinarySet(O, P, V, Receiver).
388        ordinary_try_set(agent, self, property_key, value, receiver, cache, gc)
389    }
390
391    fn internal_set<'gc>(
392        self,
393        agent: &mut Agent,
394        property_key: PropertyKey,
395        value: Value,
396        receiver: Value,
397        gc: GcScope<'gc, '_>,
398    ) -> JsResult<'gc, bool> {
399        let property_key = property_key.bind(gc.nogc());
400        if let Ok(string) = String::try_from(self.get(agent).data)
401            && string.get_property_value(agent, property_key).is_some()
402        {
403            return Ok(false);
404        }
405
406        // 1. Return ? OrdinarySet(O, P, V, Receiver).
407        ordinary_set(
408            agent,
409            self.into(),
410            property_key.unbind(),
411            value,
412            receiver,
413            gc,
414        )
415    }
416
417    fn try_delete<'gc>(
418        self,
419        agent: &mut Agent,
420        property_key: PropertyKey,
421        gc: NoGcScope<'gc, '_>,
422    ) -> TryResult<'gc, bool> {
423        if let Ok(string) = String::try_from(self.get(agent).data) {
424            // A String will return unconfigurable descriptors for length and
425            // all valid string indexes, making delete return false.
426            if property_key == BUILTIN_STRING_MEMORY.length.into() {
427                return TryResult::Continue(false);
428            } else if let PropertyKey::Integer(index) = property_key {
429                let index = index.into_i64();
430                if index >= 0 && (index as usize) < string.utf16_len_(agent) {
431                    return TryResult::Continue(false);
432                }
433            }
434        }
435
436        // 1. Return ! OrdinaryDelete(O, P).
437        match self.get_backing_object(agent) {
438            Some(backing_object) => TryResult::Continue(ordinary_delete(
439                agent,
440                self.into(),
441                backing_object,
442                property_key,
443                gc,
444            )),
445            None => TryResult::Continue(true),
446        }
447    }
448
449    fn try_own_property_keys<'gc>(
450        self,
451        agent: &mut Agent,
452        gc: NoGcScope<'gc, '_>,
453    ) -> TryResult<'gc, Vec<PropertyKey<'gc>>> {
454        if let Ok(string) = String::try_from(self.get(agent).data) {
455            let len = string.utf16_len_(agent);
456            let mut keys = Vec::with_capacity(len + 1);
457
458            // Insert keys for every index into the string.
459            keys.extend(
460                (0..len)
461                    .map(|idx| PropertyKey::Integer(SmallInteger::try_from(idx as u64).unwrap())),
462            );
463
464            let backing_object_keys;
465            let (integer_keys, other_keys) = match self.get_backing_object(agent) {
466                Some(backing_object) => {
467                    backing_object_keys = ordinary_own_property_keys(agent, backing_object, gc);
468                    if let Some(PropertyKey::Integer(smi)) = backing_object_keys.first() {
469                        debug_assert!(smi.into_i64() >= len as i64);
470                    }
471                    let split_idx = backing_object_keys
472                        .iter()
473                        .position(|pk| !pk.is_array_index());
474                    if let Some(idx) = split_idx {
475                        backing_object_keys.split_at(idx)
476                    } else {
477                        (&backing_object_keys[..], &[][..])
478                    }
479                }
480                None => (&[][..], &[][..]),
481            };
482
483            // Insert the `length` key as the first non-array index key.
484            keys.extend(integer_keys);
485            keys.push(BUILTIN_STRING_MEMORY.length.into());
486            keys.extend(other_keys);
487
488            return TryResult::Continue(keys);
489        }
490
491        // 1. Return OrdinaryOwnPropertyKeys(O).
492        match self.get_backing_object(agent) {
493            Some(backing_object) => {
494                TryResult::Continue(ordinary_own_property_keys(agent, backing_object, gc))
495            }
496            None => TryResult::Continue(vec![]),
497        }
498    }
499}
500
501#[derive(Debug, Clone, Copy, PartialEq)]
502#[repr(u8)]
503pub(crate) enum PrimitiveObjectData<'a> {
504    Boolean(bool) = BOOLEAN_DISCRIMINANT,
505    String(HeapString<'a>) = STRING_DISCRIMINANT,
506    SmallString(SmallString) = SMALL_STRING_DISCRIMINANT,
507    Symbol(Symbol<'a>) = SYMBOL_DISCRIMINANT,
508    Number(HeapNumber<'a>) = NUMBER_DISCRIMINANT,
509    Integer(SmallInteger) = INTEGER_DISCRIMINANT,
510    SmallF64(SmallF64) = FLOAT_DISCRIMINANT,
511    BigInt(HeapBigInt<'a>) = BIGINT_DISCRIMINANT,
512    SmallBigInt(SmallBigInt) = SMALL_BIGINT_DISCRIMINANT,
513}
514bindable_handle!(PrimitiveObjectData);
515
516impl<'a> TryFrom<PrimitiveObjectData<'a>> for BigInt<'a> {
517    type Error = ();
518
519    fn try_from(value: PrimitiveObjectData<'a>) -> Result<Self, Self::Error> {
520        match value {
521            PrimitiveObjectData::BigInt(data) => Ok(BigInt::BigInt(data)),
522            PrimitiveObjectData::SmallBigInt(data) => Ok(BigInt::SmallBigInt(data)),
523            _ => Err(()),
524        }
525    }
526}
527
528impl<'a> TryFrom<PrimitiveObjectData<'a>> for Number<'a> {
529    type Error = ();
530
531    fn try_from(value: PrimitiveObjectData<'a>) -> Result<Self, Self::Error> {
532        match value {
533            PrimitiveObjectData::Number(data) => Ok(Number::Number(data)),
534            PrimitiveObjectData::Integer(data) => Ok(Number::Integer(data)),
535            PrimitiveObjectData::SmallF64(data) => Ok(Number::SmallF64(data)),
536            _ => Err(()),
537        }
538    }
539}
540
541impl<'a> TryFrom<PrimitiveObjectData<'a>> for String<'a> {
542    type Error = ();
543
544    fn try_from(value: PrimitiveObjectData<'a>) -> Result<Self, Self::Error> {
545        match value {
546            PrimitiveObjectData::String(data) => Ok(String::String(data)),
547            PrimitiveObjectData::SmallString(data) => Ok(String::SmallString(data)),
548            _ => Err(()),
549        }
550    }
551}
552
553impl<'a> TryFrom<PrimitiveObjectData<'a>> for Symbol<'a> {
554    type Error = ();
555
556    fn try_from(value: PrimitiveObjectData<'a>) -> Result<Self, Self::Error> {
557        match value {
558            PrimitiveObjectData::Symbol(data) => Ok(data),
559            _ => Err(()),
560        }
561    }
562}
563
564impl<'a> From<PrimitiveObjectData<'a>> for Primitive<'a> {
565    fn from(value: PrimitiveObjectData<'a>) -> Self {
566        match value {
567            PrimitiveObjectData::Boolean(d) => Self::Boolean(d),
568            PrimitiveObjectData::String(d) => Self::String(d),
569            PrimitiveObjectData::SmallString(d) => Self::SmallString(d),
570            PrimitiveObjectData::Symbol(d) => Self::Symbol(d),
571            PrimitiveObjectData::Number(d) => Self::Number(d),
572            PrimitiveObjectData::Integer(d) => Self::Integer(d),
573            PrimitiveObjectData::SmallF64(d) => Self::SmallF64(d),
574            PrimitiveObjectData::BigInt(d) => Self::BigInt(d),
575            PrimitiveObjectData::SmallBigInt(d) => Self::SmallBigInt(d),
576        }
577    }
578}
579
580#[derive(Debug, Clone, Copy)]
581pub(crate) struct PrimitiveObjectRecord<'a> {
582    pub(crate) object_index: Option<OrdinaryObject<'a>>,
583    pub(crate) data: PrimitiveObjectData<'a>,
584}
585bindable_handle!(PrimitiveObjectRecord);
586
587impl<'a> PrimitiveObjectRecord<'a> {
588    pub(crate) const BLANK: Self = Self {
589        object_index: None,
590        data: PrimitiveObjectData::Boolean(false),
591    };
592
593    pub(crate) fn new_big_int_object(big_int: BigInt<'a>) -> Self {
594        let data = match big_int {
595            BigInt::BigInt(data) => PrimitiveObjectData::BigInt(data.unbind()),
596            BigInt::SmallBigInt(data) => PrimitiveObjectData::SmallBigInt(data),
597        };
598        Self {
599            object_index: None,
600            data,
601        }
602    }
603
604    pub(crate) fn new_boolean_object(boolean: bool) -> Self {
605        Self {
606            object_index: None,
607            data: PrimitiveObjectData::Boolean(boolean),
608        }
609    }
610
611    pub(crate) fn new_number_object(number: Number<'a>) -> Self {
612        let data = match number {
613            Number::Number(data) => PrimitiveObjectData::Number(data.unbind()),
614            Number::Integer(data) => PrimitiveObjectData::Integer(data),
615            Number::SmallF64(data) => PrimitiveObjectData::SmallF64(data),
616        };
617        Self {
618            object_index: None,
619            data,
620        }
621    }
622
623    pub(crate) fn new_string_object(string: String<'a>) -> Self {
624        let data = match string {
625            String::String(data) => PrimitiveObjectData::String(data),
626            String::SmallString(data) => PrimitiveObjectData::SmallString(data),
627        };
628        Self {
629            object_index: None,
630            data,
631        }
632    }
633
634    pub(crate) fn new_symbol_object(symbol: Symbol<'a>) -> Self {
635        Self {
636            object_index: None,
637            data: PrimitiveObjectData::Symbol(symbol.unbind()),
638        }
639    }
640}
641
642impl HeapMarkAndSweep for PrimitiveObjectRecord<'static> {
643    fn mark_values(&self, queues: &mut WorkQueues) {
644        let Self { object_index, data } = self;
645        object_index.mark_values(queues);
646        match data {
647            PrimitiveObjectData::String(data) => data.mark_values(queues),
648            PrimitiveObjectData::Symbol(data) => data.mark_values(queues),
649            PrimitiveObjectData::Number(data) => data.mark_values(queues),
650            PrimitiveObjectData::BigInt(data) => data.mark_values(queues),
651            _ => {}
652        }
653    }
654
655    fn sweep_values(&mut self, compactions: &CompactionLists) {
656        let Self { object_index, data } = self;
657        object_index.sweep_values(compactions);
658        match data {
659            PrimitiveObjectData::String(data) => data.sweep_values(compactions),
660            PrimitiveObjectData::Symbol(data) => data.sweep_values(compactions),
661            PrimitiveObjectData::Number(data) => data.sweep_values(compactions),
662            PrimitiveObjectData::BigInt(data) => data.sweep_values(compactions),
663            _ => {}
664        }
665    }
666}
667
668impl HeapMarkAndSweep for PrimitiveObject<'static> {
669    fn mark_values(&self, queues: &mut WorkQueues) {
670        queues.primitive_objects.push(*self);
671    }
672
673    fn sweep_values(&mut self, compactions: &CompactionLists) {
674        compactions.primitive_objects.shift_index(&mut self.0);
675    }
676}
677
678impl HeapSweepWeakReference for PrimitiveObject<'static> {
679    fn sweep_weak_reference(self, compactions: &CompactionLists) -> Option<Self> {
680        compactions
681            .primitive_objects
682            .shift_weak_index(self.0)
683            .map(Self)
684    }
685}
686
687impl<'a> CreateHeapData<PrimitiveObjectRecord<'a>, PrimitiveObject<'a>> for Heap {
688    fn create(&mut self, data: PrimitiveObjectRecord<'a>) -> PrimitiveObject<'a> {
689        self.primitive_objects.push(data.unbind());
690        self.alloc_counter += core::mem::size_of::<PrimitiveObjectRecord<'static>>();
691        PrimitiveObject(BaseIndex::last(&self.primitive_objects))
692    }
693}