diff --git a/servo/Cargo.lock b/servo/Cargo.lock index aec56362afe2..7ea3506776df 100644 --- a/servo/Cargo.lock +++ b/servo/Cargo.lock @@ -1874,6 +1874,11 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mitochondria" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "mozjs_sys" version = "0.0.0" @@ -2597,6 +2602,7 @@ dependencies = [ "metrics 0.0.1", "mime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "net_traits 0.0.1", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3911,6 +3917,7 @@ dependencies = [ "checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726" "checksum mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9e965267d4d58496fc4f740e9861118367f13570cadf66316ed2c3f2f14d87c7" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9de3eca27871df31c33b807f834b94ef7d000956f57aa25c5aed9c5f0aae8f6f" "checksum mozjs_sys 0.0.0 (git+https://github.com/servo/mozjs)" = "" "checksum mp3-metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2f61cf32f7fc3cec83a15a255ac60bceb6cac59a7ce190cb824ca25c0fce0feb" "checksum mp4parse 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b81651f9ede53d59281b54c7eb51ae50a868ac4765dd3bdfbbc79ce3d8aca7a" diff --git a/servo/components/script/Cargo.toml b/servo/components/script/Cargo.toml index 43f85a4e9708..edb5b7239d0d 100644 --- a/servo/components/script/Cargo.toml +++ b/servo/components/script/Cargo.toml @@ -56,6 +56,7 @@ lazy_static = "0.2" libc = "0.2" log = "0.3.5" metrics = {path = "../metrics"} +mitochondria = "1.1.2" mime = "0.2.1" mime_guess = "1.8.0" msg = {path = "../msg"} diff --git a/servo/components/script/dom/bindings/js.rs b/servo/components/script/dom/bindings/js.rs index abfd9f47eff1..976665e48500 100644 --- a/servo/components/script/dom/bindings/js.rs +++ b/servo/components/script/dom/bindings/js.rs @@ -32,6 +32,7 @@ use dom::bindings::trace::trace_reflector; use dom::node::Node; use heapsize::HeapSizeOf; use js::jsapi::{JSObject, JSTracer}; +use mitochondria::OnceCell; use script_layout_interface::TrustedNodeAddress; use script_thread::STACK_ROOTS; use std::cell::UnsafeCell; @@ -391,6 +392,55 @@ impl HeapSizeOf for MutNullableJS { } } +/// A holder that allows to lazily initialize the value only once +/// `JS`, using OnceCell +/// Essentially a `OnceCell>`. +/// +/// This should only be used as a field in other DOM objects; see warning +/// on `JS`. +#[must_root] +pub struct OnceCellJS { + ptr: OnceCell>, +} + +impl OnceCellJS { + /// Retrieve a copy of the current inner value. If it is `None`, it is + /// initialized with the result of `cb` first. + #[allow(unrooted_must_root)] + pub fn init_once(&self, cb: F) -> &T + where F: FnOnce() -> Root + { + debug_assert!(thread_state::get().is_script()); + &self.ptr.init_once(|| JS::from_ref(&cb())) + } +} + +impl Default for OnceCellJS { + #[allow(unrooted_must_root)] + fn default() -> OnceCellJS { + debug_assert!(thread_state::get().is_script()); + OnceCellJS { + ptr: OnceCell::new(), + } + } +} + +impl HeapSizeOf for OnceCellJS { + fn heap_size_of_children(&self) -> usize { + // See comment on HeapSizeOf for JS. + 0 + } +} + +#[allow(unrooted_must_root)] +unsafe impl JSTraceable for OnceCellJS { + unsafe fn trace(&self, trc: *mut JSTracer) { + if let Some(ptr) = self.ptr.as_ref() { + ptr.trace(trc); + } + } +} + impl LayoutJS { /// Returns an unsafe pointer to the interior of this JS object. This is /// the only method that be safely accessed from layout. (The fact that diff --git a/servo/components/script/dom/htmlformelement.rs b/servo/components/script/dom/htmlformelement.rs index f396bc51715a..9b63d1fca667 100755 --- a/servo/components/script/dom/htmlformelement.rs +++ b/servo/components/script/dom/htmlformelement.rs @@ -13,7 +13,7 @@ use dom::bindings::codegen::Bindings::HTMLFormElementBinding::HTMLFormElementMet use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods; use dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId}; -use dom::bindings::js::{JS, MutNullableJS, Root, RootedReference}; +use dom::bindings::js::{JS, OnceCellJS, Root, RootedReference}; use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::DomObject; use dom::bindings::str::DOMString; @@ -64,7 +64,7 @@ pub struct GenerationId(u32); pub struct HTMLFormElement { htmlelement: HTMLElement, marked_for_reset: Cell, - elements: MutNullableJS, + elements: OnceCellJS, generation_id: Cell, controls: DOMRefCell>>, } @@ -166,10 +166,6 @@ impl HTMLFormElementMethods for HTMLFormElement { // https://html.spec.whatwg.org/multipage/#dom-form-elements fn Elements(&self) -> Root { - if let Some(elements) = self.elements.get() { - return elements; - } - #[derive(HeapSizeOf, JSTraceable)] struct ElementsFilter { form: Root @@ -220,11 +216,11 @@ impl HTMLFormElementMethods for HTMLFormElement { } } } - let filter = box ElementsFilter { form: Root::from_ref(self) }; - let window = window_from_node(self); - let elements = HTMLFormControlsCollection::new(&window, self.upcast(), filter); - self.elements.set(Some(&elements)); - elements + Root::from_ref(self.elements.init_once(|| { + let filter = box ElementsFilter { form: Root::from_ref(self) }; + let window = window_from_node(self); + HTMLFormControlsCollection::new(&window, self.upcast(), filter) + })) } // https://html.spec.whatwg.org/multipage/#dom-form-length diff --git a/servo/components/script/lib.rs b/servo/components/script/lib.rs index 19047b7a59d2..3c0946c5c2ce 100644 --- a/servo/components/script/lib.rs +++ b/servo/components/script/lib.rs @@ -70,6 +70,7 @@ extern crate metrics; #[macro_use] extern crate mime; extern crate mime_guess; +extern crate mitochondria; extern crate msg; extern crate net_traits; extern crate num_traits;