aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/refcounted.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/bindings/refcounted.rs')
-rw-r--r--components/script/dom/bindings/refcounted.rs149
1 files changed, 99 insertions, 50 deletions
diff --git a/components/script/dom/bindings/refcounted.rs b/components/script/dom/bindings/refcounted.rs
index dcf11626543..ab7aea3e922 100644
--- a/components/script/dom/bindings/refcounted.rs
+++ b/components/script/dom/bindings/refcounted.rs
@@ -1,6 +1,6 @@
/* 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/. */
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! A generic, safe mechanism by which DOM objects can be pinned and transferred
//! between threads (or intra-thread for asynchronous events). Akin to Gecko's
@@ -11,7 +11,7 @@
//! To guarantee the lifetime of a DOM object when performing asynchronous operations,
//! obtain a `Trusted<T>` from that object and pass it along with each operation.
//! A usable pointer to the original DOM object can be obtained on the script thread
-//! from a `Trusted<T>` via the `to_temporary` method.
+//! from a `Trusted<T>` via the `root` method.
//!
//! The implementation of `Trusted<T>` is as follows:
//! The `Trusted<T>` object contains an atomic reference counted pointer to the Rust DOM object.
@@ -22,41 +22,43 @@
//! its hash table during the next GC. During GC, the entries of the hash table are counted
//! as JS roots.
-use core::nonzero::NonZero;
-use dom::bindings::js::Root;
-use dom::bindings::reflector::{DomObject, Reflector};
-use dom::bindings::trace::trace_reflector;
-use dom::promise::Promise;
+use crate::dom::bindings::conversions::ToJSValConvertible;
+use crate::dom::bindings::error::Error;
+use crate::dom::bindings::reflector::{DomObject, Reflector};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::trace::trace_reflector;
+use crate::dom::promise::Promise;
+use crate::task::TaskOnce;
use js::jsapi::JSTracer;
-use libc;
use std::cell::RefCell;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::hash_map::HashMap;
use std::hash::Hash;
use std::marker::PhantomData;
-use std::os;
use std::rc::Rc;
use std::sync::{Arc, Weak};
-
-#[allow(missing_docs)] // FIXME
-mod dummy { // Attributes don’t apply through the macro.
+#[allow(missing_docs)] // FIXME
+mod dummy {
+ // Attributes don’t apply through the macro.
+ use super::LiveDOMReferences;
use std::cell::RefCell;
use std::rc::Rc;
- use super::LiveDOMReferences;
thread_local!(pub static LIVE_REFERENCES: Rc<RefCell<Option<LiveDOMReferences>>> =
Rc::new(RefCell::new(None)));
}
pub use self::dummy::LIVE_REFERENCES;
-
/// A pointer to a Rust DOM object that needs to be destroyed.
-pub struct TrustedReference(*const libc::c_void);
+struct TrustedReference(*const libc::c_void);
unsafe impl Send for TrustedReference {}
impl TrustedReference {
- fn new<T: DomObject>(ptr: *const T) -> TrustedReference {
- TrustedReference(ptr as *const libc::c_void)
+ /// Creates a new TrustedReference from a pointer to a value that impements DOMObject.
+ /// This is not enforced by the type system to reduce duplicated generic code,
+ /// which is acceptable since this method is internal to this module.
+ unsafe fn new(ptr: *const libc::c_void) -> TrustedReference {
+ TrustedReference(ptr)
}
}
@@ -92,41 +94,72 @@ impl TrustedPromise {
/// Obtain a usable DOM Promise from a pinned `TrustedPromise` value. Fails if used on
/// a different thread than the original value from which this `TrustedPromise` was
/// obtained.
- #[allow(unrooted_must_root)]
pub fn root(self) -> Rc<Promise> {
LIVE_REFERENCES.with(|ref r| {
let r = r.borrow();
let live_references = r.as_ref().unwrap();
- assert!(self.owner_thread == (&*live_references) as *const _ as *const libc::c_void);
+ assert_eq!(
+ self.owner_thread,
+ (&*live_references) as *const _ as *const libc::c_void
+ );
// Borrow-check error requires the redundant `let promise = ...; promise` here.
- let promise = match live_references.promise_table.borrow_mut().entry(self.dom_object) {
+ let promise = match live_references
+ .promise_table
+ .borrow_mut()
+ .entry(self.dom_object)
+ {
Occupied(mut entry) => {
let promise = {
let promises = entry.get_mut();
- promises.pop().expect("rooted promise list unexpectedly empty")
+ promises
+ .pop()
+ .expect("rooted promise list unexpectedly empty")
};
if entry.get().is_empty() {
entry.remove();
}
promise
- }
+ },
Vacant(_) => unreachable!(),
};
promise
})
}
+
+ /// A task which will reject the promise.
+ #[allow(unrooted_must_root)]
+ pub fn reject_task(self, error: Error) -> impl TaskOnce {
+ let this = self;
+ task!(reject_promise: move || {
+ debug!("Rejecting promise.");
+ this.root().reject_error(error);
+ })
+ }
+
+ /// A task which will resolve the promise.
+ #[allow(unrooted_must_root)]
+ pub fn resolve_task<T>(self, value: T) -> impl TaskOnce
+ where
+ T: ToJSValConvertible + Send,
+ {
+ let this = self;
+ task!(resolve_promise: move || {
+ debug!("Resolving promise.");
+ this.root().resolve_native(&value);
+ })
+ }
}
/// A safe wrapper around a raw pointer to a DOM object that can be
/// shared among threads for use in asynchronous operations. The underlying
/// DOM object is guaranteed to live at least as long as the last outstanding
/// `Trusted<T>` instance.
-#[allow_unrooted_interior]
+#[unrooted_must_root_lint::allow_unrooted_interior]
pub struct Trusted<T: DomObject> {
/// A pointer to the Rust DOM object of type T, but void to allow
/// sending `Trusted<T>` between threads, regardless of T's sendability.
refcount: Arc<TrustedReference>,
- owner_thread: *const libc::c_void,
+ owner_thread: *const LiveDOMReferences,
phantom: PhantomData<T>,
}
@@ -137,30 +170,38 @@ impl<T: DomObject> Trusted<T> {
/// be prevented from being GCed for the duration of the resulting `Trusted<T>` object's
/// lifetime.
pub fn new(ptr: &T) -> Trusted<T> {
- LIVE_REFERENCES.with(|ref r| {
- let r = r.borrow();
- let live_references = r.as_ref().unwrap();
- let refcount = live_references.addref(&*ptr as *const T);
- Trusted {
- refcount: refcount,
- owner_thread: (&*live_references) as *const _ as *const libc::c_void,
- phantom: PhantomData,
- }
- })
+ fn add_live_reference(
+ ptr: *const libc::c_void,
+ ) -> (Arc<TrustedReference>, *const LiveDOMReferences) {
+ LIVE_REFERENCES.with(|ref r| {
+ let r = r.borrow();
+ let live_references = r.as_ref().unwrap();
+ let refcount = unsafe { live_references.addref(ptr) };
+ (refcount, live_references as *const _)
+ })
+ }
+
+ let (refcount, owner_thread) = add_live_reference(ptr as *const T as *const _);
+ Trusted {
+ refcount,
+ owner_thread,
+ phantom: PhantomData,
+ }
}
/// Obtain a usable DOM pointer from a pinned `Trusted<T>` value. Fails if used on
/// a different thread than the original value from which this `Trusted<T>` was
/// obtained.
- pub fn root(&self) -> Root<T> {
- assert!(LIVE_REFERENCES.with(|ref r| {
- let r = r.borrow();
- let live_references = r.as_ref().unwrap();
- self.owner_thread == (&*live_references) as *const _ as *const libc::c_void
- }));
- unsafe {
- Root::new(NonZero::new(self.refcount.0 as *const T))
+ pub fn root(&self) -> DomRoot<T> {
+ fn validate(owner_thread: *const LiveDOMReferences) {
+ assert!(LIVE_REFERENCES.with(|ref r| {
+ let r = r.borrow();
+ let live_references = r.as_ref().unwrap();
+ owner_thread == live_references
+ }));
}
+ validate(self.owner_thread);
+ unsafe { DomRoot::from_ref(&*(self.refcount.0 as *const T)) }
}
}
@@ -194,13 +235,22 @@ impl LiveDOMReferences {
});
}
+ pub fn destruct() {
+ LIVE_REFERENCES.with(|ref r| {
+ *r.borrow_mut() = None;
+ });
+ }
+
#[allow(unrooted_must_root)]
fn addref_promise(&self, promise: Rc<Promise>) {
let mut table = self.promise_table.borrow_mut();
table.entry(&*promise).or_insert(vec![]).push(promise)
}
- fn addref<T: DomObject>(&self, ptr: *const T) -> Arc<TrustedReference> {
+ /// ptr must be a pointer to a type that implements DOMObject.
+ /// This is not enforced by the type system to reduce duplicated generic code,
+ /// which is acceptable since this method is internal to this module.
+ unsafe fn addref(&self, ptr: *const libc::c_void) -> Arc<TrustedReference> {
let mut table = self.reflectable_table.borrow_mut();
let capacity = table.capacity();
let len = table.len();
@@ -209,7 +259,7 @@ impl LiveDOMReferences {
remove_nulls(&mut table);
table.reserve(len);
}
- match table.entry(ptr as *const libc::c_void) {
+ match table.entry(ptr) {
Occupied(mut entry) => match entry.get().upgrade() {
Some(refcount) => refcount,
None => {
@@ -222,15 +272,15 @@ impl LiveDOMReferences {
let refcount = Arc::new(TrustedReference::new(ptr));
entry.insert(Arc::downgrade(&refcount));
refcount
- }
+ },
}
}
}
/// Remove null entries from the live references table
-fn remove_nulls<K: Eq + Hash + Clone, V> (table: &mut HashMap<K, Weak<V>>) {
- let to_remove: Vec<K> =
- table.iter()
+fn remove_nulls<K: Eq + Hash + Clone, V>(table: &mut HashMap<K, Weak<V>>) {
+ let to_remove: Vec<K> = table
+ .iter()
.filter(|&(_, value)| Weak::upgrade(value).is_none())
.map(|(key, _)| key.clone())
.collect();
@@ -242,8 +292,7 @@ fn remove_nulls<K: Eq + Hash + Clone, V> (table: &mut HashMap<K, Weak<V>>) {
/// A JSTraceDataOp for tracing reflectors held in LIVE_REFERENCES
#[allow(unrooted_must_root)]
-pub unsafe extern "C" fn trace_refcounted_objects(tracer: *mut JSTracer,
- _data: *mut os::raw::c_void) {
+pub unsafe fn trace_refcounted_objects(tracer: *mut JSTracer) {
info!("tracing live refcounted references");
LIVE_REFERENCES.with(|ref r| {
let r = r.borrow();