diff --git a/Cargo.lock b/Cargo.lock index c9f6e440698..12afd44640d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1081,6 +1081,7 @@ dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "malloc_size_of 0.0.1", "nsstring_vendor 0.1.0", "parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.19.0", @@ -1733,6 +1734,25 @@ dependencies = [ "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "malloc_size_of" +version = "0.0.1" +dependencies = [ + "hashglobe 0.1.0", + "servo_arc 0.0.1", + "smallbitvec 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "malloc_size_of_derive" +version = "0.0.1" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "markup5ever" version = "0.4.0" @@ -2693,6 +2713,8 @@ dependencies = [ "cssparser 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "malloc_size_of 0.0.1", + "malloc_size_of_derive 0.0.1", "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3107,6 +3129,8 @@ dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "malloc_size_of 0.0.1", + "malloc_size_of_derive 0.0.1", "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "nsstring_vendor 0.1.0", "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3195,6 +3219,7 @@ dependencies = [ "geckoservo 0.0.1", "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "malloc_size_of 0.0.1", "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.19.0", "size_of_test 0.0.1", diff --git a/components/malloc_size_of/Cargo.toml b/components/malloc_size_of/Cargo.toml new file mode 100644 index 00000000000..d5edcc43c65 --- /dev/null +++ b/components/malloc_size_of/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "malloc_size_of" +version = "0.0.1" +authors = ["The Servo Project Developers"] +license = "MIT/Apache-2.0" +publish = false + +[lib] +path = "lib.rs" + +[dependencies] +hashglobe = { path = "../hashglobe" } +servo_arc = { path = "../servo_arc" } +smallbitvec = "1.0.3" +smallvec = "0.4" diff --git a/components/malloc_size_of/LICENSE-APACHE b/components/malloc_size_of/LICENSE-APACHE new file mode 100644 index 00000000000..16fe87b06e8 --- /dev/null +++ b/components/malloc_size_of/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/components/malloc_size_of/LICENSE-MIT b/components/malloc_size_of/LICENSE-MIT new file mode 100644 index 00000000000..31aa79387f2 --- /dev/null +++ b/components/malloc_size_of/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs new file mode 100644 index 00000000000..a2f080d6cb2 --- /dev/null +++ b/components/malloc_size_of/lib.rs @@ -0,0 +1,346 @@ +// Copyright 2016-2017 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A crate for measuring the heap usage of data structures in a way that +//! integrates with Firefox's memory reporting, particularly the use of +//! mozjemalloc and DMD. +//! +//! This crate has a lot of overlap with the existing `heapsize` crate, and may +//! one day be merged into it. But for now, `heapsize` has the following +//! major shortcomings. +//! - It basically assumes that the `HeapSizeOf` trait can be used for every +//! type, which is not true. Sometimes more than a single size measurement +//! needs to be returned for a type, and sometimes additional synchronization +//! arguments (such as lock guards) need to be passed in. +//! - It has no proper way of measuring some common types, such as `HashSet` +//! and `HashMap`, that don't expose internal pointers. +//! - It has no proper way of handling values with multiple referents, such as +//! `Rc` and `Arc`. +//! +//! This crate solves those problems. +//! - It provides traits for both "shallow" and "deep" measurement, which gives +//! more flexibility in the cases where the traits can't be used. +//! - It allows for measuring blocks even when only an interior pointer can be +//! obtained for heap allocations, e.g. `HashSet` and `HashMap`. (This relies +//! on the heap allocator having suitable support, which mozjemalloc has.) +//! - It allows handling of types like `Rc` and `Arc` by providing special +//! traits that are different to the ones for non-graph structures. +//! +//! Suggested uses are as follows. +//! - When possible, use the `MallocSizeOf` trait. (Deriving support is +//! provided by the `malloc_size_of_derive` crate.) +//! - If you need an additional synchronization argument, provide a function +//! that is like the standard trait method, but with the extra argument. +//! - If you need multiple measurements for a type, provide a function named +//! `add_size_of_children` that takes a mutable reference to a struct that +//! contains the multiple measurement fields. +//! - When deep measurement (via `MallocSizeOf`) cannot be implemented for a +//! type, shallow measurement (via `MallocShallowSizeOf`) in combination with +//! iteration can be a useful substitute. +//! - `Rc` and `Arc` are always tricky, which is why `MallocSizeOf` is not (and +//! should not be) implemented for them. +//! - If an `Rc` or `Arc` is known to be a "primary" reference and can always +//! be measured, it should be measured via the `MallocUnconditionalSizeOf` +//! trait. +//! - If an `Rc` or `Arc` should be measured only if it hasn't been seen +//! before, it should be measured via the `MallocConditionalSizeOf` trait. +//! - Using universal function call syntax is a good idea when measuring boxed +//! fields in structs, because it makes it clear that the Box is being +//! measured as well as the thing it points to. E.g. +//! ` as MallocSizeOf>::size_of(field, ops)`. + +extern crate hashglobe; +extern crate servo_arc; +extern crate smallbitvec; +extern crate smallvec; + +use hashglobe::hash_map::HashMap; +use servo_arc::Arc; +use smallbitvec::SmallBitVec; +use smallvec::{Array, SmallVec}; +use std::collections::HashSet; +use std::hash::{BuildHasher, Hash}; +use std::os::raw::c_void; + +/// A C function that takes a pointer to a heap allocation and returns its size. +type VoidPtrToSizeFn = unsafe extern "C" fn(ptr: *const c_void) -> usize; + +/// A closure implementing a stateful predicate on pointers. +type VoidPtrToBoolFnMut = FnMut(*const c_void) -> bool; + +/// Operations used when measuring heap usage of data structures. +pub struct MallocSizeOfOps { + /// A function that returns the size of a heap allocation. + size_of_op: VoidPtrToSizeFn, + + /// Like `size_of_op`, but can take an interior pointer. Optional, because + /// many places don't need it. + enclosing_size_of_op: Option, + + /// Check if a pointer has been seen before, and remember it for next time. + /// Useful when measuring `Rc`s and `Arc`s. Optional, because many places + /// don't need it. + have_seen_ptr_op: Option>, +} + +impl MallocSizeOfOps { + pub fn new(size_of: VoidPtrToSizeFn, + malloc_enclosing_size_of: Option, + have_seen_ptr: Option>) -> Self { + MallocSizeOfOps { + size_of_op: size_of, + enclosing_size_of_op: malloc_enclosing_size_of, + have_seen_ptr_op: have_seen_ptr, + } + } + + /// Check if an allocation is empty. This relies on knowledge of how Rust + /// handles empty allocations, which may change in the future. + fn is_empty(ptr: *const T) -> bool { + return ptr as usize <= ::std::mem::align_of::(); + } + + /// Call `size_of_op` on `ptr`, first checking that the allocation isn't + /// empty, because some types (such as `Vec`) utilize empty allocations. + pub fn malloc_size_of(&self, ptr: *const T) -> usize { + if MallocSizeOfOps::is_empty(ptr) { + 0 + } else { + unsafe { (self.size_of_op)(ptr as *const c_void) } + } + } + + /// Call `enclosing_size_of_op` on `ptr`, which must not be empty. + pub fn malloc_enclosing_size_of(&self, ptr: *const T) -> usize { + assert!(!MallocSizeOfOps::is_empty(ptr)); + let enclosing_size_of_op = self.enclosing_size_of_op.expect("missing enclosing_size_of_op"); + unsafe { enclosing_size_of_op(ptr as *const c_void) } + } + + /// Call `have_seen_ptr_op` on `ptr`. + pub fn have_seen_ptr(&mut self, ptr: *const T) -> bool { + let have_seen_ptr_op = self.have_seen_ptr_op.as_mut().expect("missing have_seen_ptr_op"); + have_seen_ptr_op(ptr as *const c_void) + } +} + +/// Trait for measuring the "deep" heap usage of a data structure. This is the +/// most commonly-used of the traits. +pub trait MallocSizeOf { + /// Measure the heap usage of all descendant heap-allocated structures, but + /// not the space taken up by the value itself. + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize; +} + +/// Trait for measuring the "shallow" heap usage of a container. +pub trait MallocShallowSizeOf { + /// Measure the heap usage of direct descendant structures, but not the + /// space taken up by the value itself. Anything pointed to by the + /// immediate children must be measured separately, using iteration. + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize; +} + +/// Like `MallocSizeOf`, but with a different name so it cannot be used +/// accidentally with derive(MallocSizeOf). For use with types like `Rc` and +/// `Arc` when appropriate (e.g. when measuring a "primary" reference). +pub trait MallocUnconditionalSizeOf { + /// Measure the heap usage of all heap-allocated descendant structures, but + /// not the space taken up by the value itself. + fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize; +} + +/// Like `MallocSizeOf`, but only measures if the value hasn't already been +/// measured. For use with types like `Rc` and `Arc` when appropriate (e.g. +/// when there is no "primary" reference). +pub trait MallocConditionalSizeOf { + /// Measure the heap usage of all heap-allocated descendant structures, but + /// not the space taken up by the value itself, and only if that heap usage + /// hasn't already been measured. + fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize; +} + +impl MallocShallowSizeOf for Box { + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + ops.malloc_size_of(&**self) + } +} + +impl MallocSizeOf for Box { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.shallow_size_of(ops) + (**self).size_of(ops) + } +} + +impl MallocSizeOf for (A, B) { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.0.size_of(ops) + self.1.size_of(ops) + } +} + +impl MallocSizeOf for Option { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + if let Some(val) = self.as_ref() { + val.size_of(ops) + } else { + 0 + } + } +} + +impl MallocShallowSizeOf for Vec { + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + ops.malloc_size_of(self.as_ptr()) + } +} + +impl MallocSizeOf for Vec { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.shallow_size_of(ops); + for elem in self.iter() { + n += elem.size_of(ops); + } + n + } +} + +impl MallocShallowSizeOf for SmallVec { + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + if self.spilled() { + ops.malloc_size_of(self.as_ptr()) + } else { + 0 + } + } +} + +impl MallocSizeOf for SmallVec + where A: Array, + A::Item: MallocSizeOf +{ + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.shallow_size_of(ops); + for elem in self.iter() { + n += elem.size_of(ops); + } + n + } +} + +impl MallocShallowSizeOf for HashSet + where T: Eq + Hash, + S: BuildHasher +{ + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + // The first value from the iterator gives us an interior pointer. + // `ops.malloc_enclosing_size_of()` then gives us the storage size. + // This assumes that the `HashSet`'s contents (values and hashes) are + // all stored in a single contiguous heap allocation. + self.iter().next().map_or(0, |t| ops.malloc_enclosing_size_of(t)) + } +} + +impl MallocSizeOf for HashSet + where T: Eq + Hash + MallocSizeOf, + S: BuildHasher, +{ + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.shallow_size_of(ops); + for t in self.iter() { + n += t.size_of(ops); + } + n + } +} + +impl MallocShallowSizeOf for HashMap + where K: Eq + Hash, + S: BuildHasher +{ + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + // The first value from the iterator gives us an interior pointer. + // `ops.malloc_enclosing_size_of()` then gives us the storage size. + // This assumes that the `HashMap`'s contents (keys, values, and + // hashes) are all stored in a single contiguous heap allocation. + self.values().next().map_or(0, |v| ops.malloc_enclosing_size_of(v)) + } +} + +impl MallocSizeOf for HashMap + where K: Eq + Hash + MallocSizeOf, + V: MallocSizeOf, + S: BuildHasher, +{ + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.shallow_size_of(ops); + for (k, v) in self.iter() { + n += k.size_of(ops); + n += v.size_of(ops); + } + n + } +} + +// XXX: we don't want MallocSizeOf to be defined for Rc and Arc. If negative +// trait bounds are ever allowed, this code should be uncommented. +// (We do have a compile-fail test for this: +// rc_arc_must_not_derive_malloc_size_of.rs) +//impl !MallocSizeOf for Arc { } +//impl !MallocShallowSizeOf for Arc { } + +impl MallocUnconditionalSizeOf for Arc { + fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + ops.malloc_size_of(self.heap_ptr()) + (**self).size_of(ops) + } +} + +impl MallocConditionalSizeOf for Arc { + fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + if ops.have_seen_ptr(self.heap_ptr()) { + 0 + } else { + self.unconditional_size_of(ops) + } + } +} + +/// For use on types where size_of() returns 0. +#[macro_export] +macro_rules! size_of_is_0( + ($($ty:ty),+) => ( + $( + impl $crate::MallocSizeOf for $ty { + #[inline(always)] + fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize { + 0 + } + } + )+ + ); + ($($ty:ident<$($gen:ident),+>),+) => ( + $( + impl<$($gen: $crate::MallocSizeOf),+> $crate::MallocSizeOf for $ty<$($gen),+> { + #[inline(always)] + fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize { + 0 + } + } + )+ + ); +); + +size_of_is_0!(char, str); +size_of_is_0!(u8, u16, u32, u64, usize); +size_of_is_0!(i8, i16, i32, i64, isize); +size_of_is_0!(bool, f32, f64); + +// XXX: once we upgrade smallbitvec to 1.0.4, use the new heap_ptr() method to +// implement this properly +size_of_is_0!(SmallBitVec); + diff --git a/components/malloc_size_of_derive/Cargo.toml b/components/malloc_size_of_derive/Cargo.toml new file mode 100644 index 00000000000..a7243e6a547 --- /dev/null +++ b/components/malloc_size_of_derive/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "malloc_size_of_derive" +version = "0.0.1" +authors = ["The Servo Project Developers"] +license = "MIT/Apache-2.0" +publish = false + +[lib] +path = "lib.rs" +proc-macro = true + +[dependencies] +quote = "0.3.15" +syn = "0.11" +synstructure = "0.5" diff --git a/components/malloc_size_of_derive/LICENSE-APACHE b/components/malloc_size_of_derive/LICENSE-APACHE new file mode 100644 index 00000000000..16fe87b06e8 --- /dev/null +++ b/components/malloc_size_of_derive/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/components/malloc_size_of_derive/LICENSE-MIT b/components/malloc_size_of_derive/LICENSE-MIT new file mode 100644 index 00000000000..31aa79387f2 --- /dev/null +++ b/components/malloc_size_of_derive/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/components/malloc_size_of_derive/lib.rs b/components/malloc_size_of_derive/lib.rs new file mode 100644 index 00000000000..fe279133cbf --- /dev/null +++ b/components/malloc_size_of_derive/lib.rs @@ -0,0 +1,117 @@ +// Copyright 2016-2017 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A crate for deriving the MallocSizeOf trait. + +#[cfg(not(test))] extern crate proc_macro; +#[macro_use] extern crate quote; +extern crate syn; +extern crate synstructure; + +#[cfg(not(test))] +#[proc_macro_derive(MallocSizeOf, attributes(ignore_malloc_size_of))] +pub fn expand_token_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + expand_string(&input.to_string()).parse().unwrap() +} + +fn expand_string(input: &str) -> String { + let mut type_ = syn::parse_macro_input(input).unwrap(); + + let style = synstructure::BindStyle::Ref.into(); + let match_body = synstructure::each_field(&mut type_, &style, |binding| { + let ignore = binding.field.attrs.iter().any(|attr| match attr.value { + syn::MetaItem::Word(ref ident) | + syn::MetaItem::List(ref ident, _) if ident == "ignore_malloc_size_of" => { + panic!("#[ignore_malloc_size_of] should have an explanation, \ + e.g. #[ignore_malloc_size_of = \"because reasons\"]"); + } + syn::MetaItem::NameValue(ref ident, _) if ident == "ignore_malloc_size_of" => { + true + } + _ => false, + }); + if ignore { + None + } else if let syn::Ty::Array(..) = binding.field.ty { + Some(quote! { + for item in #binding.iter() { + sum += ::malloc_size_of::MallocSizeOf::size_of(item, ops); + } + }) + } else { + Some(quote! { + sum += ::malloc_size_of::MallocSizeOf::size_of(#binding, ops); + }) + } + }); + + let name = &type_.ident; + let (impl_generics, ty_generics, where_clause) = type_.generics.split_for_impl(); + let mut where_clause = where_clause.clone(); + for param in &type_.generics.ty_params { + where_clause.predicates.push(syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate { + bound_lifetimes: Vec::new(), + bounded_ty: syn::Ty::Path(None, param.ident.clone().into()), + bounds: vec![syn::TyParamBound::Trait( + syn::PolyTraitRef { + bound_lifetimes: Vec::new(), + trait_ref: syn::parse_path("::malloc_size_of::MallocSizeOf").unwrap(), + }, + syn::TraitBoundModifier::None + )], + })) + } + + let tokens = quote! { + impl #impl_generics ::malloc_size_of::MallocSizeOf for #name #ty_generics #where_clause { + #[inline] + #[allow(unused_variables, unused_mut, unreachable_code)] + fn size_of(&self, ops: &mut ::malloc_size_of::MallocSizeOfOps) -> usize { + let mut sum = 0; + match *self { + #match_body + } + sum + } + } + }; + + tokens.to_string() +} + +#[test] +fn test_struct() { + let mut source = "struct Foo { bar: Bar, baz: T, #[ignore_malloc_size_of = \"\"] z: Arc }"; + let mut expanded = expand_string(source); + let mut no_space = expanded.replace(" ", ""); + macro_rules! match_count { + ($e: expr, $count: expr) => { + assert_eq!(no_space.matches(&$e.replace(" ", "")).count(), $count, + "counting occurences of {:?} in {:?} (whitespace-insensitive)", + $e, expanded) + } + } + match_count!("struct", 0); + match_count!("ignore_malloc_size_of", 0); + match_count!("impl ::malloc_size_of::MallocSizeOf for Foo where T: ::malloc_size_of::MallocSizeOf {", 1); + match_count!("sum += ::malloc_size_of::MallocSizeOf::size_of(", 2); + + source = "struct Bar([Baz; 3]);"; + expanded = expand_string(source); + no_space = expanded.replace(" ", ""); + match_count!("for item in", 1); +} + +#[should_panic(expected = "should have an explanation")] +#[test] +fn test_no_reason() { + expand_string("struct A { #[ignore_malloc_size_of] b: C }"); +} + diff --git a/components/selectors/Cargo.toml b/components/selectors/Cargo.toml index cd7f5ac2d4a..d7c666dc22e 100644 --- a/components/selectors/Cargo.toml +++ b/components/selectors/Cargo.toml @@ -28,6 +28,8 @@ matches = "0.1" cssparser = "0.20.2" log = "0.3" fnv = "1.0" +malloc_size_of = { path = "../malloc_size_of" } +malloc_size_of_derive = { path = "../malloc_size_of_derive" } phf = "0.7.18" precomputed-hash = "0.1" servo_arc = { path = "../servo_arc" } diff --git a/components/selectors/lib.rs b/components/selectors/lib.rs index c2ad24ee73e..870e1c3ca0c 100644 --- a/components/selectors/lib.rs +++ b/components/selectors/lib.rs @@ -10,6 +10,8 @@ #[macro_use] extern crate log; #[macro_use] extern crate matches; extern crate fnv; +extern crate malloc_size_of; +#[macro_use] extern crate malloc_size_of_derive; extern crate phf; extern crate precomputed_hash; #[cfg(test)] #[macro_use] extern crate size_of_test; diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index c17e8af1a71..b020a04fd03 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -218,7 +218,7 @@ impl SelectorList { /// off the upper bits) at the expense of making the fourth somewhat more /// complicated to assemble, because we often bail out before checking all the /// hashes. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] pub struct AncestorHashes { pub packed_hashes: [u32; 3], } diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index 039b09fef43..ea9e779be83 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -16,7 +16,8 @@ path = "lib.rs" doctest = false [features] -gecko = ["nsstring_vendor", "num_cpus", "style_traits/gecko", "fallible/known_system_malloc"] +gecko = ["malloc_size_of", "malloc_size_of_derive", "nsstring_vendor", "num_cpus", + "style_traits/gecko", "fallible/known_system_malloc"] use_bindgen = ["bindgen", "regex", "toml"] servo = ["serde", "heapsize", "heapsize_derive", "style_traits/servo", "servo_atoms", "servo_config", "html5ever", @@ -49,6 +50,8 @@ itoa = "0.3" html5ever = {version = "0.19", optional = true} lazy_static = "0.2" log = "0.3" +malloc_size_of = { path = "../malloc_size_of", optional=true } +malloc_size_of_derive = { path = "../malloc_size_of_derive", optional=true } matches = "0.1" nsstring_vendor = {path = "gecko_bindings/nsstring_vendor", optional = true} num_cpus = {version = "1.1.0", optional = true} diff --git a/components/style/data.rs b/components/style/data.rs index 471b279ab54..5fade0c1dc0 100644 --- a/components/style/data.rs +++ b/components/style/data.rs @@ -8,6 +8,8 @@ use context::{SharedStyleContext, StackLimitChecker}; use dom::TElement; use invalidation::element::invalidator::InvalidationResult; use invalidation::element::restyle_hints::RestyleHint; +#[cfg(feature = "gecko")] +use malloc_size_of::MallocSizeOfOps; use properties::ComputedValues; use properties::longhands::display::computed_value as display; use rule_tree::StrongRuleNode; @@ -16,8 +18,6 @@ use servo_arc::Arc; use shared_lock::StylesheetGuards; use std::fmt; use std::ops::{Deref, DerefMut}; -#[cfg(feature = "gecko")] -use stylesheets::SizeOfState; bitflags! { flags RestyleFlags: u8 { @@ -272,7 +272,7 @@ impl ElementStyles { } #[cfg(feature = "gecko")] - fn malloc_size_of_children_excluding_cvs(&self, _state: &mut SizeOfState) -> usize { + fn size_of_excluding_cvs(&self, _ops: &mut MallocSizeOfOps) -> usize { // As the method name suggests, we don't measures the ComputedValues // here, because they are measured on the C++ side. @@ -453,8 +453,8 @@ impl ElementData { /// Measures memory usage. #[cfg(feature = "gecko")] - pub fn malloc_size_of_children_excluding_cvs(&self, state: &mut SizeOfState) -> usize { - let n = self.styles.malloc_size_of_children_excluding_cvs(state); + pub fn size_of_excluding_cvs(&self, ops: &mut MallocSizeOfOps) -> usize { + let n = self.styles.size_of_excluding_cvs(ops); // We may measure more fields in the future if DMD says it's worth it. diff --git a/components/style/element_state.rs b/components/style/element_state.rs index dbc04ff0fdc..564d159538c 100644 --- a/components/style/element_state.rs +++ b/components/style/element_state.rs @@ -14,6 +14,7 @@ bitflags! { /// /// TODO(emilio): We really really want to use the NS_EVENT_STATE bindings /// for this. + #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub flags ElementState: u64 { /// The mouse is down on this element. diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index 7bc5e593881..603685763b7 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -12,12 +12,12 @@ use gecko_bindings::structs::{StyleSheetInfo, ServoStyleSheetInner}; use gecko_bindings::structs::nsIDocument; use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI}; use invalidation::media_queries::{MediaListKey, ToMediaListKey}; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use media_queries::{Device, MediaList}; use properties::ComputedValues; use servo_arc::Arc; use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard}; -use stylesheets::{MallocEnclosingSizeOfFn, MallocSizeOfFn, PerOrigin, StylesheetContents}; -use stylesheets::StylesheetInDocument; +use stylesheets::{PerOrigin, StylesheetContents, StylesheetInDocument}; use stylist::{ExtraStyleData, Stylist}; /// Little wrapper to a Gecko style sheet. @@ -186,19 +186,10 @@ impl PerDocumentStyleDataImpl { self.visited_links_enabled() && !self.is_private_browsing_enabled() } - /// Measures heap usage. - pub fn malloc_add_size_of_children(&self, malloc_size_of: MallocSizeOfFn, - malloc_enclosing_size_of: MallocEnclosingSizeOfFn, - sizes: &mut ServoStyleSetSizes) { - self.stylist.malloc_add_size_of_children(malloc_size_of, malloc_enclosing_size_of, sizes); - - let data = &self.extra_style_data; - sizes.mStylistOther += - data.user_agent.malloc_size_of_children(malloc_size_of, malloc_enclosing_size_of); - sizes.mStylistOther += - data.user.malloc_size_of_children(malloc_size_of, malloc_enclosing_size_of); - sizes.mStylistOther += - data.author.malloc_size_of_children(malloc_size_of, malloc_enclosing_size_of); + /// Measure heap usage. + pub fn add_size_of_children(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { + self.stylist.add_size_of_children(ops, sizes); + sizes.mStylistOther += self.extra_style_data.size_of(ops); } } diff --git a/components/style/gecko_string_cache/mod.rs b/components/style/gecko_string_cache/mod.rs index 3844ddc2997..0c75e0c43ca 100644 --- a/components/style/gecko_string_cache/mod.rs +++ b/components/style/gecko_string_cache/mod.rs @@ -388,3 +388,5 @@ impl From<*mut nsIAtom> for Atom { } } } + +size_of_is_0!(Atom); diff --git a/components/style/invalidation/element/invalidation_map.rs b/components/style/invalidation/element/invalidation_map.rs index eba4d028b8c..301cd2e25a9 100644 --- a/components/style/invalidation/element/invalidation_map.rs +++ b/components/style/invalidation/element/invalidation_map.rs @@ -16,8 +16,6 @@ use selectors::parser::{Combinator, Component}; use selectors::parser::{Selector, SelectorIter, SelectorMethods}; use selectors::visitor::SelectorVisitor; use smallvec::SmallVec; -#[cfg(feature = "gecko")] -use stylesheets::{MallocEnclosingSizeOfFn, MallocSizeOfFn, MallocSizeOfHash, MallocSizeOfVec}; #[cfg(feature = "gecko")] /// Gets the element state relevant to the given `:dir` pseudo-class selector. @@ -58,11 +56,15 @@ pub fn dir_selector_to_state(s: &[u16]) -> ElementState { /// rules and determine the maximum effect that a given state or attribute /// change may have on the style of elements in the document. #[derive(Clone, Debug)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct Dependency { /// The dependency selector. + #[cfg_attr(feature = "gecko", + ignore_malloc_size_of = "CssRules have primary refs, we measure there")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] pub selector: Selector, + /// The offset into the selector that we should match on. pub selector_offset: usize, } @@ -114,6 +116,7 @@ impl SelectorMapEntry for Dependency { /// The same, but for state selectors, which can track more exactly what state /// do they track. #[derive(Clone, Debug)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct StateDependency { /// The other dependency fields. @@ -137,6 +140,7 @@ impl SelectorMapEntry for StateDependency { /// selectors the better, so this looks up by id, class, or looks at the list of /// state/other attribute affecting selectors. #[derive(Debug)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct InvalidationMap { /// A map from a given class name to all the selectors with that class @@ -295,34 +299,6 @@ impl InvalidationMap { Ok(()) } - - /// Measures heap usage. - #[cfg(feature = "gecko")] - pub fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn, - malloc_enclosing_size_of: MallocEnclosingSizeOfFn) - -> usize { - // Currently we measure the HashMap storage, but not things pointed to - // by keys and values. - let mut n = 0; - - n += self.class_to_selector.malloc_shallow_size_of_hash(malloc_enclosing_size_of); - for (_, val) in self.class_to_selector.iter() { - n += val.malloc_shallow_size_of_vec(malloc_size_of); - } - - n += self.id_to_selector.malloc_shallow_size_of_hash(malloc_enclosing_size_of); - for (_, val) in self.id_to_selector.iter() { - n += val.malloc_shallow_size_of_vec(malloc_size_of); - } - - n += self.state_affecting_selectors.malloc_size_of_children(malloc_size_of, - malloc_enclosing_size_of); - - n += self.other_attribute_affecting_selectors.malloc_size_of_children( - malloc_size_of, malloc_enclosing_size_of); - - n - } } /// A struct that collects invalidations for a given compound selector. diff --git a/components/style/invalidation/media_queries.rs b/components/style/invalidation/media_queries.rs index 99792158c66..0656027555b 100644 --- a/components/style/invalidation/media_queries.rs +++ b/components/style/invalidation/media_queries.rs @@ -8,7 +8,7 @@ use context::QuirksMode; use fnv::FnvHashSet; use media_queries::Device; use shared_lock::SharedRwLockReadGuard; -use stylesheets::{DocumentRule, ImportRule, MallocEnclosingSizeOfFn, MallocSizeOfHash, MediaRule}; +use stylesheets::{DocumentRule, ImportRule, MediaRule}; use stylesheets::{NestedRuleIterationCondition, Stylesheet, SupportsRule}; /// A key for a given media query result. @@ -24,6 +24,7 @@ use stylesheets::{NestedRuleIterationCondition, Stylesheet, SupportsRule}; /// If this changes, though, we may need to remove the item from the cache if /// present before it goes away. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct MediaListKey(usize); @@ -53,6 +54,7 @@ impl ToMediaListKey for MediaRule {} /// A struct that holds the result of a media query evaluation pass for the /// media queries that evaluated successfully. #[derive(Debug)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct EffectiveMediaQueryResults { /// The set of media lists that matched last time. @@ -88,12 +90,6 @@ impl EffectiveMediaQueryResults { // because of stylesheet reusing... shrug. self.set.insert(item.to_media_list_key()); } - - /// Measure heap usage. - pub fn malloc_size_of_children(&self, malloc_enclosing_size_of: MallocEnclosingSizeOfFn) - -> usize { - self.set.malloc_shallow_size_of_hash(malloc_enclosing_size_of) - } } /// A filter that filters over effective rules, but allowing all potentially diff --git a/components/style/lib.rs b/components/style/lib.rs index d8857a7b82e..8aa3ce9507a 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -59,6 +59,8 @@ extern crate itoa; extern crate lazy_static; #[macro_use] extern crate log; +#[cfg(feature = "gecko")] #[macro_use] extern crate malloc_size_of; +#[cfg(feature = "gecko")] #[macro_use] extern crate malloc_size_of_derive; #[allow(unused_extern_crates)] #[macro_use] extern crate matches; diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index c91b3a73f30..c458bad1717 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -21,7 +21,6 @@ use std::iter::{DoubleEndedIterator, Zip}; use std::slice::Iter; use style_traits::{PARSING_MODE_DEFAULT, ToCss, ParseError, ParsingMode, StyleParseError}; use stylesheets::{CssRuleType, Origin, UrlExtraData}; -use stylesheets::{MallocSizeOf, MallocSizeOfFn}; use super::*; use values::computed::Context; #[cfg(feature = "gecko")] use properties::animated_properties::AnimationValueMap; @@ -43,6 +42,7 @@ impl AnimationRules { /// A declaration [importance][importance]. /// /// [importance]: https://drafts.csswg.org/css-cascade/#importance +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum Importance { @@ -53,12 +53,6 @@ pub enum Importance { Important, } -impl MallocSizeOf for Importance { - fn malloc_size_of_children(&self, _malloc_size_of: MallocSizeOfFn) -> usize { - 0 - } -} - impl Importance { /// Return whether this is an important declaration. pub fn important(self) -> bool { @@ -70,6 +64,7 @@ impl Importance { } /// Overridden declarations are skipped. +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[derive(Clone)] pub struct PropertyDeclarationBlock { /// The group of declarations, along with their importance. @@ -83,12 +78,6 @@ pub struct PropertyDeclarationBlock { longhands: LonghandIdSet, } -impl MallocSizeOf for PropertyDeclarationBlock { - fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn) -> usize { - self.declarations.malloc_size_of_children(malloc_size_of) - } -} - /// Iterator over `(PropertyDeclaration, Importance)` pairs. pub struct DeclarationImportanceIterator<'a> { iter: Zip, smallbitvec::Iter<'a>>, diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 7a62561a8e1..bb0fd657b5d 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -74,6 +74,7 @@ pub trait RepeatableListAnimatable: Animate {} /// not animatable from CSS animations or Web Animations. CSS transitions also does not allow /// animating 'display', but for CSS transitions we have the separate TransitionProperty type. #[derive(Clone, Debug, Eq, Hash, PartialEq)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum AnimatableLonghand { % for prop in data.longhands: diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index d9769383d1e..fffd0387a81 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -29,6 +29,7 @@ use font_metrics::FontMetricsProvider; #[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID}; #[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide}; use logical_geometry::WritingMode; +#[cfg(feature = "gecko")] use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; use media_queries::Device; use parser::ParserContext; use properties::animated_properties::AnimatableLonghand; @@ -39,8 +40,7 @@ use selectors::parser::SelectorParseError; use shared_lock::StylesheetGuards; use style_traits::{PARSING_MODE_DEFAULT, ToCss, ParseError}; use style_traits::{PropertyDeclarationParseError, StyleParseError, ValueParseError}; -use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfBox, MallocSizeOfFn, MallocSizeOfVec}; -use stylesheets::{Origin, UrlExtraData}; +use stylesheets::{CssRuleType, Origin, UrlExtraData}; #[cfg(feature = "servo")] use values::Either; use values::generics::text::LineHeight; use values::computed; @@ -292,6 +292,7 @@ static ${name}: LonghandIdSet = LonghandIdSet { /// A set of longhand properties +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[derive(Clone, PartialEq)] pub struct LonghandIdSet { storage: [u32; (${len(data.longhands)} - 1 + 32) / 32] @@ -1329,19 +1330,20 @@ impl ToCss for PropertyDeclaration { } } +#[cfg(feature = "gecko")] impl MallocSizeOf for PropertyDeclaration { - fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn) -> usize { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { match *self { % for property in data.longhands: % if property.boxed and property.is_vector: <% raise Exception("this should not happen! not smart to box a vector here") %> % elif property.boxed: PropertyDeclaration::${property.camel_case}(ref sv_box) => { - sv_box.malloc_shallow_size_of_box(malloc_size_of) + as MallocShallowSizeOf>::shallow_size_of(sv_box, ops) } % elif property.is_vector: PropertyDeclaration::${property.camel_case}(ref sv_vec) => { - sv_vec.0.malloc_shallow_size_of_vec(malloc_size_of) + sv_vec.0.shallow_size_of(ops) } % endif % endfor diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index cf0994d7a9f..83d5e32f44b 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -9,6 +9,8 @@ use applicable_declarations::ApplicableDeclarationList; #[cfg(feature = "servo")] use heapsize::HeapSizeOf; +#[cfg(feature = "gecko")] +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use properties::{Importance, LonghandIdSet, PropertyDeclarationBlock}; use servo_arc::{Arc, ArcBorrow, NonZeroPtrMut}; use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard}; @@ -17,7 +19,7 @@ use std::io::{self, Write}; use std::mem; use std::ptr; use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; -use stylesheets::{MallocSizeOf, MallocSizeOfFn, StyleRule}; +use stylesheets::StyleRule; use thread_state; /// The rule tree, the structure servo uses to preserve the results of selector @@ -62,9 +64,12 @@ impl Drop for RuleTree { } } +#[cfg(feature = "gecko")] impl MallocSizeOf for RuleTree { - fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn) -> usize { - self.root.get().malloc_size_of_including_self(malloc_size_of) + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = ops.malloc_size_of(self.root.ptr()); + n += self.root.get().size_of(ops); + n } } @@ -794,11 +799,15 @@ impl RuleNode { } } } +} - fn malloc_size_of_including_self(&self, malloc_size_of: MallocSizeOfFn) -> usize { - let mut n = unsafe { (malloc_size_of.0)(self as *const _ as *const _) }; +#[cfg(feature = "gecko")] +impl MallocSizeOf for RuleNode { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = 0; for child in self.iter_children() { - n += unsafe { (*child.ptr()).malloc_size_of_including_self(malloc_size_of) }; + n += ops.malloc_size_of(child.ptr()); + n += unsafe { (*child.ptr()).size_of(ops) }; } n } diff --git a/components/style/selector_map.rs b/components/style/selector_map.rs index 873b7559576..3b14431c06f 100644 --- a/components/style/selector_map.rs +++ b/components/style/selector_map.rs @@ -21,8 +21,6 @@ use selectors::matching::{matches_selector, MatchingContext, ElementSelectorFlag use selectors::parser::{Component, Combinator, SelectorIter}; use smallvec::{SmallVec, VecLike}; use std::hash::{BuildHasherDefault, Hash, Hasher}; -#[cfg(feature = "gecko")] -use stylesheets::{MallocEnclosingSizeOfFn, MallocSizeOfFn, MallocSizeOfHash, MallocSizeOfVec}; use stylist::Rule; /// A hasher implementation that doesn't hash anything, because it expects its @@ -96,6 +94,7 @@ pub trait SelectorMapEntry : Sized + Clone { /// /// TODO: Tune the initial capacity of the HashMap #[derive(Debug)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct SelectorMap { /// A hash from an ID to rules which contain that ID selector. @@ -148,37 +147,6 @@ impl SelectorMap { pub fn len(&self) -> usize { self.count } - - /// Measures heap usage. - #[cfg(feature = "gecko")] - pub fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn, - malloc_enclosing_size_of: MallocEnclosingSizeOfFn) - -> usize { - // Currently we measure the storage used by the HashMaps, and any - // heap-allocated SmallVec values, but not things pointed to by the T - // elements within the SmallVec values. - - let mut n = 0; - - n += self.id_hash.malloc_shallow_size_of_hash(malloc_enclosing_size_of); - for (_, val) in self.id_hash.iter() { - n += val.malloc_shallow_size_of_vec(malloc_size_of); - } - - n += self.class_hash.malloc_shallow_size_of_hash(malloc_enclosing_size_of); - for (_, val) in self.class_hash.iter() { - n += val.malloc_shallow_size_of_vec(malloc_size_of); - } - - n += self.local_name_hash.malloc_shallow_size_of_hash(malloc_enclosing_size_of); - for (_, val) in self.local_name_hash.iter() { - n += val.malloc_shallow_size_of_vec(malloc_size_of); - } - - n += self.other.malloc_shallow_size_of_vec(malloc_size_of); - - n - } } impl SelectorMap { @@ -493,6 +461,7 @@ fn find_bucket<'a>(mut iter: SelectorIter<'a, SelectorImpl>) -> Bucket<'a> { /// Wrapper for PrecomputedHashMap that does ASCII-case-insensitive lookup in quirks mode. #[derive(Debug)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct MaybeCaseInsensitiveHashMap(PrecomputedHashMap); @@ -545,13 +514,3 @@ impl MaybeCaseInsensitiveHashMap { } } -#[cfg(feature = "gecko")] -impl MallocSizeOfHash for MaybeCaseInsensitiveHashMap - where K: PrecomputedHash + Eq + Hash -{ - fn malloc_shallow_size_of_hash(&self, malloc_enclosing_size_of: MallocEnclosingSizeOfFn) - -> usize { - self.0.malloc_shallow_size_of_hash(malloc_enclosing_size_of) - } -} - diff --git a/components/style/stylesheets/document_rule.rs b/components/style/stylesheets/document_rule.rs index 327994ad3ae..4647e56f6d6 100644 --- a/components/style/stylesheets/document_rule.rs +++ b/components/style/stylesheets/document_rule.rs @@ -7,13 +7,15 @@ //! We implement the prefixed `@-moz-document`. use cssparser::{Parser, Token, SourceLocation, BasicParseError}; +#[cfg(feature = "gecko")] +use malloc_size_of::MallocSizeOfOps; use media_queries::Device; use parser::{Parse, ParserContext}; use servo_arc::Arc; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use std::fmt; use style_traits::{ToCss, ParseError, StyleParseError}; -use stylesheets::{CssRules, MallocSizeOfFn, MallocSizeOfWithGuard}; +use stylesheets::CssRules; use values::specified::url::SpecifiedUrl; #[derive(Debug)] @@ -29,10 +31,10 @@ pub struct DocumentRule { impl DocumentRule { /// Measure heap usage. - pub fn malloc_size_of_children(&self, guard: &SharedRwLockReadGuard, - malloc_size_of: MallocSizeOfFn) -> usize { + #[cfg(feature = "gecko")] + pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { // Measurement of other fields may be added later. - self.rules.read_with(guard).malloc_size_of_children(guard, malloc_size_of) + self.rules.read_with(guard).size_of(guard, ops) } } diff --git a/components/style/stylesheets/keyframes_rule.rs b/components/style/stylesheets/keyframes_rule.rs index 3671f9d4093..0fa623337d9 100644 --- a/components/style/stylesheets/keyframes_rule.rs +++ b/components/style/stylesheets/keyframes_rule.rs @@ -19,7 +19,7 @@ use shared_lock::{DeepCloneParams, DeepCloneWithLock, SharedRwLock, SharedRwLock use std::fmt; use style_traits::{PARSING_MODE_DEFAULT, ToCss, ParseError, StyleParseError}; use style_traits::PropertyDeclarationParseError; -use stylesheets::{CssRuleType, MallocSizeOfFn, MallocSizeOfVec, StylesheetContents}; +use stylesheets::{CssRuleType, StylesheetContents}; use stylesheets::rule_parser::{VendorPrefix, get_location_with_offset}; use values::{KeyframesName, serialize_percentage}; @@ -100,6 +100,7 @@ impl DeepCloneWithLock for KeyframesRule { /// A number from 0 to 1, indicating the percentage of the animation when this /// keyframe should run. #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct KeyframePercentage(pub f32); @@ -263,11 +264,14 @@ impl DeepCloneWithLock for Keyframe { /// /// TODO: Find a better name for this? #[derive(Debug)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum KeyframesStepValue { /// A step formed by a declaration block specified by the CSS. Declarations { /// The declaration block per se. + #[cfg_attr(feature = "gecko", + ignore_malloc_size_of = "XXX: Primary ref, measure if DMD says it's worthwhile")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] block: Arc> }, @@ -278,6 +282,7 @@ pub enum KeyframesStepValue { /// A single step from a keyframe animation. #[derive(Debug)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct KeyframesStep { /// The percentage of the animation duration when this step starts. @@ -349,6 +354,7 @@ impl KeyframesStep { /// /// It only takes into account animable properties. #[derive(Debug)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct KeyframesAnimation { /// The difference steps of the animation. @@ -442,14 +448,6 @@ impl KeyframesAnimation { result } - - /// Measure heap usage. - pub fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn) -> usize { - let mut n = 0; - n += self.steps.malloc_shallow_size_of_vec(malloc_size_of); - n += self.properties_changed.malloc_shallow_size_of_vec(malloc_size_of); - n - } } /// Parses a keyframes list, like: diff --git a/components/style/stylesheets/media_rule.rs b/components/style/stylesheets/media_rule.rs index f336dc12d89..ab727b43112 100644 --- a/components/style/stylesheets/media_rule.rs +++ b/components/style/stylesheets/media_rule.rs @@ -7,12 +7,14 @@ //! [media]: https://drafts.csswg.org/css-conditional/#at-ruledef-media use cssparser::SourceLocation; +#[cfg(feature = "gecko")] +use malloc_size_of::MallocSizeOfOps; use media_queries::MediaList; use servo_arc::Arc; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use std::fmt; use style_traits::ToCss; -use stylesheets::{CssRules, MallocSizeOfFn, MallocSizeOfWithGuard}; +use stylesheets::CssRules; /// An [`@media`][media] urle. /// @@ -29,10 +31,10 @@ pub struct MediaRule { impl MediaRule { /// Measure heap usage. - pub fn malloc_size_of_children(&self, guard: &SharedRwLockReadGuard, - malloc_size_of: MallocSizeOfFn) -> usize { + #[cfg(feature = "gecko")] + pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { // Measurement of other fields may be added later. - self.rules.read_with(guard).malloc_size_of_children(guard, malloc_size_of) + self.rules.read_with(guard).size_of(guard, ops) } } diff --git a/components/style/stylesheets/memory.rs b/components/style/stylesheets/memory.rs deleted file mode 100644 index b9f4f438fe5..00000000000 --- a/components/style/stylesheets/memory.rs +++ /dev/null @@ -1,215 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -//! Memory reporting for the style system when running inside of Gecko. - -#[cfg(feature = "gecko")] -use gecko_bindings::bindings::Gecko_HaveSeenPtr; -#[cfg(feature = "gecko")] -use gecko_bindings::structs::SeenPtrs; -#[cfg(feature = "gecko")] -use hash::HashMap; -#[cfg(feature = "gecko")] -use servo_arc::Arc; -use shared_lock::SharedRwLockReadGuard; -use smallvec::{Array, SmallVec}; -use std::collections::HashSet; -use std::hash::{BuildHasher, Hash}; -use std::os::raw::c_void; - -/// Like gecko_bindings::structs::MallocSizeOf, but without the Option<> -/// wrapper. -/// -/// Note that functions of this type should be called via do_malloc_size_of(), -/// rather than directly. -#[derive(Clone, Copy)] -pub struct MallocSizeOfFn(pub unsafe extern "C" fn(ptr: *const c_void) -> usize); - -/// Like MallocSizeOfFn, but can take an interior pointer. -#[derive(Clone, Copy)] -pub struct MallocEnclosingSizeOfFn(pub unsafe extern "C" fn(ptr: *const c_void) -> usize); - -/// Servo-side counterpart to mozilla::SizeOfState. The only difference is that -/// this struct doesn't contain the SeenPtrs table, just a pointer to it. -#[cfg(feature = "gecko")] -pub struct SizeOfState { - /// Function that measures the size of heap blocks. - pub malloc_size_of: MallocSizeOfFn, - /// Table recording heap blocks that have already been measured. - pub seen_ptrs: *mut SeenPtrs, -} - -/// Check if an allocation is empty. -pub unsafe fn is_empty(ptr: *const T) -> bool { - return ptr as usize <= ::std::mem::align_of::(); -} - -/// Call malloc_size_of on ptr, first checking that the allocation isn't empty. -pub unsafe fn do_malloc_size_of(malloc_size_of: MallocSizeOfFn, ptr: *const T) -> usize { - if is_empty(ptr) { - 0 - } else { - (malloc_size_of.0)(ptr as *const c_void) - } -} - -/// Call malloc_enclosing_size_of on ptr, which must not be empty. -pub unsafe fn do_malloc_enclosing_size_of( - malloc_enclosing_size_of: MallocEnclosingSizeOfFn, ptr: *const T) -> usize -{ - assert!(!is_empty(ptr)); - (malloc_enclosing_size_of.0)(ptr as *const c_void) -} - -/// Trait for measuring the size of heap data structures. -pub trait MallocSizeOf { - /// Measure the size of any heap-allocated structures that hang off this - /// value, but not the space taken up by the value itself. - fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn) -> usize; -} - -/// Like MallocSizeOf, but takes a SizeOfState which allows it to measure -/// graph-like structures such as those containing Arcs. -#[cfg(feature = "gecko")] -pub trait MallocSizeOfWithRepeats { - /// Measure the size of any heap-allocated structures that hang off this - /// value, but not the space taken up by the value itself. - fn malloc_size_of_children(&self, state: &mut SizeOfState) -> usize; -} - -/// Like MallocSizeOf, but operates with the global SharedRwLockReadGuard -/// locked. -pub trait MallocSizeOfWithGuard { - /// Like MallocSizeOf::malloc_size_of_children, but with a |guard| argument. - fn malloc_size_of_children( - &self, - guard: &SharedRwLockReadGuard, - malloc_size_of: MallocSizeOfFn - ) -> usize; -} - -impl MallocSizeOf for (A, B) { - fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn) -> usize { - self.0.malloc_size_of_children(malloc_size_of) + - self.1.malloc_size_of_children(malloc_size_of) - } -} - -impl MallocSizeOf for Vec { - fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn) -> usize { - self.iter().fold( - unsafe { do_malloc_size_of(malloc_size_of, self.as_ptr()) }, - |n, elem| n + elem.malloc_size_of_children(malloc_size_of)) - } -} - -#[cfg(feature = "gecko")] -impl MallocSizeOfWithRepeats for Arc { - fn malloc_size_of_children(&self, state: &mut SizeOfState) -> usize { - let mut n = 0; - let heap_ptr = self.heap_ptr(); - if unsafe { !is_empty(heap_ptr) && !Gecko_HaveSeenPtr(state.seen_ptrs, heap_ptr) } { - n += unsafe { (state.malloc_size_of.0)(heap_ptr) }; - n += (**self).malloc_size_of_children(state); - } - n - } -} - -impl MallocSizeOfWithGuard for Vec { - fn malloc_size_of_children( - &self, - guard: &SharedRwLockReadGuard, - malloc_size_of: MallocSizeOfFn, - ) -> usize { - self.iter().fold( - unsafe { do_malloc_size_of(malloc_size_of, self.as_ptr()) }, - |n, elem| n + elem.malloc_size_of_children(guard, malloc_size_of)) - } -} - -/// Trait for measuring the heap usage of a Box. -pub trait MallocSizeOfBox { - /// Measure shallowly the size of the memory used by the T -- anything - /// pointed to by the T must be measured separately. - fn malloc_shallow_size_of_box(&self, malloc_size_of: MallocSizeOfFn) -> usize; -} - -impl MallocSizeOfBox for Box { - fn malloc_shallow_size_of_box(&self, malloc_size_of: MallocSizeOfFn) -> usize { - unsafe { do_malloc_size_of(malloc_size_of, &**self as *const T) } - } -} - -/// Trait for measuring the heap usage of a vector. -pub trait MallocSizeOfVec { - /// Measure shallowly the size of the memory used by the Vec's elements -- - /// anything pointed to by the elements must be measured separately, using - /// iteration. - fn malloc_shallow_size_of_vec(&self, malloc_size_of: MallocSizeOfFn) -> usize; -} - -impl MallocSizeOfVec for Vec { - fn malloc_shallow_size_of_vec(&self, malloc_size_of: MallocSizeOfFn) -> usize { - unsafe { do_malloc_size_of(malloc_size_of, self.as_ptr()) } - } -} - -impl MallocSizeOfVec for SmallVec { - fn malloc_shallow_size_of_vec(&self, malloc_size_of: MallocSizeOfFn) -> usize { - if self.spilled() { - unsafe { do_malloc_size_of(malloc_size_of, self.as_ptr()) } - } else { - 0 - } - } -} - -/// Trait for measuring the heap usage of a hash table. -pub trait MallocSizeOfHash { - /// Measure shallowly the size of the memory used within a hash table -- - /// anything pointer to by the keys and values must be measured separately, - /// using iteration. - fn malloc_shallow_size_of_hash(&self, malloc_enclosing_size_of: MallocEnclosingSizeOfFn) - -> usize; -} - -impl MallocSizeOfHash for HashSet - where T: Eq + Hash, - S: BuildHasher -{ - fn malloc_shallow_size_of_hash(&self, malloc_enclosing_size_of: MallocEnclosingSizeOfFn) - -> usize { - // The first value from the iterator gives us an interior pointer. - // malloc_enclosing_size_of() then gives us the storage size. This - // assumes that the HashSet's contents (values and hashes) are all - // stored in a single contiguous heap allocation. - let mut n = 0; - for v in self.iter() { - n += unsafe { do_malloc_enclosing_size_of(malloc_enclosing_size_of, v as *const T) }; - break; - } - n - } -} - -#[cfg(feature = "gecko")] -impl MallocSizeOfHash for HashMap - where K: Eq + Hash, - S: BuildHasher -{ - fn malloc_shallow_size_of_hash(&self, malloc_enclosing_size_of: MallocEnclosingSizeOfFn) - -> usize { - // The first value from the iterator gives us an interior pointer. - // malloc_enclosing_size_of() then gives us the storage size. This - // assumes that the HashMap's contents (keys, values, and hashes) are - // all stored in a single contiguous heap allocation. - let mut n = 0; - for v in self.values() { - n += unsafe { do_malloc_enclosing_size_of(malloc_enclosing_size_of, v as *const V) }; - break; - } - n - } -} diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs index 87ee2b413c0..e0bb549a69e 100644 --- a/components/style/stylesheets/mod.rs +++ b/components/style/stylesheets/mod.rs @@ -12,7 +12,6 @@ pub mod import_rule; pub mod keyframes_rule; mod loader; mod media_rule; -mod memory; mod namespace_rule; pub mod origin; mod page_rule; @@ -26,6 +25,8 @@ pub mod viewport_rule; use cssparser::{parse_one_rule, Parser, ParserInput}; use error_reporting::NullReporter; +#[cfg(feature = "gecko")] +use malloc_size_of::MallocSizeOfOps; use parser::{ParserContext, ParserErrorContext}; use servo_arc::Arc; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; @@ -40,10 +41,6 @@ pub use self::import_rule::ImportRule; pub use self::keyframes_rule::KeyframesRule; pub use self::loader::StylesheetLoader; pub use self::media_rule::MediaRule; -pub use self::memory::{MallocEnclosingSizeOfFn, MallocSizeOf, MallocSizeOfBox, MallocSizeOfFn}; -pub use self::memory::{MallocSizeOfHash, MallocSizeOfVec, MallocSizeOfWithGuard}; -#[cfg(feature = "gecko")] -pub use self::memory::{MallocSizeOfWithRepeats, SizeOfState}; pub use self::namespace_rule::NamespaceRule; pub use self::origin::{Origin, OriginSet, PerOrigin, PerOriginIter}; pub use self::page_rule::PageRule; @@ -109,12 +106,10 @@ pub enum CssRule { Document(Arc>), } -impl MallocSizeOfWithGuard for CssRule { - fn malloc_size_of_children( - &self, - guard: &SharedRwLockReadGuard, - malloc_size_of: MallocSizeOfFn - ) -> usize { +impl CssRule { + /// Measure heap usage. + #[cfg(feature = "gecko")] + fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { match *self { // Not all fields are currently fully measured. Extra measurement // may be added later. @@ -125,13 +120,9 @@ impl MallocSizeOfWithGuard for CssRule { // it on the C++ side in the child list of the ServoStyleSheet. CssRule::Import(_) => 0, - CssRule::Style(ref lock) => { - lock.read_with(guard).malloc_size_of_children(guard, malloc_size_of) - }, + CssRule::Style(ref lock) => lock.read_with(guard).size_of(guard, ops), - CssRule::Media(ref lock) => { - lock.read_with(guard).malloc_size_of_children(guard, malloc_size_of) - }, + CssRule::Media(ref lock) => lock.read_with(guard).size_of(guard, ops), CssRule::FontFace(_) => 0, CssRule::FontFeatureValues(_) => 0, @@ -139,17 +130,11 @@ impl MallocSizeOfWithGuard for CssRule { CssRule::Viewport(_) => 0, CssRule::Keyframes(_) => 0, - CssRule::Supports(ref lock) => { - lock.read_with(guard).malloc_size_of_children(guard, malloc_size_of) - }, + CssRule::Supports(ref lock) => lock.read_with(guard).size_of(guard, ops), - CssRule::Page(ref lock) => { - lock.read_with(guard).malloc_size_of_children(guard, malloc_size_of) - }, + CssRule::Page(ref lock) => lock.read_with(guard).size_of(guard, ops), - CssRule::Document(ref lock) => { - lock.read_with(guard).malloc_size_of_children(guard, malloc_size_of) - }, + CssRule::Document(ref lock) => lock.read_with(guard).size_of(guard, ops), } } } diff --git a/components/style/stylesheets/origin.rs b/components/style/stylesheets/origin.rs index 9a875731e9b..46dac5f6fd4 100644 --- a/components/style/stylesheets/origin.rs +++ b/components/style/stylesheets/origin.rs @@ -103,6 +103,7 @@ impl Iterator for OriginSetIterator { } /// An object that stores a `T` for each origin of the CSS cascade. +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Debug, Default)] pub struct PerOrigin { diff --git a/components/style/stylesheets/page_rule.rs b/components/style/stylesheets/page_rule.rs index c334df44042..5384ca5b02f 100644 --- a/components/style/stylesheets/page_rule.rs +++ b/components/style/stylesheets/page_rule.rs @@ -7,12 +7,13 @@ //! [page]: https://drafts.csswg.org/css2/page.html#page-box use cssparser::SourceLocation; +#[cfg(feature = "gecko")] +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use properties::PropertyDeclarationBlock; use servo_arc::Arc; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use std::fmt; use style_traits::ToCss; -use stylesheets::{MallocSizeOf, MallocSizeOfFn}; /// A [`@page`][page] rule. /// @@ -33,10 +34,10 @@ pub struct PageRule { impl PageRule { /// Measure heap usage. - pub fn malloc_size_of_children(&self, guard: &SharedRwLockReadGuard, - malloc_size_of: MallocSizeOfFn) -> usize { + #[cfg(feature = "gecko")] + pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { // Measurement of other fields may be added later. - self.block.read_with(guard).malloc_size_of_children(malloc_size_of) + self.block.read_with(guard).size_of(ops) } } diff --git a/components/style/stylesheets/rule_list.rs b/components/style/stylesheets/rule_list.rs index 14b3dc5e769..97e7e9b3cc7 100644 --- a/components/style/stylesheets/rule_list.rs +++ b/components/style/stylesheets/rule_list.rs @@ -4,11 +4,12 @@ //! A list of CSS rules. +#[cfg(feature = "gecko")] +use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps}; use servo_arc::{Arc, RawOffsetArc}; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard}; use stylesheets::{CssRule, RulesMutateError}; use stylesheets::loader::StylesheetLoader; -use stylesheets::memory::{MallocSizeOfFn, MallocSizeOfWithGuard}; use stylesheets::rule_parser::State; use stylesheets::stylesheet::StylesheetContents; @@ -36,17 +37,17 @@ impl DeepCloneWithLock for CssRules { } } -impl MallocSizeOfWithGuard for CssRules { - fn malloc_size_of_children( - &self, - guard: &SharedRwLockReadGuard, - malloc_size_of: MallocSizeOfFn - ) -> usize { - self.0.malloc_size_of_children(guard, malloc_size_of) - } -} - impl CssRules { + /// Measure heap usage. + #[cfg(feature = "gecko")] + pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.0.shallow_size_of(ops); + for rule in self.0.iter() { + n += rule.size_of(guard, ops); + } + n + } + /// Trivially construct a new set of CSS rules. pub fn new(rules: Vec, shared_lock: &SharedRwLock) -> Arc> { Arc::new(shared_lock.wrap(CssRules(rules))) diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs index 2dc1c3060e6..7dce3fc64f8 100644 --- a/components/style/stylesheets/rule_parser.rs +++ b/components/style/stylesheets/rule_parser.rs @@ -102,6 +102,7 @@ pub enum State { } #[derive(Clone, Debug)] +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] /// Vendor prefix. pub enum VendorPrefix { diff --git a/components/style/stylesheets/style_rule.rs b/components/style/stylesheets/style_rule.rs index 72dbbed0548..79f365cf36f 100644 --- a/components/style/stylesheets/style_rule.rs +++ b/components/style/stylesheets/style_rule.rs @@ -5,6 +5,8 @@ //! A style rule. use cssparser::SourceLocation; +#[cfg(feature = "gecko")] +use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; use properties::PropertyDeclarationBlock; use selector_parser::SelectorImpl; use selectors::SelectorList; @@ -12,7 +14,6 @@ use servo_arc::Arc; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use std::fmt; use style_traits::ToCss; -use stylesheets::{MallocSizeOf, MallocSizeOfFn, MallocSizeOfVec, MallocSizeOfWithGuard}; /// A style rule, with selectors and declarations. #[derive(Debug)] @@ -41,26 +42,23 @@ impl DeepCloneWithLock for StyleRule { } } -impl MallocSizeOfWithGuard for StyleRule { - fn malloc_size_of_children( - &self, - guard: &SharedRwLockReadGuard, - malloc_size_of: MallocSizeOfFn - ) -> usize { +impl StyleRule { + /// Measure heap usage. + #[cfg(feature = "gecko")] + pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { let mut n = 0; // We may add measurement of things hanging off the embedded Components // later. - n += self.selectors.0.malloc_shallow_size_of_vec(malloc_size_of); + n += self.selectors.0.shallow_size_of(ops); for selector in self.selectors.0.iter() { // It's safe to measure this ThinArc directly because it's the // "primary" reference. (The secondary references are on the // Stylist.) - let ptr = selector.thin_arc_heap_ptr(); - n += unsafe { (malloc_size_of.0)(ptr) }; + n += ops.malloc_size_of(selector.thin_arc_heap_ptr()); } - n += self.block.read_with(guard).malloc_size_of_children(malloc_size_of); + n += self.block.read_with(guard).size_of(ops); n } diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs index c647077f7e7..9dfe1faed70 100644 --- a/components/style/stylesheets/stylesheet.rs +++ b/components/style/stylesheets/stylesheet.rs @@ -9,6 +9,8 @@ use error_reporting::{ParseErrorReporter, ContextualParseError}; use fallible::FallibleVec; use fnv::FnvHashMap; use invalidation::media_queries::{MediaListKey, ToMediaListKey}; +#[cfg(feature = "gecko")] +use malloc_size_of::MallocSizeOfOps; use media_queries::{MediaList, Device}; use parking_lot::RwLock; use parser::{ParserContext, ParserErrorContext}; @@ -19,7 +21,6 @@ use std::sync::atomic::{AtomicBool, Ordering}; use style_traits::PARSING_MODE_DEFAULT; use stylesheets::{CssRule, CssRules, Origin, UrlExtraData}; use stylesheets::loader::StylesheetLoader; -use stylesheets::memory::{MallocSizeOfFn, MallocSizeOfWithGuard}; use stylesheets::rule_parser::{State, TopLevelRuleParser}; use stylesheets::rules_iterator::{EffectiveRules, EffectiveRulesIterator, NestedRuleIterationCondition, RulesIterator}; use values::specified::NamespaceId; @@ -116,6 +117,13 @@ impl StylesheetContents { &self.rules.read_with(guard) ) } + + /// Measure heap usage. + #[cfg(feature = "gecko")] + pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { + // Measurement of other fields may be added later. + self.rules.read_with(guard).size_of(guard, ops) + } } impl DeepCloneWithLock for StylesheetContents { @@ -141,17 +149,6 @@ impl DeepCloneWithLock for StylesheetContents { } } -impl MallocSizeOfWithGuard for StylesheetContents { - fn malloc_size_of_children( - &self, - guard: &SharedRwLockReadGuard, - malloc_size_of: MallocSizeOfFn - ) -> usize { - // Measurement of other fields may be added later. - self.rules.read_with(guard).malloc_size_of_children(guard, malloc_size_of) - } -} - /// The structure servo uses to represent a stylesheet. #[derive(Debug)] pub struct Stylesheet { diff --git a/components/style/stylesheets/supports_rule.rs b/components/style/stylesheets/supports_rule.rs index 2f21bd3b555..4886553c7a8 100644 --- a/components/style/stylesheets/supports_rule.rs +++ b/components/style/stylesheets/supports_rule.rs @@ -6,6 +6,8 @@ use cssparser::{BasicParseError, ParseError as CssParseError, ParserInput}; use cssparser::{Delimiter, parse_important, Parser, SourceLocation, Token}; +#[cfg(feature = "gecko")] +use malloc_size_of::MallocSizeOfOps; use parser::ParserContext; use properties::{PropertyId, PropertyDeclaration, PropertyParserContext, SourcePropertyDeclaration}; use selectors::parser::SelectorParseError; @@ -13,7 +15,7 @@ use servo_arc::Arc; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use std::fmt; use style_traits::{ToCss, ParseError, StyleParseError}; -use stylesheets::{CssRuleType, CssRules, MallocSizeOfFn, MallocSizeOfWithGuard}; +use stylesheets::{CssRuleType, CssRules}; /// An [`@supports`][supports] rule. /// @@ -32,10 +34,10 @@ pub struct SupportsRule { impl SupportsRule { /// Measure heap usage. - pub fn malloc_size_of_children(&self, guard: &SharedRwLockReadGuard, - malloc_size_of: MallocSizeOfFn) -> usize { + #[cfg(feature = "gecko")] + pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { // Measurement of other fields may be added later. - self.rules.read_with(guard).malloc_size_of_children(guard, malloc_size_of) + self.rules.read_with(guard).size_of(guard, ops) } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index ea0945fe9e5..165307f7532 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -15,6 +15,8 @@ use gecko_bindings::structs::{nsIAtom, ServoStyleSetSizes, StyleRuleInclusion}; use hashglobe::FailedAllocationError; use invalidation::element::invalidation_map::InvalidationMap; use invalidation::media_queries::{EffectiveMediaQueryResults, ToMediaListKey}; +#[cfg(feature = "gecko")] +use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; use media_queries::Device; use properties::{self, CascadeFlags, ComputedValues}; use properties::{AnimationRules, PropertyDeclarationBlock}; @@ -43,10 +45,6 @@ use stylesheet_set::{OriginValidity, SheetRebuildKind, StylesheetSet, Stylesheet #[cfg(feature = "gecko")] use stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule, PageRule}; use stylesheets::{CssRule, Origin, OriginSet, PerOrigin, PerOriginIter}; -#[cfg(feature = "gecko")] -use stylesheets::{MallocEnclosingSizeOfFn, MallocSizeOf, MallocSizeOfBox, MallocSizeOfFn}; -#[cfg(feature = "gecko")] -use stylesheets::{MallocSizeOfHash, MallocSizeOfVec}; use stylesheets::StyleRule; use stylesheets::StylesheetInDocument; use stylesheets::UserAgentStylesheets; @@ -379,19 +377,14 @@ impl DocumentCascadeData { /// Measures heap usage. #[cfg(feature = "gecko")] - pub fn malloc_add_size_of_children(&self, malloc_size_of: MallocSizeOfFn, - malloc_enclosing_size_of: MallocEnclosingSizeOfFn, - sizes: &mut ServoStyleSetSizes) { - self.per_origin.user_agent.malloc_add_size_of_children(malloc_size_of, - malloc_enclosing_size_of, sizes); - self.per_origin.user.malloc_add_size_of_children(malloc_size_of, - malloc_enclosing_size_of, sizes); - self.per_origin.author.malloc_add_size_of_children(malloc_size_of, - malloc_enclosing_size_of, sizes); + pub fn add_size_of_children(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { + self.per_origin.user_agent.add_size_of_children(ops, sizes); + self.per_origin.user.add_size_of_children(ops, sizes); + self.per_origin.author.add_size_of_children(ops, sizes); for elem in self.precomputed_pseudo_element_decls.iter() { if let Some(ref elem) = *elem { - sizes.mStylistPrecomputedPseudos += elem.malloc_shallow_size_of_vec(malloc_size_of); + sizes.mStylistPrecomputedPseudos += elem.shallow_size_of(ops); } } } @@ -1652,12 +1645,9 @@ impl Stylist { /// Measures heap usage. #[cfg(feature = "gecko")] - pub fn malloc_add_size_of_children(&self, malloc_size_of: MallocSizeOfFn, - malloc_enclosing_size_of: MallocEnclosingSizeOfFn, - sizes: &mut ServoStyleSetSizes) { - self.cascade_data.malloc_add_size_of_children(malloc_size_of, malloc_enclosing_size_of, - sizes); - sizes.mStylistRuleTree += self.rule_tree.malloc_size_of_children(malloc_size_of); + pub fn add_size_of_children(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { + self.cascade_data.add_size_of_children(ops, sizes); + sizes.mStylistRuleTree += self.rule_tree.size_of(ops); // We may measure other fields in the future if DMD says it's worth it. } @@ -1722,22 +1712,27 @@ impl ExtraStyleData { self.pages.clear(); } } +} +#[cfg(feature = "gecko")] +impl MallocSizeOf for ExtraStyleData { /// Measure heap usage. - #[cfg(feature = "gecko")] - pub fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn, - malloc_enclosing_size_of: MallocEnclosingSizeOfFn) -> usize { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { let mut n = 0; - n += self.font_faces.malloc_shallow_size_of_vec(malloc_size_of); - n += self.font_feature_values.malloc_shallow_size_of_vec(malloc_size_of); - n += self.counter_styles.malloc_shallow_size_of_hash(malloc_enclosing_size_of); + n += self.font_faces.shallow_size_of(ops); + n += self.font_feature_values.shallow_size_of(ops); + n += self.counter_styles.shallow_size_of(ops); + n += self.pages.shallow_size_of(ops); n } } /// SelectorMapEntry implementation for use in our revalidation selector map. +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[derive(Clone, Debug)] struct RevalidationSelectorAndHashes { + #[cfg_attr(feature = "gecko", + ignore_malloc_size_of = "CssRules have primary refs, we measure there")] selector: Selector, selector_offset: usize, hashes: AncestorHashes, @@ -2029,35 +2024,22 @@ impl CascadeData { /// Measures heap usage. #[cfg(feature = "gecko")] - pub fn malloc_add_size_of_children(&self, malloc_size_of: MallocSizeOfFn, - malloc_enclosing_size_of: MallocEnclosingSizeOfFn, - sizes: &mut ServoStyleSetSizes) { - sizes.mStylistElementAndPseudosMaps += - self.element_map.malloc_size_of_children(malloc_size_of, malloc_enclosing_size_of); + pub fn add_size_of_children(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { + sizes.mStylistElementAndPseudosMaps += self.element_map.size_of(ops); for elem in self.pseudos_map.iter() { if let Some(ref elem) = *elem { - sizes.mStylistElementAndPseudosMaps += - elem.malloc_shallow_size_of_box(malloc_size_of) + - elem.malloc_size_of_children(malloc_size_of, malloc_enclosing_size_of) + sizes.mStylistElementAndPseudosMaps += as MallocSizeOf>::size_of(elem, ops); } } - sizes.mStylistOther += - self.animations.malloc_shallow_size_of_hash(malloc_enclosing_size_of); - for val in self.animations.values() { - sizes.mStylistOther += val.malloc_size_of_children(malloc_size_of); - } + sizes.mStylistOther += self.animations.size_of(ops); - sizes.mStylistInvalidationMap += - self.invalidation_map.malloc_size_of_children(malloc_size_of, malloc_enclosing_size_of); + sizes.mStylistInvalidationMap += self.invalidation_map.size_of(ops); - sizes.mStylistRevalidationSelectors += - self.selectors_for_cache_revalidation.malloc_size_of_children(malloc_size_of, - malloc_enclosing_size_of); + sizes.mStylistRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops); - sizes.mStylistOther += - self.effective_media_query_results.malloc_size_of_children(malloc_enclosing_size_of); + sizes.mStylistOther += self.effective_media_query_results.size_of(ops); } } @@ -2069,6 +2051,7 @@ impl Default for CascadeData { /// A rule, that wraps a style rule, but represents a single selector of the /// rule. +#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Clone, Debug)] pub struct Rule { @@ -2076,16 +2059,24 @@ pub struct Rule { /// any_{important,normal} booleans inline in the Rule to avoid /// pointer-chasing when gathering applicable declarations, which /// can ruin performance when there are a lot of rules. + #[cfg_attr(feature = "gecko", + ignore_malloc_size_of = "CssRules have primary refs, we measure there")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] pub selector: Selector, + /// The ancestor hashes associated with the selector. #[cfg_attr(feature = "servo", ignore_heap_size_of = "No heap data")] pub hashes: AncestorHashes, + /// The source order this style rule appears in. Note that we only use /// three bytes to store this value in ApplicableDeclarationsBlock, so /// we could repurpose that storage here if we needed to. pub source_order: u32, + /// The actual style rule. + #[cfg_attr(feature = "gecko", + ignore_malloc_size_of = + "Secondary ref. Primary ref is in StyleRule under Stylesheet.")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] pub style_rule: Arc>, } diff --git a/ports/geckolib/Cargo.toml b/ports/geckolib/Cargo.toml index b4ed43cac94..24a8cc067e8 100644 --- a/ports/geckolib/Cargo.toml +++ b/ports/geckolib/Cargo.toml @@ -19,6 +19,7 @@ cssparser = "0.20.2" env_logger = {version = "0.4", default-features = false} # disable `regex` to reduce code size libc = "0.2" log = {version = "0.3.5", features = ["release_max_level_info"]} +malloc_size_of = {path = "../../components/malloc_size_of"} nsstring_vendor = {path = "../../components/style/gecko_bindings/nsstring_vendor"} parking_lot = "0.4" selectors = {path = "../../components/selectors"} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index a5489f1b65b..cf0842ac856 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -5,6 +5,7 @@ use cssparser::{Parser, ParserInput}; use cssparser::ToCss as ParserToCss; use env_logger::LogBuilder; +use malloc_size_of::MallocSizeOfOps; use selectors::Element; use selectors::matching::{MatchingContext, MatchingMode, matches_selector}; use servo_arc::{Arc, ArcBorrow, RawOffsetArc}; @@ -52,6 +53,7 @@ use style::gecko_bindings::bindings::Gecko_ConstructFontFeatureValueSet; use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe; use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe; use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart; +use style::gecko_bindings::bindings::Gecko_HaveSeenPtr; use style::gecko_bindings::bindings::Gecko_NewNoneTransform; use style::gecko_bindings::bindings::RawGeckoAnimationPropertySegmentBorrowed; use style::gecko_bindings::bindings::RawGeckoCSSPropertyIDListBorrowed; @@ -120,9 +122,8 @@ use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard use style::string_cache::Atom; use style::style_adjuster::StyleAdjuster; use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers, DocumentRule}; -use style::stylesheets::{FontFeatureValuesRule, ImportRule, KeyframesRule, MallocEnclosingSizeOfFn}; -use style::stylesheets::{MallocSizeOfFn, MallocSizeOfWithGuard, MediaRule}; -use style::stylesheets::{NamespaceRule, Origin, OriginSet, PageRule, SizeOfState, StyleRule}; +use style::stylesheets::{FontFeatureValuesRule, ImportRule, KeyframesRule, MediaRule}; +use style::stylesheets::{NamespaceRule, Origin, OriginSet, PageRule, StyleRule}; use style::stylesheets::{StylesheetContents, SupportsRule}; use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue}; @@ -778,15 +779,13 @@ pub extern "C" fn Servo_Element_ClearData(element: RawGeckoElementBorrowed) { pub extern "C" fn Servo_Element_SizeOfExcludingThisAndCVs(malloc_size_of: GeckoMallocSizeOf, seen_ptrs: *mut SeenPtrs, element: RawGeckoElementBorrowed) -> usize { - let malloc_size_of = MallocSizeOfFn(malloc_size_of.unwrap()); let element = GeckoElement(element); let borrow = element.borrow_data(); if let Some(data) = borrow { - let mut state = SizeOfState { - malloc_size_of: malloc_size_of, - seen_ptrs: seen_ptrs, - }; - (*data).malloc_size_of_children_excluding_cvs(&mut state) + let have_seen_ptr = move |ptr| { unsafe { Gecko_HaveSeenPtr(seen_ptrs, ptr) } }; + let mut ops = MallocSizeOfOps::new(malloc_size_of.unwrap(), None, + Some(Box::new(have_seen_ptr))); + (*data).size_of_excluding_cvs(&mut ops) } else { 0 } @@ -1086,8 +1085,8 @@ pub extern "C" fn Servo_StyleSheet_SizeOfIncludingThis( ) -> usize { let global_style_data = &*GLOBAL_STYLE_DATA; let guard = global_style_data.shared_lock.read(); - let malloc_size_of = MallocSizeOfFn(malloc_size_of.unwrap()); - StylesheetContents::as_arc(&sheet).malloc_size_of_children(&guard, malloc_size_of) + let mut ops = MallocSizeOfOps::new(malloc_size_of.unwrap(), None, None); + StylesheetContents::as_arc(&sheet).size_of(&guard, &mut ops) } #[no_mangle] @@ -3710,10 +3709,10 @@ pub extern "C" fn Servo_StyleSet_AddSizeOfExcludingThis( raw_data: RawServoStyleSetBorrowed ) { let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - let malloc_size_of = MallocSizeOfFn(malloc_size_of.unwrap()); - let malloc_enclosing_size_of = MallocEnclosingSizeOfFn(malloc_enclosing_size_of.unwrap()); + let mut ops = MallocSizeOfOps::new(malloc_size_of.unwrap(), + malloc_enclosing_size_of, None); let sizes = unsafe { sizes.as_mut() }.unwrap(); - data.malloc_add_size_of_children(malloc_size_of, malloc_enclosing_size_of, sizes); + data.add_size_of_children(&mut ops, sizes); } #[no_mangle] diff --git a/ports/geckolib/lib.rs b/ports/geckolib/lib.rs index 7c2c9debc82..f1222823730 100644 --- a/ports/geckolib/lib.rs +++ b/ports/geckolib/lib.rs @@ -8,6 +8,7 @@ extern crate cssparser; extern crate env_logger; extern crate libc; #[macro_use] extern crate log; +extern crate malloc_size_of; extern crate selectors; extern crate servo_arc; #[macro_use] extern crate style; diff --git a/tests/compiletest/plugin/compile-fail/arc_rc_must_not_derive_malloc_size_of.rs b/tests/compiletest/plugin/compile-fail/arc_rc_must_not_derive_malloc_size_of.rs new file mode 100644 index 00000000000..72a5eaa1e9c --- /dev/null +++ b/tests/compiletest/plugin/compile-fail/arc_rc_must_not_derive_malloc_size_of.rs @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +extern crate malloc_size_of; +extern crate servo_arc; + +use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf}; + +fn sizeable() { +} + +fn shallow_sizeable() { +} + +fn main() { + sizeable::<::servo_arc::Arc>(); + //~^ ERROR the trait bound `servo_arc::Arc: malloc_size_of::MallocSizeOf` is not satisfied + + sizeable::<::std::sync::Arc>(); + //~^ ERROR the trait bound `std::sync::Arc: malloc_size_of::MallocSizeOf` is not satisfied + + sizeable::<::std::rc::Rc>(); + //~^ ERROR the trait bound `std::rc::Rc: malloc_size_of::MallocSizeOf` is not satisfied + + shallow_sizeable::<::servo_arc::Arc>(); + //~^ ERROR the trait bound `servo_arc::Arc: malloc_size_of::MallocShallowSizeOf` is not satisfied + + shallow_sizeable::<::std::sync::Arc>(); + //~^ ERROR the trait bound `std::sync::Arc: malloc_size_of::MallocShallowSizeOf` is not satisfied + + shallow_sizeable::<::std::rc::Rc>(); + //~^ ERROR the trait bound `std::rc::Rc: malloc_size_of::MallocShallowSizeOf` is not satisfied +} diff --git a/tests/unit/stylo/Cargo.toml b/tests/unit/stylo/Cargo.toml index c0ec244f78c..99764c66526 100644 --- a/tests/unit/stylo/Cargo.toml +++ b/tests/unit/stylo/Cargo.toml @@ -19,6 +19,7 @@ euclid = "0.15" geckoservo = {path = "../../../ports/geckolib"} libc = "0.2" log = {version = "0.3.5", features = ["release_max_level_info"]} +malloc_size_of = {path = "../../../components/malloc_size_of"} selectors = {path = "../../../components/selectors", features = ["gecko_like_types"]} size_of_test = {path = "../../../components/size_of_test"} style_traits = {path = "../../../components/style_traits"} diff --git a/tests/unit/stylo/lib.rs b/tests/unit/stylo/lib.rs index 85ac29c09e5..a00d6d44c55 100644 --- a/tests/unit/stylo/lib.rs +++ b/tests/unit/stylo/lib.rs @@ -7,6 +7,7 @@ extern crate cssparser; extern crate env_logger; extern crate geckoservo; #[macro_use] extern crate log; +extern crate malloc_size_of; extern crate selectors; #[macro_use] extern crate size_of_test; #[macro_use] extern crate style;