Bug 1519454 - Implement MallocSizeOf for Interner and DataStore. r=emilio
☠☠ backed out by 5d2e7b3ecb63 ☠ ☠
authorBobby Holley <bobbyholley@gmail.com>
Sat, 12 Jan 2019 19:22:01 +0000
changeset 510745 054028a8d4a75083599eda3791913d0d66aa1b8d
parent 510744 e9b1d04247debbf9506351b855091546ce59c4d1
child 510746 21d74c03c00a986914f5dc6ad44e5027b186f049
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1519454
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1519454 - Implement MallocSizeOf for Interner and DataStore. r=emilio Depends on D16354 Differential Revision: https://phabricator.services.mozilla.com/D16355
gfx/wr/webrender/src/border.rs
gfx/wr/webrender/src/box_shadow.rs
gfx/wr/webrender/src/clip.rs
gfx/wr/webrender/src/freelist.rs
gfx/wr/webrender/src/glyph_rasterizer/mod.rs
gfx/wr/webrender/src/gpu_cache.rs
gfx/wr/webrender/src/gpu_types.rs
gfx/wr/webrender/src/intern.rs
gfx/wr/webrender/src/prim_store/borders.rs
gfx/wr/webrender/src/prim_store/gradient.rs
gfx/wr/webrender/src/prim_store/image.rs
gfx/wr/webrender/src/prim_store/line_dec.rs
gfx/wr/webrender/src/prim_store/mod.rs
gfx/wr/webrender/src/prim_store/picture.rs
gfx/wr/webrender/src/prim_store/text_run.rs
gfx/wr/webrender/src/render_task.rs
gfx/wr/webrender/src/scene_builder.rs
gfx/wr/webrender_api/src/api.rs
gfx/wr/webrender_api/src/color.rs
gfx/wr/webrender_api/src/display_item.rs
gfx/wr/webrender_api/src/font.rs
gfx/wr/webrender_api/src/image.rs
--- a/gfx/wr/webrender/src/border.rs
+++ b/gfx/wr/webrender/src/border.rs
@@ -29,17 +29,17 @@ pub const MAX_BORDER_RESOLUTION: u32 = 2
 /// a list of per-dot information in the first place.
 pub const MAX_DASH_COUNT: u32 = 2048;
 
 // TODO(gw): Perhaps there is a better way to store
 //           the border cache key than duplicating
 //           all the border structs with hashable
 //           variants...
 
-#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct BorderRadiusAu {
     pub top_left: LayoutSizeAu,
     pub top_right: LayoutSizeAu,
     pub bottom_left: LayoutSizeAu,
     pub bottom_right: LayoutSizeAu,
 }
@@ -61,17 +61,17 @@ impl From<BorderRadiusAu> for BorderRadi
             top_left: LayoutSize::from_au(radius.top_left),
             top_right: LayoutSize::from_au(radius.top_right),
             bottom_right: LayoutSize::from_au(radius.bottom_right),
             bottom_left: LayoutSize::from_au(radius.bottom_left),
         }
     }
 }
 
-#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct BorderSideAu {
     pub color: ColorU,
     pub style: BorderStyle,
 }
 
 impl From<BorderSide> for BorderSideAu {
@@ -89,17 +89,17 @@ impl From<BorderSideAu> for BorderSide {
             color: side.color.into(),
             style: side.style,
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Hash, Eq, PartialEq)]
+#[derive(Debug, Clone, Hash, Eq, MallocSizeOf, PartialEq)]
 pub struct NormalBorderAu {
     pub left: BorderSideAu,
     pub right: BorderSideAu,
     pub top: BorderSideAu,
     pub bottom: BorderSideAu,
     pub radius: BorderRadiusAu,
     /// Whether to apply anti-aliasing on the border corners.
     ///
@@ -143,17 +143,17 @@ impl From<NormalBorderAu> for ApiNormalB
             radius: border.radius.into(),
             do_aa: border.do_aa,
         }
     }
 }
 
 /// Cache key that uniquely identifies a border
 /// segment in the render task cache.
-#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct BorderSegmentCacheKey {
     pub size: LayoutSizeAu,
     pub radius: LayoutSizeAu,
     pub side0: BorderSideAu,
     pub side1: BorderSideAu,
     pub segment: BorderSegment,
--- a/gfx/wr/webrender/src/box_shadow.rs
+++ b/gfx/wr/webrender/src/box_shadow.rs
@@ -7,17 +7,17 @@ use api::{LayoutRect, LayoutSize, Layout
 use clip::ClipItemKey;
 use display_list_flattener::DisplayListFlattener;
 use gpu_cache::GpuCacheHandle;
 use gpu_types::BoxShadowStretchMode;
 use prim_store::{ScrollNodeAndClipChain, PrimitiveKeyKind};
 use render_task::RenderTaskCacheEntryHandle;
 use util::RectHelpers;
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, MallocSizeOf)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct BoxShadowClipSource {
     // Parameters that define the shadow and are constant.
     pub shadow_radius: BorderRadius,
     pub blur_radius: f32,
     pub clip_mode: BoxShadowClipMode,
     pub stretch_mode_x: BoxShadowStretchMode,
@@ -46,17 +46,17 @@ pub struct BoxShadowClipSource {
 }
 
 // The blur shader samples BLUR_SAMPLE_SCALE * blur_radius surrounding texels.
 pub const BLUR_SAMPLE_SCALE: f32 = 3.0;
 
 // A cache key that uniquely identifies a minimally sized
 // and blurred box-shadow rect that can be stored in the
 // texture cache and applied to clip-masks.
-#[derive(Debug, Clone, Eq, Hash, PartialEq)]
+#[derive(Debug, Clone, Eq, Hash, MallocSizeOf, PartialEq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct BoxShadowCacheKey {
     pub blur_radius_dp: i32,
     pub clip_mode: BoxShadowClipMode,
     // NOTE(emilio): Only the original allocation size needs to be in the cache
     // key, since the actual size is derived from that.
     pub original_alloc_size: DeviceIntSize,
--- a/gfx/wr/webrender/src/clip.rs
+++ b/gfx/wr/webrender/src/clip.rs
@@ -128,16 +128,17 @@ enum ClipResult {
 
 // A clip node is a single clip source, along with some
 // positioning information and implementation details
 // that control where the GPU data for this clip source
 // can be found.
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct ClipNode {
     pub item: ClipItem,
     pub gpu_cache_handle: GpuCacheHandle,
 }
 
 // Convert from an interning key for a clip item
 // to a clip node, which is cached in the document.
 // TODO(gw): These enums are a bit messy - we should
@@ -776,17 +777,17 @@ impl ClipRegion<Option<ComplexClipRegion
 
 // The ClipItemKey is a hashable representation of the contents
 // of a clip item. It is used during interning to de-duplicate
 // clip nodes between frames and display lists. This allows quick
 // comparison of clip node equality by handle, and also allows
 // the uploaded GPU cache handle to be retained between display lists.
 // TODO(gw): Maybe we should consider constructing these directly
 //           in the DL builder?
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub enum ClipItemKey {
     Rectangle(SizeKey, ClipMode),
     RoundedRectangle(SizeKey, BorderRadiusAu, ClipMode),
     ImageMask(SizeKey, ImageKey, bool),
     BoxShadow(PointKey, SizeKey, BorderRadiusAu, RectangleKey, Au, BoxShadowClipMode),
 }
@@ -839,17 +840,17 @@ impl ClipItemKey {
             Au::from_f32_px(blur_radius),
             clip_mode,
         )
     }
 }
 
 impl intern::InternDebug for ClipItemKey {}
 
