зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
848f9f69d4
Коммит
dda5ec8a69
|
@ -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)]
|
||||
|
|
Загрузка…
Ссылка в новой задаче