aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock7
-rw-r--r--components/script/Cargo.toml1
-rw-r--r--components/script/dom/bindings/js.rs50
-rwxr-xr-xcomponents/script/dom/htmlformelement.rs18
-rw-r--r--components/script/lib.rs1
5 files changed, 66 insertions, 11 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 489a7fabaf3..3e11bf9e8d8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1856,6 +1856,11 @@ dependencies = [
]
[[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"
@@ -2570,6 +2575,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)",
@@ -3872,6 +3878,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)" = "<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"
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml
index b2f5bfd40c2..d1c8e6dbc03 100644
--- a/components/script/Cargo.toml
+++ b/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/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs
index abfd9f47eff..976665e4850 100644
--- a/components/script/dom/bindings/js.rs
+++ b/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<T: DomObject> HeapSizeOf for MutNullableJS<T> {
}
}
+/// 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
diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs
index 34ce7c25ec1..c3a56954ea5 100755
--- a/components/script/dom/htmlformelement.rs
+++ b/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;
@@ -66,7 +66,7 @@ pub struct GenerationId(u32);
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>>>,
}
@@ -168,10 +168,6 @@ impl HTMLFormElementMethods for HTMLFormElement {
// 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>
@@ -222,11 +218,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/components/script/lib.rs b/components/script/lib.rs
index 5ba671440bd..941ac2bedd2 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -68,6 +68,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;