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> MallocUnconditionalShallowSizeOf for servo_arc::Arc<T> {
536    fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
537        unsafe { ops.malloc_size_of(self.heap_ptr()) }
538    }
539}
540
541impl<T: MallocSizeOf> MallocUnconditionalSizeOf for servo_arc::Arc<T> {
542    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
543        self.unconditional_shallow_size_of(ops) + (**self).size_of(ops)
544    }
545}
546
547impl<T> MallocConditionalShallowSizeOf for servo_arc::Arc<T> {
548    fn conditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
549        if ops.have_seen_ptr(self.heap_ptr()) {
550            0
551        } else {
552            self.unconditional_shallow_size_of(ops)
553        }
554    }
555}
556
557impl<T: MallocSizeOf> MallocConditionalSizeOf for servo_arc::Arc<T> {
558    fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
559        if ops.have_seen_ptr(self.heap_ptr()) {
560            0
561        } else {
562            self.unconditional_size_of(ops)
563        }
564    }
565}
566
567/// If a mutex is stored directly as a member of a data type that is being measured,
568/// it is the unique owner of its contents and deserves to be measured.
569///
570/// If a mutex is stored inside of an Arc value as a member of a data type that is being measured,
571/// the Arc will not be automatically measured so there is no risk of overcounting the mutex's
572/// contents.
573impl<T: MallocSizeOf> MallocSizeOf for std::sync::Mutex<T> {
574    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
575        (*self.lock().unwrap()).size_of(ops)
576    }
577}
578
579impl MallocSizeOf for smallbitvec::SmallBitVec {
580    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
581        if let Some(ptr) = self.heap_ptr() {
582            unsafe { ops.malloc_size_of(ptr) }
583        } else {
584            0
585        }
586    }
587}
588
589impl<T: MallocSizeOf, Unit> MallocSizeOf for euclid::Length<T, Unit> {
590    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
591        self.0.size_of(ops)
592    }
593}
594
595impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Scale<T, Src, Dst> {
596    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
597        self.0.size_of(ops)
598    }
599}
600
601impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Point2D<T, U> {
602    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
603        self.x.size_of(ops) + self.y.size_of(ops)
604    }
605}
606
607impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Rect<T, U> {
608    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
609        self.origin.size_of(ops) + self.size.size_of(ops)
610    }
611}
612
613impl<T: MallocSizeOf, U> MallocSizeOf for euclid::SideOffsets2D<T, U> {
614    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
615        self.top.size_of(ops)
616            + self.right.size_of(ops)
617            + self.bottom.size_of(ops)
618            + self.left.size_of(ops)
619    }
620}
621
622impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Size2D<T, U> {
623    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
624        self.width.size_of(ops) + self.height.size_of(ops)
625    }
626}
627
628impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Transform2D<T, Src, Dst> {
629    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
630        self.m11.size_of(ops)
631            + self.m12.size_of(ops)
632            + self.m21.size_of(ops)
633            + self.m22.size_of(ops)
634            + self.m31.size_of(ops)
635            + self.m32.size_of(ops)
636    }
637}
638
639impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for euclid::Transform3D<T, Src, Dst> {
640    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
641        self.m11.size_of(ops)
642            + self.m12.size_of(ops)
643            + self.m13.size_of(ops)
644            + self.m14.size_of(ops)
645            + self.m21.size_of(ops)
646            + self.m22.size_of(ops)
647            + self.m23.size_of(ops)
648            + self.m24.size_of(ops)
649            + self.m31.size_of(ops)
650            + self.m32.size_of(ops)
651            + self.m33.size_of(ops)
652            + self.m34.size_of(ops)
653            + self.m41.size_of(ops)
654            + self.m42.size_of(ops)
655            + self.m43.size_of(ops)
656            + self.m44.size_of(ops)
657    }
658}
659
660impl<T: MallocSizeOf, U> MallocSizeOf for euclid::Vector2D<T, U> {
661    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
662        self.x.size_of(ops) + self.y.size_of(ops)
663    }
664}
665
666impl MallocSizeOf for selectors::parser::AncestorHashes {
667    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
668        let selectors::parser::AncestorHashes { ref packed_hashes } = *self;
669        packed_hashes.size_of(ops)
670    }
671}
672
673impl<Impl: selectors::parser::SelectorImpl> MallocUnconditionalSizeOf
674    for selectors::parser::Selector<Impl>
675where
676    Impl::NonTSPseudoClass: MallocSizeOf,
677    Impl::PseudoElement: MallocSizeOf,
678{
679    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
680        let mut n = 0;
681
682        // It's OK to measure this ThinArc directly because it's the
683        // "primary" reference. (The secondary references are on the
684        // Stylist.)
685        n += unsafe { ops.malloc_size_of(self.thin_arc_heap_ptr()) };
686        for component in self.iter_raw_match_order() {
687            n += component.size_of(ops);
688        }
689
690        n
691    }
692}
693
694impl<Impl: selectors::parser::SelectorImpl> MallocUnconditionalSizeOf
695    for selectors::parser::SelectorList<Impl>
696where
697    Impl::NonTSPseudoClass: MallocSizeOf,
698    Impl::PseudoElement: MallocSizeOf,
699{
700    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
701        let mut n = 0;
702
703        // It's OK to measure this ThinArc directly because it's the "primary" reference. (The
704        // secondary references are on the Stylist.)
705        n += unsafe { ops.malloc_size_of(self.thin_arc_heap_ptr()) };
706        if self.len() > 1 {
707            for selector in self.slice().iter() {
708                n += selector.size_of(ops);
709            }
710        }
711        n
712    }
713}
714
715impl<Impl: selectors::parser::SelectorImpl> MallocUnconditionalSizeOf
716    for selectors::parser::Component<Impl>
717where
718    Impl::NonTSPseudoClass: MallocSizeOf,
719    Impl::PseudoElement: MallocSizeOf,
720{
721    fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
722        use selectors::parser::Component;
723
724        match self {
725            Component::AttributeOther(attr_selector) => attr_selector.size_of(ops),
726            Component::Negation(components) => components.unconditional_size_of(ops),
727            Component::NonTSPseudoClass(pseudo) => (*pseudo).size_of(ops),
728            Component::Slotted(selector) | Component::Host(Some(selector)) => {
729                selector.unconditional_size_of(ops)
730            },
731            Component::Is(list) | Component::Where(list) => list.unconditional_size_of(ops),
732            Component::Has(relative_selectors) => relative_selectors.size_of(ops),
733            Component::NthOf(nth_of_data) => nth_of_data.size_of(ops),
734            Component::PseudoElement(pseudo) => (*pseudo).size_of(ops),
735            Component::Combinator(..)
736            | Component::ExplicitAnyNamespace
737            | Component::ExplicitNoNamespace
738            | Component::DefaultNamespace(..)
739            | Component::Namespace(..)
740            | Component::ExplicitUniversalType
741            | Component::LocalName(..)
742            | Component::ID(..)
743            | Component::Part(..)
744            | Component::Class(..)
745            | Component::AttributeInNoNamespaceExists { .. }
746            | Component::AttributeInNoNamespace { .. }
747            | Component::Root
748            | Component::Empty
749            | Component::Scope
750            | Component::ImplicitScope
751            | Component::ParentSelector
752            | Component::Nth(..)
753            | Component::Host(None)
754            | Component::RelativeSelectorAnchor
755            | Component::Invalid(..) => 0,
756        }
757    }
758}
759
760impl<Impl: selectors::parser::SelectorImpl> MallocSizeOf
761    for selectors::attr::AttrSelectorWithOptionalNamespace<Impl>
762{
763    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
764        0
765    }
766}
767
768impl MallocSizeOf for selectors::parser::AnPlusB {
769    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
770        0
771    }
772}
773
774impl MallocSizeOf for Void {
775    #[inline]
776    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
777        void::unreachable(*self)
778    }
779}
780
781#[cfg(feature = "servo")]
782impl<Static: string_cache::StaticAtomSet> MallocSizeOf for string_cache::Atom<Static> {
783    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
784        0
785    }
786}
787
788/// For use on types where size_of() returns 0.
789#[macro_export]
790macro_rules! malloc_size_of_is_0(
791    ($($ty:ty),+) => (
792        $(
793            impl $crate::MallocSizeOf for $ty {
794                #[inline(always)]
795                fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize {
796                    0
797                }
798            }
799        )+
800    );
801    ($($ty:ident<$($gen:ident),+>),+) => (
802        $(
803        impl<$($gen: $crate::MallocSizeOf),+> $crate::MallocSizeOf for $ty<$($gen),+> {
804            #[inline(always)]
805            fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize {
806                0
807            }
808        }
809        )+
810    );
811);
812
813malloc_size_of_is_0!(bool, char, str);
814malloc_size_of_is_0!(u8, u16, u32, u64, u128, usize);
815malloc_size_of_is_0!(i8, i16, i32, i64, i128, isize);
816malloc_size_of_is_0!(f32, f64);
817
818malloc_size_of_is_0!(std::sync::atomic::AtomicBool);
819malloc_size_of_is_0!(std::sync::atomic::AtomicIsize);
820malloc_size_of_is_0!(std::sync::atomic::AtomicU32);
821malloc_size_of_is_0!(std::sync::atomic::AtomicUsize);
822malloc_size_of_is_0!(std::num::NonZeroUsize);
823malloc_size_of_is_0!(std::num::NonZeroU64);
824
825malloc_size_of_is_0!(Range<u8>, Range<u16>, Range<u32>, Range<u64>, Range<usize>);
826malloc_size_of_is_0!(Range<i8>, Range<i16>, Range<i32>, Range<i64>, Range<isize>);
827malloc_size_of_is_0!(Range<f32>, Range<f64>);
828
829malloc_size_of_is_0!(app_units::Au);
830
831malloc_size_of_is_0!(
832    cssparser::TokenSerializationType,
833    cssparser::SourceLocation,
834    cssparser::SourcePosition,
835    cssparser::UnicodeRange
836);
837
838malloc_size_of_is_0!(selectors::OpaqueElement);
839
840/// Measurable that defers to inner value and used to verify MallocSizeOf implementation in a
841/// struct.
842#[derive(Clone)]
843pub struct Measurable<T: MallocSizeOf>(pub T);
844
845impl<T: MallocSizeOf> Deref for Measurable<T> {
846    type Target = T;
847
848    fn deref(&self) -> &T {
849        &self.0
850    }
851}
852
853impl<T: MallocSizeOf> DerefMut for Measurable<T> {
854    fn deref_mut(&mut self) -> &mut T {
855        &mut self.0
856    }
857}
858
859impl<T: MallocSizeOf> MallocSizeOf for parking_lot::RwLock<T> {
860    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
861        self.read().size_of(ops)
862    }
863}