Skip to main content

stylo_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::hash::{BuildHasher, Hash};
50use std::mem::size_of;
51use std::ops::Range;
52use std::ops::{Deref, DerefMut};
53use std::os::raw::c_void;
54use void::Void;
55
56/// A C function that takes a pointer to a heap allocation and returns its size.
57type VoidPtrToSizeFn = unsafe extern "C" fn(ptr: *const c_void) -> usize;
58
59/// A closure implementing a stateful predicate on pointers.
60type VoidPtrToBoolFnMut = dyn FnMut(*const c_void) -> bool;
61
62/// Operations used when measuring heap usage of data structures.
63pub struct MallocSizeOfOps {
64    /// A function that returns the size of a heap allocation.
65    size_of_op: VoidPtrToSizeFn,
66
67    /// Like `size_of_op`, but can take an interior pointer. Optional because
68    /// not all allocators support this operation. If it's not provided, some
69    /// memory measurements will actually be computed estimates rather than
70    /// real and accurate measurements.
71    enclosing_size_of_op: Option<VoidPtrToSizeFn>,
72
73    /// Check if a pointer has been seen before, and remember it for next time.
74    /// Useful when measuring `Rc`s and `Arc`s. Optional, because many places
75    /// don't need it.
76    have_seen_ptr_op: Option<Box<VoidPtrToBoolFnMut>>,
77}
78
79impl MallocSizeOfOps {
80    pub fn new(
81        size_of: VoidPtrToSizeFn,
82        malloc_enclosing_size_of: Option<VoidPtrToSizeFn>,
83        have_seen_ptr: Option<Box<VoidPtrToBoolFnMut>>,
84    ) -> Self {
85        MallocSizeOfOps {
86            size_of_op: size_of,
87            enclosing_size_of_op: malloc_enclosing_size_of,
88            have_seen_ptr_op: have_seen_ptr,
89        }
90    }
91
92    /// Check if an allocation is empty. This relies on knowledge of how Rust
93    /// handles empty allocations, which may change in the future.
94    fn is_empty<T: ?Sized>(ptr: *const T) -> bool {
95        // The correct condition is this:
96        //   `ptr as usize <= ::std::mem::align_of::<T>()`
97        // But we can't call align_of() on a ?Sized T. So we approximate it
98        // with the following. 256 is large enough that it should always be
99        // larger than the required alignment, but small enough that it is
100        // always in the first page of memory and therefore not a legitimate
101        // address.
102        return ptr as *const usize as usize <= 256;
103    }
104
105    /// Call `size_of_op` on `ptr`, first checking that the allocation isn't
106    /// empty, because some types (such as `Vec`) utilize empty allocations.
107    pub unsafe fn malloc_size_of<T: ?Sized>(&self, ptr: *const T) -> usize {
108        if MallocSizeOfOps::is_empty(ptr) {
109            0
110        } else {
111            (self.size_of_op)(ptr as *const c_void)
112        }
113    }
114
115    /// Is an `enclosing_size_of_op` available?
116    pub fn has_malloc_enclosing_size_of(&self) -> bool {
117        self.enclosing_size_of_op.is_some()
118    }
119
120    /// Call `enclosing_size_of_op`, which must be available, on `ptr`, which
121    /// must not be empty.
122    pub unsafe fn malloc_enclosing_size_of<T>(&self, ptr: *const T) -> usize {
123        assert!(!MallocSizeOfOps::is_empty(ptr));
124        (self.enclosing_size_of_op.unwrap())(ptr as *const c_void)
125    }
126
127    /// Call `have_seen_ptr_op` on `ptr`.
128    pub fn have_seen_ptr<T>(&mut self, ptr: *const T) -> bool {
129        let have_seen_ptr_op = self
130            .have_seen_ptr_op
131            .as_mut()
132            .expect("missing have_seen_ptr_op");
133        have_seen_ptr_op(ptr as *const c_void)
134    }
135}
136
137/// Trait for measuring the "deep" heap usage of a data structure. This is the
138/// most commonly-used of the traits.
139pub trait MallocSizeOf {
140    /// Measure the heap usage of all descendant heap-allocated structures, but
141    /// not the space taken up by the value itself.
142    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
143}
144
145/// Trait for measuring the "shallow" heap usage of a container.
146pub trait MallocShallowSizeOf {
147    /// Measure the heap usage of immediate heap-allocated descendant
148    /// structures, but not the space taken up by the value itself. Anything
149    /// beyond the immediate descendants must be measured separately, using
150    /// iteration.
151    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
152}
153
154/// Like `MallocSizeOf`, but with a different name so it cannot be used
155/// accidentally with derive(MallocSizeOf). For use with types like `Rc` and
156/// `Arc` when appropriate (e.g. when measuring a "primary" reference).
157pub trait MallocUnconditionalSizeOf {
158    /// Measure the heap usage of all heap-allocated descendant structures, but
159    /// not the space taken up by the value itself.
160    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
161}
162
163/// `MallocUnconditionalSizeOf` combined with `MallocShallowSizeOf`.
164pub trait MallocUnconditionalShallowSizeOf {
165    /// `unconditional_size_of` combined with `shallow_size_of`.
166    fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
167}
168
169/// Like `MallocSizeOf`, but only measures if the value hasn't already been
170/// measured. For use with types like `Rc` and `Arc` when appropriate (e.g.
171/// when there is no "primary" reference).
172pub trait MallocConditionalSizeOf {
173    /// Measure the heap usage of all heap-allocated descendant structures, but
174    /// not the space taken up by the value itself, and only if that heap usage
175    /// hasn't already been measured.
176    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
177}
178
179/// `MallocConditionalSizeOf` combined with `MallocShallowSizeOf`.
180pub trait MallocConditionalShallowSizeOf {
181    /// `conditional_size_of` combined with `shallow_size_of`.
182    fn conditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize;
183}
184
185impl MallocSizeOf for String {
186    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
187        unsafe { ops.malloc_size_of(self.as_ptr()) }
188    }
189}
190
191impl<'a, T: ?Sized> MallocSizeOf for &'a T {
192    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
193        // Zero makes sense for a non-owning reference.
194        0
195    }
196}
197
198impl<T: ?Sized> MallocShallowSizeOf for Box<T> {
199    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
200        unsafe { ops.malloc_size_of(&**self) }
201    }
202}
203
204impl<T: MallocSizeOf + ?Sized> MallocSizeOf for Box<T> {
205    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
206        self.shallow_size_of(ops) + (**self).size_of(ops)
207    }
208}
209
210impl MallocSizeOf for () {
211    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
212        0
213    }
214}
215
216impl<T1, T2> MallocSizeOf for (T1, T2)
217where
218    T1: MallocSizeOf,
219    T2: MallocSizeOf,
220{
221    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
222        self.0.size_of(ops) + self.1.size_of(ops)
223    }
224}
225
226impl<T1, T2, T3> MallocSizeOf for (T1, T2, T3)
227where
228    T1: MallocSizeOf,
229    T2: MallocSizeOf,
230    T3: MallocSizeOf,
231{
232    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
233        self.0.size_of(ops) + self.1.size_of(ops) + self.2.size_of(ops)
234    }
235}
236
237impl<T1, T2, T3, T4> MallocSizeOf for (T1, T2, T3, T4)
238where
239    T1: MallocSizeOf,
240    T2: MallocSizeOf,
241    T3: MallocSizeOf,
242    T4: MallocSizeOf,
243{
244    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
245        self.0.size_of(ops) + self.1.size_of(ops) + self.2.size_of(ops) + self.3.size_of(ops)
246    }
247}
248
249impl<T: MallocSizeOf> MallocSizeOf for Option<T> {
250    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
251        if let Some(val) = self.as_ref() {
252            val.size_of(ops)
253        } else {
254            0
255        }
256    }
257}
258
259impl<T: MallocSizeOf, E: MallocSizeOf> MallocSizeOf for Result<T, E> {
260    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
261        match *self {
262            Ok(ref x) => x.size_of(ops),
263            Err(ref e) => e.size_of(ops),
264        }
265    }
266}
267
268impl<T: MallocSizeOf + Copy> MallocSizeOf for std::cell::Cell<T> {
269    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
270        self.get().size_of(ops)
271    }
272}
273
274impl<T: MallocSizeOf> MallocSizeOf for std::cell::RefCell<T> {
275    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
276        self.borrow().size_of(ops)
277    }
278}
279
280impl<T: MallocSizeOf> MallocSizeOf for std::sync::OnceLock<T> {
281    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
282        self.get()
283            .map(|value| value.size_of(ops))
284            .unwrap_or_default()
285    }
286}
287
288impl<'a, B: ?Sized + ToOwned> MallocSizeOf for std::borrow::Cow<'a, B>
289where
290    B::Owned: MallocSizeOf,
291{
292    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
293        match *self {
294            std::borrow::Cow::Borrowed(_) => 0,
295            std::borrow::Cow::Owned(ref b) => b.size_of(ops),
296        }
297    }
298}
299
300impl<T: MallocSizeOf> MallocSizeOf for [T] {
301    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
302        let mut n = 0;
303        for elem in self.iter() {
304            n += elem.size_of(ops);
305        }
306        n
307    }
308}
309
310impl<T> MallocShallowSizeOf for Vec<T> {
311    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
312        unsafe { ops.malloc_size_of(self.as_ptr()) }
313    }
314}
315
316impl<T: MallocSizeOf> MallocSizeOf for Vec<T> {
317    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
318        let mut n = self.shallow_size_of(ops);
319        for elem in self.iter() {
320            n += elem.size_of(ops);
321        }
322        n
323    }
324}
325
326impl<T> MallocShallowSizeOf for std::collections::VecDeque<T> {
327    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
328        if ops.has_malloc_enclosing_size_of() {
329            if let Some(front) = self.front() {
330                // The front element is an interior pointer.
331                unsafe { ops.malloc_enclosing_size_of(&*front) }
332            } else {
333                // This assumes that no memory is allocated when the VecDeque is empty.
334                0
335            }
336        } else {
337            // An estimate.
338            self.capacity() * size_of::<T>()
339        }
340    }
341}
342
343impl<T: MallocSizeOf> MallocSizeOf for std::collections::VecDeque<T> {
344    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
345        let mut n = self.shallow_size_of(ops);
346        for elem in self.iter() {
347            n += elem.size_of(ops);
348        }
349        n
350    }
351}
352
353impl<A: smallvec::Array> MallocShallowSizeOf for smallvec::SmallVec<A> {
354    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
355        if self.spilled() {
356            unsafe { ops.malloc_size_of(self.as_ptr()) }
357        } else {
358            0
359        }
360    }
361}
362
363impl<A> MallocSizeOf for smallvec::SmallVec<A>
364where
365    A: smallvec::Array,
366    A::Item: MallocSizeOf,
367{
368    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
369        let mut n = self.shallow_size_of(ops);
370        for elem in self.iter() {
371            n += elem.size_of(ops);
372        }
373        n
374    }
375}
376
377impl<T> MallocShallowSizeOf for thin_vec::ThinVec<T> {
378    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
379        if self.capacity() == 0 {
380            // If it's the singleton we might not be a heap pointer.
381            return 0;
382        }
383
384        assert_eq!(
385            std::mem::size_of::<Self>(),
386            std::mem::size_of::<*const ()>()
387        );
388        unsafe { ops.malloc_size_of(*(self as *const Self as *const *const ())) }
389    }
390}
391
392impl<T: MallocSizeOf> MallocSizeOf for thin_vec::ThinVec<T> {
393    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
394        let mut n = self.shallow_size_of(ops);
395        for elem in self.iter() {
396            n += elem.size_of(ops);
397        }
398        n
399    }
400}
401
402macro_rules! malloc_size_of_hash_set {
403    ($ty:ty) => {
404        impl<T, S> MallocShallowSizeOf for $ty
405        where
406            T: Eq + Hash,
407            S: BuildHasher,
408        {
409            fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
410                if ops.has_malloc_enclosing_size_of() {
411                    // The first value from the iterator gives us an interior pointer.
412                    // `ops.malloc_enclosing_size_of()` then gives us the storage size.
413                    // This assumes that the `HashSet`'s contents (values and hashes)
414                    // are all stored in a single contiguous heap allocation.
415                    self.iter()
416                        .next()
417                        .map_or(0, |t| unsafe { ops.malloc_enclosing_size_of(t) })
418                } else {
419                    // An estimate.
420                    self.capacity() * (size_of::<T>() + size_of::<usize>())
421                }
422            }
423        }
424
425        impl<T, S> MallocSizeOf for $ty
426        where
427            T: Eq + Hash + MallocSizeOf,
428            S: BuildHasher,
429        {
430            fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
431                let mut n = self.shallow_size_of(ops);
432                for t in self.iter() {
433                    n += t.size_of(ops);
434                }
435                n
436            }
437        }
438    };
439}
440
441malloc_size_of_hash_set!(std::collections::HashSet<T, S>);
442
443macro_rules! malloc_size_of_hash_map {
444    ($ty:ty) => {
445        impl<K, V, S> MallocShallowSizeOf for $ty
446        where
447            K: Eq + Hash,
448            S: BuildHasher,
449        {
450            fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
451                // See the implementation for std::collections::HashSet for details.
452                if ops.has_malloc_enclosing_size_of() {
453                    self.values()
454                        .next()
455                        .map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) })
456                } else {
457                    self.capacity() * (size_of::<V>() + size_of::<K>() + size_of::<usize>())
458                }
459            }
460        }
461
462        impl<K, V, S> MallocSizeOf for $ty
463        where
464            K: Eq + Hash + MallocSizeOf,
465            V: MallocSizeOf,
466            S: BuildHasher,
467        {
468            fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
469                let mut n = self.shallow_size_of(ops);
470                for (k, v) in self.iter() {
471                    n += k.size_of(ops);
472                    n += v.size_of(ops);
473                }
474                n
475            }
476        }
477    };
478}
479
480malloc_size_of_hash_map!(std::collections::HashMap<K, V, S>);
481
482impl<K, V> MallocShallowSizeOf for std::collections::BTreeMap<K, V>
483where
484    K: Eq + Hash,
485{
486    fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
487        if ops.has_malloc_enclosing_size_of() {
488            self.values()
489                .next()
490                .map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) })
491        } else {
492            self.len() * (size_of::<V>() + size_of::<K>() + size_of::<usize>())
493        }
494    }
495}
496
497impl<K, V> MallocSizeOf for std::collections::BTreeMap<K, V>
498where
499    K: Eq + Hash + MallocSizeOf,
500    V: MallocSizeOf,
501{
502    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
503        let mut n = self.shallow_size_of(ops);
504        for (k, v) in self.iter() {
505            n += k.size_of(ops);
506            n += v.size_of(ops);
507        }
508        n
509    }
510}
511
512// PhantomData is always 0.
513impl<T> MallocSizeOf for std::marker::PhantomData<T> {
514    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
515        0
516    }
517}
518
519// XXX: we don't want MallocSizeOf to be defined for Rc and Arc. If negative
520// trait bounds are ever allowed, this code should be uncommented.
521// (We do have a compile-fail test for this:
522// rc_arc_must_not_derive_malloc_size_of.rs)
523//impl<T> !MallocSizeOf for Arc<T> { }
524//impl<T> !MallocShallowSizeOf for Arc<T> { }
525
526impl<T> MallocUnconditionalShallowSizeOf for servo_arc::Arc<T> {
527    fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
528        unsafe { ops.malloc_size_of(self.heap_ptr()) }
529    }
530}
531
532impl<T: MallocSizeOf> MallocUnconditionalSizeOf for servo_arc::Arc<T> {
533    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
534        self.unconditional_shallow_size_of(ops) + (**self).size_of(ops)
535    }
536}
537
538impl<T> MallocConditionalShallowSizeOf for servo_arc::Arc<T> {
539    fn conditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
540        if ops.have_seen_ptr(self.heap_ptr()) {
541            0
542        } else {
543            self.unconditional_shallow_size_of(ops)
544        }
545    }
546}
547
548impl<T: MallocSizeOf> MallocConditionalSizeOf for servo_arc::Arc<T> {
549    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
550        if ops.have_seen_ptr(self.heap_ptr()) {
551            0
552        } else {
553            self.unconditional_size_of(ops)
554        }
555    }
556}
557
558/// If a mutex is stored directly as a member of a data type that is being measured,
559/// it is the unique owner of its contents and deserves to be measured.
560///
561/// If a mutex is stored inside of an Arc value as a member of a data type that is being measured,
562/// the Arc will not be automatically measured so there is no risk of overcounting the mutex's
563/// contents.
564impl<T: MallocSizeOf> MallocSizeOf for std::sync::Mutex<T> {
565    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
566        (*self.lock().unwrap()).size_of(ops)
567    }
568}
569
570impl MallocSizeOf for smallbitvec::SmallBitVec {
571    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
572        if let Some(ptr) = self.heap_ptr() {
573            unsafe { ops.malloc_size_of(ptr) }
574        } else {
575            0
576        }
577    }
578}
579
580impl<T: MallocSizeOf, Unit> MallocSizeOf for euclid::Length<T, Unit> {
581    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
582        self.0.size_of(ops)
583    }
584}
585
586impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Scale<T, Src, Dst> {
587    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
588        self.0.size_of(ops)
589    }
590}
591
592impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Point2D<T, U> {
593    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
594        self.x.size_of(ops) + self.y.size_of(ops)
595    }
596}
597
598impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Rect<T, U> {
599    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
600        self.origin.size_of(ops) + self.size.size_of(ops)
601    }
602}
603
604impl<T: MallocSizeOf, U> MallocSizeOf for euclid::SideOffsets2D<T, U> {
605    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
606        self.top.size_of(ops)
607            + self.right.size_of(ops)
608            + self.bottom.size_of(ops)
609            + self.left.size_of(ops)
610    }
611}
612
613impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Size2D<T, U> {
614    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
615        self.width.size_of(ops) + self.height.size_of(ops)
616    }
617}
618
619impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Transform2D<T, Src, Dst> {
620    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
621        self.m11.size_of(ops)
622            + self.m12.size_of(ops)
623            + self.m21.size_of(ops)
624            + self.m22.size_of(ops)
625            + self.m31.size_of(ops)
626            + self.m32.size_of(ops)
627    }
628}
629
630impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Transform3D<T, Src, Dst> {
631    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
632        self.m11.size_of(ops)
633            + self.m12.size_of(ops)
634            + self.m13.size_of(ops)
635            + self.m14.size_of(ops)
636            + self.m21.size_of(ops)
637            + self.m22.size_of(ops)
638            + self.m23.size_of(ops)
639            + self.m24.size_of(ops)
640            + self.m31.size_of(ops)
641            + self.m32.size_of(ops)
642            + self.m33.size_of(ops)
643            + self.m34.size_of(ops)
644            + self.m41.size_of(ops)
645            + self.m42.size_of(ops)
646            + self.m43.size_of(ops)
647            + self.m44.size_of(ops)
648    }
649}
650
651impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Vector2D<T, U> {
652    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
653        self.x.size_of(ops) + self.y.size_of(ops)
654    }
655}
656
657impl MallocSizeOf for selectors::parser::AncestorHashes {
658    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
659        let selectors::parser::AncestorHashes { ref packed_hashes } = *self;
660        packed_hashes.size_of(ops)
661    }
662}
663
664impl<Impl: selectors::parser::SelectorImpl> MallocUnconditionalSizeOf
665    for selectors::parser::Selector<Impl>
666where
667    Impl::NonTSPseudoClass: MallocSizeOf,
668    Impl::PseudoElement: MallocSizeOf,
669{
670    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
671        let mut n = 0;
672
673        // It's OK to measure this ThinArc directly because it's the
674        // "primary" reference. (The secondary references are on the
675        // Stylist.)
676        n += unsafe { ops.malloc_size_of(self.thin_arc_heap_ptr()) };
677        for component in self.iter_raw_match_order() {
678            n += component.size_of(ops);
679        }
680
681        n
682    }
683}
684
685impl<Impl: selectors::parser::SelectorImpl> MallocUnconditionalSizeOf
686    for selectors::parser::SelectorList<Impl>
687where
688    Impl::NonTSPseudoClass: MallocSizeOf,
689    Impl::PseudoElement: MallocSizeOf,
690{
691    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
692        let mut n = 0;
693
694        // It's OK to measure this ThinArc directly because it's the "primary" reference. (The
695        // secondary references are on the Stylist.)
696        n += unsafe { ops.malloc_size_of(self.thin_arc_heap_ptr()) };
697        if self.len() > 1 {
698            for selector in self.slice().iter() {
699                n += selector.size_of(ops);
700            }
701        }
702        n
703    }
704}
705
706impl<Impl: selectors::parser::SelectorImpl> MallocUnconditionalSizeOf
707    for selectors::parser::Component<Impl>
708where
709    Impl::NonTSPseudoClass: MallocSizeOf,
710    Impl::PseudoElement: MallocSizeOf,
711{
712    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
713        use selectors::parser::Component;
714
715        match self {
716            Component::AttributeOther(ref attr_selector) => attr_selector.size_of(ops),
717            Component::Negation(ref components) => components.unconditional_size_of(ops),
718            Component::NonTSPseudoClass(ref pseudo) => (*pseudo).size_of(ops),
719            Component::Slotted(ref selector) | Component::Host(Some(ref selector)) => {
720                selector.unconditional_size_of(ops)
721            },
722            Component::Is(ref list) | Component::Where(ref list) => list.unconditional_size_of(ops),
723            Component::Has(ref relative_selectors) => relative_selectors.size_of(ops),
724            Component::NthOf(ref nth_of_data) => nth_of_data.size_of(ops),
725            Component::PseudoElement(ref pseudo) => (*pseudo).size_of(ops),
726            Component::Combinator(..)
727            | Component::ExplicitAnyNamespace
728            | Component::ExplicitNoNamespace
729            | Component::DefaultNamespace(..)
730            | Component::Namespace(..)
731            | Component::ExplicitUniversalType
732            | Component::LocalName(..)
733            | Component::ID(..)
734            | Component::Part(..)
735            | Component::Class(..)
736            | Component::AttributeInNoNamespaceExists { .. }
737            | Component::AttributeInNoNamespace { .. }
738            | Component::Root
739            | Component::Empty
740            | Component::Scope
741            | Component::ImplicitScope
742            | Component::ParentSelector
743            | Component::Nth(..)
744            | Component::Host(None)
745            | Component::RelativeSelectorAnchor
746            | Component::Invalid(..) => 0,
747        }
748    }
749}
750
751impl<Impl: selectors::parser::SelectorImpl> MallocSizeOf
752    for selectors::attr::AttrSelectorWithOptionalNamespace<Impl>
753{
754    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
755        0
756    }
757}
758
759impl MallocSizeOf for selectors::parser::AnPlusB {
760    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
761        0
762    }
763}
764
765impl MallocSizeOf for Void {
766    #[inline]
767    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
768        void::unreachable(*self)
769    }
770}
771
772#[cfg(feature = "servo")]
773impl<Static: string_cache::StaticAtomSet> MallocSizeOf for string_cache::Atom<Static> {
774    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
775        0
776    }
777}
778
779/// For use on types where size_of() returns 0.
780#[macro_export]
781macro_rules! malloc_size_of_is_0(
782    ($($ty:ty),+) => (
783        $(
784            impl $crate::MallocSizeOf for $ty {
785                #[inline(always)]
786                fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize {
787                    0
788                }
789            }
790        )+
791    );
792    ($($ty:ident<$($gen:ident),+>),+) => (
793        $(
794        impl<$($gen: $crate::MallocSizeOf),+> $crate::MallocSizeOf for $ty<$($gen),+> {
795            #[inline(always)]
796            fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize {
797                0
798            }
799        }
800        )+
801    );
802);
803
804malloc_size_of_is_0!(bool, char, str);
805malloc_size_of_is_0!(u8, u16, u32, u64, u128, usize);
806malloc_size_of_is_0!(i8, i16, i32, i64, i128, isize);
807malloc_size_of_is_0!(f32, f64);
808
809malloc_size_of_is_0!(std::sync::atomic::AtomicBool);
810malloc_size_of_is_0!(std::sync::atomic::AtomicIsize);
811malloc_size_of_is_0!(std::sync::atomic::AtomicU32);
812malloc_size_of_is_0!(std::sync::atomic::AtomicUsize);
813malloc_size_of_is_0!(std::num::NonZeroUsize);
814malloc_size_of_is_0!(std::num::NonZeroU64);
815
816malloc_size_of_is_0!(Range<u8>, Range<u16>, Range<u32>, Range<u64>, Range<usize>);
817malloc_size_of_is_0!(Range<i8>, Range<i16>, Range<i32>, Range<i64>, Range<isize>);
818malloc_size_of_is_0!(Range<f32>, Range<f64>);
819
820malloc_size_of_is_0!(app_units::Au);
821
822malloc_size_of_is_0!(
823    cssparser::TokenSerializationType,
824    cssparser::SourceLocation,
825    cssparser::SourcePosition,
826    cssparser::UnicodeRange
827);
828
829malloc_size_of_is_0!(selectors::OpaqueElement);
830
831/// Measurable that defers to inner value and used to verify MallocSizeOf implementation in a
832/// struct.
833#[derive(Clone)]
834pub struct Measurable<T: MallocSizeOf>(pub T);
835
836impl<T: MallocSizeOf> Deref for Measurable<T> {
837    type Target = T;
838
839    fn deref(&self) -> &T {
840        &self.0
841    }
842}
843
844impl<T: MallocSizeOf> DerefMut for Measurable<T> {
845    fn deref_mut(&mut self) -> &mut T {
846        &mut self.0
847    }
848}