-#[derive(Debug)]
+#[derive(Debug, MallocSizeOf)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub enum ClipItem {
     Rectangle(LayoutSize, ClipMode),
     RoundedRectangle(LayoutSize, BorderRadius, ClipMode),
     Image {
         image: ImageKey,
         size: LayoutSize,
--- a/gfx/wr/webrender/src/freelist.rs
+++ b/gfx/wr/webrender/src/freelist.rs
@@ -18,17 +18,17 @@
 //! reused.
 //!
 //! TODO(gw): Add an occupied list head, for fast iteration of the occupied list
 //! to implement retain() style functionality.
 
 use std::{fmt, u32};
 use std::marker::PhantomData;
 
-#[derive(Debug, Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct Epoch(u32);
 
 impl Epoch {
     /// Mints a new epoch.
     ///
     /// We start at 1 so that 0 is always an invalid epoch.
@@ -91,16 +91,17 @@ impl<M> Clone for WeakFreeListHandle<M> 
 impl<M> PartialEq for WeakFreeListHandle<M> {
     fn eq(&self, other: &Self) -> bool {
         self.index == other.index && self.epoch == other.epoch
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct WeakFreeListHandle<M> {
     index: u32,
     epoch: Epoch,
     _marker: PhantomData<M>,
 }
 
 /// More-compact textual representation for debug logging.
 impl<M> fmt::Debug for WeakFreeListHandle<M> {
--- a/gfx/wr/webrender/src/glyph_rasterizer/mod.rs
+++ b/gfx/wr/webrender/src/glyph_rasterizer/mod.rs
@@ -23,17 +23,17 @@ mod pathfinder;
 #[cfg(feature = "pathfinder")]
 use self::pathfinder::create_pathfinder_font_context;
 #[cfg(feature = "pathfinder")]
 pub use self::pathfinder::{ThreadSafePathfinderFontContext, NativeFontHandleWrapper};
 
 #[cfg(not(feature = "pathfinder"))]
 mod no_pathfinder;
 
-#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct FontTransform {
     pub scale_x: f32,
     pub skew_x: f32,
     pub skew_y: f32,
     pub scale_y: f32,
 }
@@ -159,17 +159,17 @@ impl<'a> From<&'a LayoutToWorldTransform
         FontTransform::new(xform.m11, xform.m21, xform.m12, xform.m22)
     }
 }
 
 // Some platforms (i.e. Windows) may have trouble rasterizing glyphs above this size.
 // Ensure glyph sizes are reasonably limited to avoid that scenario.
 pub const FONT_SIZE_LIMIT: f64 = 512.0;
 
-#[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
+#[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd, MallocSizeOf)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct FontInstance {
     pub font_key: FontKey,
     // The font size is in *device* pixels, not logical pixels.
     // It is stored as an Au since we need sub-pixel sizes, but
     // can't store as a f32 due to use of this type as a hash key.
     // TODO(gw): Perhaps consider having LogicalAu and DeviceAu
--- a/gfx/wr/webrender/src/gpu_cache.rs
+++ b/gfx/wr/webrender/src/gpu_cache.rs
@@ -59,17 +59,17 @@ const RECLAIM_DELAY_S: u64 = 5;
 struct Epoch(u32);
 
 impl Epoch {
     fn next(&mut self) {
         *self = Epoch(self.0.wrapping_add(1));
     }
 }
 
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, MallocSizeOf)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct CacheLocation {
     block_index: BlockIndex,
     epoch: Epoch,
 }
 
 /// A single texel in RGBAF32 texture - 16 bytes.
@@ -124,17 +124,17 @@ impl From<TexelRect> for GpuBlockData {
 // Any data type that can be stored in the GPU cache should
 // implement this trait.
 pub trait ToGpuBlocks {
     // Request an arbitrary number of GPU data blocks.
     fn write_gpu_blocks(&self, GpuDataRequest);
 }
 
 // A handle to a GPU resource.
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, MallocSizeOf)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct GpuCacheHandle {
     location: Option<CacheLocation>,
 }
 
 impl GpuCacheHandle {
     pub fn new() -> Self {
--- a/gfx/wr/webrender/src/gpu_types.rs
+++ b/gfx/wr/webrender/src/gpu_types.rs
@@ -54,17 +54,17 @@ impl ZBufferIdGenerator {
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[repr(C)]
 pub enum RasterizationSpace {
     Local = 0,
     Screen = 1,
 }
 
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, MallocSizeOf)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[repr(C)]
 pub enum BoxShadowStretchMode {
     Stretch = 0,
     Simple = 1,
 }
 
@@ -91,17 +91,17 @@ pub struct BlurInstance {
 #[repr(C)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct ScalingInstance {
     pub task_address: RenderTaskAddress,
     pub src_task_address: RenderTaskAddress,
 }
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
 #[repr(C)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub enum BorderSegment {
     TopLeft,
     TopRight,
     BottomRight,
     BottomLeft,
@@ -312,16 +312,17 @@ impl From<SplitCompositeInstance> for Pr
     }
 }
 
 bitflags! {
     /// Flags that define how the common brush shader
     /// code should process this instance.
     #[cfg_attr(feature = "capture", derive(Serialize))]
     #[cfg_attr(feature = "replay", derive(Deserialize))]
+    #[derive(MallocSizeOf)]
     pub struct BrushFlags: u8 {
         /// Apply perspective interpolation to UVs
         const PERSPECTIVE_INTERPOLATION = 0x1;
         /// Do interpolation relative to segment rect,
         /// rather than primitive rect.
         const SEGMENT_RELATIVE = 0x2;
         /// Repeat UVs horizontally.
         const SEGMENT_REPEAT_X = 0x4;
--- a/gfx/wr/webrender/src/intern.rs
+++ b/gfx/wr/webrender/src/intern.rs
@@ -1,15 +1,16 @@
 /* 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/. */
 
 use api::{LayoutPrimitiveInfo, LayoutRect};
 use api::VoidPtrToSizeFn;
 use internal_types::FastHashMap;
+use malloc_size_of::MallocSizeOf;
 use profiler::ResourceProfileCounter;
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::marker::PhantomData;
 use std::{mem, ops, u64};
 use std::os::raw::c_void;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use util::VecHelper;
@@ -101,64 +102,76 @@ pub struct Handle<M: Copy> {
 impl <M> Handle<M> where M: Copy {
     pub fn uid(&self) -> ItemUid {
         self.uid
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub enum UpdateKind {
     Insert,
     Remove,
     UpdateEpoch,
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct Update {
     index: usize,
     kind: UpdateKind,
 }
 
 /// The data item is stored with an epoch, for validating
 /// correct access patterns.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-struct Item<T> {
+#[derive(MallocSizeOf)]
+struct Item<T: MallocSizeOf> {
     epoch: Epoch,
     data: T,
 }
 
 pub trait InternDebug {
     fn on_interned(&self, _uid: ItemUid) {}
 }
 
 /// The data store lives in the frame builder thread. It
 /// contains a free-list of items for fast access.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-pub struct DataStore<S, T, M> {
+#[derive(MallocSizeOf)]
+pub struct DataStore<S, T: MallocSizeOf, M> {
     items: Vec<Item<T>>,
     _source: PhantomData<S>,
     _marker: PhantomData<M>,
 }
 
-impl<S, T, M> ::std::default::Default for DataStore<S, T, M> where S: Debug, T: From<S>, M: Debug
+impl<S, T, M> ::std::default::Default for DataStore<S, T, M>
+where
+    S: Debug + MallocSizeOf,
+    T: From<S> + MallocSizeOf,
+    M: Debug
 {
     fn default() -> Self {
         DataStore {
             items: Vec::new(),
             _source: PhantomData,
             _marker: PhantomData,
         }
     }
 }
 
-impl<S, T, M> DataStore<S, T, M> where S: Debug, T: From<S>, M: Debug
+impl<S, T, M> DataStore<S, T, M>
+where
+    S: Debug + MallocSizeOf,
+    T: From<S> + MallocSizeOf,
+    M: Debug
 {
     /// Apply any updates from the scene builder thread to
     /// this data store.
     pub fn apply_updates(
         &mut self,
         update_list: UpdateList<S>,
         profile_counter: &mut ResourceProfileCounter,
     ) {
@@ -189,50 +202,57 @@ impl<S, T, M> DataStore<S, T, M> where S
     /// Reports CPU heap usage.
     pub fn malloc_size_of(&self, op: VoidPtrToSizeFn) -> usize {
         unsafe { op(self.items.as_ptr() as *const c_void) }
     }
 }
 
 /// Retrieve an item from the store via handle
 impl<S, T, M> ops::Index<Handle<M>> for DataStore<S, T, M>
-where M: Copy
+where
+    S: MallocSizeOf,
+    T: MallocSizeOf,
+    M: Copy
 {
     type Output = T;
     fn index(&self, handle: Handle<M>) -> &T {
         let item = &self.items[handle.index as usize];
         assert_eq!(item.epoch, handle.epoch);
         &item.data
     }
 }
 
 /// Retrieve a mutable item from the store via handle
 /// Retrieve an item from the store via handle
 impl<S, T, M> ops::IndexMut<Handle<M>> for DataStore<S, T, M>
 where
+    S: MallocSizeOf,
+    T: MallocSizeOf,
     M: Copy
 {
     fn index_mut(&mut self, handle: Handle<M>) -> &mut T {
         let item = &mut self.items[handle.index as usize];
         assert_eq!(item.epoch, handle.epoch);
         &mut item.data
     }
 }
 
 /// The main interning data structure. This lives in the
 /// scene builder thread, and handles hashing and interning
 /// unique data structures. It also manages a free-list for
 /// the items in the data store, which is synchronized via
 /// an update list of additions / removals.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct Interner<S, D, M>
 where
-    S: Eq + Hash + Clone + Debug,
-    M: Copy
+    S: Eq + Hash + Clone + Debug + MallocSizeOf,
+    D: MallocSizeOf,
+    M: Copy + MallocSizeOf,
 {
     /// Uniquely map an interning key to a handle
     map: FastHashMap<S, Handle<M>>,
     /// List of free slots in the data store for re-use.
     free_list: Vec<usize>,
     /// Pending list of updates that need to be applied.
     updates: Vec<Update>,
     /// Pending new data to insert.
@@ -241,35 +261,37 @@ where
     current_epoch: Epoch,
     /// The information associated with each interned
     /// item that can be accessed by the interner.
     local_data: Vec<Item<D>>,
 }
 
 impl<S, D, M> ::std::default::Default for Interner<S, D, M>
 where
-    S: Eq + Hash + Clone + Debug,
-    M: Copy + Debug
+    S: Eq + Hash + Clone + Debug + MallocSizeOf,
+    D: MallocSizeOf,
+    M: Copy + Debug + MallocSizeOf,
 {
     fn default() -> Self {
         Interner {
             map: FastHashMap::default(),
             free_list: Vec::new(),
             updates: Vec::new(),
             update_data: Vec::new(),
             current_epoch: Epoch(1),
             local_data: Vec::new(),
         }
     }
 }
 
 impl<S, D, M> Interner<S, D, M>
 where
-    S: Eq + Hash + Clone + Debug + InternDebug,
-    M: Copy + Debug
+    S: Eq + Hash + Clone + Debug + InternDebug + MallocSizeOf,
+    D: MallocSizeOf,
+    M: Copy + Debug + MallocSizeOf
 {
     /// Intern a data structure, and return a handle to
     /// that data. The handle can then be stored in the
     /// frame builder, and safely accessed via the data
     /// store that lives in the frame builder thread.
     /// The provided closure is invoked to build the
     /// local data about an interned structure if the
     /// key isn't already interned.
@@ -393,35 +415,36 @@ where
         }
         bytes
     }
 }
 
 /// Retrieve the local data for an item from the interner via handle
 impl<S, D, M> ops::Index<Handle<M>> for Interner<S, D, M>
 where
-    S: Eq + Clone + Hash + Debug,
-    M: Copy + Debug
+    S: Eq + Clone + Hash + Debug + MallocSizeOf,
+    D: MallocSizeOf,
+    M: Copy + Debug + MallocSizeOf
 {
     type Output = D;
     fn index(&self, handle: Handle<M>) -> &D {
         let item = &self.local_data[handle.index as usize];
         assert_eq!(item.epoch, handle.epoch);
         &item.data
     }
 }
 
 /// Implement `Internable` for a type that wants participate in interning.
 ///
 /// see DisplayListFlattener::add_interned_primitive<P>
 pub trait Internable {
-    type Marker: Copy + Debug;
-    type Source: Eq + Hash + Clone + Debug;
-    type StoreData: From<Self::Source>;
-    type InternData;
+    type Marker: Copy + Debug + MallocSizeOf;
+    type Source: Eq + Hash + Clone + Debug + MallocSizeOf;
+    type StoreData: From<Self::Source> + MallocSizeOf;
+    type InternData: MallocSizeOf;
 
     /// Build a new key from self with `info`.
     fn build_key(
         self,
         info: &LayoutPrimitiveInfo,
         prim_relative_clip_rect: LayoutRect,
     ) -> Self::Source;
 }
--- a/gfx/wr/webrender/src/prim_store/borders.rs
+++ b/gfx/wr/webrender/src/prim_store/borders.rs
@@ -19,17 +19,17 @@ use prim_store::{
     PrimitiveInstanceKind, PrimitiveOpacity, PrimitiveSceneData,
     PrimitiveStore
 };
 use resource_cache::ImageRequest;
 use storage;
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
 pub struct NormalBorderPrim {
     pub border: NormalBorderAu,
     pub widths: LayoutSideOffsetsAu,
 }
 
 pub type NormalBorderKey = PrimKey<NormalBorderPrim>;
 
 impl NormalBorderKey {
@@ -62,16 +62,17 @@ impl AsInstanceKind<NormalBorderDataHand
             data_handle,
             cache_handles: storage::Range::empty(),
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct NormalBorderData {
     pub brush_segments: Vec<BrushSegment>,
     pub border_segments: Vec<BorderSegmentInfo>,
     pub border: NormalBorder,
     pub widths: LayoutSideOffsets,
 }
 
 impl NormalBorderData {
@@ -156,17 +157,17 @@ impl From<NormalBorderKey> for NormalBor
                 widths,
             }
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)]
 pub struct NormalBorderDataMarker;
 
 pub type NormalBorderDataStore = intern::DataStore<NormalBorderKey, NormalBorderTemplate, NormalBorderDataMarker>;
 pub type NormalBorderDataHandle = intern::Handle<NormalBorderDataMarker>;
 pub type NormalBorderDataUpdateList = intern::UpdateList<NormalBorderKey>;
 pub type NormalBorderDataInterner = intern::Interner<NormalBorderKey, PrimitiveSceneData, NormalBorderDataMarker>;
 
 impl intern::Internable for NormalBorderPrim {
@@ -204,18 +205,19 @@ impl IsVisible for NormalBorderPrim {
         true
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
 pub struct ImageBorder {
+    #[ignore_malloc_size_of = "Arc"]
     pub request: ImageRequest,
     pub nine_patch: NinePatchDescriptor,
 }
 
 pub type ImageBorderKey = PrimKey<ImageBorder>;
 
 impl ImageBorderKey {
     pub fn new(
@@ -246,17 +248,19 @@ impl AsInstanceKind<ImageBorderDataHandl
         PrimitiveInstanceKind::ImageBorder {
             data_handle
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct ImageBorderData {
+    #[ignore_malloc_size_of = "Arc"]
     pub request: ImageRequest,
     pub brush_segments: Vec<BrushSegment>,
 }
 
 impl ImageBorderData {
     /// Update the GPU cache for a given primitive template. This may be called multiple
     /// times per frame, by each primitive reference that refers to this interned
     /// template. The initial request call to the GPU cache ensures that work is only
@@ -334,17 +338,17 @@ impl From<ImageBorderKey> for ImageBorde
                 brush_segments,
             }
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)]
 pub struct ImageBorderDataMarker;
 
 pub type ImageBorderDataStore = intern::DataStore<ImageBorderKey, ImageBorderTemplate, ImageBorderDataMarker>;
 pub type ImageBorderDataHandle = intern::Handle<ImageBorderDataMarker>;
 pub type ImageBorderDataUpdateList = intern::UpdateList<ImageBorderKey>;
 pub type ImageBorderDataInterner = intern::Interner<ImageBorderKey, PrimitiveSceneData, ImageBorderDataMarker>;
 
 impl intern::Internable for ImageBorder {
--- a/gfx/wr/webrender/src/prim_store/gradient.rs
+++ b/gfx/wr/webrender/src/prim_store/gradient.rs
@@ -15,17 +15,17 @@ use prim_store::{PrimitiveInstanceKind, 
 use prim_store::{PrimKeyCommonData, PrimTemplateCommonData, PrimitiveStore};
 use prim_store::{NinePatchDescriptor, PointKey, SizeKey};
 use std::{hash, ops::{Deref, DerefMut}, mem};
 use util::pack_as_float;
 
 /// A hashable gradient stop that can be used in primitive keys.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
 pub struct GradientStopKey {
     pub offset: f32,
     pub color: ColorU,
 }
 
 impl Eq for GradientStopKey {}
 
 impl hash::Hash for GradientStopKey {
@@ -33,17 +33,17 @@ impl hash::Hash for GradientStopKey {
         self.offset.to_bits().hash(state);
         self.color.hash(state);
     }
 }
 
 /// Identifying key for a line decoration.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash, MallocSizeOf)]
 pub struct LinearGradientKey {
     pub common: PrimKeyCommonData,
     pub extend_mode: ExtendMode,
     pub start_point: PointKey,
     pub end_point: PointKey,
     pub stretch_size: SizeKey,
     pub tile_spacing: SizeKey,
     pub stops: Vec<GradientStopKey>,
@@ -90,16 +90,17 @@ impl AsInstanceKind<LinearGradientDataHa
             data_handle,
             visible_tiles_range: GradientTileRange::empty(),
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct LinearGradientTemplate {
     pub common: PrimTemplateCommonData,
     pub extend_mode: ExtendMode,
     pub start_point: LayoutPoint,
     pub end_point: LayoutPoint,
     pub stretch_size: LayoutSize,
     pub tile_spacing: LayoutSize,
     pub stops_opacity: PrimitiveOpacity,
@@ -223,17 +224,17 @@ impl LinearGradientTemplate {
                PrimitiveOpacity::translucent()
             }
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)]
 pub struct LinearGradientDataMarker;
 
 pub type LinearGradientDataStore = DataStore<LinearGradientKey, LinearGradientTemplate, LinearGradientDataMarker>;
 pub type LinearGradientDataHandle = Handle<LinearGradientDataMarker>;
 pub type LinearGradientDataUpdateList = UpdateList<LinearGradientKey>;
 pub type LinearGradientDataInterner = Interner<LinearGradientKey, PrimitiveSceneData, LinearGradientDataMarker>;
 
 pub struct LinearGradient {
@@ -274,17 +275,17 @@ impl IsVisible for LinearGradient {
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 /// Hashable radial gradient parameters, for use during prim interning.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
 pub struct RadialGradientParams {
     pub start_radius: f32,
     pub end_radius: f32,
     pub ratio_xy: f32,
 }
 
 impl Eq for RadialGradientParams {}
 
@@ -294,17 +295,17 @@ impl hash::Hash for RadialGradientParams
         self.end_radius.to_bits().hash(state);
         self.ratio_xy.to_bits().hash(state);
     }
 }
 
 /// Identifying key for a line decoration.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash, MallocSizeOf)]
 pub struct RadialGradientKey {
     pub common: PrimKeyCommonData,
     pub extend_mode: ExtendMode,
     pub center: PointKey,
     pub params: RadialGradientParams,
     pub stretch_size: SizeKey,
     pub stops: Vec<GradientStopKey>,
     pub tile_spacing: SizeKey,
@@ -349,16 +350,17 @@ impl AsInstanceKind<RadialGradientDataHa
             data_handle,
             visible_tiles_range: GradientTileRange::empty(),
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct RadialGradientTemplate {
     pub common: PrimTemplateCommonData,
     pub extend_mode: ExtendMode,
     pub center: LayoutPoint,
     pub params: RadialGradientParams,
     pub stretch_size: LayoutSize,
     pub tile_spacing: LayoutSize,
     pub brush_segments: Vec<BrushSegment>,
@@ -453,17 +455,17 @@ impl RadialGradientTemplate {
         }
 
         self.opacity = PrimitiveOpacity::translucent();
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)]
 pub struct RadialGradientDataMarker;
 
 pub type RadialGradientDataStore = DataStore<RadialGradientKey, RadialGradientTemplate, RadialGradientDataMarker>;
 pub type RadialGradientDataHandle = Handle<RadialGradientDataMarker>;
 pub type RadialGradientDataUpdateList = UpdateList<RadialGradientKey>;
 pub type RadialGradientDataInterner = Interner<RadialGradientKey, PrimitiveSceneData, RadialGradientDataMarker>;
 
 pub struct RadialGradient {
--- a/gfx/wr/webrender/src/prim_store/image.rs
+++ b/gfx/wr/webrender/src/prim_store/image.rs
@@ -62,17 +62,17 @@ pub struct ImageCacheKey {
 pub struct ImageInstance {
     pub opacity_binding_index: OpacityBindingIndex,
     pub segment_instance_index: SegmentInstanceIndex,
     pub visible_tiles: Vec<VisibleImageTile>,
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, MallocSizeOf, Hash)]
 pub struct Image {
     pub key: ApiImageKey,
     pub stretch_size: SizeKey,
     pub tile_spacing: SizeKey,
     pub color: ColorU,
     pub sub_rect: Option<DeviceIntRect>,
     pub image_rendering: ImageRendering,
     pub alpha_type: AlphaType,
@@ -122,30 +122,31 @@ impl AsInstanceKind<ImageDataHandle> for
             image_instance_index,
         }
     }
 }
 
 // Where to find the texture data for an image primitive.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug)]
+#[derive(Debug, MallocSizeOf)]
 pub enum ImageSource {
     // A normal image - just reference the texture cache.
     Default,
     // An image that is pre-rendered into the texture cache
     // via a render task.
     Cache {
         size: DeviceIntSize,
         handle: Option<RenderTaskCacheEntryHandle>,
     },
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct ImageData {
     pub key: ApiImageKey,
     pub stretch_size: LayoutSize,
     pub tile_spacing: LayoutSize,
     pub color: ColorF,
     pub source: ImageSource,
     pub image_rendering: ImageRendering,
     pub sub_rect: Option<DeviceIntRect>,
@@ -331,17 +332,17 @@ impl From<ImageKey> for ImageTemplate {
             common,
             kind: image.kind.into(),
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)]
 pub struct ImageDataMarker;
 
 pub type ImageDataStore = DataStore<ImageKey, ImageTemplate, ImageDataMarker>;
 pub type ImageDataHandle = Handle<ImageDataMarker>;
 pub type ImageDataUpdateList = UpdateList<ImageKey>;
 pub type ImageDataInterner = Interner<ImageKey, PrimitiveSceneData, ImageDataMarker>;
 
 impl Internable for Image {
@@ -384,17 +385,17 @@ impl IsVisible for Image {
         true
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
 pub struct YuvImage {
     pub color_depth: ColorDepth,
     pub yuv_key: [ApiImageKey; 3],
     pub format: YuvFormat,
     pub color_space: YuvColorSpace,
     pub image_rendering: ImageRendering,
 }
 
@@ -433,16 +434,17 @@ impl AsInstanceKind<YuvImageDataHandle> 
             data_handle,
             segment_instance_index: SegmentInstanceIndex::INVALID
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct YuvImageData {
     pub color_depth: ColorDepth,
     pub yuv_key: [ApiImageKey; 3],
     pub format: YuvFormat,
     pub color_space: YuvColorSpace,
     pub image_rendering: ImageRendering,
 }
 
@@ -508,17 +510,17 @@ impl From<YuvImageKey> for YuvImageTempl
             common,
             kind: image.kind.into(),
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)]
 pub struct YuvImageDataMarker;
 
 pub type YuvImageDataStore = DataStore<YuvImageKey, YuvImageTemplate, YuvImageDataMarker>;
 pub type YuvImageDataHandle = Handle<YuvImageDataMarker>;
 pub type YuvImageDataUpdateList = UpdateList<YuvImageKey>;
 pub type YuvImageDataInterner = Interner<YuvImageKey, PrimitiveSceneData, YuvImageDataMarker>;
 
 impl Internable for YuvImage {
--- a/gfx/wr/webrender/src/prim_store/line_dec.rs
+++ b/gfx/wr/webrender/src/prim_store/line_dec.rs
@@ -12,28 +12,28 @@ use frame_builder::{FrameBuildingState};
 use gpu_cache::GpuDataRequest;
 use intern;
 use prim_store::{
     PrimKey, PrimKeyCommonData, PrimTemplate, PrimTemplateCommonData,
     PrimitiveSceneData, PrimitiveStore,
 };
 use prim_store::PrimitiveInstanceKind;
 
-#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct LineDecorationCacheKey {
     pub style: LineStyle,
     pub orientation: LineOrientation,
     pub wavy_line_thickness: Au,
     pub size: LayoutSizeAu,
 }
 
 /// Identifying key for a line decoration.
-#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct LineDecoration {
     // If the cache_key is Some(..) it is a line decoration
     // that relies on a render task (e.g. wavy). If the
     // cache key is None, it uses a fast path to draw the
     // line decoration as a solid rect.
     pub cache_key: Option<LineDecorationCacheKey>,
@@ -72,16 +72,17 @@ impl AsInstanceKind<LineDecorationDataHa
             data_handle,
             cache_handle: None,
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct LineDecorationData {
     pub cache_key: Option<LineDecorationCacheKey>,
     pub color: ColorF,
 }
 
 impl LineDecorationData {
     /// Update the GPU cache for a given primitive template. This may be called multiple
     /// times per frame, by each primitive reference that refers to this interned
@@ -131,17 +132,17 @@ impl From<LineDecorationKey> for LineDec
                 color: line_dec.kind.color.into(),
             }
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)]
 pub struct LineDecorationDataMarker;
 
 pub type LineDecorationDataStore = intern::DataStore<LineDecorationKey, LineDecorationTemplate, LineDecorationDataMarker>;
 pub type LineDecorationDataHandle = intern::Handle<LineDecorationDataMarker>;
 pub type LineDecorationDataUpdateList = intern::UpdateList<LineDecorationKey>;
 pub type LineDecorationDataInterner = intern::Interner<LineDecorationKey, PrimitiveSceneData, LineDecorationDataMarker>;
 
 impl intern::Internable for LineDecoration {
--- a/gfx/wr/webrender/src/prim_store/mod.rs
+++ b/gfx/wr/webrender/src/prim_store/mod.rs
@@ -23,16 +23,17 @@ use display_list_flattener::{AsInstanceK
 use euclid::{SideOffsets2D, TypedTransform3D, TypedRect, TypedScale, TypedSize2D};
 use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureContext, PictureState};
 use frame_builder::PrimitiveContext;
 use glyph_rasterizer::GlyphKey;
 use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks};
 use gpu_types::BrushFlags;
 use image::{Repetition};
 use intern;
+use malloc_size_of::MallocSizeOf;
 use picture::{PictureCompositeMode, PicturePrimitive, PictureUpdateState, TileCacheUpdateState};
 use picture::{ClusterIndex, PrimitiveList, SurfaceIndex, SurfaceInfo, RetainedTiles, RasterConfig};
 use prim_store::borders::{ImageBorderDataHandle, NormalBorderDataHandle};
 use prim_store::gradient::{LinearGradientDataHandle, RadialGradientDataHandle};
 use prim_store::image::{ImageDataHandle, ImageInstance, VisibleImageTile, YuvImageDataHandle};
 use prim_store::line_dec::LineDecorationDataHandle;
 use prim_store::picture::PictureDataHandle;
 use prim_store::text_run::{TextRunDataHandle, TextRunPrimitive};
@@ -94,17 +95,17 @@ impl ScrollNodeAndClipChain {
             spatial_node_index,
             clip_chain_id,
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, MallocSizeOf)]
 pub struct PrimitiveOpacity {
     pub is_opaque: bool,
 }
 
 impl PrimitiveOpacity {
     pub fn opaque() -> PrimitiveOpacity {
         PrimitiveOpacity { is_opaque: true }
     }
@@ -342,38 +343,39 @@ impl GpuCacheAddress {
     }
 }
 
 /// The information about an interned primitive that
 /// is stored and available in the scene builder
 /// thread.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct PrimitiveSceneData {
     pub prim_size: LayoutSize,
     pub prim_relative_clip_rect: LayoutRect,
     pub is_backface_visible: bool,
 }
 
 /// Information specific to a primitive type that
 /// uniquely identifies a primitive template by key.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
 pub enum PrimitiveKeyKind {
     /// Clear an existing rect, used for special effects on some platforms.
     Clear,
     Rectangle {
         color: ColorU,
     },
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
 pub struct RectangleKey {
     x: f32,
     y: f32,
     w: f32,
     h: f32,
 }
 
 impl Eq for RectangleKey {}
@@ -405,17 +407,17 @@ impl From<LayoutRect> for RectangleKey {
             h: rect.size.height,
         }
     }
 }
 
 /// A hashable SideOffset2D that can be used in primitive keys.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
 pub struct SideOffsetsKey {
     pub top: f32,
     pub right: f32,
     pub bottom: f32,
     pub left: f32,
 }
 
 impl Eq for SideOffsetsKey {}
@@ -460,17 +462,17 @@ impl From<SideOffsets2D<f32>> for SideOf
             left: offsets.left,
         }
     }
 }
 
 /// A hashable size for using as a key during primitive interning.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Copy, Debug, Clone, PartialEq)]
+#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
 pub struct SizeKey {
     w: f32,
     h: f32,
 }
 
 impl Eq for SizeKey {}
 
 impl hash::Hash for SizeKey {
@@ -493,17 +495,17 @@ impl<U> From<TypedSize2D<f32, U>> for Si
             h: size.height,
         }
     }
 }
 
 /// A hashable vec for using as a key during primitive interning.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Copy, Debug, Clone, PartialEq)]
