servo: Merge #18059 - Using OnceCell<T> from Mitochondria (from sendilkumarn:mito); r=nox
authorsendilkumarn <sendilkumarn@live.com>
Thu, 21 Sep 2017 13:20:29 -0500
changeset 435489 3c6f413d3326197966c99f80c7097229e3d30d22
parent 435488 05569ef2d175e7b3814141af3cd8085ce0898ecf
child 435490 953afb698050792f6c3cde4e9fab84f8c6bf8450
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnox
milestone58.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
servo: Merge #18059 - Using OnceCell<T> from Mitochondria (from sendilkumarn:mito); r=nox <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #13402 (github issue number if applicable). <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 5c797d194346d5be3c55da51d82bfcd1031a51f5
servo/Cargo.lock
servo/components/script/Cargo.toml
servo/components/script/dom/bindings/js.rs
servo/components/script/dom/htmlformelement.rs
servo/components/script/lib.rs
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -1870,16 +1870,21 @@ source = "registry+https://github.com/ru
 dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "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"
 source = "git+https://github.com/servo/mozjs#834ce35c3f008010213351107b68f397989d2ffd"
 dependencies = [
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -2592,16 +2597,17 @@ dependencies = [
  "js 0.1.6 (git+https://github.com/servo/rust-mozjs)",
  "jstraceable_derive 0.0.1",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "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)",
  "offscreen_gl_context 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3906,16 +3912,17 @@ dependencies = [
 "checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1"
 "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
 "checksum metadeps 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829fffe7ea1d747e23f64be972991bc516b2f1ac2ae4a3b33d8bea150c410151"
 "checksum mime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9d69889cdc6336ed56b174514ce876c4c3dc564cc23dd872e7bca589bb2a36c8"
 "checksum mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76da6df85047af8c0edfa53f48eb1073012ce1cc95c8fedc0a374f659a89dd65"
 "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)" = "<none>"
 "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"
 "checksum multistr 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "90fb6e1b4f6ca2f2098a437e1c7f09c122da62bbf2bde45b3693defc1eb61e2d"
 "checksum net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "bc01404e7568680f1259aa5729539f221cb1e6d047a0d9053cab4be8a73b5d67"
 "checksum nodrop 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbadd3f4c98dea0bd3d9b4be4c0cdaf1ab57035cb2e41fce3983db5add7cc5"
 "checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
 "checksum num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ef1a4bf6f9174aa5783a9b4cc892cacd11aebad6c69ad027a0b65c6ca5f8aa37"
--- a/servo/components/script/Cargo.toml
+++ b/servo/components/script/Cargo.toml
@@ -51,16 +51,17 @@ hyper_serde = "0.7"
 image = "0.12"
 ipc-channel = "0.8"
 js = {git = "https://github.com/servo/rust-mozjs", features = ["promises"]}
 jstraceable_derive = {path = "../jstraceable_derive"}
 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"}
 net_traits = {path = "../net_traits"}
 num-traits = "0.1.32"
 offscreen_gl_context = { version = "0.11", features = ["serde"] }
 open = "1.1.1"
 parking_lot = "0.4"
--- a/servo/components/script/dom/bindings/js.rs
+++ b/servo/components/script/dom/bindings/js.rs
@@ -27,16 +27,17 @@ use core::nonzero::NonZero;
 use dom::bindings::conversions::DerivedFrom;
 use dom::bindings::inheritance::Castable;
 use dom::bindings::reflector::{DomObject, Reflector};
 use dom::bindings::trace::JSTraceable;
 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;
 use std::default::Default;
 use std::hash::{Hash, Hasher};
 #[cfg(debug_assertions)]
 use std::intrinsics::type_name;
 use std::mem;
@@ -386,16 +387,65 @@ impl<T: DomObject> Default for MutNullab
 
 impl<T: DomObject> HeapSizeOf for MutNullableJS<T> {
     fn heap_size_of_children(&self) -> usize {
         // See comment on HeapSizeOf for JS<T>.
         0
     }
 }
 
+/// A holder that allows to lazily initialize the value only once
+/// `JS<T>`, using OnceCell
+/// Essentially a `OnceCell<JS<T>>`.
+///
+/// This should only be used as a field in other DOM objects; see warning
+/// on `JS<T>`.
+#[must_root]
+pub struct OnceCellJS<T: DomObject> {
+    ptr: OnceCell<JS<T>>,
+}
+
+impl<T: DomObject> OnceCellJS<T> {
+    /// 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<F>(&self, cb: F) -> &T
+        where F: FnOnce() -> Root<T>
+    {
+        debug_assert!(thread_state::get().is_script());
+        &self.ptr.init_once(|| JS::from_ref(&cb()))
+    }
+}
+
+impl<T: DomObject> Default for OnceCellJS<T> {
+    #[allow(unrooted_must_root)]
+    fn default() -> OnceCellJS<T> {
+        debug_assert!(thread_state::get().is_script());
+        OnceCellJS {
+            ptr: OnceCell::new(),
+        }
+    }
+}
+
+impl<T: DomObject> HeapSizeOf for OnceCellJS<T> {
+    fn heap_size_of_children(&self) -> usize {
+        // See comment on HeapSizeOf for JS<T>.
+        0
+    }
+}
+
+#[allow(unrooted_must_root)]
+unsafe impl<T: DomObject> JSTraceable for OnceCellJS<T> {
+    unsafe fn trace(&self, trc: *mut JSTracer) {
+        if let Some(ptr) = self.ptr.as_ref() {
+            ptr.trace(trc);
+        }
+    }
+}
+
 impl<T: DomObject> LayoutJS<T> {
     /// 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
     /// this is unsafe is what necessitates the layout wrappers.)
     pub unsafe fn unsafe_get(&self) -> *const T {
         debug_assert!(thread_state::get().is_layout());
         self.ptr.get()
     }
--- a/servo/components/script/dom/htmlformelement.rs
+++ b/servo/components/script/dom/htmlformelement.rs
@@ -8,17 +8,17 @@ use dom::bindings::codegen::Bindings::Do
 use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
 use dom::bindings::codegen::Bindings::HTMLButtonElementBinding::HTMLButtonElementMethods;
 use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding::HTMLFormControlsCollectionMethods;
 use dom::bindings::codegen::Bindings::HTMLFormElementBinding;
 use dom::bindings::codegen::Bindings::HTMLFormElementBinding::HTMLFormElementMethods;
 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;
 use dom::blob::Blob;
 use dom::document::Document;
 use dom::element::{AttributeMutation, Element};
 use dom::eventtarget::EventTarget;
 use dom::file::File;
@@ -59,17 +59,17 @@ use task_source::TaskSource;
 
 #[derive(Clone, Copy, HeapSizeOf, JSTraceable, PartialEq)]
 pub struct GenerationId(u32);
 
 #[dom_struct]
 pub struct HTMLFormElement {
     htmlelement: HTMLElement,
     marked_for_reset: Cell<bool>,
-    elements: MutNullableJS<HTMLFormControlsCollection>,
+    elements: OnceCellJS<HTMLFormControlsCollection>,
     generation_id: Cell<GenerationId>,
     controls: DOMRefCell<Vec<JS<Element>>>,
 }
 
 impl HTMLFormElement {
     fn new_inherited(local_name: LocalName,
                      prefix: Option<Prefix>,
                      document: &Document) -> HTMLFormElement {
@@ -161,20 +161,16 @@ impl HTMLFormElementMethods for HTMLForm
 
     // https://html.spec.whatwg.org/multipage/#dom-form-reset
     fn Reset(&self) {
         self.reset(ResetFrom::FromForm);
     }
 
     // https://html.spec.whatwg.org/multipage/#dom-form-elements
     fn Elements(&self) -> Root<HTMLFormControlsCollection> {
-        if let Some(elements) = self.elements.get() {
-            return elements;
-        }
-
         #[derive(HeapSizeOf, JSTraceable)]
         struct ElementsFilter {
             form: Root<HTMLFormElement>
         }
         impl CollectionFilter for ElementsFilter {
             fn filter<'a>(&self, elem: &'a Element, _root: &'a Node) -> bool {
                 let form_owner = match elem.upcast::<Node>().type_id() {
                     NodeTypeId::Element(ElementTypeId::HTMLElement(t)) => {
@@ -215,21 +211,21 @@ impl HTMLFormElementMethods for HTMLForm
                 };
 
                 match form_owner {
                     Some(form_owner) => form_owner == self.form,
                     None => false,
                 }
             }
         }
-        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
     fn Length(&self) -> u32 {
         self.Elements().Length() as u32
     }
 
     // https://html.spec.whatwg.org/multipage/#dom-form-item
--- a/servo/components/script/lib.rs
+++ b/servo/components/script/lib.rs
@@ -65,16 +65,17 @@ extern crate jstraceable_derive;
 extern crate lazy_static;
 extern crate libc;
 #[macro_use]
 extern crate log;
 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;
 extern crate offscreen_gl_context;
 extern crate open;
 extern crate parking_lot;
 extern crate phf;
 #[macro_use]