diff --git a/components/plugins/heapsize.rs b/components/plugins/heapsize.rs new file mode 100644 index 00000000000..4da8cc070a8 --- /dev/null +++ b/components/plugins/heapsize.rs @@ -0,0 +1,54 @@ + +use syntax::ext::base::{Annotatable, ExtCtxt}; +use syntax::codemap::Span; +use syntax::ptr::P; +use syntax::ast::*; +use syntax::attr::AttrMetaMethods; +use syntax::ext::build::AstBuilder; +use syntax::ext::deriving::generic::*; + +pub fn expand_heapsize(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: Annotatable, push: &mut FnMut(Annotatable)) { + let trait_def = TraitDef { + span: span, + attributes: Vec::new(), + path: ty::Path::new(vec!("util", "mem", "HeapSizeOf")), + additional_bounds: Vec::new(), + generics: ty::LifetimeBounds::empty(), + methods: vec![ + MethodDef { + name: "heap_size_of_children", + generics: ty::LifetimeBounds::empty(), + explicit_self: ty::borrowed_explicit_self(), + args: vec!(), + ret_ty: ty::Literal(ty::Path::new_local("usize")), + attributes: vec!(), + is_unsafe: false, + combine_substructure: combine_substructure(Box::new(heapsize_substructure)) + } + ], + associated_types: vec![], + }; + trait_def.expand(cx, mitem, &item, push) +} + +fn heapsize_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { + let fields = match *substr.fields { + Struct(ref fs) | EnumMatching(_, _, ref fs) => fs, + _ => cx.span_bug(trait_span, "impossible substructure in `heapsize`") + }; + + fields.iter().fold(cx.expr_usize(trait_span, 0), + |acc, ref item| { + if item.attrs.iter() + .find(|ref a| a.check_name("ignore_heapsize")) + .is_some() { + acc + } else { + cx.expr_binary(item.span, BiAdd, acc, + cx.expr_method_call(item.span, + item.self_.clone(), + substr.method_ident, + Vec::new())) + } + }) +} diff --git a/components/plugins/lib.rs b/components/plugins/lib.rs index 614cce94ab3..6138e4bef84 100644 --- a/components/plugins/lib.rs +++ b/components/plugins/lib.rs @@ -8,8 +8,7 @@ //! //! - `#[privatize]` : Forces all fields in a struct/enum to be private //! - `#[jstraceable]` : Auto-derives an implementation of `JSTraceable` for a struct in the script crate -//! - `#[must_root]` : Prevents data of the marked type from being used on the stack. See the lints module for more -//! details +//! - `#[must_root]` : Prevents data of the marked type from being used on the stack. See the lints module for more details //! - `#[dom_struct]` : Implies `#[privatize]`,`#[jstraceable]`, and `#[must_root]`. //! Use this for structs that correspond to a DOM type @@ -31,6 +30,8 @@ use syntax::parse::token::intern; // Public for documentation to show up /// Handles the auto-deriving for `#[jstraceable]` pub mod jstraceable; +/// Handles the auto-deriving for `#[heapsize]` +pub mod heapsize; /// Autogenerates implementations of Reflectable on DOM structs pub mod reflector; pub mod lints; @@ -43,6 +44,8 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_syntax_extension(intern("dom_struct"), MultiModifier(box jstraceable::expand_dom_struct)); reg.register_syntax_extension(intern("jstraceable"), MultiDecorator(box jstraceable::expand_jstraceable)); reg.register_syntax_extension(intern("_generate_reflector"), MultiDecorator(box reflector::expand_reflector)); + reg.register_syntax_extension(intern("derive_HeapSizeOf"), MultiDecorator(box heapsize::expand_heapsize)); + reg.register_syntax_extension(intern("heapsize"), MultiDecorator(box heapsize::expand_heapsize)); reg.register_macro("to_lower", casing::expand_lower); reg.register_macro("to_upper", casing::expand_upper); reg.register_lint_pass(box lints::transmute_type::TransmutePass as LintPassObject); diff --git a/components/util/mem.rs b/components/util/mem.rs index cd1b9834e48..175863ddb9e 100644 --- a/components/util/mem.rs +++ b/components/util/mem.rs @@ -158,3 +158,31 @@ impl Drop for LinkedList2 { fn drop(&mut self) {} } +/// For use on types defined in external crates +/// with known heap sizes +#[macro_export] +macro_rules! known_heap_size( + ($size:expr, $($ty:ident),+) => ( + $( + impl $crate::mem::HeapSizeOf for $ty { + #[inline] + fn heap_size_of_children(&self) -> usize { + $size + } + } + )+ + ); + ($size: expr, $ty:ident<$($gen:ident),+>) => ( + impl<$($gen),+> $crate::mem::HeapSizeOf for $ty<$($gen),+> { + #[inline] + fn heap_size_of_children(&self) -> usize { + $size + } + } + ); +); + + +known_heap_size!(0, u8, u16, u32, u64, usize); +known_heap_size!(0, i8, i16, i32, i64, isize); +known_heap_size!(0, bool); \ No newline at end of file