diff options
Diffstat (limited to 'components/script')
29 files changed, 330 insertions, 96 deletions
diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 60d410bbda8..8b4dfb12e6f 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -43,7 +43,6 @@ pub fn handle_evaluate_js(global: &GlobalRef, eval: String, reply: IpcSender<Eva } else if rval.ptr.is_null() { EvaluateJSReply::NullValue } else { - //FIXME: jsvals don't have an is_int32/is_number yet assert!(rval.ptr.is_object()); panic!("object values unimplemented") }).unwrap(); diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs index 56ee98bdbbf..9046f5cbbcf 100644 --- a/components/script/document_loader.rs +++ b/components/script/document_loader.rs @@ -12,7 +12,7 @@ use net_traits::AsyncResponseTarget; use std::sync::Arc; use url::Url; -#[derive(JSTraceable, PartialEq, Clone, Debug)] +#[derive(JSTraceable, PartialEq, Clone, Debug, HeapSizeOf)] pub enum LoadType { Image(Url), Script(Url), @@ -33,17 +33,19 @@ impl LoadType { } } -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] pub struct DocumentLoader { /// We use an `Arc<ResourceTask>` here in order to avoid file descriptor exhaustion when there /// are lots of iframes. + #[ignore_heap_size_of = "channels are hard"] pub resource_task: Arc<ResourceTask>, notifier_data: Option<NotifierData>, blocking_loads: Vec<LoadType>, } -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] pub struct NotifierData { + #[ignore_heap_size_of = "trait objects are hard"] pub script_chan: Box<ScriptChan + Send>, pub pipeline: PipelineId, } diff --git a/components/script/dom/bindings/cell.rs b/components/script/dom/bindings/cell.rs index 35b20d0a417..80bab8839bc 100644 --- a/components/script/dom/bindings/cell.rs +++ b/components/script/dom/bindings/cell.rs @@ -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>, } diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index a46c58ff7c7..9bfaa0c9cfd 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -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 } diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index 4a2879e9f41..053059cec9f 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -125,7 +125,7 @@ impl<'a> GlobalRef<'a> { pub fn get_worker_id(&self) -> Option<WorkerId> { match *self { GlobalRef::Window(_) => None, - GlobalRef::Worker(ref worker) => worker.get_worker_id(), + GlobalRef::Worker(ref worker) => Some(worker.get_worker_id()), } } diff --git a/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs index fc929db1cac..0fde5678ab2 100644 --- a/components/script/dom/bindings/js.rs +++ b/components/script/dom/bindings/js.rs @@ -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>> } diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index bacb6bc05ae..80db27bd894 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -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>, } diff --git a/components/script/dom/browsercontext.rs b/components/script/dom/browsercontext.rs index cc4dc346c3f..8fe518844ba 100644 --- a/components/script/dom/browsercontext.rs +++ b/components/script/dom/browsercontext.rs @@ -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> diff --git a/components/script/dom/characterdata.rs b/components/script/dom/characterdata.rs index 377a69b3d2d..f15b66c68f8 100644 --- a/components/script/dom/characterdata.rs +++ b/components/script/dom/characterdata.rs @@ -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, diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index 90fb0283507..cef9c5f9789 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -21,21 +21,19 @@ use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::messageevent::MessageEvent; use dom::worker::{TrustedWorkerAddress, WorkerMessageHandler, WorkerEventHandler, WorkerErrorHandler}; use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers}; -use dom::workerglobalscope::WorkerGlobalScopeTypeId; +use dom::workerglobalscope::{WorkerGlobalScopeTypeId, WorkerGlobalScopeInit}; use script_task::{ScriptTask, ScriptChan, ScriptMsg, TimerSource, ScriptPort}; use script_task::StackRootTLS; -use msg::constellation_msg::{ConstellationChan, PipelineId, WorkerId}; - -use devtools_traits::{ScriptToDevtoolsControlMsg, DevtoolScriptControlMsg}; - -use net_traits::{load_whole_resource, ResourceTask}; +use devtools_traits::DevtoolScriptControlMsg; +use msg::constellation_msg::PipelineId; +use net_traits::load_whole_resource; use profile_traits::mem::{self, Reporter, ReporterRequest}; use util::task::spawn_named; use util::task_state; use util::task_state::{SCRIPT, IN_WORKER}; -use ipc_channel::ipc::{self, IpcSender, IpcReceiver}; +use ipc_channel::ipc::{self, IpcReceiver}; use ipc_channel::router::ROUTER; use js::jsapi::{JSContext, RootedValue, HandleValue}; use js::jsapi::{JSAutoRequest, JSAutoCompartment}; @@ -107,25 +105,19 @@ pub struct DedicatedWorkerGlobalScope { } impl DedicatedWorkerGlobalScope { - fn new_inherited(worker_url: Url, + fn new_inherited(init: WorkerGlobalScopeInit, + worker_url: Url, id: PipelineId, - mem_profiler_chan: mem::ProfilerChan, - devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, - devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, devtools_port: Receiver<DevtoolScriptControlMsg>, runtime: Rc<Runtime>, - resource_task: ResourceTask, - constellation_chan: ConstellationChan, parent_sender: Box<ScriptChan+Send>, own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, - receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>, - worker_id: Option<WorkerId>) + receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>) -> DedicatedWorkerGlobalScope { DedicatedWorkerGlobalScope { workerglobalscope: WorkerGlobalScope::new_inherited( - WorkerGlobalScopeTypeId::DedicatedGlobalScope, worker_url, runtime, resource_task, - mem_profiler_chan, devtools_chan, devtools_sender, devtools_port, constellation_chan, - worker_id), + WorkerGlobalScopeTypeId::DedicatedGlobalScope, init, worker_url, + runtime, devtools_port), id: id, receiver: receiver, own_sender: own_sender, @@ -134,43 +126,32 @@ impl DedicatedWorkerGlobalScope { } } - pub fn new(worker_url: Url, + pub fn new(init: WorkerGlobalScopeInit, + worker_url: Url, id: PipelineId, - mem_profiler_chan: mem::ProfilerChan, - devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, - devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, devtools_port: Receiver<DevtoolScriptControlMsg>, runtime: Rc<Runtime>, - resource_task: ResourceTask, - constellation_chan: ConstellationChan, parent_sender: Box<ScriptChan+Send>, own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, - receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>, - worker_id: Option<WorkerId>) + receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>) -> Root<DedicatedWorkerGlobalScope> { let scope = box DedicatedWorkerGlobalScope::new_inherited( - worker_url, id, mem_profiler_chan, devtools_chan, devtools_sender, devtools_port, - runtime.clone(), resource_task, constellation_chan, parent_sender, own_sender, receiver, - worker_id); + init, worker_url, id, devtools_port, runtime.clone(), parent_sender, + own_sender, receiver); DedicatedWorkerGlobalScopeBinding::Wrap(runtime.cx(), scope) } } impl DedicatedWorkerGlobalScope { #[allow(unsafe_code)] - pub fn run_worker_scope(worker_url: Url, + pub fn run_worker_scope(init: WorkerGlobalScopeInit, + worker_url: Url, id: PipelineId, - mem_profiler_chan: mem::ProfilerChan, - devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, - devtools_ipc_chan: Option<IpcSender<DevtoolScriptControlMsg>>, devtools_ipc_port: IpcReceiver<DevtoolScriptControlMsg>, worker: TrustedWorkerAddress, - resource_task: ResourceTask, - constellation_chan: ConstellationChan, parent_sender: Box<ScriptChan+Send>, own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, - receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>, - worker_id: Option<WorkerId>) { + receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>) { let serialized_worker_url = worker_url.serialize(); spawn_named(format!("WebWorker for {}", serialized_worker_url), move || { task_state::initialize(SCRIPT | IN_WORKER); @@ -178,7 +159,7 @@ impl DedicatedWorkerGlobalScope { let roots = RootCollection::new(); let _stack_roots_tls = StackRootTLS::new(&roots); - let (url, source) = match load_whole_resource(&resource_task, worker_url) { + let (url, source) = match load_whole_resource(&init.resource_task, worker_url) { Err(_) => { println!("error loading script {}", serialized_worker_url); parent_sender.send(ScriptMsg::RunnableMsg( @@ -198,9 +179,8 @@ impl DedicatedWorkerGlobalScope { ROUTER.route_ipc_receiver_to_mpsc_sender(devtools_ipc_port, devtools_mpsc_chan); let global = DedicatedWorkerGlobalScope::new( - url, id, mem_profiler_chan.clone(), devtools_chan, devtools_ipc_chan, devtools_mpsc_port, - runtime.clone(), resource_task, constellation_chan, parent_sender, own_sender, receiver, - worker_id); + init, url, id, devtools_mpsc_port, runtime.clone(), + parent_sender, own_sender, receiver); // FIXME(njn): workers currently don't have a unique ID suitable for using in reporter // registration (#6631), so we instead use a random number and cross our fingers. let scope = WorkerGlobalScopeCast::from_ref(global.r()); @@ -230,7 +210,7 @@ impl DedicatedWorkerGlobalScope { parent_sender_for_reporter.send(ScriptMsg::CollectReports( reporter_request.reports_channel)).unwrap() }); - mem_profiler_chan.send(mem::ProfilerMsg::RegisterReporter( + scope.mem_profiler_chan().send(mem::ProfilerMsg::RegisterReporter( reporter_name.clone(), Reporter(reporter_sender))); } @@ -292,7 +272,7 @@ impl DedicatedWorkerGlobalScope { // Unregister this task as a memory reporter. let msg = mem::ProfilerMsg::UnregisterReporter(reporter_name); - mem_profiler_chan.send(msg); + scope.mem_profiler_chan().send(msg); }); } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index dd7dc90e0fe..5383ea6df33 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -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>, diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 046b9a57c5f..1b200ed4e61 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -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, diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs index dfeae4ff08f..79679ff14d2 100644 --- a/components/script/dom/eventtarget.rs +++ b/components/script/dom/eventtarget.rs @@ -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, diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index 513a9d39775..2a196073513 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -12,7 +12,7 @@ use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementM use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDerived}; use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLInputElementCast, NodeCast}; -use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived}; +use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived, HTMLHtmlElementDerived}; use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::error::ErrorResult; use dom::bindings::error::Error::Syntax; @@ -216,6 +216,63 @@ impl<'a> HTMLElementMethods for &'a HTMLElement { // If `request_focus` is not called, focus will be set to None. document.r().commit_focus_transaction(FocusType::Element); } + + // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface + fn GetOffsetParent(self) -> Option<Root<Element>> { + if self.is_htmlbodyelement() || self.is_htmlhtmlelement() { + return None; + } + + let node = NodeCast::from_ref(self); + let window = window_from_node(self); + let (element, _) = window.offset_parent_query(node.to_trusted_node_address()); + + element + } + + // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface + fn OffsetTop(self) -> i32 { + if self.is_htmlbodyelement() { + return 0; + } + + let node = NodeCast::from_ref(self); + let window = window_from_node(self); + let (_, rect) = window.offset_parent_query(node.to_trusted_node_address()); + + rect.origin.y.to_nearest_px() + } + + // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface + fn OffsetLeft(self) -> i32 { + if self.is_htmlbodyelement() { + return 0; + } + + let node = NodeCast::from_ref(self); + let window = window_from_node(self); + let (_, rect) = window.offset_parent_query(node.to_trusted_node_address()); + + rect.origin.x.to_nearest_px() + } + + // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface + fn OffsetWidth(self) -> i32 { + let node = NodeCast::from_ref(self); + let window = window_from_node(self); + let (_, rect) = window.offset_parent_query(node.to_trusted_node_address()); + + rect.size.width.to_nearest_px() + } + + // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface + fn OffsetHeight(self) -> i32 { + let node = NodeCast::from_ref(self); + let window = window_from_node(self); + let (_, rect) = window.offset_parent_query(node.to_trusted_node_address()); + + rect.size.height.to_nearest_px() + } } // https://html.spec.whatwg.org/#attr-data-* @@ -309,7 +366,7 @@ impl<'a> VirtualMethods for &'a HTMLElement { } } -#[derive(JSTraceable, Copy, Clone, Debug)] +#[derive(JSTraceable, Copy, Clone, Debug, HeapSizeOf)] pub enum HTMLElementTypeId { HTMLElement, diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index b0b3ae9c6e9..847132c6452 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -41,7 +41,7 @@ impl HTMLMediaElement { } } -#[derive(JSTraceable, Copy, Clone, Debug)] +#[derive(JSTraceable, Copy, Clone, Debug, HeapSizeOf)] pub enum HTMLMediaElementTypeId { HTMLAudioElement = 0, HTMLVideoElement = 1, diff --git a/components/script/dom/htmltablecellelement.rs b/components/script/dom/htmltablecellelement.rs index 66359deb22f..873cbb184e8 100644 --- a/components/script/dom/htmltablecellelement.rs +++ b/components/script/dom/htmltablecellelement.rs @@ -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, diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 1f6a681e582..94a0a1e05c0 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -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, diff --git a/components/script/dom/webidls/CSSStyleDeclaration.webidl b/components/script/dom/webidls/CSSStyleDeclaration.webidl index 16fc0c63a6a..85506b8173c 100644 --- a/components/script/dom/webidls/CSSStyleDeclaration.webidl +++ b/components/script/dom/webidls/CSSStyleDeclaration.webidl @@ -99,6 +99,7 @@ partial interface CSSStyleDeclaration { [TreatNullAs=EmptyString] attribute DOMString backfaceVisibility; [TreatNullAs=EmptyString] attribute DOMString direction; + [TreatNullAs=EmptyString] attribute DOMString unicodeBidi; [TreatNullAs=EmptyString] attribute DOMString filter; diff --git a/components/script/dom/webidls/HTMLElement.webidl b/components/script/dom/webidls/HTMLElement.webidl index f4c0376b618..90b11d85bff 100644 --- a/components/script/dom/webidls/HTMLElement.webidl +++ b/components/script/dom/webidls/HTMLElement.webidl @@ -45,5 +45,16 @@ interface HTMLElement : Element { //readonly attribute boolean? commandDisabled; //readonly attribute boolean? commandChecked; }; + +// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-htmlelement-interface +partial interface HTMLElement { + // CSSOM things are not [Pure] because they can flush + readonly attribute Element? offsetParent; + readonly attribute long offsetTop; + readonly attribute long offsetLeft; + readonly attribute long offsetWidth; + readonly attribute long offsetHeight; +}; + HTMLElement implements GlobalEventHandlers; HTMLElement implements ElementCSSInlineStyle; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index d7a9e9f243a..ba86c85b3ac 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -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, 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; @@ -27,7 +27,7 @@ use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::location::Location; use dom::navigator::Navigator; -use dom::node::{window_from_node, TrustedNodeAddress, NodeHelpers}; +use dom::node::{window_from_node, TrustedNodeAddress, NodeHelpers, from_untrusted_node_address}; use dom::performance::Performance; use dom::screen::Screen; use dom::storage::Storage; @@ -72,6 +72,7 @@ use std::cell::{Cell, Ref, RefMut, RefCell}; use std::collections::HashSet; use std::default::Default; use std::ffi::CString; +use std::io::{stdout, Write}; use std::mem as std_mem; use std::rc::Rc; use std::sync::Arc; @@ -80,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. @@ -105,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>, @@ -128,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 @@ -159,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 @@ -193,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 @@ -342,7 +361,10 @@ impl<'a> WindowMethods for &'a Window { // https://html.spec.whatwg.org/#dom-alert fn Alert(self, s: DOMString) { // Right now, just print to the console - println!("ALERT: {}", s); + let stdout = stdout(); + let mut stdout = stdout.lock(); + writeln!(&mut stdout, "ALERT: {}", s).unwrap(); + stdout.flush().unwrap(); } // https://html.spec.whatwg.org/multipage/#dom-window-close @@ -578,6 +600,7 @@ pub trait WindowHelpers { fn client_rect_query(self, node_geometry_request: TrustedNodeAddress) -> Rect<i32>; fn resolved_style_query(self, element: TrustedNodeAddress, pseudo: Option<PseudoElement>, property: &Atom) -> Option<String>; + fn offset_parent_query(self, node: TrustedNodeAddress) -> (Option<Root<Element>>, Rect<Au>); fn handle_reflow_complete_msg(self, reflow_id: u32); fn set_fragment_name(self, fragment: Option<String>); fn steal_fragment_name(self) -> Option<String>; @@ -827,6 +850,27 @@ impl<'a> WindowHelpers for &'a Window { resolved } + fn offset_parent_query(self, node: TrustedNodeAddress) -> (Option<Root<Element>>, Rect<Au>) { + self.reflow(ReflowGoal::ForScriptQuery, + ReflowQueryType::OffsetParentQuery(node), + ReflowReason::Query); + let response = self.layout_rpc.offset_parent(); + let js_runtime = self.js_runtime.borrow(); + let js_runtime = js_runtime.as_ref().unwrap(); + let element = match response.node_address { + Some(parent_node_address) => { + let node = from_untrusted_node_address(js_runtime.rt(), + parent_node_address); + let element = ElementCast::to_ref(node.r()); + element.map(Root::from_ref) + } + None => { + None + } + }; + (element, response.rect) + } + fn handle_reflow_complete_msg(self, reflow_id: u32) { let last_reflow_id = self.last_reflow_id.get(); if last_reflow_id == reflow_id { @@ -1135,6 +1179,7 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason: ReflowQueryType::ContentBoxesQuery(_n) => "\tContentBoxesQuery", ReflowQueryType::NodeGeometryQuery(_n) => "\tNodeGeometryQuery", ReflowQueryType::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery", + ReflowQueryType::OffsetParentQuery(_n) => "\tOffsetParentQuery", }); debug_msg.push_str(match *reason { @@ -1155,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 + } +} diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index daa752052b7..628b1178c32 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -20,6 +20,7 @@ use dom::errorevent::ErrorEvent; use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers}; use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::messageevent::MessageEvent; +use dom::workerglobalscope::WorkerGlobalScopeInit; use script_task::{ScriptChan, ScriptMsg, Runnable}; use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg}; @@ -95,10 +96,17 @@ impl Worker { None => None, }; + let init = WorkerGlobalScopeInit { + resource_task: resource_task, + mem_profiler_chan: global.mem_profiler_chan(), + devtools_chan: global.devtools_chan(), + devtools_sender: optional_sender, + constellation_chan: constellation_chan, + worker_id: worker_id, + }; DedicatedWorkerGlobalScope::run_worker_scope( - worker_url, global.pipeline(), global.mem_profiler_chan(), global.devtools_chan(), - optional_sender, devtools_receiver, worker_ref, resource_task, - constellation_chan, global.script_chan(), sender, receiver, Some(worker_id)); + init, worker_url, global.pipeline(), devtools_receiver, worker_ref, + global.script_chan(), sender, receiver); Ok(worker) } diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 0887b6addcf..550834f7d09 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -37,16 +37,25 @@ 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, } +pub struct WorkerGlobalScopeInit { + pub resource_task: ResourceTask, + pub mem_profiler_chan: mem::ProfilerChan, + pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, + pub devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, + pub constellation_chan: ConstellationChan, + pub worker_id: WorkerId, +} + // https://html.spec.whatwg.org/multipage/#the-workerglobalscope-common-interface #[dom_struct] pub struct WorkerGlobalScope { eventtarget: EventTarget, - worker_id: Option<WorkerId>, + worker_id: WorkerId, worker_url: Url, runtime: Rc<Runtime>, next_worker_id: Cell<WorkerId>, @@ -76,34 +85,29 @@ pub struct WorkerGlobalScope { impl WorkerGlobalScope { pub fn new_inherited(type_id: WorkerGlobalScopeTypeId, + init: WorkerGlobalScopeInit, worker_url: Url, runtime: Rc<Runtime>, - resource_task: ResourceTask, - mem_profiler_chan: mem::ProfilerChan, - devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, - devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, - devtools_receiver: Receiver<DevtoolScriptControlMsg>, - constellation_chan: ConstellationChan, - worker_id: Option<WorkerId>) + devtools_receiver: Receiver<DevtoolScriptControlMsg>) -> WorkerGlobalScope { WorkerGlobalScope { eventtarget: EventTarget::new_inherited(EventTargetTypeId::WorkerGlobalScope(type_id)), next_worker_id: Cell::new(WorkerId(0)), - worker_id: worker_id, + worker_id: init.worker_id, worker_url: worker_url, runtime: runtime, - resource_task: resource_task, + resource_task: init.resource_task, location: Default::default(), navigator: Default::default(), console: Default::default(), crypto: Default::default(), timers: TimerManager::new(), - mem_profiler_chan: mem_profiler_chan, - devtools_chan: devtools_chan, - devtools_sender: devtools_sender, + mem_profiler_chan: init.mem_profiler_chan, + devtools_chan: init.devtools_chan, + devtools_sender: init.devtools_sender, devtools_receiver: devtools_receiver, devtools_wants_updates: Cell::new(false), - constellation_chan: constellation_chan, + constellation_chan: init.constellation_chan, } } @@ -144,7 +148,7 @@ impl WorkerGlobalScope { &self.worker_url } - pub fn get_worker_id(&self) -> Option<WorkerId> { + pub fn get_worker_id(&self) -> WorkerId { self.worker_id.clone() } diff --git a/components/script/dom/xmlhttprequesteventtarget.rs b/components/script/dom/xmlhttprequesteventtarget.rs index 8c17d3c8b1a..6b50898ab27 100644 --- a/components/script/dom/xmlhttprequesteventtarget.rs +++ b/components/script/dom/xmlhttprequesteventtarget.rs @@ -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, diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index 8fcb298880c..a6fb9ad8491 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -104,6 +104,7 @@ pub trait LayoutRPC { fn mouse_over(&self, node: TrustedNodeAddress, point: Point2D<f32>) -> Result<MouseOverResponse, ()>; /// Query layout for the resolved value of a given CSS property fn resolved_style(&self) -> ResolvedStyleResponse; + fn offset_parent(&self) -> OffsetParentResponse; } @@ -116,6 +117,21 @@ pub struct HitTestResponse(pub UntrustedNodeAddress); pub struct MouseOverResponse(pub Vec<UntrustedNodeAddress>); pub struct ResolvedStyleResponse(pub Option<String>); +#[derive(Clone)] +pub struct OffsetParentResponse { + pub node_address: Option<UntrustedNodeAddress>, + pub rect: Rect<Au>, +} + +impl OffsetParentResponse { + pub fn empty() -> OffsetParentResponse { + OffsetParentResponse { + node_address: None, + rect: Rect::zero(), + } + } +} + /// Why we're doing reflow. #[derive(PartialEq, Copy, Clone, Debug)] pub enum ReflowGoal { @@ -133,6 +149,7 @@ pub enum ReflowQueryType { ContentBoxesQuery(TrustedNodeAddress), NodeGeometryQuery(TrustedNodeAddress), ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, Atom), + OffsetParentQuery(TrustedNodeAddress), } /// Information needed for a reflow. diff --git a/components/script/lib.rs b/components/script/lib.rs index 47dadf0d956..8fc23dc78b4 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -84,6 +84,7 @@ pub mod dom; pub mod parse; pub mod layout_interface; +mod mem; mod network_listener; pub mod page; pub mod script_task; diff --git a/components/script/mem.rs b/components/script/mem.rs new file mode 100644 index 00000000000..6dbd45e5b8a --- /dev/null +++ b/components/script/mem.rs @@ -0,0 +1,36 @@ +/* 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/. */ + +//! Routines for handling measuring the memory usage of arbitrary DOM nodes. + +use dom::bindings::codegen::InheritTypes::{DocumentCast, WindowCast, CharacterDataCast, NodeCast}; +use dom::eventtarget::{EventTarget, EventTargetTypeId}; +use dom::node::NodeTypeId; +use libc; +use util::mem::{HeapSizeOf, heap_size_of}; + +// This is equivalent to measuring a Box<T>, except that DOM objects lose their +// associated box in order to stash their pointers in a reserved slot of their +// JS reflector. It is assumed that the caller passes a pointer to the most-derived +// type that this pointer represents, or the actual heap usage of the pointee will +// be under-reported. +fn heap_size_of_self_and_children<T: HeapSizeOf>(obj: &T) -> usize { + heap_size_of(obj as *const T as *const libc::c_void) + obj.heap_size_of_children() +} + +pub fn heap_size_of_eventtarget(target: &EventTarget) -> usize { + //TODO: add more specific matches for concrete element types as derive(HeapSizeOf) is + // added to each one. + match target.type_id() { + &EventTargetTypeId::Window => + heap_size_of_self_and_children(WindowCast::to_ref(target).unwrap()), + &EventTargetTypeId::Node(NodeTypeId::CharacterData(_)) => + heap_size_of_self_and_children(CharacterDataCast::to_ref(target).unwrap()), + &EventTargetTypeId::Node(NodeTypeId::Document) => + heap_size_of_self_and_children(DocumentCast::to_ref(target).unwrap()), + &EventTargetTypeId::Node(_) => + heap_size_of_self_and_children(NodeCast::to_ref(target).unwrap()), + _ => 0, + } +} diff --git a/components/script/page.rs b/components/script/page.rs index 1286a1427f1..f4b3fd6cd18 100644 --- a/components/script/page.rs +++ b/components/script/page.rs @@ -13,7 +13,7 @@ use std::cell::Cell; use std::rc::Rc; /// Encapsulates a handle to a frame in a frame tree. -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] #[allow(unrooted_must_root)] // FIXME(#6687) this is wrong pub struct Page { /// Pipeline id associated with this page. @@ -127,7 +127,7 @@ impl Page { } /// Information for one frame in the browsing context. -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] #[must_root] pub struct Frame { /// The document for this frame. diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 279ff364bda..b3ea5b16818 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -46,6 +46,7 @@ use dom::worker::TrustedWorkerAddress; use parse::html::{ParseContext, parse_html}; use layout_interface::{self, NewLayoutTaskInfo, ScriptLayoutChan, LayoutChan, ReflowGoal}; use layout_interface::{ReflowQueryType}; +use mem::heap_size_of_eventtarget; use network_listener::NetworkListener; use page::{Page, IterablePage, Frame}; use timers::TimerId; @@ -1104,11 +1105,28 @@ impl ScriptTask { fn collect_reports(&self, reports_chan: ReportsChan) { let mut urls = vec![]; + let mut dom_tree_size = 0; + let mut reports = vec![]; for it_page in self.root_page().iter() { - urls.push(it_page.document().url().serialize()); + let current_url = it_page.document().url().serialize(); + urls.push(current_url.clone()); + + for child in NodeCast::from_ref(&*it_page.document()).traverse_preorder() { + let target = EventTargetCast::from_ref(&*child); + dom_tree_size += heap_size_of_eventtarget(target); + } + let window = it_page.window(); + let target = EventTargetCast::from_ref(&*window); + dom_tree_size += heap_size_of_eventtarget(target); + + reports.push(Report { + path: path![format!("url({})", current_url), "dom-tree"], + kind: ReportKind::ExplicitJemallocHeapSize, + size: dom_tree_size, + }) } let path_seg = format!("url({})", urls.join(", ")); - let reports = ScriptTask::get_reports(self.get_cx(), path_seg); + reports.extend(ScriptTask::get_reports(self.get_cx(), path_seg)); reports_chan.send(reports); } diff --git a/components/script/timers.rs b/components/script/timers.rs index 0a0a37e0a7a..ac7142914ad 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -13,6 +13,7 @@ use dom::window::ScriptHelpers; use script_task::{ScriptChan, ScriptMsg, TimerSource}; use horribly_inefficient_timers; +use util::mem::HeapSizeOf; use util::task::spawn_named; use util::str::DOMString; @@ -29,14 +30,15 @@ use std::hash::{Hash, Hasher}; use std::rc::Rc; use std::default::Default; -#[derive(JSTraceable, PartialEq, Eq, Copy, Clone)] +#[derive(JSTraceable, PartialEq, Eq, Copy, Clone, HeapSizeOf)] pub struct TimerId(i32); -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] #[privatize] struct TimerHandle { handle: TimerId, data: TimerData, + #[ignore_heap_size_of = "channels are hard"] control_chan: Option<Sender<TimerControlMsg>>, } @@ -46,6 +48,13 @@ pub enum TimerCallback { FunctionTimerCallback(Rc<Function>) } +impl HeapSizeOf for TimerCallback { + 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 Hash for TimerId { fn hash<H: Hasher>(&self, state: &mut H) { let TimerId(id) = *self; @@ -65,7 +74,7 @@ impl TimerHandle { } } -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] #[privatize] pub struct TimerManager { active_timers: DOMRefCell<HashMap<TimerId, TimerHandle>>, @@ -82,7 +91,7 @@ impl Drop for TimerManager { } // Enum allowing more descriptive values for the is_interval field -#[derive(JSTraceable, PartialEq, Copy, Clone)] +#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)] pub enum IsInterval { Interval, NonInterval, @@ -100,7 +109,7 @@ pub enum TimerControlMsg { // (ie. function value to invoke and all arguments to pass // to the function when calling it) // TODO: Handle rooting during fire_timer when movable GC is turned on -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] #[privatize] struct TimerData { is_interval: IsInterval, |