Start reporting memory usage for Window and all nodes in all DOM trees for frame treese in script tasks.

This commit is contained in:
Josh Matthews 2015-07-31 12:46:36 -04:00
parent c2497fcd49
commit 8620fe5995
33 changed files with 317 additions and 107 deletions

View file

@ -16,7 +16,7 @@ use std::cell::{BorrowState, RefCell, Ref, RefMut};
///
/// This extends the API of `core::cell::RefCell` to allow unsafe access in
/// certain situations, with dynamic checking in debug builds.
#[derive(Clone)]
#[derive(Clone, HeapSizeOf)]
pub struct DOMRefCell<T> {
value: RefCell<T>,
}

View file

@ -3314,7 +3314,7 @@ class CGEnum(CGThing):
decl = """\
#[repr(usize)]
#[derive(JSTraceable, PartialEq, Copy, Clone)]
#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)]
pub enum %s {
%s
}

View file

@ -31,6 +31,7 @@ use js::jsapi::{JSObject, Heap, JSTracer};
use js::jsval::JSVal;
use layout_interface::TrustedNodeAddress;
use script_task::STACK_ROOTS;
use util::mem::HeapSizeOf;
use core::nonzero::NonZero;
use std::cell::{Cell, UnsafeCell};
@ -44,6 +45,14 @@ pub struct JS<T> {
ptr: NonZero<*const T>
}
// JS<T> is similar to Rc<T>, in that it's not always clear how to avoid double-counting.
// For now, we choose not to follow any such pointers.
impl<T> HeapSizeOf for JS<T> {
fn heap_size_of_children(&self) -> usize {
0
}
}
impl<T> JS<T> {
/// Returns `LayoutJS<T>` containing the same pointer.
pub unsafe fn to_layout(self) -> LayoutJS<T> {
@ -226,7 +235,7 @@ impl<T: HeapGCValue+Copy> MutHeap<T> {
/// place of traditional internal mutability to ensure that the proper GC
/// barriers are enforced.
#[must_root]
#[derive(JSTraceable)]
#[derive(JSTraceable, HeapSizeOf)]
pub struct MutNullableHeap<T: HeapGCValue+Copy> {
ptr: Cell<Option<T>>
}

View file

@ -16,6 +16,7 @@ use dom::bindings::js::Root;
use dom::bindings::trace::trace_object;
use dom::browsercontext;
use dom::window;
use util::mem::HeapSizeOf;
use util::str::DOMString;
use libc;
@ -61,10 +62,18 @@ use js;
use string_cache::{Atom, Namespace};
/// Proxy handler for a WindowProxy.
#[allow(raw_pointer_derive)]
pub struct WindowProxyHandler(pub *const libc::c_void);
impl HeapSizeOf for WindowProxyHandler {
fn heap_size_of_children(&self) -> usize {
//FIXME(#6907) this is a pointer to memory allocated by `new` in NewProxyHandler in rust-mozjs.
0
}
}
#[allow(raw_pointer_derive)]
#[derive(JSTraceable)]
#[derive(JSTraceable, HeapSizeOf)]
/// Static data associated with a global object.
pub struct GlobalStaticData {
/// The WindowProxy proxy handler for this global.
@ -416,8 +425,10 @@ pub fn reflect_dom_object<T: Reflectable>
#[allow(raw_pointer_derive, unrooted_must_root)]
#[must_root]
#[servo_lang = "reflector"]
#[derive(HeapSizeOf)]
// If you're renaming or moving this field, update the path in plugins::reflector as well
pub struct Reflector {
#[ignore_heap_size_of = "defined and measured in rust-mozjs"]
object: UnsafeCell<*mut JSObject>,
}

View file

@ -27,7 +27,7 @@ use js::{JSTrue, JSFalse};
use std::ptr;
use std::default::Default;
#[derive(JSTraceable)]
#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
#[allow(raw_pointer_derive)]
#[must_root]
@ -88,7 +88,7 @@ impl BrowsingContext {
// without a reflector, so we don't mark this as #[dom_struct]
#[must_root]
#[privatize]
#[derive(JSTraceable)]
#[derive(JSTraceable, HeapSizeOf)]
pub struct SessionHistoryEntry {
document: JS<Document>,
children: Vec<BrowsingContext>

View file

@ -24,6 +24,7 @@ use std::cell::Ref;
// https://dom.spec.whatwg.org/#characterdata
#[dom_struct]
#[derive(HeapSizeOf)]
pub struct CharacterData {
node: Node,
data: DOMRefCell<DOMString>,
@ -150,7 +151,7 @@ impl<'a> CharacterDataMethods for &'a CharacterData {
}
/// The different types of CharacterData.
#[derive(JSTraceable, Copy, Clone, PartialEq, Debug)]
#[derive(JSTraceable, Copy, Clone, PartialEq, Debug, HeapSizeOf)]
pub enum CharacterDataTypeId {
Comment,
Text,

View file

@ -110,6 +110,7 @@ pub enum IsHTMLDocument {
// https://dom.spec.whatwg.org/#document
#[dom_struct]
#[derive(HeapSizeOf)]
pub struct Document {
node: Node,
window: JS<Window>,
@ -144,6 +145,7 @@ pub struct Document {
animation_frame_ident: Cell<i32>,
/// https://html.spec.whatwg.org/multipage/#list-of-animation-frame-callbacks
/// List of animation frame callbacks
#[ignore_heap_size_of = "closures are hard"]
animation_frame_list: RefCell<HashMap<i32, Box<Fn(f64)>>>,
/// Tracks all outstanding loads related to this document.
loader: DOMRefCell<DocumentLoader>,

View file

@ -120,7 +120,7 @@ impl PartialEq for Element {
}
}
#[derive(JSTraceable, Copy, Clone, PartialEq, Debug)]
#[derive(JSTraceable, Copy, Clone, PartialEq, Debug, HeapSizeOf)]
pub enum ElementTypeId {
HTMLElement(HTMLElementTypeId),
Element,

View file

@ -20,6 +20,7 @@ use js::jsapi::{CompileFunction, JS_GetFunctionObject};
use js::jsapi::{JSContext, RootedFunction, HandleObject};
use js::jsapi::{JSAutoCompartment, JSAutoRequest};
use js::rust::{AutoObjectVectorWrapper, CompileOptionsWrapper};
use util::mem::HeapSizeOf;
use util::str::DOMString;
use fnv::FnvHasher;
@ -36,13 +37,14 @@ use url::Url;
use std::collections::HashMap;
#[derive(JSTraceable, Copy, Clone, PartialEq)]
#[derive(JSTraceable, Copy, Clone, PartialEq, HeapSizeOf)]
pub enum ListenerPhase {
Capturing,
Bubbling,
}
#[derive(JSTraceable, Copy, Clone)]
#[derive(HeapSizeOf)]
pub enum EventTargetTypeId {
Node(NodeTypeId),
WebSocket,
@ -95,6 +97,13 @@ pub enum EventListenerType {
Inline(Rc<EventListener>),
}
impl HeapSizeOf for EventListenerType {
fn heap_size_of_children(&self) -> usize {
// FIXME: Rc<T> isn't HeapSizeOf and we can't ignore it due to #6870 and #6871
0
}
}
impl EventListenerType {
fn get_listener(&self) -> Rc<EventListener> {
match *self {
@ -104,7 +113,7 @@ impl EventListenerType {
}
}
#[derive(JSTraceable, Clone, PartialEq)]
#[derive(JSTraceable, Clone, PartialEq, HeapSizeOf)]
#[privatize]
pub struct EventListenerEntry {
phase: ListenerPhase,
@ -112,6 +121,7 @@ pub struct EventListenerEntry {
}
#[dom_struct]
#[derive(HeapSizeOf)]
pub struct EventTarget {
reflector_: Reflector,
type_id: EventTargetTypeId,

View file

@ -366,7 +366,7 @@ impl<'a> VirtualMethods for &'a HTMLElement {
}
}
#[derive(JSTraceable, Copy, Clone, Debug)]
#[derive(JSTraceable, Copy, Clone, Debug, HeapSizeOf)]
pub enum HTMLElementTypeId {
HTMLElement,

View file

@ -41,7 +41,7 @@ impl HTMLMediaElement {
}
}
#[derive(JSTraceable, Copy, Clone, Debug)]
#[derive(JSTraceable, Copy, Clone, Debug, HeapSizeOf)]
pub enum HTMLMediaElementTypeId {
HTMLAudioElement = 0,
HTMLVideoElement = 1,

View file

@ -22,7 +22,7 @@ use std::cmp::max;
const DEFAULT_COLSPAN: u32 = 1;
#[derive(JSTraceable, Copy, Clone, Debug)]
#[derive(JSTraceable, Copy, Clone, Debug, HeapSizeOf)]
pub enum HTMLTableCellElementTypeId {
HTMLTableDataCellElement = 0,
HTMLTableHeaderCellElement = 1,

View file

@ -78,6 +78,7 @@ use string_cache::{Atom, Namespace, QualName};
/// An HTML node.
#[dom_struct]
#[derive(HeapSizeOf)]
pub struct Node {
/// The JavaScript reflector for this node.
eventtarget: EventTarget,
@ -135,7 +136,7 @@ impl NodeDerived for EventTarget {
bitflags! {
#[doc = "Flags for node items."]
#[derive(JSTraceable)]
#[derive(JSTraceable, HeapSizeOf)]
flags NodeFlags: u16 {
#[doc = "Specifies whether this node is in a document."]
const IS_IN_DOC = 0x01,
@ -206,20 +207,25 @@ enum SuppressObserver {
}
/// Layout data that is shared between the script and layout tasks.
#[derive(HeapSizeOf)]
pub struct SharedLayoutData {
/// The results of CSS styling for this node.
pub style: Option<Arc<ComputedValues>>,
}
/// Encapsulates the abstract layout data.
#[allow(raw_pointer_derive)]
#[derive(HeapSizeOf)]
pub struct LayoutData {
_shared_data: SharedLayoutData,
#[ignore_heap_size_of = "TODO(#6910) Box value that should be counted but the type lives in layout"]
_data: NonZero<*const ()>,
}
#[allow(unsafe_code)]
unsafe impl Send for LayoutData {}
#[derive(HeapSizeOf)]
pub struct LayoutDataRef {
data_cell: RefCell<Option<LayoutData>>,
}
@ -274,6 +280,7 @@ impl LayoutDataRef {
/// The different types of nodes.
#[derive(JSTraceable, Copy, Clone, PartialEq, Debug)]
#[derive(HeapSizeOf)]
pub enum NodeTypeId {
CharacterData(CharacterDataTypeId),
DocumentType,

View file

@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::EventHandlerBinding::{OnErrorEventHandlerN
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::codegen::Bindings::WindowBinding::{self, WindowMethods, FrameRequestCallback};
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, EventTargetCast};
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, EventTargetCast, WindowDerived};
use dom::bindings::global::global_object_for_js_object;
use dom::bindings::error::{report_pending_exception, Fallible};
use dom::bindings::error::Error::InvalidCharacter;
@ -81,7 +81,7 @@ use std::sync::mpsc::{channel, Receiver};
use time;
/// Current state of the window object
#[derive(JSTraceable, Copy, Clone, Debug, PartialEq)]
#[derive(JSTraceable, Copy, Clone, Debug, PartialEq, HeapSizeOf)]
enum WindowState {
Alive,
Zombie, // Pipeline is closed, but the window hasn't been GCed yet.
@ -106,15 +106,21 @@ pub enum ReflowReason {
}
#[dom_struct]
#[derive(HeapSizeOf)]
pub struct Window {
eventtarget: EventTarget,
#[ignore_heap_size_of = "trait objects are hard"]
script_chan: Box<ScriptChan+Send>,
#[ignore_heap_size_of = "channels are hard"]
control_chan: ScriptControlChan,
console: MutNullableHeap<JS<Console>>,
crypto: MutNullableHeap<JS<Crypto>>,
navigator: MutNullableHeap<JS<Navigator>>,
#[ignore_heap_size_of = "channels are hard"]
image_cache_task: ImageCacheTask,
#[ignore_heap_size_of = "channels are hard"]
image_cache_chan: ImageCacheChan,
#[ignore_heap_size_of = "TODO(#6911) newtypes containing unmeasurable types are hard"]
compositor: DOMRefCell<ScriptListener>,
browsing_context: DOMRefCell<Option<BrowsingContext>>,
page: Rc<Page>,
@ -129,13 +135,17 @@ pub struct Window {
next_worker_id: Cell<WorkerId>,
/// For sending messages to the memory profiler.
#[ignore_heap_size_of = "channels are hard"]
mem_profiler_chan: mem::ProfilerChan,
/// For providing instructions to an optional devtools server.
#[ignore_heap_size_of = "channels are hard"]
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
/// For sending timeline markers. Will be ignored if
/// no devtools server
#[ignore_heap_size_of = "TODO(#6909) need to measure HashSet"]
devtools_markers: RefCell<HashSet<TimelineMarkerType>>,
#[ignore_heap_size_of = "channels are hard"]
devtools_marker_sender: RefCell<Option<IpcSender<TimelineMarker>>>,
/// A flag to indicate whether the developer tools have requested live updates of
@ -160,27 +170,34 @@ pub struct Window {
dom_static: GlobalStaticData,
/// The JavaScript runtime.
#[ignore_heap_size_of = "Rc<T> is hard"]
js_runtime: DOMRefCell<Option<Rc<Runtime>>>,
/// A handle for communicating messages to the layout task.
#[ignore_heap_size_of = "channels are hard"]
layout_chan: LayoutChan,
/// A handle to perform RPC calls into the layout, quickly.
#[ignore_heap_size_of = "trait objects are hard"]
layout_rpc: Box<LayoutRPC+'static>,
/// The port that we will use to join layout. If this is `None`, then layout is not running.
#[ignore_heap_size_of = "channels are hard"]
layout_join_port: DOMRefCell<Option<Receiver<()>>>,
/// The current size of the window, in pixels.
window_size: Cell<Option<WindowSizeData>>,
/// Associated resource task for use by DOM objects like XMLHttpRequest
#[ignore_heap_size_of = "channels are hard"]
resource_task: Arc<ResourceTask>,
/// A handle for communicating messages to the storage task.
#[ignore_heap_size_of = "channels are hard"]
storage_task: StorageTask,
/// A handle for communicating messages to the constellation task.
#[ignore_heap_size_of = "channels are hard"]
constellation_chan: ConstellationChan,
/// Pending scroll to fragment event, if any
@ -194,6 +211,7 @@ pub struct Window {
pending_reflow_count: Cell<u32>,
/// A channel for communicating results of async scripts back to the webdriver server
#[ignore_heap_size_of = "channels are hard"]
webdriver_script_chan: RefCell<Option<IpcSender<WebDriverJSResult>>>,
/// The current state of the window object
@ -1182,3 +1200,9 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason:
println!("{}", debug_msg);
}
impl WindowDerived for EventTarget {
fn is_window(&self) -> bool {
self.type_id() == &EventTargetTypeId::Window
}
}

View file

@ -37,7 +37,7 @@ use std::cell::Cell;
use std::rc::Rc;
use std::sync::mpsc::Receiver;
#[derive(JSTraceable, Copy, Clone, PartialEq)]
#[derive(JSTraceable, Copy, Clone, PartialEq, HeapSizeOf)]
pub enum WorkerGlobalScopeTypeId {
DedicatedGlobalScope,
}

View file

@ -8,7 +8,7 @@ use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::InheritTypes::XMLHttpRequestEventTargetDerived;
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
#[derive(JSTraceable, Copy, Clone, PartialEq)]
#[derive(JSTraceable, Copy, Clone, PartialEq, HeapSizeOf)]
pub enum XMLHttpRequestEventTargetTypeId {
XMLHttpRequest,
XMLHttpRequestUpload,