aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/root.rs
diff options
context:
space:
mode:
authorAnthony Ramine <n.oxyde@gmail.com>2017-09-28 14:51:23 +0200
committerAnthony Ramine <n.oxyde@gmail.com>2017-09-28 15:42:43 +0200
commitdee38475b8da91ad2cea9f40a425fcab5e3ab70b (patch)
treee46416f270cc952b0e7196d3b1a599697779ccfa /components/script/dom/bindings/root.rs
parent7574d2647699e211638379f8f89760c57a1d6cc8 (diff)
downloadservo-dee38475b8da91ad2cea9f40a425fcab5e3ab70b.tar.gz
servo-dee38475b8da91ad2cea9f40a425fcab5e3ab70b.zip
Make DomRoot<T> a type alias of a more general Root<T> type
This Root<T> relies on the concept of a stable trace object, which doesn't move for the whole lifetime of the T value. For safety reasons, T must be 'static. The only implementor of StableTraceObject for now is Dom<T>.
Diffstat (limited to 'components/script/dom/bindings/root.rs')
-rw-r--r--components/script/dom/bindings/root.rs166
1 files changed, 107 insertions, 59 deletions
diff --git a/components/script/dom/bindings/root.rs b/components/script/dom/bindings/root.rs
index cbab8951184..5aaa806ceaf 100644
--- a/components/script/dom/bindings/root.rs
+++ b/components/script/dom/bindings/root.rs
@@ -11,6 +11,7 @@
//!
//! Here is a brief overview of the important types:
//!
+//! - `Root<T>`: a stack-based rooted value.
//! - `DomRoot<T>`: a stack-based reference to a rooted DOM object.
//! - `Dom<T>`: a reference to a DOM object that can automatically be traced by
//! the GC when encountered as a field of a Rust structure.
@@ -47,21 +48,89 @@ use std::ptr;
use std::rc::Rc;
use style::thread_state;
-/// A rooted reference to a DOM object.
-///
-/// The JS value is pinned for the duration of this object's lifetime; roots
-/// are additive, so this object's destruction will not invalidate other roots
-/// for the same JS value. `Root`s cannot outlive the associated
-/// `RootCollection` object.
+/// A rooted value.
#[allow(unrooted_must_root)]
#[allow_unrooted_interior]
-pub struct DomRoot<T: DomObject> {
- /// Reference to rooted value that must not outlive this container
- ptr: Dom<T>,
+pub struct Root<T: StableTraceObject> {
+ /// The value to root.
+ value: T,
/// List that ensures correct dynamic root ordering
root_list: *const RootCollection,
}
+impl<T> Root<T>
+where
+ T: StableTraceObject + 'static,
+{
+ /// Create a new stack-bounded root for the provided value.
+ /// It cannot outlive its associated `RootCollection`, and it gives
+ /// out references which cannot outlive this new `Root`.
+ #[allow(unrooted_must_root)]
+ unsafe fn new(value: T) -> Self {
+ debug_assert!(thread_state::get().is_script());
+ STACK_ROOTS.with(|ref root_list| {
+ let root_list = &*root_list.get().unwrap();
+ root_list.root(value.stable_trace_object());
+ Root { value, root_list }
+ })
+ }
+}
+
+/// Represents values that can be rooted through a stable address that will
+/// not change for their whole lifetime.
+pub unsafe trait StableTraceObject {
+ /// Returns a stable trace object which address won't change for the whole
+ /// lifetime of the value.
+ fn stable_trace_object(&self) -> *const JSTraceable;
+}
+
+unsafe impl<T> StableTraceObject for Dom<T>
+where
+ T: DomObject,
+{
+ fn stable_trace_object<'a>(&'a self) -> *const JSTraceable {
+ // The JSTraceable impl for Reflector doesn't actually do anything,
+ // so we need this shenanigan to actually trace the reflector of the
+ // T pointer in Dom<T>.
+ #[allow(unrooted_must_root)]
+ struct ReflectorStackRoot(Reflector);
+ unsafe impl JSTraceable for ReflectorStackRoot {
+ unsafe fn trace(&self, tracer: *mut JSTracer) {
+ trace_reflector(tracer, "on stack", &self.0);
+ }
+ }
+ unsafe {
+ &*(self.reflector() as *const Reflector as *const ReflectorStackRoot)
+ }
+ }
+}
+
+impl<T> Deref for Root<T>
+where
+ T: Deref + StableTraceObject,
+{
+ type Target = <T as Deref>::Target;
+
+ fn deref(&self) -> &Self::Target {
+ debug_assert!(thread_state::get().is_script());
+ &self.value
+ }
+}
+
+impl<T> Drop for Root<T>
+where
+ T: StableTraceObject,
+{
+ fn drop(&mut self) {
+ unsafe {
+ (*self.root_list).unroot(self.value.stable_trace_object());
+ }
+ }
+}
+
+/// A rooted reference to a DOM object.
+pub type DomRoot<T> = Root<Dom<T>>;
+
impl<T: Castable> DomRoot<T> {
/// Cast a DOM object root upwards to one of the interfaces it derives from.
pub fn upcast<U>(root: DomRoot<T>) -> DomRoot<U>
@@ -84,75 +153,55 @@ impl<T: Castable> DomRoot<T> {
}
impl<T: DomObject> DomRoot<T> {
- /// Create a new stack-bounded root for the provided JS-owned value.
- /// It cannot outlive its associated `RootCollection`, and it gives
- /// out references which cannot outlive this new `Root`.
- #[allow(unrooted_must_root)]
- unsafe fn new(unrooted: Dom<T>) -> DomRoot<T> {
- debug_assert!(thread_state::get().is_script());
- STACK_ROOTS.with(|ref collection| {
- let collection = collection.get().unwrap();
- (*collection).root(unrooted.reflector());
- DomRoot {
- ptr: unrooted,
- root_list: collection,
- }
- })
- }
-
/// Generate a new root from a reference
pub fn from_ref(unrooted: &T) -> DomRoot<T> {
unsafe { DomRoot::new(Dom::from_ref(unrooted)) }
}
}
-impl<T: DomObject> Deref for DomRoot<T> {
- type Target = T;
- fn deref(&self) -> &T {
- debug_assert!(thread_state::get().is_script());
- &self.ptr
- }
-}
-
-impl<T: DomObject + HeapSizeOf> HeapSizeOf for DomRoot<T> {
+impl<T> HeapSizeOf for DomRoot<T>
+where
+ T: DomObject + HeapSizeOf,
+{
fn heap_size_of_children(&self) -> usize {
(**self).heap_size_of_children()
}
}
-impl<T: DomObject> PartialEq for DomRoot<T> {
+impl<T> PartialEq for DomRoot<T>
+where
+ T: DomObject,
+{
fn eq(&self, other: &Self) -> bool {
- self.ptr == other.ptr
+ self.value == other.value
}
}
-impl<T: DomObject> Clone for DomRoot<T> {
+impl<T> Clone for DomRoot<T>
+where
+ T: DomObject,
+{
fn clone(&self) -> DomRoot<T> {
DomRoot::from_ref(&*self)
}
}
-unsafe impl<T: DomObject> JSTraceable for DomRoot<T> {
+unsafe impl<T> JSTraceable for DomRoot<T>
+where
+ T: DomObject,
+{
unsafe fn trace(&self, _: *mut JSTracer) {
// Already traced.
}
}
-impl<T: DomObject> Drop for DomRoot<T> {
- fn drop(&mut self) {
- unsafe {
- (*self.root_list).unroot(self.reflector());
- }
- }
-}
-
/// A rooting mechanism for reflectors on the stack.
/// LIFO is not required.
///
/// See also [*Exact Stack Rooting - Storing a GCPointer on the CStack*]
/// (https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Internals/GC/Exact_Stack_Rooting).
pub struct RootCollection {
- roots: UnsafeCell<Vec<*const Reflector>>,
+ roots: UnsafeCell<Vec<*const JSTraceable>>,
}
thread_local!(static STACK_ROOTS: Cell<Option<*const RootCollection>> = Cell::new(None));
@@ -183,21 +232,17 @@ impl RootCollection {
}
}
- /// Start tracking a stack-based root
- unsafe fn root(&self, untracked_reflector: *const Reflector) {
+ /// Starts tracking a trace object.
+ unsafe fn root(&self, object: *const JSTraceable) {
debug_assert!(thread_state::get().is_script());
- let roots = &mut *self.roots.get();
- roots.push(untracked_reflector);
- assert!(!(*untracked_reflector).get_jsobject().is_null())
+ (*self.roots.get()).push(object);
}
- /// Stop tracking a stack-based reflector, asserting if it isn't found.
- unsafe fn unroot(&self, tracked_reflector: *const Reflector) {
- assert!(!tracked_reflector.is_null());
- assert!(!(*tracked_reflector).get_jsobject().is_null());
+ /// Stops tracking a trace object, asserting if it isn't found.
+ unsafe fn unroot(&self, object: *const JSTraceable) {
debug_assert!(thread_state::get().is_script());
let roots = &mut *self.roots.get();
- match roots.iter().rposition(|r| *r == tracked_reflector) {
+ match roots.iter().rposition(|r| *r == object) {
Some(idx) => {
roots.remove(idx);
},
@@ -212,7 +257,7 @@ pub unsafe fn trace_roots(tracer: *mut JSTracer) {
STACK_ROOTS.with(|ref collection| {
let collection = &*(*collection.get().unwrap()).roots.get();
for root in collection {
- trace_reflector(tracer, "on stack", &**root);
+ (**root).trace(tracer);
}
});
}
@@ -610,7 +655,10 @@ pub struct DomOnceCell<T: DomObject> {
ptr: OnceCell<Dom<T>>,
}
-impl<T: DomObject> DomOnceCell<T> {
+impl<T> DomOnceCell<T>
+where
+ T: DomObject
+{
/// 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)]