servo_malloc_size_of/
lib.rs

1// Copyright 2016-2017 The Servo Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! A crate for measuring the heap usage of data structures in a way that
12//! integrates with Firefox's memory reporting, particularly the use of
13//! mozjemalloc and DMD. In particular, it has the following features.
14//! - It isn't bound to a particular heap allocator.
15//! - It provides traits for both "shallow" and "deep" measurement, which gives
16//!   flexibility in the cases where the traits can't be used.
17//! - It allows for measuring blocks even when only an interior pointer can be
18//!   obtained for heap allocations, e.g. `HashSet` and `HashMap`. (This relies
19//!   on the heap allocator having suitable support, which mozjemalloc has.)
20//! - It allows handling of types like `Rc` and `Arc` by providing traits that
21//!   are different to the ones for non-graph structures.
22//!
23//! Suggested uses are as follows.
24//! - When possible, use the `MallocSizeOf` trait. (Deriving support is
25//!   provided by the `malloc_size_of_derive` crate.)
26//! - If you need an additional synchronization argument, provide a function
27//!   that is like the standard trait method, but with the extra argument.
28//! - If you need multiple measurements for a type, provide a function named
29//!   `add_size_of` that takes a mutable reference to a struct that contains
30//!   the multiple measurement fields.
31//! - When deep measurement (via `MallocSizeOf`) cannot be implemented for a
32//!   type, shallow measurement (via `MallocShallowSizeOf`) in combination with
33//!   iteration can be a useful substitute.
34//! - `Rc` and `Arc` are always tricky, which is why `MallocSizeOf` is not (and
35//!   should not be) implemented for them.
36//! - If an `Rc` or `Arc` is known to be a "primary" reference and can always
37//!   be measured, it should be measured via the `MallocUnconditionalSizeOf`
38//!   trait.
39//! - If an `Rc` or `Arc` should be measured only if it hasn't been seen
40//!   before, it should be measured via the `MallocConditionalSizeOf` trait.
41//! - Using universal function call syntax is a good idea when measuring boxed
42//!   fields in structs, because it makes it clear that the Box is being
43//!   measured as well as the thing it points to. E.g.
44//!   `<Box<_> as MallocSizeOf>::size_of(field, ops)`.
45//!
46//!   Note: WebRender has a reduced fork of this crate, so that we can avoid
47//!   publishing this crate on crates.io.
48
49use std::cell::OnceCell;
50use std::collections::BinaryHeap;
51use std::hash::{BuildHasher, Hash};
52use std::ops::Range;
53use std::rc::Rc;
54use std::sync::Arc;
55
56use style::properties::ComputedValues;
57use style::values::generics::length::GenericLengthPercentageOrAuto;
58pub use stylo_malloc_size_of::MallocSizeOfOps;
59use uuid::Uuid;
60
61/// Trait for measuring the "deep" heap usage of a data structure. This is the
62/// most commonly-used of the traits.
63pub trait MallocSizeOf {
64    /// Measure the heap usage of all descendant heap-allocated structures, but
65    /// not the space taken up by the value itself.
66    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
67}
68
69/// Trait for measuring the "shallow" heap usage of a container.
70pub trait MallocShallowSizeOf {
71    /// Measure the heap usage of immediate heap-allocated descendant
72    /// structures, but not the space taken up by the value itself. Anything
73    /// beyond the immediate descendants must be measured separately, using
74    /// iteration.
75    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
76}
77
78/// Like `MallocSizeOf`, but with a different name so it cannot be used
79/// accidentally with derive(MallocSizeOf). For use with types like `Rc` and
80/// `Arc` when appropriate (e.g. when measuring a "primary" reference).
81pub trait MallocUnconditionalSizeOf {
82    /// Measure the heap usage of all heap-allocated descendant structures, but
83    /// not the space taken up by the value itself.
84    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
85}
86
87/// `MallocUnconditionalSizeOf` combined with `MallocShallowSizeOf`.
88pub trait MallocUnconditionalShallowSizeOf {
89    /// `unconditional_size_of` combined with `shallow_size_of`.
90    fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
91}
92
93/// Like `MallocSizeOf`, but only measures if the value hasn't already been
94/// measured. For use with types like `Rc` and `Arc` when appropriate (e.g.
95/// when there is no "primary" reference).
96pub trait MallocConditionalSizeOf {
97    /// Measure the heap usage of all heap-allocated descendant structures, but
98    /// not the space taken up by the value itself, and only if that heap usage
99    /// hasn't already been measured.
100    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
101}
102
103/// `MallocConditionalSizeOf` combined with `MallocShallowSizeOf`.
104pub trait MallocConditionalShallowSizeOf {
105    /// `conditional_size_of` combined with `shallow_size_of`.
106    fn conditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
107}
108
109impl<T: MallocSizeOf> MallocSizeOf for [T] {
110    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
111        let mut n = 0;
112        for elem in self.iter() {
113            n += elem.size_of(ops);
114        }
115        n
116    }
117}
118
119impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for [T] {
120    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
121        self.iter()
122            .map(|element| element.conditional_size_of(ops))
123            .sum()
124    }
125}
126
127/// For use on types where size_of() returns 0.
128#[macro_export]
129macro_rules! malloc_size_of_is_0(
130    ($($ty:ty),+) => (
131        $(
132            impl $crate::MallocSizeOf for $ty {
133                #[inline(always)]
134                fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize {
135                    0
136                }
137            }
138        )+
139    );
140    ($($ty:ident<$($gen:ident),+>),+) => (
141        $(
142            impl<$($gen: $crate::MallocSizeOf),+> $crate::MallocSizeOf for $ty<$($gen),+> {
143                #[inline(always)]
144                fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize {
145                    0
146                }
147            }
148        )+
149    );
150);
151
152impl MallocSizeOf for keyboard_types::Key {
153    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
154        match &self {
155            keyboard_types::Key::Character(string) => {
156                <String as MallocSizeOf>::size_of(string, ops)
157            },
158            _ => 0,
159        }
160    }
161}
162
163impl MallocSizeOf for markup5ever::QualName {
164    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
165        self.prefix.size_of(ops) + self.ns.size_of(ops) + self.local.size_of(ops)
166    }
167}
168
169impl MallocSizeOf for String {
170    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
171        unsafe { ops.malloc_size_of(self.as_ptr()) }
172    }
173}
174
175impl<T: ?Sized> MallocSizeOf for &'_ T {
176    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
177        // Zero makes sense for a non-owning reference.
178        0
179    }
180}
181
182impl<T: ?Sized> MallocShallowSizeOf for Box<T> {
183    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
184        unsafe { ops.malloc_size_of(&**self) }
185    }
186}
187
188impl<T: MallocSizeOf + ?Sized> MallocSizeOf for Box<T> {
189    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
190        self.shallow_size_of(ops) + (**self).size_of(ops)
191    }
192}
193
194impl MallocSizeOf for () {
195    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
196        0
197    }
198}
199
200impl<T1, T2> MallocSizeOf for (T1, T2)
201where
202    T1: MallocSizeOf,
203    T2: MallocSizeOf,
204{
205    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
206        self.0.size_of(ops) + self.1.size_of(ops)
207    }
208}
209
210impl<T1, T2, T3> MallocSizeOf for (T1, T2, T3)
211where
212    T1: MallocSizeOf,
213    T2: MallocSizeOf,
214    T3: MallocSizeOf,
215{
216    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
217        self.0.size_of(ops) + self.1.size_of(ops) + self.2.size_of(ops)
218    }
219}
220
221impl<T1, T2, T3, T4> MallocSizeOf for (T1, T2, T3, T4)
222where
223    T1: MallocSizeOf,
224    T2: MallocSizeOf,
225    T3: MallocSizeOf,
226    T4: MallocSizeOf,
227{
228    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
229        self.0.size_of(ops) + self.1.size_of(ops) + self.2.size_of(ops) + self.3.size_of(ops)
230    }
231}
232
233impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for Option<T> {
234    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
235        if let Some(val) = self.as_ref() {
236            val.conditional_size_of(ops)
237        } else {
238            0
239        }
240    }
241}
242
243impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for Vec<T> {
244    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
245        let mut n = self.shallow_size_of(ops);
246        for elem in self.iter() {
247            n += elem.conditional_size_of(ops);
248        }
249        n
250    }
251}
252
253impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for std::collections::VecDeque<T> {
254    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
255        let mut n = self.shallow_size_of(ops);
256        for elem in self.iter() {
257            n += elem.conditional_size_of(ops);
258        }
259        n
260    }
261}
262
263impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for std::cell::RefCell<T> {
264    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
265        self.borrow().conditional_size_of(ops)
266    }
267}
268
269impl<T1, T2> MallocConditionalSizeOf for (T1, T2)
270where
271    T1: MallocConditionalSizeOf,
272    T2: MallocConditionalSizeOf,
273{
274    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
275        self.0.conditional_size_of(ops) + self.1.conditional_size_of(ops)
276    }
277}
278
279impl<T: MallocConditionalSizeOf + ?Sized> MallocConditionalSizeOf for Box<T> {
280    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
281        self.shallow_size_of(ops) + (**self).conditional_size_of(ops)
282    }
283}
284
285impl<T: MallocConditionalSizeOf, E: MallocSizeOf> MallocConditionalSizeOf for Result<T, E> {
286    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
287        match *self {
288            Ok(ref x) => x.conditional_size_of(ops),
289            Err(ref e) => e.size_of(ops),
290        }
291    }
292}
293
294impl MallocConditionalSizeOf for () {
295    fn conditional_size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
296        0
297    }
298}
299
300impl<T: MallocSizeOf> MallocSizeOf for Option<T> {
301    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
302        if let Some(val) = self.as_ref() {
303            val.size_of(ops)
304        } else {
305            0
306        }
307    }
308}
309
310impl<T: MallocSizeOf, E: MallocSizeOf> MallocSizeOf for Result<T, E> {
311    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
312        match *self {
313            Ok(ref x) => x.size_of(ops),
314            Err(ref e) => e.size_of(ops),
315        }
316    }
317}
318
319impl<T: MallocSizeOf + Copy> MallocSizeOf for std::cell::Cell<T> {
320    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
321        self.get().size_of(ops)
322    }
323}
324
325impl<T: MallocSizeOf> MallocSizeOf for std::cell::RefCell<T> {
326    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
327        self.borrow().size_of(ops)
328    }
329}
330
331impl<B: ?Sized + ToOwned> MallocSizeOf for std::borrow::Cow<'_, B>
332where
333    B::Owned: MallocSizeOf,
334{
335    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
336        match *self {
337            std::borrow::Cow::Borrowed(_) => 0,
338            std::borrow::Cow::Owned(ref b) => b.size_of(ops),
339        }
340    }
341}
342
343impl<T> MallocShallowSizeOf for Vec<T> {
344    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
345        unsafe { ops.malloc_size_of(self.as_ptr()) }
346    }
347}
348
349impl<T: MallocSizeOf> MallocSizeOf for Vec<T> {
350    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
351        let mut n = self.shallow_size_of(ops);
352        for elem in self.iter() {
353            n += elem.size_of(ops);
354        }
355        n
356    }
357}
358
359impl<T> MallocShallowSizeOf for std::collections::VecDeque<T> {
360    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
361        if ops.has_malloc_enclosing_size_of() {
362            if let Some(front) = self.front() {
363                // The front element is an interior pointer.
364                unsafe { ops.malloc_enclosing_size_of(front) }
365            } else {
366                // This assumes that no memory is allocated when the VecDeque is empty.
367                0
368            }
369        } else {
370            // An estimate.
371            self.capacity() * size_of::<T>()
372        }
373    }
374}
375
376impl<T: MallocSizeOf> MallocSizeOf for std::collections::VecDeque<T> {
377    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
378        let mut n = self.shallow_size_of(ops);
379        for elem in self.iter() {
380            n += elem.size_of(ops);
381        }
382        n
383    }
384}
385
386impl<A: smallvec::Array> MallocShallowSizeOf for smallvec::SmallVec<A> {
387    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
388        if self.spilled() {
389            unsafe { ops.malloc_size_of(self.as_ptr()) }
390        } else {
391            0
392        }
393    }
394}
395
396impl<A> MallocSizeOf for smallvec::SmallVec<A>
397where
398    A: smallvec::Array,
399    A::Item: MallocSizeOf,
400{
401    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
402        let mut n = self.shallow_size_of(ops);
403        for elem in self.iter() {
404            n += elem.size_of(ops);
405        }
406        n
407    }
408}
409
410impl<A: MallocConditionalSizeOf> MallocConditionalSizeOf for smallvec::SmallVec<A>
411where
412    A: smallvec::Array,
413    A::Item: MallocConditionalSizeOf,
414{
415    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
416        if !self.spilled() {
417            return 0;
418        }
419
420        self.shallow_size_of(ops) +
421            self.iter()
422                .map(|element| element.conditional_size_of(ops))
423                .sum::<usize>()
424    }
425}
426
427impl<T: MallocSizeOf> MallocSizeOf for BinaryHeap<T> {
428    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
429        self.iter().map(|element| element.size_of(ops)).sum()
430    }
431}
432
433macro_rules! malloc_size_of_hash_set {
434    ($ty:ty) => {
435        impl<T, S> MallocShallowSizeOf for $ty
436        where
437            T: Eq + Hash,
438            S: BuildHasher,
439        {
440            fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
441                if ops.has_malloc_enclosing_size_of() {
442                    // The first value from the iterator gives us an interior pointer.
443                    // `ops.malloc_enclosing_size_of()` then gives us the storage size.
444                    // This assumes that the `HashSet`'s contents (values and hashes)
445                    // are all stored in a single contiguous heap allocation.
446                    self.iter()
447                        .next()
448                        .map_or(0, |t| unsafe { ops.malloc_enclosing_size_of(t) })
449                } else {
450                    // An estimate.
451                    self.capacity() * (size_of::<T>() + size_of::<usize>())
452                }
453            }
454        }
455
456        impl<T, S> MallocSizeOf for $ty
457        where
458            T: Eq + Hash + MallocSizeOf,
459            S: BuildHasher,
460        {
461            fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
462                let mut n = self.shallow_size_of(ops);
463                for t in self.iter() {
464                    n += t.size_of(ops);
465                }
466                n
467            }
468        }
469    };
470}
471
472malloc_size_of_hash_set!(std::collections::HashSet<T, S>);
473
474macro_rules! malloc_size_of_hash_map {
475    ($ty:ty) => {
476        impl<K, V, S> MallocShallowSizeOf for $ty
477        where
478            K: Eq + Hash,
479            S: BuildHasher,
480        {
481            fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
482                // See the implementation for std::collections::HashSet for details.
483                if ops.has_malloc_enclosing_size_of() {
484                    self.values()
485                        .next()
486                        .map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) })
487                } else {
488                    self.capacity() * (size_of::<V>() + size_of::<K>() + size_of::<usize>())
489                }
490            }
491        }
492
493        impl<K, V, S> MallocSizeOf for $ty
494        where
495            K: Eq + Hash + MallocSizeOf,
496            V: MallocSizeOf,
497            S: BuildHasher,
498        {
499            fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
500                let mut n = self.shallow_size_of(ops);
501                for (k, v) in self.iter() {
502                    n += k.size_of(ops);
503                    n += v.size_of(ops);
504                }
505                n
506            }
507        }
508
509        impl<K, V, S> MallocConditionalSizeOf for $ty
510        where
511            K: Eq + Hash + MallocSizeOf,
512            V: MallocConditionalSizeOf,
513            S: BuildHasher,
514        {
515            fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
516                let mut n = self.shallow_size_of(ops);
517                for (k, v) in self.iter() {
518                    n += k.size_of(ops);
519                    n += v.conditional_size_of(ops);
520                }
521                n
522            }
523        }
524    };
525}
526
527malloc_size_of_hash_map!(std::collections::HashMap<K, V, S>);
528
529impl<K, V> MallocShallowSizeOf for std::collections::BTreeMap<K, V>
530where
531    K: Eq + Hash,
532{
533    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
534        if ops.has_malloc_enclosing_size_of() {
535            self.values()
536                .next()
537                .map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) })
538        } else {
539            self.len() * (size_of::<V>() + size_of::<K>() + size_of::<usize>())
540        }
541    }
542}
543
544impl<K, V> MallocSizeOf for std::collections::BTreeMap<K, V>
545where
546    K: Eq + Hash + MallocSizeOf,
547    V: MallocSizeOf,
548{
549    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
550        let mut n = self.shallow_size_of(ops);
551        for (k, v) in self.iter() {
552            n += k.size_of(ops);
553            n += v.size_of(ops);
554        }
555        n
556    }
557}
558
559// PhantomData is always 0.
560impl<T> MallocSizeOf for std::marker::PhantomData<T> {
561    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
562        0
563    }
564}
565
566impl<T: MallocSizeOf> MallocSizeOf for OnceCell<T> {
567    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
568        self.get()
569            .map(|interior| interior.size_of(ops))
570            .unwrap_or_default()
571    }
572}
573
574// See https://github.com/rust-lang/rust/issues/68318:
575// We don't want MallocSizeOf to be defined for Rc and Arc. If negative trait bounds are
576// ever allowed, this code should be uncommented.  Instead, there is a compile-fail test for
577// this.
578// impl<T> !MallocSizeOf for Arc<T> { }
579// impl<T> !MallocShallowSizeOf for Arc<T> { }
580
581impl<T> MallocUnconditionalShallowSizeOf for servo_arc::Arc<T> {
582    fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
583        unsafe { ops.malloc_size_of(self.heap_ptr()) }
584    }
585}
586
587impl<T: MallocSizeOf> MallocUnconditionalSizeOf for servo_arc::Arc<T> {
588    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
589        self.unconditional_shallow_size_of(ops) + (**self).size_of(ops)
590    }
591}
592
593impl<T> MallocConditionalShallowSizeOf for servo_arc::Arc<T> {
594    fn conditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
595        if ops.have_seen_ptr(self.heap_ptr()) {
596            0
597        } else {
598            self.unconditional_shallow_size_of(ops)
599        }
600    }
601}
602
603impl<T: MallocSizeOf> MallocConditionalSizeOf for servo_arc::Arc<T> {
604    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
605        if ops.have_seen_ptr(self.heap_ptr()) {
606            0
607        } else {
608            self.unconditional_size_of(ops)
609        }
610    }
611}
612
613impl<T> MallocUnconditionalShallowSizeOf for Arc<T> {
614    fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
615        unsafe { ops.malloc_size_of(Arc::as_ptr(self)) }
616    }
617}
618
619impl<T: MallocSizeOf> MallocUnconditionalSizeOf for Arc<T> {
620    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
621        self.unconditional_shallow_size_of(ops) + (**self).size_of(ops)
622    }
623}
624
625impl<T> MallocConditionalShallowSizeOf for Arc<T> {
626    fn conditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
627        if ops.have_seen_ptr(Arc::as_ptr(self)) {
628            0
629        } else {
630            self.unconditional_shallow_size_of(ops)
631        }
632    }
633}
634
635impl<T: MallocSizeOf> MallocConditionalSizeOf for Arc<T> {
636    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
637        if ops.have_seen_ptr(Arc::as_ptr(self)) {
638            0
639        } else {
640            self.unconditional_size_of(ops)
641        }
642    }
643}
644
645impl<T> MallocUnconditionalShallowSizeOf for Rc<T> {
646    fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
647        unsafe { ops.malloc_size_of(Rc::as_ptr(self)) }
648    }
649}
650
651impl<T: MallocSizeOf> MallocUnconditionalSizeOf for Rc<T> {
652    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
653        self.unconditional_shallow_size_of(ops) + (**self).size_of(ops)
654    }
655}
656
657impl<T: MallocSizeOf> MallocConditionalSizeOf for Rc<T> {
658    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
659        if ops.have_seen_ptr(Rc::as_ptr(self)) {
660            0
661        } else {
662            self.unconditional_size_of(ops)
663        }
664    }
665}
666
667/// If a mutex is stored directly as a member of a data type that is being measured,
668/// it is the unique owner of its contents and deserves to be measured.
669///
670/// If a mutex is stored inside of an Arc value as a member of a data type that is being measured,
671/// the Arc will not be automatically measured so there is no risk of overcounting the mutex's
672/// contents.
673impl<T: MallocSizeOf> MallocSizeOf for std::sync::Mutex<T> {
674    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
675        (*self.lock().unwrap()).size_of(ops)
676    }
677}
678
679impl<T: MallocSizeOf> MallocSizeOf for parking_lot::Mutex<T> {
680    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
681        (*self.lock()).size_of(ops)
682    }
683}
684
685impl<T: MallocSizeOf> MallocSizeOf for parking_lot::RwLock<T> {
686    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
687        (*self.read()).size_of(ops)
688    }
689}
690
691impl<T: MallocSizeOf, Unit> MallocSizeOf for euclid::Length<T, Unit> {
692    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
693        self.0.size_of(ops)
694    }
695}
696
697impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Scale<T, Src, Dst> {
698    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
699        self.0.size_of(ops)
700    }
701}
702
703impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Point2D<T, U> {
704    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
705        self.x.size_of(ops) + self.y.size_of(ops)
706    }
707}
708
709impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Box2D<T, U> {
710    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
711        self.min.size_of(ops) + self.max.size_of(ops)
712    }
713}
714
715impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Rect<T, U> {
716    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
717        self.origin.size_of(ops) + self.size.size_of(ops)
718    }
719}
720
721impl<T: MallocSizeOf, U> MallocSizeOf for euclid::SideOffsets2D<T, U> {
722    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
723        self.top.size_of(ops) +
724            self.right.size_of(ops) +
725            self.bottom.size_of(ops) +
726            self.left.size_of(ops)
727    }
728}
729
730impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Size2D<T, U> {
731    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
732        self.width.size_of(ops) + self.height.size_of(ops)
733    }
734}
735
736impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Transform2D<T, Src, Dst> {
737    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
738        self.m11.size_of(ops) +
739            self.m12.size_of(ops) +
740            self.m21.size_of(ops) +
741            self.m22.size_of(ops) +
742            self.m31.size_of(ops) +
743            self.m32.size_of(ops)
744    }
745}
746
747impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Transform3D<T, Src, Dst> {
748    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
749        self.m11.size_of(ops) +
750            self.m12.size_of(ops) +
751            self.m13.size_of(ops) +
752            self.m14.size_of(ops) +
753            self.m21.size_of(ops) +
754            self.m22.size_of(ops) +
755            self.m23.size_of(ops) +
756            self.m24.size_of(ops) +
757            self.m31.size_of(ops) +
758            self.m32.size_of(ops) +
759            self.m33.size_of(ops) +
760            self.m34.size_of(ops) +
761            self.m41.size_of(ops) +
762            self.m42.size_of(ops) +
763            self.m43.size_of(ops) +
764            self.m44.size_of(ops)
765    }
766}
767
768impl MallocSizeOf for url::Host {
769    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
770        match *self {
771            url::Host::Domain(ref s) => s.size_of(ops),
772            _ => 0,
773        }
774    }
775}
776
777impl MallocSizeOf for url::Url {
778    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
779        // TODO: This is an estimate, but a real size should be calculated in `rust-url` once
780        // it has support for `malloc_size_of`.
781        self.to_string().size_of(ops)
782    }
783}
784
785impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Vector2D<T, U> {
786    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
787        self.x.size_of(ops) + self.y.size_of(ops)
788    }
789}
790
791impl<Static: string_cache::StaticAtomSet> MallocSizeOf for string_cache::Atom<Static> {
792    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
793        0
794    }
795}
796
797// Placeholder for unique case where internals of Sender cannot be measured.
798// malloc size of is 0 macro complains about type supplied!
799impl<T> MallocSizeOf for crossbeam_channel::Sender<T> {
800    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
801        0
802    }
803}
804
805impl<T> MallocSizeOf for tokio::sync::mpsc::UnboundedSender<T> {
806    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
807        0
808    }
809}
810
811impl<T> MallocSizeOf for ipc_channel::ipc::IpcSender<T> {
812    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
813        0
814    }
815}
816
817impl<T> MallocSizeOf for ipc_channel::ipc::IpcReceiver<T> {
818    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
819        0
820    }
821}
822
823impl MallocSizeOf for ipc_channel::ipc::IpcSharedMemory {
824    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
825        self.len()
826    }
827}
828
829impl<T: MallocSizeOf> MallocSizeOf for accountable_refcell::RefCell<T> {
830    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
831        self.borrow().size_of(ops)
832    }
833}
834
835impl MallocSizeOf for servo_arc::Arc<ComputedValues> {
836    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
837        self.conditional_size_of(ops)
838    }
839}
840
841malloc_size_of_hash_map!(indexmap::IndexMap<K, V, S>);
842malloc_size_of_hash_set!(indexmap::IndexSet<T, S>);
843
844malloc_size_of_is_0!(bool, char, str);
845malloc_size_of_is_0!(f32, f64);
846malloc_size_of_is_0!(i8, i16, i32, i64, i128, isize);
847malloc_size_of_is_0!(u8, u16, u32, u64, u128, usize);
848
849malloc_size_of_is_0!(Range<f32>, Range<f64>);
850malloc_size_of_is_0!(Range<i8>, Range<i16>, Range<i32>, Range<i64>, Range<isize>);
851malloc_size_of_is_0!(Range<u8>, Range<u16>, Range<u32>, Range<u64>, Range<usize>);
852malloc_size_of_is_0!(Uuid);
853malloc_size_of_is_0!(app_units::Au);
854malloc_size_of_is_0!(content_security_policy::Destination);
855malloc_size_of_is_0!(content_security_policy::sandboxing_directive::SandboxingFlagSet);
856malloc_size_of_is_0!(http::StatusCode);
857malloc_size_of_is_0!(keyboard_types::Modifiers);
858malloc_size_of_is_0!(mime::Mime);
859malloc_size_of_is_0!(resvg::usvg::Tree);
860malloc_size_of_is_0!(std::num::NonZeroU16);
861malloc_size_of_is_0!(std::num::NonZeroU64);
862malloc_size_of_is_0!(std::num::NonZeroUsize);
863malloc_size_of_is_0!(std::sync::atomic::AtomicBool);
864malloc_size_of_is_0!(std::sync::atomic::AtomicIsize);
865malloc_size_of_is_0!(std::sync::atomic::AtomicUsize);
866malloc_size_of_is_0!(std::time::Duration);
867malloc_size_of_is_0!(std::time::Instant);
868malloc_size_of_is_0!(std::time::SystemTime);
869malloc_size_of_is_0!(style::data::ElementData);
870malloc_size_of_is_0!(style::font_face::SourceList);
871malloc_size_of_is_0!(style::properties::ComputedValues);
872malloc_size_of_is_0!(style::properties::declaration_block::PropertyDeclarationBlock);
873malloc_size_of_is_0!(style::queries::values::PrefersColorScheme);
874malloc_size_of_is_0!(style::stylesheets::Stylesheet);
875malloc_size_of_is_0!(style::values::specified::source_size_list::SourceSizeList);
876malloc_size_of_is_0!(taffy::Layout);
877malloc_size_of_is_0!(unicode_bidi::Level);
878malloc_size_of_is_0!(unicode_script::Script);
879malloc_size_of_is_0!(urlpattern::UrlPattern);
880
881macro_rules! malloc_size_of_is_webrender_malloc_size_of(
882    ($($ty:ty),+) => (
883        $(
884            impl MallocSizeOf for $ty {
885                fn size_of(&self, _: &mut MallocSizeOfOps) -> usize {
886                    let mut ops = wr_malloc_size_of::MallocSizeOfOps::new(servo_allocator::usable_size, None);
887                    <$ty as wr_malloc_size_of::MallocSizeOf>::size_of(self, &mut ops)
888                }
889            }
890        )+
891    );
892);
893
894malloc_size_of_is_webrender_malloc_size_of!(webrender_api::BorderRadius);
895malloc_size_of_is_webrender_malloc_size_of!(webrender_api::BorderStyle);
896malloc_size_of_is_webrender_malloc_size_of!(webrender_api::BoxShadowClipMode);
897malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ColorF);
898malloc_size_of_is_webrender_malloc_size_of!(webrender_api::Epoch);
899malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ExtendMode);
900malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ExternalScrollId);
901malloc_size_of_is_webrender_malloc_size_of!(webrender_api::FontKey);
902malloc_size_of_is_webrender_malloc_size_of!(webrender_api::FontInstanceFlags);
903malloc_size_of_is_webrender_malloc_size_of!(webrender_api::FontInstanceKey);
904malloc_size_of_is_webrender_malloc_size_of!(webrender_api::GlyphInstance);
905malloc_size_of_is_webrender_malloc_size_of!(webrender_api::GradientStop);
906malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ImageKey);
907malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ImageRendering);
908malloc_size_of_is_webrender_malloc_size_of!(webrender_api::LineStyle);
909malloc_size_of_is_webrender_malloc_size_of!(webrender_api::MixBlendMode);
910malloc_size_of_is_webrender_malloc_size_of!(webrender_api::NormalBorder);
911malloc_size_of_is_webrender_malloc_size_of!(webrender_api::PipelineId);
912malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ReferenceFrameKind);
913malloc_size_of_is_webrender_malloc_size_of!(webrender_api::RepeatMode);
914malloc_size_of_is_webrender_malloc_size_of!(webrender_api::FontVariation);
915malloc_size_of_is_webrender_malloc_size_of!(webrender_api::SpatialId);
916malloc_size_of_is_webrender_malloc_size_of!(webrender_api::StickyOffsetBounds);
917malloc_size_of_is_webrender_malloc_size_of!(webrender_api::TransformStyle);
918malloc_size_of_is_webrender_malloc_size_of!(webrender::FastTransform<webrender_api::units::LayoutPixel,webrender_api::units::LayoutPixel>);
919
920macro_rules! malloc_size_of_is_stylo_malloc_size_of(
921    ($($ty:ty),+) => (
922        $(
923            impl MallocSizeOf for $ty {
924                fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
925                    <$ty as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
926                }
927            }
928        )+
929    );
930);
931
932impl<S> MallocSizeOf for style::author_styles::GenericAuthorStyles<S>
933where
934    S: style::stylesheets::StylesheetInDocument
935        + std::cmp::PartialEq
936        + stylo_malloc_size_of::MallocSizeOf,
937{
938    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
939        <style::author_styles::GenericAuthorStyles<S> as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
940    }
941}
942
943impl<S> MallocSizeOf for style::stylesheet_set::DocumentStylesheetSet<S>
944where
945    S: style::stylesheets::StylesheetInDocument
946        + std::cmp::PartialEq
947        + stylo_malloc_size_of::MallocSizeOf,
948{
949    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
950        <style::stylesheet_set::DocumentStylesheetSet<S> as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
951    }
952}
953
954impl<T> MallocSizeOf for style::shared_lock::Locked<T> {
955    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
956        // TODO: fix this implementation when Locked derives MallocSizeOf.
957        0
958        // <style::shared_lock::Locked<T> as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
959    }
960}
961
962impl<T: MallocSizeOf> MallocSizeOf for atomic_refcell::AtomicRefCell<T> {
963    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
964        self.borrow().size_of(ops)
965    }
966}
967
968malloc_size_of_is_stylo_malloc_size_of!(style::animation::DocumentAnimationSet);
969malloc_size_of_is_stylo_malloc_size_of!(style::attr::AttrIdentifier);
970malloc_size_of_is_stylo_malloc_size_of!(style::attr::AttrValue);
971malloc_size_of_is_stylo_malloc_size_of!(style::color::AbsoluteColor);
972malloc_size_of_is_stylo_malloc_size_of!(style::computed_values::font_variant_caps::T);
973malloc_size_of_is_stylo_malloc_size_of!(style::computed_values::text_decoration_style::T);
974malloc_size_of_is_stylo_malloc_size_of!(style::dom::OpaqueNode);
975malloc_size_of_is_stylo_malloc_size_of!(style::invalidation::element::restyle_hints::RestyleHint);
976malloc_size_of_is_stylo_malloc_size_of!(style::logical_geometry::WritingMode);
977malloc_size_of_is_stylo_malloc_size_of!(style::media_queries::MediaList);
978malloc_size_of_is_stylo_malloc_size_of!(
979    style::properties::longhands::align_items::computed_value::T
980);
981malloc_size_of_is_stylo_malloc_size_of!(
982    style::properties::longhands::flex_direction::computed_value::T
983);
984malloc_size_of_is_stylo_malloc_size_of!(style::properties::longhands::flex_wrap::computed_value::T);
985malloc_size_of_is_stylo_malloc_size_of!(style::properties::style_structs::Font);
986malloc_size_of_is_stylo_malloc_size_of!(style::selector_parser::PseudoElement);
987malloc_size_of_is_stylo_malloc_size_of!(style::selector_parser::RestyleDamage);
988malloc_size_of_is_stylo_malloc_size_of!(style::selector_parser::Snapshot);
989malloc_size_of_is_stylo_malloc_size_of!(style::shared_lock::SharedRwLock);
990malloc_size_of_is_stylo_malloc_size_of!(style::stylesheets::DocumentStyleSheet);
991malloc_size_of_is_stylo_malloc_size_of!(style::stylist::Stylist);
992malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::AlignContent);
993malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::BorderStyle);
994malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::FontStretch);
995malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::FontStyle);
996malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::FontWeight);
997malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::font::SingleFontFamily);
998malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::JustifyContent);
999malloc_size_of_is_stylo_malloc_size_of!(style::values::specified::align::AlignFlags);
1000malloc_size_of_is_stylo_malloc_size_of!(style::values::specified::box_::Overflow);
1001malloc_size_of_is_stylo_malloc_size_of!(style::values::specified::font::FontSynthesis);
1002malloc_size_of_is_stylo_malloc_size_of!(style::values::specified::TextDecorationLine);
1003malloc_size_of_is_stylo_malloc_size_of!(stylo_dom::ElementState);
1004
1005impl<T> MallocSizeOf for GenericLengthPercentageOrAuto<T>
1006where
1007    T: stylo_malloc_size_of::MallocSizeOf,
1008{
1009    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1010        <GenericLengthPercentageOrAuto<T> as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
1011    }
1012}