Skip to main content

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::ffi::CString;
52use std::hash::{BuildHasher, Hash};
53use std::ops::{Range, RangeInclusive};
54use std::rc::Rc;
55use std::sync::{Arc, OnceLock};
56
57use cookie::Cookie;
58use resvg::usvg::fontdb::Source;
59use resvg::usvg::{self, tiny_skia_path};
60use style::properties::ComputedValues;
61use style::values::generics::length::GenericLengthPercentageOrAuto;
62pub use stylo_malloc_size_of::MallocSizeOfOps;
63
64/// Trait for measuring the "deep" heap usage of a data structure. This is the
65/// most commonly-used of the traits.
66pub trait MallocSizeOf {
67    /// Measure the heap usage of all descendant heap-allocated structures, but
68    /// not the space taken up by the value itself.
69    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
70}
71
72/// Trait for measuring the "shallow" heap usage of a container.
73pub trait MallocShallowSizeOf {
74    /// Measure the heap usage of immediate heap-allocated descendant
75    /// structures, but not the space taken up by the value itself. Anything
76    /// beyond the immediate descendants must be measured separately, using
77    /// iteration.
78    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
79}
80
81/// Like `MallocSizeOf`, but with a different name so it cannot be used
82/// accidentally with derive(MallocSizeOf). For use with types like `Rc` and
83/// `Arc` when appropriate (e.g. when measuring a "primary" reference).
84pub trait MallocUnconditionalSizeOf {
85    /// Measure the heap usage of all heap-allocated descendant structures, but
86    /// not the space taken up by the value itself.
87    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
88}
89
90/// `MallocUnconditionalSizeOf` combined with `MallocShallowSizeOf`.
91pub trait MallocUnconditionalShallowSizeOf {
92    /// `unconditional_size_of` combined with `shallow_size_of`.
93    fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
94}
95
96/// Like `MallocSizeOf`, but only measures if the value hasn't already been
97/// measured. For use with types like `Rc` and `Arc` when appropriate (e.g.
98/// when there is no "primary" reference).
99pub trait MallocConditionalSizeOf {
100    /// Measure the heap usage of all heap-allocated descendant structures, but
101    /// not the space taken up by the value itself, and only if that heap usage
102    /// hasn't already been measured.
103    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
104}
105
106/// `MallocConditionalSizeOf` combined with `MallocShallowSizeOf`.
107pub trait MallocConditionalShallowSizeOf {
108    /// `conditional_size_of` combined with `shallow_size_of`.
109    fn conditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
110}
111
112impl<T: MallocSizeOf> MallocSizeOf for [T] {
113    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
114        let mut n = 0;
115        for elem in self.iter() {
116            n += elem.size_of(ops);
117        }
118        n
119    }
120}
121
122impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for [T] {
123    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
124        self.iter()
125            .map(|element| element.conditional_size_of(ops))
126            .sum()
127    }
128}
129
130/// For use on types where size_of() returns 0.
131#[macro_export]
132macro_rules! malloc_size_of_is_0(
133    ($($ty:ty),+) => (
134        $(
135            impl $crate::MallocSizeOf for $ty {
136                #[inline(always)]
137                fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize {
138                    0
139                }
140            }
141        )+
142    );
143    ($($ty:ident<$($gen:ident),+>),+) => (
144        $(
145            impl<$($gen: $crate::MallocSizeOf),+> $crate::MallocSizeOf for $ty<$($gen),+> {
146                #[inline(always)]
147                fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize {
148                    0
149                }
150            }
151        )+
152    );
153);
154
155impl MallocSizeOf for keyboard_types::Key {
156    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
157        match &self {
158            keyboard_types::Key::Character(string) => {
159                <String as MallocSizeOf>::size_of(string, ops)
160            },
161            _ => 0,
162        }
163    }
164}
165
166impl MallocSizeOf for markup5ever::QualName {
167    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
168        self.prefix.size_of(ops) + self.ns.size_of(ops) + self.local.size_of(ops)
169    }
170}
171
172impl MallocSizeOf for String {
173    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
174        unsafe { ops.malloc_size_of(self.as_ptr()) }
175    }
176}
177
178impl MallocSizeOf for CString {
179    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
180        unsafe { ops.malloc_size_of(self.as_ptr()) }
181    }
182}
183
184impl<T: ?Sized> MallocSizeOf for &'_ T {
185    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
186        // Zero makes sense for a non-owning reference.
187        0
188    }
189}
190
191impl<T: ?Sized> MallocShallowSizeOf for Box<T> {
192    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
193        unsafe { ops.malloc_size_of(&**self) }
194    }
195}
196
197impl<T: MallocSizeOf + ?Sized> MallocSizeOf for Box<T> {
198    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
199        self.shallow_size_of(ops) + (**self).size_of(ops)
200    }
201}
202
203impl MallocSizeOf for () {
204    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
205        0
206    }
207}
208
209impl<T1, T2> MallocSizeOf for (T1, T2)
210where
211    T1: MallocSizeOf,
212    T2: MallocSizeOf,
213{
214    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
215        self.0.size_of(ops) + self.1.size_of(ops)
216    }
217}
218
219impl<T1, T2, T3> MallocSizeOf for (T1, T2, T3)
220where
221    T1: MallocSizeOf,
222    T2: MallocSizeOf,
223    T3: MallocSizeOf,
224{
225    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
226        self.0.size_of(ops) + self.1.size_of(ops) + self.2.size_of(ops)
227    }
228}
229
230impl<T1, T2, T3, T4> MallocSizeOf for (T1, T2, T3, T4)
231where
232    T1: MallocSizeOf,
233    T2: MallocSizeOf,
234    T3: MallocSizeOf,
235    T4: MallocSizeOf,
236{
237    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
238        self.0.size_of(ops) + self.1.size_of(ops) + self.2.size_of(ops) + self.3.size_of(ops)
239    }
240}
241
242impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for Option<T> {
243    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
244        if let Some(val) = self.as_ref() {
245            val.conditional_size_of(ops)
246        } else {
247            0
248        }
249    }
250}
251
252impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for Vec<T> {
253    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
254        let mut n = self.shallow_size_of(ops);
255        for elem in self.iter() {
256            n += elem.conditional_size_of(ops);
257        }
258        n
259    }
260}
261
262impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for std::collections::VecDeque<T> {
263    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
264        let mut n = self.shallow_size_of(ops);
265        for elem in self.iter() {
266            n += elem.conditional_size_of(ops);
267        }
268        n
269    }
270}
271
272impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for std::cell::RefCell<T> {
273    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
274        self.borrow().conditional_size_of(ops)
275    }
276}
277
278impl<T1, T2> MallocConditionalSizeOf for (T1, T2)
279where
280    T1: MallocConditionalSizeOf,
281    T2: MallocConditionalSizeOf,
282{
283    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
284        self.0.conditional_size_of(ops) + self.1.conditional_size_of(ops)
285    }
286}
287
288impl<T: MallocConditionalSizeOf + ?Sized> MallocConditionalSizeOf for Box<T> {
289    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
290        self.shallow_size_of(ops) + (**self).conditional_size_of(ops)
291    }
292}
293
294impl<T: MallocConditionalSizeOf, E: MallocSizeOf> MallocConditionalSizeOf for Result<T, E> {
295    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
296        match *self {
297            Ok(ref x) => x.conditional_size_of(ops),
298            Err(ref e) => e.size_of(ops),
299        }
300    }
301}
302
303impl MallocConditionalSizeOf for () {
304    fn conditional_size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
305        0
306    }
307}
308
309impl<T: MallocSizeOf> MallocSizeOf for Option<T> {
310    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
311        if let Some(val) = self.as_ref() {
312            val.size_of(ops)
313        } else {
314            0
315        }
316    }
317}
318
319impl<T: MallocSizeOf, E: MallocSizeOf> MallocSizeOf for Result<T, E> {
320    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
321        match *self {
322            Ok(ref x) => x.size_of(ops),
323            Err(ref e) => e.size_of(ops),
324        }
325    }
326}
327
328impl<T: MallocSizeOf + Copy> MallocSizeOf for std::cell::Cell<T> {
329    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
330        self.get().size_of(ops)
331    }
332}
333
334impl<T: MallocSizeOf> MallocSizeOf for std::cell::RefCell<T> {
335    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
336        self.borrow().size_of(ops)
337    }
338}
339
340impl<B: ?Sized + ToOwned> MallocSizeOf for std::borrow::Cow<'_, B>
341where
342    B::Owned: MallocSizeOf,
343{
344    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
345        match *self {
346            std::borrow::Cow::Borrowed(_) => 0,
347            std::borrow::Cow::Owned(ref b) => b.size_of(ops),
348        }
349    }
350}
351
352impl<T> MallocShallowSizeOf for Vec<T> {
353    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
354        unsafe { ops.malloc_size_of(self.as_ptr()) }
355    }
356}
357
358impl<T: MallocSizeOf> MallocSizeOf for Vec<T> {
359    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
360        let mut n = self.shallow_size_of(ops);
361        for elem in self.iter() {
362            n += elem.size_of(ops);
363        }
364        n
365    }
366}
367
368impl<T> MallocShallowSizeOf for std::collections::VecDeque<T> {
369    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
370        if ops.has_malloc_enclosing_size_of() {
371            if let Some(front) = self.front() {
372                // The front element is an interior pointer.
373                unsafe { ops.malloc_enclosing_size_of(front) }
374            } else {
375                // This assumes that no memory is allocated when the VecDeque is empty.
376                0
377            }
378        } else {
379            // An estimate.
380            self.capacity() * size_of::<T>()
381        }
382    }
383}
384
385impl<T: MallocSizeOf> MallocSizeOf for std::collections::VecDeque<T> {
386    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
387        let mut n = self.shallow_size_of(ops);
388        for elem in self.iter() {
389            n += elem.size_of(ops);
390        }
391        n
392    }
393}
394
395impl MallocSizeOf for std::path::PathBuf {
396    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
397        // This should be an approximation of the actual size
398        self.as_os_str().as_encoded_bytes().len()
399    }
400}
401
402impl<A: smallvec::Array> MallocShallowSizeOf for smallvec::SmallVec<A> {
403    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
404        if self.spilled() {
405            unsafe { ops.malloc_size_of(self.as_ptr()) }
406        } else {
407            0
408        }
409    }
410}
411
412impl<A> MallocSizeOf for smallvec::SmallVec<A>
413where
414    A: smallvec::Array,
415    A::Item: MallocSizeOf,
416{
417    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
418        let mut n = self.shallow_size_of(ops);
419        for elem in self.iter() {
420            n += elem.size_of(ops);
421        }
422        n
423    }
424}
425
426impl<A: MallocConditionalSizeOf> MallocConditionalSizeOf for smallvec::SmallVec<A>
427where
428    A: smallvec::Array,
429    A::Item: MallocConditionalSizeOf,
430{
431    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
432        if !self.spilled() {
433            return 0;
434        }
435
436        self.shallow_size_of(ops) +
437            self.iter()
438                .map(|element| element.conditional_size_of(ops))
439                .sum::<usize>()
440    }
441}
442
443impl<T: MallocSizeOf> MallocSizeOf for BinaryHeap<T> {
444    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
445        self.iter().map(|element| element.size_of(ops)).sum()
446    }
447}
448
449impl<T: MallocSizeOf> MallocSizeOf for std::collections::BTreeSet<T> {
450    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
451        self.iter().map(|element| element.size_of(ops)).sum()
452    }
453}
454
455impl<T: MallocSizeOf> MallocSizeOf for Range<T> {
456    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
457        self.start.size_of(ops) + self.end.size_of(ops)
458    }
459}
460
461impl<T: MallocSizeOf> MallocSizeOf for RangeInclusive<T> {
462    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
463        self.start().size_of(ops) + self.end().size_of(ops)
464    }
465}
466
467macro_rules! malloc_size_of_hash_set {
468    ($ty:ty) => {
469        impl<T, S> MallocShallowSizeOf for $ty
470        where
471            T: Eq + Hash,
472            S: BuildHasher,
473        {
474            fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
475                if ops.has_malloc_enclosing_size_of() {
476                    // The first value from the iterator gives us an interior pointer.
477                    // `ops.malloc_enclosing_size_of()` then gives us the storage size.
478                    // This assumes that the `HashSet`'s contents (values and hashes)
479                    // are all stored in a single contiguous heap allocation.
480                    self.iter()
481                        .next()
482                        .map_or(0, |t| unsafe { ops.malloc_enclosing_size_of(t) })
483                } else {
484                    // An estimate.
485                    self.capacity() * (size_of::<T>() + size_of::<usize>())
486                }
487            }
488        }
489
490        impl<T, S> MallocSizeOf for $ty
491        where
492            T: Eq + Hash + MallocSizeOf,
493            S: BuildHasher,
494        {
495            fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
496                let mut n = self.shallow_size_of(ops);
497                for t in self.iter() {
498                    n += t.size_of(ops);
499                }
500                n
501            }
502        }
503    };
504}
505
506malloc_size_of_hash_set!(std::collections::HashSet<T, S>);
507
508macro_rules! malloc_size_of_hash_map {
509    ($ty:ty) => {
510        impl<K, V, S> MallocShallowSizeOf for $ty
511        where
512            K: Eq + Hash,
513            S: BuildHasher,
514        {
515            fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
516                // See the implementation for std::collections::HashSet for details.
517                if ops.has_malloc_enclosing_size_of() {
518                    self.values()
519                        .next()
520                        .map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) })
521                } else {
522                    self.capacity() * (size_of::<V>() + size_of::<K>() + size_of::<usize>())
523                }
524            }
525        }
526
527        impl<K, V, S> MallocSizeOf for $ty
528        where
529            K: Eq + Hash + MallocSizeOf,
530            V: MallocSizeOf,
531            S: BuildHasher,
532        {
533            fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
534                let mut n = self.shallow_size_of(ops);
535                for (k, v) in self.iter() {
536                    n += k.size_of(ops);
537                    n += v.size_of(ops);
538                }
539                n
540            }
541        }
542
543        impl<K, V, S> MallocConditionalSizeOf for $ty
544        where
545            K: Eq + Hash + MallocSizeOf,
546            V: MallocConditionalSizeOf,
547            S: BuildHasher,
548        {
549            fn conditional_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.conditional_size_of(ops);
554                }
555                n
556            }
557        }
558    };
559}
560
561malloc_size_of_hash_map!(std::collections::HashMap<K, V, S>);
562
563impl<K, V> MallocShallowSizeOf for std::collections::BTreeMap<K, V>
564where
565    K: Eq + Hash,
566{
567    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
568        if ops.has_malloc_enclosing_size_of() {
569            self.values()
570                .next()
571                .map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) })
572        } else {
573            self.len() * (size_of::<V>() + size_of::<K>() + size_of::<usize>())
574        }
575    }
576}
577
578impl<K, V> MallocSizeOf for std::collections::BTreeMap<K, V>
579where
580    K: Eq + Hash + MallocSizeOf,
581    V: MallocSizeOf,
582{
583    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
584        let mut n = self.shallow_size_of(ops);
585        for (k, v) in self.iter() {
586            n += k.size_of(ops);
587            n += v.size_of(ops);
588        }
589        n
590    }
591}
592
593// PhantomData is always 0.
594impl<T> MallocSizeOf for std::marker::PhantomData<T> {
595    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
596        0
597    }
598}
599
600impl<T: MallocSizeOf> MallocSizeOf for OnceCell<T> {
601    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
602        self.get()
603            .map(|interior| interior.size_of(ops))
604            .unwrap_or_default()
605    }
606}
607
608impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for OnceCell<T> {
609    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
610        self.get()
611            .map(|interior| interior.conditional_size_of(ops))
612            .unwrap_or_default()
613    }
614}
615
616impl<T: MallocSizeOf> MallocSizeOf for OnceLock<T> {
617    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
618        self.get()
619            .map(|interior| interior.size_of(ops))
620            .unwrap_or_default()
621    }
622}
623
624impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for OnceLock<T> {
625    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
626        self.get()
627            .map(|interior| interior.conditional_size_of(ops))
628            .unwrap_or_default()
629    }
630}
631
632// See https://github.com/rust-lang/rust/issues/68318:
633// We don't want MallocSizeOf to be defined for Rc and Arc. If negative trait bounds are
634// ever allowed, this code should be uncommented.  Instead, there is a compile-fail test for
635// this.
636// impl<T> !MallocSizeOf for Arc<T> { }
637// impl<T> !MallocShallowSizeOf for Arc<T> { }
638
639impl<T> MallocUnconditionalShallowSizeOf for servo_arc::Arc<T> {
640    fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
641        unsafe { ops.malloc_size_of(self.heap_ptr()) }
642    }
643}
644
645impl<T: MallocSizeOf> MallocUnconditionalSizeOf for servo_arc::Arc<T> {
646    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
647        self.unconditional_shallow_size_of(ops) + (**self).size_of(ops)
648    }
649}
650
651impl<T> MallocConditionalShallowSizeOf for servo_arc::Arc<T> {
652    fn conditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
653        if ops.have_seen_ptr(self.heap_ptr()) {
654            0
655        } else {
656            self.unconditional_shallow_size_of(ops)
657        }
658    }
659}
660
661impl<T: MallocSizeOf> MallocConditionalSizeOf for servo_arc::Arc<T> {
662    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
663        if ops.have_seen_ptr(self.heap_ptr()) {
664            0
665        } else {
666            self.unconditional_size_of(ops)
667        }
668    }
669}
670
671/// Recover the allocation base: `Arc::as_ptr`/`Rc::as_ptr` point at the data
672/// after the two reference counts in the `#[repr(C)]` heap allocation.
673fn refcounted_allocation_base<T>(data: *const T) -> *const T {
674    let data_offset = std::mem::align_of::<T>().max(std::mem::size_of::<usize>() * 2);
675    data.wrapping_byte_sub(data_offset)
676}
677
678impl<T> MallocUnconditionalShallowSizeOf for Arc<T> {
679    fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
680        unsafe { ops.malloc_size_of(refcounted_allocation_base(Arc::as_ptr(self))) }
681    }
682}
683
684impl<T: MallocSizeOf> MallocUnconditionalSizeOf for Arc<T> {
685    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
686        self.unconditional_shallow_size_of(ops) + (**self).size_of(ops)
687    }
688}
689
690impl<T> MallocConditionalShallowSizeOf for Arc<T> {
691    fn conditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
692        if ops.have_seen_ptr(Arc::as_ptr(self)) {
693            0
694        } else {
695            self.unconditional_shallow_size_of(ops)
696        }
697    }
698}
699
700impl<T: MallocSizeOf> MallocConditionalSizeOf for Arc<T> {
701    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
702        if ops.have_seen_ptr(Arc::as_ptr(self)) {
703            0
704        } else {
705            self.unconditional_size_of(ops)
706        }
707    }
708}
709
710impl<T> MallocUnconditionalShallowSizeOf for Rc<T> {
711    fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
712        unsafe { ops.malloc_size_of(refcounted_allocation_base(Rc::as_ptr(self))) }
713    }
714}
715
716impl<T: MallocSizeOf> MallocUnconditionalSizeOf for Rc<T> {
717    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
718        self.unconditional_shallow_size_of(ops) + (**self).size_of(ops)
719    }
720}
721
722impl<T: MallocSizeOf> MallocConditionalSizeOf for Rc<T> {
723    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
724        if ops.have_seen_ptr(Rc::as_ptr(self)) {
725            0
726        } else {
727            self.unconditional_size_of(ops)
728        }
729    }
730}
731
732impl<T: MallocSizeOf> MallocSizeOf for std::sync::Weak<T> {
733    fn size_of(&self, _: &mut MallocSizeOfOps) -> usize {
734        // A weak reference to the data necessarily has another strong reference
735        // somewhere else where it can be measured or...it's been released and is zero.
736        0
737    }
738}
739
740impl MallocSizeOf for bytes::Bytes {
741    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
742        // This is an underapproximation but because it is efficiently stored, we might not have the correct data.
743        if self.is_unique() { self.len() } else { 0 }
744    }
745}
746
747impl MallocSizeOf for bytes::BytesMut {
748    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
749        // This is an underapproximation but because it is efficiently stored, we might not have the correct data.
750        self.len()
751    }
752}
753
754/// If a mutex is stored directly as a member of a data type that is being measured,
755/// it is the unique owner of its contents and deserves to be measured.
756///
757/// If a mutex is stored inside of an Arc value as a member of a data type that is being measured,
758/// the Arc will not be automatically measured so there is no risk of overcounting the mutex's
759/// contents.
760impl<T: MallocSizeOf> MallocSizeOf for std::sync::Mutex<T> {
761    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
762        (*self.lock().unwrap()).size_of(ops)
763    }
764}
765
766impl<T: MallocSizeOf> MallocSizeOf for std::sync::RwLock<T> {
767    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
768        (*self.read().unwrap()).size_of(ops)
769    }
770}
771
772impl<T: MallocSizeOf> MallocSizeOf for parking_lot::Mutex<T> {
773    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
774        (*self.lock()).size_of(ops)
775    }
776}
777
778impl<T: MallocSizeOf> MallocSizeOf for tokio::sync::Mutex<T> {
779    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
780        self.blocking_lock().size_of(ops)
781    }
782}
783
784impl<T: MallocSizeOf> MallocSizeOf for tokio::sync::RwLock<T> {
785    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
786        self.blocking_read().size_of(ops)
787    }
788}
789
790impl<T: MallocSizeOf> MallocSizeOf for parking_lot::RwLock<T> {
791    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
792        (*self.read()).size_of(ops)
793    }
794}
795
796impl<T: MallocConditionalSizeOf> MallocConditionalSizeOf for parking_lot::RwLock<T> {
797    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
798        (*self.read()).conditional_size_of(ops)
799    }
800}
801
802impl<T: MallocSizeOf, Unit> MallocSizeOf for euclid::Length<T, Unit> {
803    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
804        self.0.size_of(ops)
805    }
806}
807
808impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Scale<T, Src, Dst> {
809    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
810        self.0.size_of(ops)
811    }
812}
813
814impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Point2D<T, U> {
815    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
816        self.x.size_of(ops) + self.y.size_of(ops)
817    }
818}
819
820impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Box2D<T, U> {
821    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
822        self.min.size_of(ops) + self.max.size_of(ops)
823    }
824}
825
826impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Vector3D<T, U> {
827    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
828        self.x.size_of(ops) + self.y.size_of(ops) + self.z.size_of(ops)
829    }
830}
831
832impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Rect<T, U> {
833    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
834        self.origin.size_of(ops) + self.size.size_of(ops)
835    }
836}
837
838impl<T: MallocSizeOf, U> MallocSizeOf for euclid::SideOffsets2D<T, U> {
839    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
840        self.top.size_of(ops) +
841            self.right.size_of(ops) +
842            self.bottom.size_of(ops) +
843            self.left.size_of(ops)
844    }
845}
846
847impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Size2D<T, U> {
848    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
849        self.width.size_of(ops) + self.height.size_of(ops)
850    }
851}
852
853impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Transform2D<T, Src, Dst> {
854    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
855        self.m11.size_of(ops) +
856            self.m12.size_of(ops) +
857            self.m21.size_of(ops) +
858            self.m22.size_of(ops) +
859            self.m31.size_of(ops) +
860            self.m32.size_of(ops)
861    }
862}
863
864impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Transform3D<T, Src, Dst> {
865    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
866        self.m11.size_of(ops) +
867            self.m12.size_of(ops) +
868            self.m13.size_of(ops) +
869            self.m14.size_of(ops) +
870            self.m21.size_of(ops) +
871            self.m22.size_of(ops) +
872            self.m23.size_of(ops) +
873            self.m24.size_of(ops) +
874            self.m31.size_of(ops) +
875            self.m32.size_of(ops) +
876            self.m33.size_of(ops) +
877            self.m34.size_of(ops) +
878            self.m41.size_of(ops) +
879            self.m42.size_of(ops) +
880            self.m43.size_of(ops) +
881            self.m44.size_of(ops)
882    }
883}
884
885impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::RigidTransform3D<T, Src, Dst> {
886    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
887        self.rotation.i.size_of(ops) +
888            self.rotation.j.size_of(ops) +
889            self.rotation.k.size_of(ops) +
890            self.rotation.r.size_of(ops) +
891            self.translation.x.size_of(ops) +
892            self.translation.y.size_of(ops) +
893            self.translation.z.size_of(ops)
894    }
895}
896
897impl MallocSizeOf for url::Host {
898    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
899        match *self {
900            url::Host::Domain(ref s) => s.size_of(ops),
901            _ => 0,
902        }
903    }
904}
905
906impl MallocSizeOf for url::Url {
907    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
908        // TODO: This is an estimate, but a real size should be calculated in `rust-url` once
909        // it has support for `malloc_size_of`.
910        self.to_string().size_of(ops)
911    }
912}
913
914impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Vector2D<T, U> {
915    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
916        self.x.size_of(ops) + self.y.size_of(ops)
917    }
918}
919
920impl<Static: string_cache::StaticAtomSet> MallocSizeOf for string_cache::Atom<Static> {
921    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
922        0
923    }
924}
925
926impl MallocSizeOf for usvg::Tree {
927    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
928        let root = self.root();
929        let linear_gradients = self.linear_gradients();
930        let radial_gradients = self.radial_gradients();
931        let patterns = self.patterns();
932        let clip_paths = self.clip_paths();
933        let masks = self.masks();
934        let filters = self.filters();
935        let fontdb = self.fontdb();
936
937        let mut sum = root.size_of(ops) +
938            linear_gradients.size_of(ops) +
939            radial_gradients.size_of(ops) +
940            patterns.size_of(ops) +
941            clip_paths.size_of(ops) +
942            masks.size_of(ops) +
943            filters.size_of(ops);
944
945        sum += fontdb.conditional_size_of(ops);
946
947        if ops.has_malloc_enclosing_size_of() {
948            unsafe {
949                sum += ops.malloc_enclosing_size_of(root);
950                if !linear_gradients.is_empty() {
951                    sum += ops.malloc_enclosing_size_of(linear_gradients.as_ptr());
952                }
953                if !radial_gradients.is_empty() {
954                    sum += ops.malloc_enclosing_size_of(radial_gradients.as_ptr());
955                }
956                if !patterns.is_empty() {
957                    sum += ops.malloc_enclosing_size_of(patterns.as_ptr());
958                }
959                if !clip_paths.is_empty() {
960                    sum += ops.malloc_enclosing_size_of(clip_paths.as_ptr());
961                }
962                if !masks.is_empty() {
963                    sum += ops.malloc_enclosing_size_of(masks.as_ptr());
964                }
965                if !filters.is_empty() {
966                    sum += ops.malloc_enclosing_size_of(filters.as_ptr());
967                }
968            }
969        }
970        sum
971    }
972}
973
974impl MallocSizeOf for usvg::Group {
975    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
976        let id = self.id();
977        let children = self.children();
978        let filters = self.filters();
979        let clip_path = self.clip_path();
980
981        let mut sum =
982            id.size_of(ops) + children.size_of(ops) + filters.size_of(ops) + clip_path.size_of(ops);
983
984        if ops.has_malloc_enclosing_size_of() {
985            unsafe {
986                if !id.is_empty() {
987                    sum += ops.malloc_enclosing_size_of(id.as_ptr());
988                }
989                if let Some(c) = clip_path {
990                    sum += ops.malloc_enclosing_size_of(c)
991                }
992                if !children.is_empty() {
993                    sum += ops.malloc_enclosing_size_of(children.as_ptr());
994                }
995                if !filters.is_empty() {
996                    sum += ops.malloc_enclosing_size_of(filters.as_ptr());
997                }
998            }
999        }
1000        sum
1001    }
1002}
1003
1004impl MallocSizeOf for usvg::Node {
1005    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1006        let id = self.id();
1007
1008        let mut sum = id.size_of(ops);
1009        if ops.has_malloc_enclosing_size_of() {
1010            unsafe {
1011                if !id.is_empty() {
1012                    sum += ops.malloc_enclosing_size_of(id.as_ptr())
1013                }
1014            }
1015        }
1016        match self {
1017            usvg::Node::Group(group) => {
1018                sum += group.size_of(ops);
1019                if ops.has_malloc_enclosing_size_of() {
1020                    unsafe { sum += ops.malloc_enclosing_size_of(group) }
1021                }
1022            },
1023            usvg::Node::Path(path) => {
1024                sum += path.size_of(ops);
1025                if ops.has_malloc_enclosing_size_of() {
1026                    unsafe { sum += ops.malloc_enclosing_size_of(path) }
1027                }
1028            },
1029            usvg::Node::Image(image) => {
1030                sum += image.size_of(ops);
1031            },
1032            usvg::Node::Text(text) => {
1033                sum += text.size_of(ops);
1034            },
1035        };
1036        sum
1037    }
1038}
1039
1040impl MallocSizeOf for usvg::Path {
1041    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1042        let id = self.id();
1043        let data = self.data();
1044        let fill = self.fill();
1045        let stroke = self.stroke();
1046
1047        let mut sum = id.size_of(ops) + data.size_of(ops) + fill.size_of(ops) + stroke.size_of(ops);
1048        if ops.has_malloc_enclosing_size_of() {
1049            unsafe {
1050                if !id.is_empty() {
1051                    sum += ops.malloc_enclosing_size_of(id.as_ptr());
1052                }
1053                sum += ops.malloc_enclosing_size_of(data);
1054                if let Some(f) = fill {
1055                    sum += ops.malloc_enclosing_size_of(f)
1056                }
1057                if let Some(s) = stroke {
1058                    sum += ops.malloc_enclosing_size_of(s)
1059                }
1060            }
1061        }
1062        sum
1063    }
1064}
1065impl MallocSizeOf for tiny_skia_path::Path {
1066    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1067        let verbs = self.verbs();
1068        let points = self.points();
1069
1070        let mut sum = verbs.size_of(ops) + points.size_of(ops);
1071        if ops.has_malloc_enclosing_size_of() {
1072            unsafe {
1073                if !points.is_empty() {
1074                    sum += ops.malloc_enclosing_size_of(points.as_ptr());
1075                }
1076                if !verbs.is_empty() {
1077                    sum += ops.malloc_enclosing_size_of(verbs.as_ptr());
1078                }
1079            }
1080        }
1081
1082        sum
1083    }
1084}
1085
1086impl MallocSizeOf for usvg::ClipPath {
1087    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1088        let id = self.id();
1089        let clip_path = self.clip_path();
1090        let root = self.root();
1091
1092        let mut sum = id.size_of(ops) + clip_path.size_of(ops) + root.size_of(ops);
1093        if ops.has_malloc_enclosing_size_of() {
1094            unsafe {
1095                sum += ops.malloc_enclosing_size_of(root);
1096                if !id.is_empty() {
1097                    sum += ops.malloc_enclosing_size_of(id.as_ptr());
1098                }
1099                if let Some(c) = clip_path {
1100                    sum += c.size_of(ops)
1101                }
1102            }
1103        }
1104        sum
1105    }
1106}
1107
1108impl<'a> MallocSizeOf for usvg::Options<'a> {
1109    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1110        self.font_family.size_of(ops) +
1111            self.languages.size_of(ops) +
1112            self.style_sheet.size_of(ops) +
1113            self.fontdb.conditional_size_of(ops) +
1114            self.resources_dir.size_of(ops)
1115    }
1116}
1117
1118impl MallocSizeOf for usvg::Font {
1119    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1120        self.families().size_of(ops) + self.variations().size_of(ops)
1121    }
1122}
1123
1124// Placeholder for unique case where internals of Sender cannot be measured.
1125// malloc size of is 0 macro complains about type supplied!
1126impl<T> MallocSizeOf for crossbeam_channel::Sender<T> {
1127    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
1128        0
1129    }
1130}
1131
1132impl<T> MallocSizeOf for crossbeam_channel::Receiver<T> {
1133    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
1134        0
1135    }
1136}
1137
1138impl<T> MallocSizeOf for tokio::sync::mpsc::UnboundedSender<T> {
1139    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
1140        0
1141    }
1142}
1143
1144impl<T> MallocSizeOf for tokio::sync::oneshot::Sender<T> {
1145    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
1146        0
1147    }
1148}
1149
1150impl<T> MallocSizeOf for ipc_channel::ipc::IpcSender<T> {
1151    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
1152        0
1153    }
1154}
1155
1156impl<T> MallocSizeOf for ipc_channel::ipc::IpcReceiver<T> {
1157    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
1158        0
1159    }
1160}
1161
1162impl MallocSizeOf for ipc_channel::ipc::IpcSharedMemory {
1163    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
1164        self.len()
1165    }
1166}
1167
1168impl MallocSizeOf for vello_cpu::Pixmap {
1169    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1170        let data = self.data();
1171        if data.is_empty() {
1172            0
1173        } else {
1174            unsafe { ops.malloc_size_of(data.as_ptr()) }
1175        }
1176    }
1177}
1178
1179impl<T> MallocSizeOf for std::sync::mpsc::Sender<T> {
1180    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
1181        0
1182    }
1183}
1184
1185impl MallocSizeOf for servo_arc::Arc<ComputedValues> {
1186    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1187        self.conditional_size_of(ops)
1188    }
1189}
1190
1191impl MallocSizeOf for http::HeaderMap {
1192    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1193        // The headermap in http is more complicated than a simple hashmap
1194        // However, this should give us a reasonable approximation.
1195        self.iter()
1196            .map(|entry| entry.0.size_of(ops) + entry.1.size_of(ops))
1197            .sum()
1198    }
1199}
1200
1201impl<'a> MallocSizeOf for Cookie<'a> {
1202    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1203        // While the cookie storage can be more efficient by using the same striing it is unlikely that the values have this property.
1204        // We take the string that is probably allocated in cookie an allocate it here to get the correct heap size.
1205        self.value().to_owned().size_of(ops)
1206    }
1207}
1208
1209impl MallocSizeOf for data_url::mime::Mime {
1210    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1211        self.type_.size_of(ops) + self.parameters.size_of(ops) + self.subtype.size_of(ops)
1212    }
1213}
1214
1215malloc_size_of_hash_map!(indexmap::IndexMap<K, V, S>);
1216malloc_size_of_hash_set!(indexmap::IndexSet<T, S>);
1217
1218malloc_size_of_is_0!(bool, char, str);
1219malloc_size_of_is_0!(f32, f64);
1220malloc_size_of_is_0!(i8, i16, i32, i64, i128, isize);
1221malloc_size_of_is_0!(u8, u16, u32, u64, u128, usize);
1222
1223malloc_size_of_is_0!(uuid::Uuid);
1224malloc_size_of_is_0!(app_units::Au);
1225malloc_size_of_is_0!(content_security_policy::Destination);
1226malloc_size_of_is_0!(content_security_policy::sandboxing_directive::SandboxingFlagSet);
1227malloc_size_of_is_0!(encoding_rs::Decoder);
1228malloc_size_of_is_0!(http::StatusCode);
1229malloc_size_of_is_0!(http::Method);
1230malloc_size_of_is_0!(icu_locale_core::subtags::Language);
1231malloc_size_of_is_0!(keyboard_types::Code);
1232malloc_size_of_is_0!(keyboard_types::Modifiers);
1233malloc_size_of_is_0!(mime::Mime);
1234malloc_size_of_is_0!(resvg::usvg::fontdb::ID);
1235malloc_size_of_is_0!(resvg::usvg::fontdb::Style);
1236malloc_size_of_is_0!(resvg::usvg::fontdb::Weight);
1237malloc_size_of_is_0!(resvg::usvg::fontdb::Stretch);
1238malloc_size_of_is_0!(resvg::usvg::fontdb::Language);
1239malloc_size_of_is_0!(std::num::NonZeroU16);
1240malloc_size_of_is_0!(std::num::NonZeroU32);
1241malloc_size_of_is_0!(std::num::NonZeroU64);
1242malloc_size_of_is_0!(std::num::NonZeroUsize);
1243malloc_size_of_is_0!(std::sync::atomic::AtomicBool);
1244malloc_size_of_is_0!(std::sync::atomic::AtomicI32);
1245malloc_size_of_is_0!(std::sync::atomic::AtomicIsize);
1246malloc_size_of_is_0!(std::sync::atomic::AtomicU32);
1247malloc_size_of_is_0!(std::sync::atomic::AtomicU8);
1248malloc_size_of_is_0!(std::sync::atomic::AtomicUsize);
1249malloc_size_of_is_0!(std::time::Duration);
1250malloc_size_of_is_0!(std::time::Instant);
1251malloc_size_of_is_0!(std::time::SystemTime);
1252malloc_size_of_is_0!(style::data::ElementDataWrapper);
1253malloc_size_of_is_0!(style::font_face::SourceList);
1254malloc_size_of_is_0!(style::properties::ComputedValues);
1255malloc_size_of_is_0!(style::properties::declaration_block::PropertyDeclarationBlock);
1256malloc_size_of_is_0!(style::queries::values::PrefersColorScheme);
1257malloc_size_of_is_0!(style::stylesheets::Stylesheet);
1258malloc_size_of_is_0!(style::stylesheets::FontFaceRule);
1259malloc_size_of_is_0!(style::values::specified::source_size_list::SourceSizeList);
1260malloc_size_of_is_0!(time::Duration);
1261malloc_size_of_is_0!(unicode_bidi::Level);
1262malloc_size_of_is_0!(unicode_script::Script);
1263malloc_size_of_is_0!(std::net::TcpStream);
1264
1265malloc_size_of_is_0!(taffy::Layout);
1266malloc_size_of_is_0!(taffy::Baselines);
1267malloc_size_of_is_0!(taffy::DetailedGridItemsInfo);
1268impl<T> MallocSizeOf for taffy::Line<T>
1269where
1270    T: MallocSizeOf,
1271{
1272    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1273        self.start.size_of(ops) + self.end.size_of(ops)
1274    }
1275}
1276impl<T> MallocSizeOf for taffy::DetailedGridInfo<T>
1277where
1278    T: MallocSizeOf + taffy::CheapCloneStr,
1279{
1280    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1281        self.items.size_of(ops) +
1282            self.rows.positions.size_of(ops) +
1283            self.columns.positions.size_of(ops)
1284    }
1285}
1286
1287impl MallocSizeOf for urlpattern::UrlPattern {
1288    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
1289        // This is an approximation
1290        self.protocol().len() +
1291            self.username().len() +
1292            self.password().len() +
1293            self.hostname().len() +
1294            self.port().len() +
1295            self.pathname().len() +
1296            self.search().len() +
1297            self.hash().len()
1298    }
1299}
1300
1301impl<S: tendril::TendrilSink<tendril::fmt::UTF8, A>, A: tendril::Atomicity> MallocSizeOf
1302    for tendril::stream::LossyDecoder<S, A>
1303{
1304    fn size_of(&self, _: &mut MallocSizeOfOps) -> usize {
1305        0
1306    }
1307}
1308
1309impl<F: tendril::Format> MallocSizeOf for tendril::SendTendril<F> {
1310    fn size_of(&self, _: &mut MallocSizeOfOps) -> usize {
1311        0
1312    }
1313}
1314
1315macro_rules! malloc_size_of_is_webrender_malloc_size_of(
1316    ($($ty:ty),+) => (
1317        $(
1318            impl MallocSizeOf for $ty {
1319                fn size_of(&self, _: &mut MallocSizeOfOps) -> usize {
1320                    let mut ops = wr_malloc_size_of::MallocSizeOfOps::new(servo_allocator::usable_size, None);
1321                    <$ty as wr_malloc_size_of::MallocSizeOf>::size_of(self, &mut ops)
1322                }
1323            }
1324        )+
1325    );
1326);
1327
1328malloc_size_of_is_webrender_malloc_size_of!(webrender::FastTransform<webrender_api::units::LayoutPixel, webrender_api::units::LayoutPixel>);
1329malloc_size_of_is_webrender_malloc_size_of!(webrender_api::BorderRadius);
1330malloc_size_of_is_webrender_malloc_size_of!(webrender_api::BorderStyle);
1331malloc_size_of_is_webrender_malloc_size_of!(webrender_api::BoxShadowClipMode);
1332malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ColorF);
1333malloc_size_of_is_webrender_malloc_size_of!(webrender_api::Epoch);
1334malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ExtendMode);
1335malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ExternalScrollId);
1336malloc_size_of_is_webrender_malloc_size_of!(webrender_api::FontInstanceFlags);
1337malloc_size_of_is_webrender_malloc_size_of!(webrender_api::FontInstanceKey);
1338malloc_size_of_is_webrender_malloc_size_of!(webrender_api::FontKey);
1339malloc_size_of_is_webrender_malloc_size_of!(webrender_api::FontVariation);
1340malloc_size_of_is_webrender_malloc_size_of!(webrender_api::GlyphInstance);
1341malloc_size_of_is_webrender_malloc_size_of!(webrender_api::GradientStop);
1342malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ImageKey);
1343malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ImageRendering);
1344malloc_size_of_is_webrender_malloc_size_of!(webrender_api::LineStyle);
1345malloc_size_of_is_webrender_malloc_size_of!(webrender_api::MixBlendMode);
1346malloc_size_of_is_webrender_malloc_size_of!(webrender_api::NormalBorder);
1347malloc_size_of_is_webrender_malloc_size_of!(webrender_api::PipelineId);
1348malloc_size_of_is_webrender_malloc_size_of!(
1349    webrender_api::PropertyBindingKey<webrender_api::ColorF>
1350);
1351malloc_size_of_is_webrender_malloc_size_of!(webrender_api::ReferenceFrameKind);
1352malloc_size_of_is_webrender_malloc_size_of!(webrender_api::RepeatMode);
1353malloc_size_of_is_webrender_malloc_size_of!(webrender_api::SpatialId);
1354malloc_size_of_is_webrender_malloc_size_of!(webrender_api::StickyOffsetBounds);
1355malloc_size_of_is_webrender_malloc_size_of!(webrender_api::TransformStyle);
1356
1357macro_rules! malloc_size_of_is_stylo_malloc_size_of(
1358    ($($ty:ty),+) => (
1359        $(
1360            impl MallocSizeOf for $ty {
1361                fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1362                    <$ty as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
1363                }
1364            }
1365        )+
1366    );
1367);
1368
1369impl<S> MallocSizeOf for style::author_styles::GenericAuthorStyles<S>
1370where
1371    S: style::stylesheets::StylesheetInDocument
1372        + std::cmp::PartialEq
1373        + stylo_malloc_size_of::MallocSizeOf,
1374{
1375    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1376        <style::author_styles::GenericAuthorStyles<S> as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
1377    }
1378}
1379
1380impl<S> MallocSizeOf for style::stylesheet_set::DocumentStylesheetSet<S>
1381where
1382    S: style::stylesheets::StylesheetInDocument
1383        + std::cmp::PartialEq
1384        + stylo_malloc_size_of::MallocSizeOf,
1385{
1386    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1387        <style::stylesheet_set::DocumentStylesheetSet<S> as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
1388    }
1389}
1390
1391impl<T> MallocSizeOf for style::shared_lock::Locked<T> {
1392    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
1393        // TODO: fix this implementation when Locked derives MallocSizeOf.
1394        0
1395        // <style::shared_lock::Locked<T> as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
1396    }
1397}
1398
1399impl<T: MallocSizeOf> MallocSizeOf for atomic_refcell::AtomicRefCell<T> {
1400    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1401        self.borrow().size_of(ops)
1402    }
1403}
1404
1405impl<T: stylo_malloc_size_of::MallocSizeOf, const FRACTION_BITS: u16> MallocSizeOf
1406    for style::values::computed::font::FixedPoint<T, FRACTION_BITS>
1407{
1408    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1409        <Self as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
1410    }
1411}
1412
1413impl<Integer, Number, LinearStops> MallocSizeOf
1414    for style::values::generics::easing::TimingFunction<Integer, Number, LinearStops>
1415where
1416    Integer: stylo_malloc_size_of::MallocSizeOf,
1417    Number: stylo_malloc_size_of::MallocSizeOf,
1418    LinearStops: stylo_malloc_size_of::MallocSizeOf,
1419{
1420    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1421        <Self as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
1422    }
1423}
1424
1425malloc_size_of_is_stylo_malloc_size_of!(style::properties::PropertyId);
1426malloc_size_of_is_stylo_malloc_size_of!(style::animation::DocumentAnimationSet);
1427malloc_size_of_is_stylo_malloc_size_of!(style::attr::AttrIdentifier);
1428malloc_size_of_is_stylo_malloc_size_of!(style::attr::AttrValue);
1429malloc_size_of_is_stylo_malloc_size_of!(style::color::AbsoluteColor);
1430malloc_size_of_is_stylo_malloc_size_of!(style::computed_values::font_variant_caps::T);
1431malloc_size_of_is_stylo_malloc_size_of!(style::computed_values::font_variant_position::T);
1432malloc_size_of_is_stylo_malloc_size_of!(style::computed_values::text_decoration_style::T);
1433malloc_size_of_is_stylo_malloc_size_of!(style::computed_values::text_decoration_thickness::T);
1434malloc_size_of_is_stylo_malloc_size_of!(style::computed_values::text_rendering::T);
1435malloc_size_of_is_stylo_malloc_size_of!(style::dom::OpaqueNode);
1436malloc_size_of_is_stylo_malloc_size_of!(style::font_face::ComputedFontStyleRange);
1437malloc_size_of_is_stylo_malloc_size_of!(style::font_face::ComputedFontWeightRange);
1438malloc_size_of_is_stylo_malloc_size_of!(style::font_face::ComputedFontWidthRange);
1439malloc_size_of_is_stylo_malloc_size_of!(style::font_face::Source);
1440malloc_size_of_is_stylo_malloc_size_of!(style::invalidation::element::restyle_hints::RestyleHint);
1441malloc_size_of_is_stylo_malloc_size_of!(style::logical_geometry::WritingMode);
1442malloc_size_of_is_stylo_malloc_size_of!(style::media_queries::MediaList);
1443malloc_size_of_is_stylo_malloc_size_of!(style::properties::generated::font_face::Descriptors);
1444malloc_size_of_is_stylo_malloc_size_of!(
1445    style::properties::longhands::align_items::computed_value::T
1446);
1447malloc_size_of_is_stylo_malloc_size_of!(
1448    style::properties::longhands::flex_direction::computed_value::T
1449);
1450malloc_size_of_is_stylo_malloc_size_of!(style::properties::longhands::flex_wrap::computed_value::T);
1451malloc_size_of_is_stylo_malloc_size_of!(style::properties::style_structs::Font);
1452malloc_size_of_is_stylo_malloc_size_of!(style::selector_parser::PseudoElement);
1453malloc_size_of_is_stylo_malloc_size_of!(style::selector_parser::RestyleDamage);
1454malloc_size_of_is_stylo_malloc_size_of!(style::selector_parser::Snapshot);
1455malloc_size_of_is_stylo_malloc_size_of!(style::shared_lock::SharedRwLock);
1456malloc_size_of_is_stylo_malloc_size_of!(style::stylesheets::DocumentStyleSheet);
1457malloc_size_of_is_stylo_malloc_size_of!(style::stylesheets::Origin);
1458malloc_size_of_is_stylo_malloc_size_of!(style::stylist::Stylist);
1459malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::BorderStyle);
1460malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::ContentDistribution);
1461malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::FontFeatureSettings);
1462malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::FontStyle);
1463malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::FontWeight);
1464malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::FontWidth);
1465malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::FontVariantAlternates);
1466malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::FontVariantLigatures);
1467malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::FontVariantNumeric);
1468malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::FontVariantEastAsian);
1469malloc_size_of_is_stylo_malloc_size_of!(style::values::computed::font::SingleFontFamily);
1470malloc_size_of_is_stylo_malloc_size_of!(style::values::specified::align::AlignFlags);
1471malloc_size_of_is_stylo_malloc_size_of!(style::values::specified::box_::Overflow);
1472malloc_size_of_is_stylo_malloc_size_of!(style::values::specified::font::FontSynthesis);
1473malloc_size_of_is_stylo_malloc_size_of!(style::values::specified::font::XLang);
1474malloc_size_of_is_stylo_malloc_size_of!(style::values::specified::TextDecorationLine);
1475malloc_size_of_is_stylo_malloc_size_of!(stylo_dom::ElementState);
1476malloc_size_of_is_stylo_malloc_size_of!(style::computed_values::font_optical_sizing::T);
1477malloc_size_of_is_stylo_malloc_size_of!(style::computed_values::font_kerning::T);
1478malloc_size_of_is_stylo_malloc_size_of!(style::stylesheets::font_feature_values_rule::SingleValue);
1479malloc_size_of_is_stylo_malloc_size_of!(style::stylesheets::font_feature_values_rule::PairValues);
1480malloc_size_of_is_stylo_malloc_size_of!(style::stylesheets::font_feature_values_rule::VectorValues);
1481malloc_size_of_is_stylo_malloc_size_of!(
1482    style::stylesheets::font_feature_values_rule::FontFeatureValuesRule
1483);
1484
1485impl<T> MallocSizeOf for GenericLengthPercentageOrAuto<T>
1486where
1487    T: stylo_malloc_size_of::MallocSizeOf,
1488{
1489    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1490        <GenericLengthPercentageOrAuto<T> as stylo_malloc_size_of::MallocSizeOf>::size_of(self, ops)
1491    }
1492}
1493
1494impl MallocSizeOf for resvg::usvg::fontdb::Source {
1495    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1496        match self {
1497            Source::Binary(_) => 0,
1498            Source::File(path) => path.size_of(ops),
1499            Source::SharedFile(path, _) => path.size_of(ops),
1500        }
1501    }
1502}
1503
1504impl MallocSizeOf for resvg::usvg::fontdb::FaceInfo {
1505    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1506        self.id.size_of(ops) +
1507            self.source.size_of(ops) +
1508            self.families.size_of(ops) +
1509            self.post_script_name.size_of(ops) +
1510            self.style.size_of(ops) +
1511            self.weight.size_of(ops) +
1512            self.stretch.size_of(ops)
1513    }
1514}
1515
1516impl MallocSizeOf for resvg::usvg::fontdb::Database {
1517    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1518        self.faces().map(|face| face.size_of(ops)).sum()
1519    }
1520}
1521
1522impl<T> MallocSizeOf for once_cell::race::OnceBox<T>
1523where
1524    T: MallocSizeOf,
1525{
1526    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1527        if let Some(value) = self.get() {
1528            (unsafe { ops.malloc_size_of::<T>(value) }) + value.size_of(ops)
1529        } else {
1530            0
1531        }
1532    }
1533}