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