servo: Merge #18663 - Make DomRoot<T> a type alias of a more general Root<T> type (from servo:ROOT-ALL-THE-THINGS); r=jdm

Source-Repo: https://github.com/servo/servo
Source-Revision: 056c08511997967ceaa2de4d53afa7787276b770

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 667938133fe155a919e8aaea76d144c50bf49889
This commit is contained in:
Anthony Ramine 2017-09-28 10:45:11 -05:00
Родитель 848f9f69d4
Коммит dda5ec8a69
2 изменённых файлов: 108 добавлений и 60 удалений

Просмотреть файл

@ -72,7 +72,7 @@ impl Reflector {
}
/// A trait to provide access to the `Reflector` for a DOM object.
pub trait DomObject {
pub trait DomObject: 'static {
/// Returns the receiver's reflector.
fn reflector(&self) -> &Reflector;

Просмотреть файл

@ -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)]