+#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
 pub struct VectorKey {
     pub x: f32,
     pub y: f32,
 }
 
 impl Eq for VectorKey {}
 
 impl hash::Hash for VectorKey {
@@ -526,17 +528,17 @@ impl From<LayoutVector2D> for VectorKey 
             y: vec.y,
         }
     }
 }
 
 /// A hashable point for using as a key during primitive interning.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
 pub struct PointKey {
     pub x: f32,
     pub y: f32,
 }
 
 impl Eq for PointKey {}
 
 impl hash::Hash for PointKey {
@@ -558,17 +560,17 @@ impl From<LayoutPoint> for PointKey {
             x: p.x,
             y: p.y,
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
 pub struct PrimKeyCommonData {
     pub is_backface_visible: bool,
     pub prim_size: SizeKey,
     pub prim_relative_clip_rect: RectangleKey,
 }
 
 impl PrimKeyCommonData {
     pub fn with_info(
@@ -580,25 +582,25 @@ impl PrimKeyCommonData {
             prim_size: info.rect.size.into(),
             prim_relative_clip_rect: prim_relative_clip_rect.into(),
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct PrimKey<T> {
+#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
+pub struct PrimKey<T: MallocSizeOf> {
     pub common: PrimKeyCommonData,
     pub kind: T,
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
 pub struct PrimitiveKey {
     pub common: PrimKeyCommonData,
     pub kind: PrimitiveKeyKind,
 }
 
 impl PrimitiveKey {
     pub fn new(
         is_backface_visible: bool,
@@ -643,16 +645,17 @@ impl AsInstanceKind<PrimitiveDataHandle>
         }
     }
 }
 
 /// The shared information for a given primitive. This is interned and retained
 /// both across frames and display lists, by comparing the matching PrimitiveKey.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub enum PrimitiveTemplateKind {
     Rectangle {
         color: ColorF,
     },
     Clear,
 }
 
 /// Construct the primitive template data from a primitive key. This
@@ -670,16 +673,17 @@ impl PrimitiveKeyKind {
                 }
             }
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct PrimTemplateCommonData {
     pub is_backface_visible: bool,
     pub prim_size: LayoutSize,
     pub prim_relative_clip_rect: LayoutRect,
     pub opacity: PrimitiveOpacity,
     /// The GPU cache handle for a primitive template. Since this structure
     /// is retained across display lists by interning, this GPU cache handle
     /// also remains valid, which reduces the number of updates to the GPU
@@ -696,23 +700,25 @@ impl PrimTemplateCommonData {
             gpu_cache_handle: GpuCacheHandle::new(),
             opacity: PrimitiveOpacity::translucent(),
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct PrimTemplate<T> {
     pub common: PrimTemplateCommonData,
     pub kind: T,
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct PrimitiveTemplate {
     pub common: PrimTemplateCommonData,
     pub kind: PrimitiveTemplateKind,
 }
 
 impl ops::Deref for PrimitiveTemplate {
     type Target = PrimTemplateCommonData;
     fn deref(&self) -> &Self::Target {
@@ -775,17 +781,17 @@ impl PrimitiveTemplate {
             }
         };
     }
 }
 
 // Type definitions for interning primitives.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)]
 pub struct PrimitiveDataMarker;
 
 impl intern::Internable for PrimitiveKeyKind {
     type Marker = PrimitiveDataMarker;
     type Source = PrimitiveKey;
     type StoreData = PrimitiveTemplate;
     type InternData = PrimitiveSceneData;
 
@@ -860,31 +866,32 @@ pub struct VisibleGradientTile {
     pub local_rect: LayoutRect,
     pub local_clip_rect: LayoutRect,
 }
 
 /// Information about how to cache a border segment,
 /// along with the current render task cache entry.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug)]
+#[derive(Debug, MallocSizeOf)]
 pub struct BorderSegmentInfo {
     pub local_task_size: LayoutSize,
     pub cache_key: BorderSegmentCacheKey,
 }
 
 bitflags! {
     /// Each bit of the edge AA mask is:
     /// 0, when the edge of the primitive needs to be considered for AA
     /// 1, when the edge of the segment needs to be considered for AA
     ///
     /// *Note*: the bit values have to match the shader logic in
     /// `write_transform_vertex()` function.
     #[cfg_attr(feature = "capture", derive(Serialize))]
     #[cfg_attr(feature = "replay", derive(Deserialize))]
+    #[derive(MallocSizeOf)]
     pub struct EdgeAaSegmentMask: u8 {
         const LEFT = 0x1;
         const TOP = 0x2;
         const RIGHT = 0x4;
         const BOTTOM = 0x8;
     }
 }
 
@@ -896,17 +903,17 @@ pub enum ClipMaskKind {
     /// The segment has no clip mask.
     None,
     /// The segment is made invisible / clipped completely.
     Clipped,
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, MallocSizeOf)]
 pub struct BrushSegment {
     pub local_rect: LayoutRect,
     pub may_need_clip_mask: bool,
     pub edge_flags: EdgeAaSegmentMask,
     pub extra_data: [f32; 4],
     pub brush_flags: BrushFlags,
 }
 
@@ -1186,17 +1193,17 @@ impl ClipData {
         ] {
             corner.write(request);
         }
     }
 }
 
 /// A hashable descriptor for nine-patches, used by image and
 /// gradient borders.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash, MallocSizeOf)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct NinePatchDescriptor {
     pub width: i32,
     pub height: i32,
     pub slice: SideOffsets2D<i32>,
     pub fill: bool,
     pub repeat_horizontal: RepeatMode,
--- a/gfx/wr/webrender/src/prim_store/picture.rs
+++ b/gfx/wr/webrender/src/prim_store/picture.rs
@@ -14,17 +14,17 @@ use prim_store::{
     PrimKey, PrimKeyCommonData, PrimTemplate, PrimTemplateCommonData,
     PrimitiveInstanceKind, PrimitiveSceneData, PrimitiveStore, VectorKey,
 };
 
 /// Represents a hashable description of how a picture primitive
 /// will be composited into its parent.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, PartialEq, Hash, Eq)]
+#[derive(Debug, Clone, MallocSizeOf, PartialEq, Hash, Eq)]
 pub enum PictureCompositeKey {
     // No visual compositing effect
     Identity,
 
     // FilterOp
     Blur(Au),
     Brightness(Au),
     Contrast(Au),
@@ -122,17 +122,17 @@ impl From<Option<PictureCompositeMode>> 
                 PictureCompositeKey::Identity
             }
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
 pub struct Picture {
     pub composite_mode_key: PictureCompositeKey,
 }
 
 pub type PictureKey = PrimKey<Picture>;
 
 impl PictureKey {
     pub fn new(
@@ -166,16 +166,17 @@ impl AsInstanceKind<PictureDataHandle> f
         // Should never be hit as this method should not be
         // called for pictures.
         unreachable!();
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct PictureData;
 
 pub type PictureTemplate = PrimTemplate<PictureData>;
 
 impl From<PictureKey> for PictureTemplate {
     fn from(key: PictureKey) -> Self {
         let common = PrimTemplateCommonData::with_key_common(key.common);
 
@@ -183,17 +184,17 @@ impl From<PictureKey> for PictureTemplat
             common,
             kind: PictureData,
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)]
 pub struct PictureDataMarker;
 
 pub type PictureDataStore = DataStore<PictureKey, PictureTemplate, PictureDataMarker>;
 pub type PictureDataHandle = Handle<PictureDataMarker>;
 pub type PictureDataUpdateList = UpdateList<PictureKey>;
 pub type PictureDataInterner = Interner<PictureKey, PrimitiveSceneData, PictureDataMarker>;
 
 impl Internable for Picture {
--- a/gfx/wr/webrender/src/prim_store/text_run.rs
+++ b/gfx/wr/webrender/src/prim_store/text_run.rs
@@ -18,17 +18,17 @@ use resource_cache::{ResourceCache};
 use util::{MatrixHelpers};
 use prim_store::PrimitiveInstanceKind;
 use std::ops;
 use storage;
 
 /// A run of glyphs, with associated font information.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
 pub struct TextRunKey {
     pub common: PrimKeyCommonData,
     pub font: FontInstance,
     pub offset: VectorKey,
     pub glyphs: Vec<GlyphInstance>,
     pub shadow: bool,
 }
 
@@ -68,16 +68,17 @@ impl AsInstanceKind<TextRunDataHandle> f
         });
 
         PrimitiveInstanceKind::TextRun{ data_handle, run_index }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(MallocSizeOf)]
 pub struct TextRunTemplate {
     pub common: PrimTemplateCommonData,
     pub font: FontInstance,
     pub offset: LayoutVector2D,
     pub glyphs: Vec<GlyphInstance>,
 }
 
 impl ops::Deref for TextRunTemplate {
@@ -156,17 +157,17 @@ impl TextRunTemplate {
 
             assert!(request.current_used_block_num() <= MAX_VERTEX_TEXTURE_WIDTH);
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)]
 pub struct TextRunDataMarker;
 
 pub type TextRunDataStore = intern::DataStore<TextRunKey, TextRunTemplate, TextRunDataMarker>;
 pub type TextRunDataHandle = intern::Handle<TextRunDataMarker>;
 pub type TextRunDataUpdateList = intern::UpdateList<TextRunKey>;
 pub type TextRunDataInterner = intern::Interner<TextRunKey, PrimitiveSceneData, TextRunDataMarker>;
 
 pub struct TextRun {
--- a/gfx/wr/webrender/src/render_task.rs
+++ b/gfx/wr/webrender/src/render_task.rs
@@ -1108,17 +1108,17 @@ pub struct RenderTaskCacheKey {
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RenderTaskCacheEntry {
     pending_render_task_id: Option<RenderTaskId>,
     user_data: Option<[f32; 3]>,
     is_opaque: bool,
     pub handle: TextureCacheHandle,
 }
 
-#[derive(Debug)]
+#[derive(Debug, MallocSizeOf)]
 pub enum RenderTaskCacheMarker {}
 
 // A cache of render tasks that are stored in the texture
 // cache for usage across frames.
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RenderTaskCache {
--- a/gfx/wr/webrender/src/scene_builder.rs
+++ b/gfx/wr/webrender/src/scene_builder.rs
@@ -10,17 +10,17 @@ use api::channel::MsgSender;
 #[cfg(feature = "capture")]
 use capture::CaptureConfig;
 use frame_builder::{FrameBuilderConfig, FrameBuilder};
 use clip::{ClipDataInterner, ClipDataUpdateList};
 use clip_scroll_tree::ClipScrollTree;
 use display_list_flattener::DisplayListFlattener;
 use intern::{Internable, Interner};
 use internal_types::{FastHashMap, FastHashSet};
-use malloc_size_of::MallocSizeOfOps;
+use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
 use prim_store::{PrimitiveDataInterner, PrimitiveDataUpdateList, PrimitiveKeyKind};
 use prim_store::PrimitiveStoreStats;
 use prim_store::borders::{
     ImageBorder, ImageBorderDataInterner, ImageBorderDataUpdateList,
     NormalBorderPrim, NormalBorderDataInterner, NormalBorderDataUpdateList
 };
 use prim_store::gradient::{
     LinearGradient, LinearGradientDataInterner, LinearGradientDataUpdateList,
--- a/gfx/wr/webrender_api/src/api.rs
+++ b/gfx/wr/webrender_api/src/api.rs
@@ -1284,17 +1284,17 @@ impl ZoomFactor {
 
     /// Get the zoom factor as an untyped float.
     pub fn get(&self) -> f32 {
         self.0
     }
 }
 
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, Eq, Hash)]
+#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)]
 pub struct PropertyBindingId {
     namespace: IdNamespace,
     uid: u32,
 }
 
 impl PropertyBindingId {
     pub fn new(value: u64) -> Self {
         PropertyBindingId {
--- a/gfx/wr/webrender_api/src/color.rs
+++ b/gfx/wr/webrender_api/src/color.rs
@@ -34,17 +34,17 @@ impl PremultipliedColorF {
     }
 }
 
 /// Represents RGBA screen colors with floating point numbers.
 ///
 /// All components must be between 0.0 and 1.0.
 /// An alpha value of 1.0 is opaque while 0.0 is fully transparent.
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
 pub struct ColorF {
     pub r: f32,
     pub g: f32,
     pub b: f32,
     pub a: f32,
 }
 
 impl ColorF {
@@ -107,17 +107,17 @@ impl Hash for PremultipliedColorF {
         self.a.to_bits().hash(state);
     }
 }
 
 /// Represents RGBA screen colors with one byte per channel.
 ///
 /// If the alpha value `a` is 255 the color is opaque.
 #[repr(C)]
-#[derive(Clone, Copy, Hash, Eq, Debug, Deserialize, PartialEq, PartialOrd, Ord, Serialize)]
+#[derive(Clone, Copy, Hash, Eq, Debug, Deserialize, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
 pub struct ColorU {
     pub r: u8,
     pub g: u8,
     pub b: u8,
     pub a: u8,
 }
 
 impl ColorU {
--- a/gfx/wr/webrender_api/src/display_item.rs
+++ b/gfx/wr/webrender_api/src/display_item.rs
@@ -242,39 +242,39 @@ pub struct RectangleDisplayItem {
 pub struct LineDisplayItem {
     pub orientation: LineOrientation, // toggles whether above values are interpreted as x/y values
     pub wavy_line_thickness: f32,
     pub color: ColorF,
     pub style: LineStyle,
 }
 
 #[repr(u8)]
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, Eq, Hash)]
+#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)]
 pub enum LineOrientation {
     Vertical,
     Horizontal,
 }
 
 #[repr(u8)]
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, Eq, Hash)]
+#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)]
 pub enum LineStyle {
     Solid,
     Dotted,
     Dashed,
     Wavy,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct TextDisplayItem {
     pub font_key: FontInstanceKey,
     pub color: ColorF,
     pub glyph_options: Option<GlyphOptions>,
 } // IMPLICIT: glyphs: Vec<GlyphInstance>
 
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
 pub struct NormalBorder {
     pub left: BorderSide,
     pub right: BorderSide,
     pub top: BorderSide,
     pub bottom: BorderSide,
     pub radius: BorderRadius,
     /// Whether to apply anti-aliasing on the border corners.
     ///
@@ -323,17 +323,17 @@ impl NormalBorder {
         normalize_side(&mut self.left, widths.left);
         normalize_side(&mut self.right, widths.right);
         normalize_side(&mut self.top, widths.top);
         normalize_side(&mut self.bottom, widths.bottom);
     }
 }
 
 #[repr(u32)]
-#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, Eq, Hash)]
+#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash)]
 pub enum RepeatMode {
     Stretch,
     Repeat,
     Round,
     Space,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
@@ -405,24 +405,24 @@ pub enum BorderRadiusKind {
 pub struct BorderRadius {
     pub top_left: LayoutSize,
     pub top_right: LayoutSize,
     pub bottom_left: LayoutSize,
     pub bottom_right: LayoutSize,
 }
 
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
 pub struct BorderSide {
     pub color: ColorF,
     pub style: BorderStyle,
 }
 
 #[repr(u32)]
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, Hash, Eq)]
+#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Hash, Eq)]
 pub enum BorderStyle {
     None = 0,
     Solid = 1,
     Double = 2,
     Dotted = 3,
     Dashed = 4,
     Hidden = 5,
     Groove = 6,
@@ -433,17 +433,17 @@ pub enum BorderStyle {
 
 impl BorderStyle {
     pub fn is_hidden(&self) -> bool {
         *self == BorderStyle::Hidden || *self == BorderStyle::None
     }
 }
 
 #[repr(u32)]
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
 pub enum BoxShadowClipMode {
     Outset = 0,
     Inset = 1,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct BoxShadowDisplayItem {
     pub box_bounds: LayoutRect,
@@ -459,17 +459,17 @@ pub struct BoxShadowDisplayItem {
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct Shadow {
     pub offset: LayoutVector2D,
     pub color: ColorF,
     pub blur_radius: f32,
 }
 
 #[repr(u8)]
-#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
+#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
 pub enum ExtendMode {
     Clamp,
     Repeat,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct Gradient {
     pub start_point: LayoutPoint,
@@ -480,17 +480,17 @@ pub struct Gradient {
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct GradientDisplayItem {
     pub gradient: Gradient,
     pub tile_size: LayoutSize,
     pub tile_spacing: LayoutSize,
 }
 
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
 pub struct GradientStop {
     pub offset: f32,
     pub color: ColorF,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct RadialGradient {
     pub center: LayoutPoint,
@@ -654,39 +654,39 @@ pub struct ImageDisplayItem {
     pub stretch_size: LayoutSize,
     pub tile_spacing: LayoutSize,
     pub image_rendering: ImageRendering,
     pub alpha_type: AlphaType,
     pub color: ColorF,
 }
 
 #[repr(u32)]
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
 pub enum ImageRendering {
     Auto = 0,
     CrispEdges = 1,
     Pixelated = 2,
 }
 
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
 pub enum AlphaType {
     Alpha = 0,
     PremultipliedAlpha = 1,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct YuvImageDisplayItem {
     pub yuv_data: YuvData,
     pub color_depth: ColorDepth,
     pub color_space: YuvColorSpace,
     pub image_rendering: ImageRendering,
 }
 
 #[repr(u32)]
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
 pub enum YuvColorSpace {
     Rec601 = 0,
     Rec709 = 1,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
 pub enum YuvData {
     NV12(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel)
@@ -699,17 +699,17 @@ impl YuvData {
         match *self {
             YuvData::NV12(..) => YuvFormat::NV12,
             YuvData::PlanarYCbCr(..) => YuvFormat::PlanarYCbCr,
             YuvData::InterleavedYCbCr(..) => YuvFormat::InterleavedYCbCr,
         }
     }
 }
 
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
 pub enum YuvFormat {
     NV12 = 0,
     PlanarYCbCr = 1,
     InterleavedYCbCr = 2,
 }
 
 impl YuvFormat {
     pub fn get_plane_num(&self) -> usize {
--- a/gfx/wr/webrender_api/src/font.rs
+++ b/gfx/wr/webrender_api/src/font.rs
@@ -66,17 +66,17 @@ pub struct GlyphDimensions {
     pub left: i32,
     pub top: i32,
     pub width: i32,
     pub height: i32,
     pub advance: f32,
 }
 
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Ord, PartialOrd)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, Ord, PartialOrd)]
 pub struct FontKey(pub IdNamespace, pub u32);
 
 impl FontKey {
     pub fn new(namespace: IdNamespace, key: u32) -> FontKey {
         FontKey(namespace, key)
     }
 }
 
@@ -89,17 +89,17 @@ impl FontKey {
 /// intended to distinguish this data from instance-specific data.
 #[derive(Clone)]
 pub enum FontTemplate {
     Raw(Arc<Vec<u8>>, u32),
     Native(NativeFontHandle),
 }
 
 #[repr(u32)]
-#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
+#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
 pub enum FontRenderMode {
     Mono = 0,
     Alpha,
     Subpixel,
 }
 
 impl FontRenderMode {
     // Combine two font render modes such that the lesser amount of AA limits the AA of the result.
@@ -107,17 +107,17 @@ impl FontRenderMode {
         match (self, other) {
             (FontRenderMode::Subpixel, _) | (_, FontRenderMode::Mono) => other,
             _ => self,
         }
     }
 }
 
 #[repr(C)]
-#[derive(Clone, Copy, Debug, PartialOrd, Deserialize, Serialize)]
+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialOrd, Deserialize, Serialize)]
 pub struct FontVariation {
     pub tag: u32,
     pub value: f32,
 }
 
 impl Ord for FontVariation {
     fn cmp(&self, other: &FontVariation) -> Ordering {
         self.tag.cmp(&other.tag)
@@ -154,17 +154,17 @@ impl Default for GlyphOptions {
             render_mode: FontRenderMode::Subpixel,
             flags: FontInstanceFlags::empty(),
         }
     }
 }
 
 bitflags! {
     #[repr(C)]
-    #[derive(Deserialize, Serialize)]
+    #[derive(Deserialize, MallocSizeOf, Serialize)]
     pub struct FontInstanceFlags: u32 {
         // Common flags
         const SYNTHETIC_BOLD    = 1 << 1;
         const EMBEDDED_BITMAPS  = 1 << 2;
         const SUBPIXEL_BGR      = 1 << 3;
         const TRANSPOSE         = 1 << 4;
         const FLIP_X            = 1 << 5;
         const FLIP_Y            = 1 << 6;
@@ -199,17 +199,17 @@ impl Default for FontInstanceFlags {
     #[cfg(not(any(target_os = "macos", target_os = "windows")))]
     fn default() -> FontInstanceFlags {
         FontInstanceFlags::SUBPIXEL_POSITION
     }
 }
 
 
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
 pub struct SyntheticItalics {
     // Angle in degrees (-90..90) for synthetic italics in 8.8 fixed-point.
     pub angle: i16,
 }
 
 impl SyntheticItalics {
     pub const ANGLE_SCALE: f32 = 256.0;
 
@@ -268,17 +268,17 @@ impl Default for FontInstanceOptions {
             bg_color: ColorU::new(0, 0, 0, 0),
             synthetic_italics: SyntheticItalics::disabled(),
         }
     }
 }
 
 #[cfg(target_os = "windows")]
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
 pub struct FontInstancePlatformOptions {
     pub gamma: u16, // percent
     pub contrast: u16, // percent
 }
 
 #[cfg(target_os = "windows")]
 impl Default for FontInstancePlatformOptions {
     fn default() -> FontInstancePlatformOptions {
@@ -286,54 +286,54 @@ impl Default for FontInstancePlatformOpt
             gamma: 180, // Default DWrite gamma
             contrast: 100,
         }
     }
 }
 
 #[cfg(target_os = "macos")]
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
 pub struct FontInstancePlatformOptions {
     pub unused: u32,
 }
 
 #[cfg(target_os = "macos")]
 impl Default for FontInstancePlatformOptions {
     fn default() -> FontInstancePlatformOptions {
         FontInstancePlatformOptions {
             unused: 0,
         }
     }
 }
 
 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
 #[repr(u8)]
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
 pub enum FontLCDFilter {
     None,
     Default,
     Light,
     Legacy,
 }
 
 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
 #[repr(u8)]
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
 pub enum FontHinting {
     None,
     Mono,
     Light,
     Normal,
     LCD,
 }
 
 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
 pub struct FontInstancePlatformOptions {
     pub lcd_filter: FontLCDFilter,
     pub hinting: FontHinting,
 }
 
 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
 impl Default for FontInstancePlatformOptions {
     fn default() -> FontInstancePlatformOptions {
@@ -365,17 +365,17 @@ pub struct FontInstanceData {
     pub options: Option<FontInstanceOptions>,
     pub platform_options: Option<FontInstancePlatformOptions>,
     pub variations: Vec<FontVariation>,
 }
 
 pub type GlyphIndex = u32;
 
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
 pub struct GlyphInstance {
     pub index: GlyphIndex,
     pub point: LayoutPoint,
 }
 
 impl Eq for GlyphInstance {}
 
 impl Hash for GlyphInstance {
--- a/gfx/wr/webrender_api/src/image.rs
+++ b/gfx/wr/webrender_api/src/image.rs
@@ -12,17 +12,17 @@ use {DeviceIntPoint, DeviceIntRect, Devi
 use {BlobDirtyRect, IdNamespace, TileOffset, TileSize};
 use euclid::{size2, TypedRect, num::Zero};
 use std::ops::{Add, Sub};
 
 /// An opaque identifier describing an image registered with WebRender.
 /// This is used as a handle to reference images, and is used as the
 /// hash map key for the actual image storage in the `ResourceCache`.
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
 pub struct ImageKey(pub IdNamespace, pub u32);
 
 impl ImageKey {
     /// Placeholder Image key, used to represent None.
     pub const DUMMY: Self = ImageKey(IdNamespace(0), 0);
 
     /// Mints a new ImageKey. The given ID must be unique.
     pub fn new(namespace: IdNamespace, key: u32) -> Self {
@@ -132,17 +132,17 @@ impl ImageFormat {
             ImageFormat::RGBAI32 => 16,
             ImageFormat::RGBA8 => 4,
         }
     }
 }
 
 /// Specifies the color depth of an image. Currently only used for YUV images.
 #[repr(u8)]
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
 pub enum ColorDepth {
     /// 8 bits image (most common)
     Color8,
     /// 10 bits image
     Color10,
     /// 12 bits image
     Color12,
     /// 16 bits image