diff options
Diffstat (limited to 'components/script/dom/bindings/js.rs')
-rw-r--r-- | components/script/dom/bindings/js.rs | 543 |
1 files changed, 148 insertions, 395 deletions
diff --git a/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs index fc22078360f..400200c3df3 100644 --- a/components/script/dom/bindings/js.rs +++ b/components/script/dom/bindings/js.rs @@ -11,178 +11,32 @@ //! //! Here is a brief overview of the important types: //! -//! - `JSRef<T>`: a freely-copyable reference to a rooted DOM object. //! - `Root<T>`: a stack-based reference to a rooted DOM object. //! - `JS<T>`: a reference to a DOM object that can automatically be traced by //! the GC when encountered as a field of a Rust structure. -//! - `Temporary<T>`: a reference to a DOM object that will remain rooted for -//! the duration of its lifetime. //! -//! The rule of thumb is as follows: +//! `JS<T>` does not allow access to their inner value without explicitly +//! creating a stack-based root via the `root` method. This returns a `Root<T>`, +//! which causes the JS-owned value to be uncollectable for the duration of the +//! `Root` object's lifetime. A reference to the object can then be obtained +//! from the `Root` object. These references are not allowed to outlive their +//! originating `Root<T>`. //! -//! - All methods return `Temporary<T>`, to ensure the value remains alive -//! until it is stored somewhere that is reachable by the GC. -//! - All functions take `JSRef<T>` arguments, to ensure that they will remain -//! uncollected for the duration of their usage. -//! - All DOM structs contain `JS<T>` fields and derive the `JSTraceable` -//! trait, to ensure that they are transitively marked as reachable by the GC -//! if the enclosing value is reachable. -//! - All methods for type `T` are implemented for `JSRef<T>`, to ensure that -//! the self value will not be collected for the duration of the method call. -//! -//! Both `Temporary<T>` and `JS<T>` do not allow access to their inner value -//! without explicitly creating a stack-based root via the `root` method -//! through the `Rootable<T>` trait. This returns a `Root<T>`, which causes the -//! JS-owned value to be uncollectable for the duration of the `Root` object's -//! lifetime. A `JSRef<T>` can be obtained from a `Root<T>` by calling the `r` -//! method. These `JSRef<T>` values are not allowed to outlive their -//! originating `Root<T>`, to ensure that all interactions with the enclosed -//! value only occur when said value is uncollectable, and will cause static -//! lifetime errors if misused. -//! -//! Other miscellaneous helper traits: -//! -//! - `OptionalRootable` and `OptionalOptionalRootable`: make rooting `Option` -//! values easy via a `root` method -//! - `ResultRootable`: make rooting successful `Result` values easy -//! - `TemporaryPushable`: allows mutating vectors of `JS<T>` with new elements -//! of `JSRef`/`Temporary` -//! - `RootedReference`: makes obtaining an `Option<JSRef<T>>` from an -//! `Option<Root<T>>` easy use dom::bindings::trace::JSTraceable; -use dom::bindings::trace::RootedVec; +use dom::bindings::trace::trace_reflector; use dom::bindings::utils::{Reflector, Reflectable}; use dom::node::Node; -use js::jsapi::JSObject; -use js::jsval::JSVal; +use js::jsapi::{JSObject, Heap, JSTracer}; +use js::jsval::{JSVal, UndefinedValue}; use layout_interface::TrustedNodeAddress; use script_task::STACK_ROOTS; use core::nonzero::NonZero; -use libc; use std::cell::{Cell, UnsafeCell}; use std::default::Default; -use std::intrinsics::return_address; -use std::marker::PhantomData; use std::ops::Deref; -/// An unrooted, JS-owned value. Must not be held across a GC. -/// -/// This is used in particular to wrap pointers extracted from a reflector. -#[must_root] -pub struct Unrooted<T> { - ptr: NonZero<*const T> -} - -impl<T: Reflectable> Unrooted<T> { - /// Create a new JS-owned value wrapped from a raw Rust pointer. - pub unsafe fn from_raw(raw: *const T) -> Unrooted<T> { - assert!(!raw.is_null()); - Unrooted { - ptr: NonZero::new(raw) - } - } - - /// Create a new unrooted value from a `JS<T>`. - #[allow(unrooted_must_root)] - pub fn from_js(ptr: JS<T>) -> Unrooted<T> { - Unrooted { - ptr: ptr.ptr - } - } - - /// Create a new unrooted value from a `Temporary<T>`. - #[allow(unrooted_must_root)] - pub fn from_temporary(ptr: Temporary<T>) -> Unrooted<T> { - Unrooted::from_js(ptr.inner) - } - - /// Get the `Reflector` for this pointer. - pub fn reflector<'a>(&'a self) -> &'a Reflector { - unsafe { - (**self.ptr).reflector() - } - } - - /// Returns an unsafe pointer to the interior of this object. - pub unsafe fn unsafe_get(&self) -> *const T { - *self.ptr - } -} - -impl<T: Reflectable> Rootable<T> for Unrooted<T> { - /// Create a stack-bounded root for this value. - fn root(&self) -> Root<T> { - STACK_ROOTS.with(|ref collection| { - let RootCollectionPtr(collection) = collection.get().unwrap(); - unsafe { - Root::new(&*collection, self.ptr) - } - }) - } -} - -impl<T> Copy for Unrooted<T> {} -impl<T> Clone for Unrooted<T> { - fn clone(&self) -> Unrooted<T> { *self } -} - -/// A type that represents a JS-owned value that is rooted for the lifetime of -/// this value. Importantly, it requires explicit rooting in order to interact -/// with the inner value. Can be assigned into JS-owned member fields (i.e. -/// `JS<T>` types) safely via the `JS<T>::assign` method or -/// `OptionalSettable::assign` (for `Option<JS<T>>` fields). -#[allow(unrooted_must_root)] -pub struct Temporary<T> { - inner: JS<T>, - /// On-stack JS pointer to assuage conservative stack scanner - _js_ptr: *mut JSObject, -} - -impl<T> Clone for Temporary<T> { - fn clone(&self) -> Temporary<T> { - Temporary { - inner: self.inner, - _js_ptr: self._js_ptr, - } - } -} - -impl<T> PartialEq for Temporary<T> { - fn eq(&self, other: &Temporary<T>) -> bool { - self.inner == other.inner - } -} - -impl<T: Reflectable> Temporary<T> { - /// Create a new `Temporary` value from an unrooted value. - #[allow(unrooted_must_root)] - pub fn from_unrooted(unrooted: Unrooted<T>) -> Temporary<T> { - Temporary { - inner: JS { ptr: unrooted.ptr }, - _js_ptr: unrooted.reflector().get_jsobject(), - } - } - - /// Create a new `Temporary` value from a rooted value. - #[allow(unrooted_must_root)] - pub fn from_rooted<U: Assignable<T>>(root: U) -> Temporary<T> { - let inner = JS::from_rooted(root); - Temporary { - inner: inner, - _js_ptr: inner.reflector().get_jsobject(), - } - } -} - -impl<T: Reflectable> Rootable<T> for Temporary<T> { - /// Create a stack-bounded root for this value. - fn root(&self) -> Root<T> { - self.inner.root() - } -} - /// A traced reference to a DOM object. Must only be used as a field in other /// DOM objects. #[must_root] @@ -198,6 +52,32 @@ impl<T> JS<T> { } } } +impl<T: Reflectable> JS<T> { + /// Root this JS-owned value to prevent its collection as garbage. + pub fn root(&self) -> Root<T> { + Root::new(self.ptr) + } + /// Create a JS<T> from a Root<T> + /// XXX Not a great API. Should be a call on Root<T> instead + pub fn from_rooted(root: &Root<T>) -> JS<T> { + JS { + ptr: unsafe { NonZero::new(&**root) } + } + } + /// Create a JS<T> from a &T + pub fn from_ref(obj: &T) -> JS<T> { + JS { + ptr: unsafe { NonZero::new(&*obj) } + } + } + /// Store an rooted value in this field. This is safe under the + /// assumption that JS<T> values are only used as fields in DOM types that + /// are reachable in the GC graph, so this unrooted value becomes + /// transitively rooted for the lifetime of its new owner. + pub fn assign(&mut self, val: Root<T>) { + self.ptr = val.ptr.clone(); + } +} /// An unrooted reference to a DOM object for use in layout. `Layout*Helpers` /// traits must be implemented on this. @@ -208,7 +88,7 @@ pub struct LayoutJS<T> { impl<T: Reflectable> LayoutJS<T> { /// Get the reflector. pub unsafe fn get_jsobject(&self) -> *mut JSObject { - (**self.ptr).reflector().get_jsobject() + (**self.ptr).reflector().get_jsobject().get() } } @@ -217,14 +97,12 @@ impl<T> Copy for JS<T> {} impl<T> Copy for LayoutJS<T> {} impl<T> PartialEq for JS<T> { - #[allow(unrooted_must_root)] fn eq(&self, other: &JS<T>) -> bool { self.ptr == other.ptr } } impl<T> PartialEq for LayoutJS<T> { - #[allow(unrooted_must_root)] fn eq(&self, other: &LayoutJS<T>) -> bool { self.ptr == other.ptr } @@ -260,29 +138,6 @@ impl LayoutJS<Node> { } } -impl<T: Reflectable> Rootable<T> for JS<T> { - /// Root this JS-owned value to prevent its collection as garbage. - fn root(&self) -> Root<T> { - STACK_ROOTS.with(|ref collection| { - let RootCollectionPtr(collection) = collection.get().unwrap(); - unsafe { - Root::new(&*collection, self.ptr) - } - }) - } -} - -impl<U: Reflectable> JS<U> { - /// Create a `JS<T>` from any JS-managed pointer. - pub fn from_rooted<T: Assignable<U>>(root: T) -> JS<U> { - unsafe { - root.get_js() - } - } -} - -//XXXjdm This is disappointing. This only gets called from trace hooks, in theory, -// so it's safe to assume that self is rooted and thereby safe to access. impl<T: Reflectable> Reflectable for JS<T> { fn reflector<'a>(&'a self) -> &'a Reflector { unsafe { @@ -298,19 +153,50 @@ impl<T: Reflectable> Reflectable for JS<T> { pub trait HeapGCValue: JSTraceable { } -impl HeapGCValue for JSVal { +impl HeapGCValue for Heap<JSVal> { } impl<T: Reflectable> HeapGCValue for JS<T> { } -/// A holder that provides interior mutability for GC-managed values such as -/// `JSVal` and `JS<T>`. +/// A holder that provides interior mutability for GC-managed JSVals. /// /// Must be used in place of traditional interior mutability to ensure proper /// GC barriers are enforced. #[must_root] #[jstraceable] +pub struct MutHeapJSVal { + val: UnsafeCell<Heap<JSVal>>, +} + +impl MutHeapJSVal { + /// Create a new `MutHeapJSVal`. + pub fn new() -> MutHeapJSVal { + MutHeapJSVal { + val: UnsafeCell::new(Heap::default()), + } + } + + /// Set this `MutHeapJSVal` to the given value, calling write barriers as + /// appropriate. + pub fn set(&self, val: JSVal) { + unsafe { + let cell = self.val.get(); + (*cell).set(val); + } + } + + /// Set the value in this `MutHeapJSVal`, calling read barriers as appropriate. + pub fn get(&self) -> JSVal { + unsafe { (*self.val.get()).get() } + } +} + + +/// A holder that provides interior mutability for GC-managed values such as +/// `JS<T>`. +#[must_root] +#[jstraceable] pub struct MutHeap<T: HeapGCValue+Copy> { val: Cell<T>, } @@ -323,13 +209,12 @@ impl<T: HeapGCValue+Copy> MutHeap<T> { } } - /// Set this `MutHeap` to the given value, calling write barriers as - /// appropriate. + /// Set this `MutHeap` to the given value. pub fn set(&self, val: T) { self.val.set(val) } - /// Set the value in this `MutHeap`, calling read barriers as appropriate. + /// Set the value in this `MutHeap`. pub fn get(&self) -> T { self.val.get() } @@ -353,8 +238,7 @@ impl<T: HeapGCValue+Copy> MutNullableHeap<T> { } } - /// Set this `MutNullableHeap` to the given value, calling write barriers - /// as appropriate. + /// Set this `MutNullableHeap` to the given value. pub fn set(&self, val: Option<T>) { self.ptr.set(val); } @@ -368,14 +252,14 @@ impl<T: HeapGCValue+Copy> MutNullableHeap<T> { impl<T: Reflectable> MutNullableHeap<JS<T>> { /// Retrieve a copy of the current inner value. If it is `None`, it is /// initialized with the result of `cb` first. - pub fn or_init<F>(&self, cb: F) -> Temporary<T> - where F: FnOnce() -> Temporary<T> + pub fn or_init<F>(&self, cb: F) -> Root<T> + where F: FnOnce() -> Root<T> { match self.get() { - Some(inner) => Temporary::from_rooted(inner), + Some(inner) => Root::from_rooted(inner), None => { let inner = cb(); - self.set(Some(JS::from_rooted(inner.clone()))); + self.set(Some(JS::from_rooted(&inner))); inner }, } @@ -396,16 +280,6 @@ impl<T: HeapGCValue+Copy> Default for MutNullableHeap<T> { } } -impl<T: Reflectable> JS<T> { - /// Store an unrooted value in this field. This is safe under the - /// assumption that JS<T> values are only used as fields in DOM types that - /// are reachable in the GC graph, so this unrooted value becomes - /// transitively rooted for the lifetime of its new owner. - pub fn assign(&mut self, val: Temporary<T>) { - *self = val.inner.clone(); - } -} - impl<T: Reflectable> 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 @@ -419,129 +293,36 @@ impl<T: Reflectable> LayoutJS<T> { pub trait RootedReference<T> { /// Obtain a safe optional reference to the wrapped JS owned-value that /// cannot outlive the lifetime of this root. - fn r<'a>(&'a self) -> Option<JSRef<'a, T>>; + fn r<'a>(&'a self) -> Option<&'a T>; } impl<T: Reflectable> RootedReference<T> for Option<Root<T>> { - fn r<'a>(&'a self) -> Option<JSRef<'a, T>> { + fn r<'a>(&'a self) -> Option<&'a T> { self.as_ref().map(|root| root.r()) } } -/// Get an `Option<Option<JSRef<T>>>` out of an `Option<Option<Root<T>>>` +/// Get an `Option<Option<&T>>` out of an `Option<Option<Root<T>>>` pub trait OptionalRootedReference<T> { /// Obtain a safe optional optional reference to the wrapped JS owned-value /// that cannot outlive the lifetime of this root. - fn r<'a>(&'a self) -> Option<Option<JSRef<'a, T>>>; + fn r<'a>(&'a self) -> Option<Option<&'a T>>; } impl<T: Reflectable> OptionalRootedReference<T> for Option<Option<Root<T>>> { - fn r<'a>(&'a self) -> Option<Option<JSRef<'a, T>>> { + fn r<'a>(&'a self) -> Option<Option<&'a T>> { self.as_ref().map(|inner| inner.r()) } } -/// Trait that allows extracting a `JS<T>` value from a variety of -/// rooting-related containers, which in general is an unsafe operation since -/// they can outlive the rooted lifetime of the original value. -pub trait Assignable<T> { - /// Extract an unrooted `JS<T>`. - unsafe fn get_js(&self) -> JS<T>; -} - -impl<T> Assignable<T> for JS<T> { - unsafe fn get_js(&self) -> JS<T> { - self.clone() - } -} - -impl<'a, T: Reflectable> Assignable<T> for JSRef<'a, T> { - unsafe fn get_js(&self) -> JS<T> { - JS { - ptr: self.ptr - } - } -} - -impl<T: Reflectable> Assignable<T> for Temporary<T> { - unsafe fn get_js(&self) -> JS<T> { - self.inner.clone() - } -} - - -/// Root a rootable `Option` type (used for `Option<Temporary<T>>`) -pub trait OptionalRootable<T> { - /// Root the inner value, if it exists. - fn root(&self) -> Option<Root<T>>; -} - -impl<T: Reflectable, U: Rootable<T>> OptionalRootable<T> for Option<U> { - fn root(&self) -> Option<Root<T>> { - self.as_ref().map(|inner| inner.root()) - } -} - -/// Root a rootable `Option<Option>` type (used for `Option<Option<JS<T>>>`) -pub trait OptionalOptionalRootable<T> { - /// Root the inner value, if it exists. - fn root(&self) -> Option<Option<Root<T>>>; -} - -impl<T: Reflectable, U: OptionalRootable<T>> OptionalOptionalRootable<T> for Option<U> { - fn root(&self) -> Option<Option<Root<T>>> { - self.as_ref().map(|inner| inner.root()) - } -} - -/// Root a rootable `Result` type (any of `Temporary<T>` or `JS<T>`) -pub trait ResultRootable<T,U> { - /// Root the inner value, if it exists. - fn root(self) -> Result<Root<T>, U>; -} - -impl<T: Reflectable, U, V: Rootable<T>> ResultRootable<T, U> for Result<V, U> { - fn root(self) -> Result<Root<T>, U> { - self.map(|inner| inner.root()) - } -} - -/// Root a rootable type. -pub trait Rootable<T> { - /// Root the value. - fn root(&self) -> Root<T>; -} - - -/// Provides a facility to push unrooted values onto lists of rooted values. -/// This is safe under the assumption that said lists are reachable via the GC -/// graph, and therefore the new values are transitively rooted for the -/// lifetime of their new owner. -pub trait TemporaryPushable<T> { - /// Push a new value onto this container. - fn push_unrooted(&mut self, val: &T); - /// Insert a new value into this container. - fn insert_unrooted(&mut self, index: usize, val: &T); -} - -impl<T: Assignable<U>, U: Reflectable> TemporaryPushable<T> for Vec<JS<U>> { - fn push_unrooted(&mut self, val: &T) { - self.push(unsafe { val.get_js() }); - } - - fn insert_unrooted(&mut self, index: usize, val: &T) { - self.insert(index, unsafe { val.get_js() }); - } -} - -/// An opaque, LIFO rooting mechanism. This tracks roots and ensures that they -/// are destructed in a LIFO order. +/// 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). #[no_move] pub struct RootCollection { - roots: UnsafeCell<RootedVec<*mut JSObject>>, + roots: UnsafeCell<Vec<*const Reflector>>, } /// A pointer to a RootCollection, for use in global variables. @@ -555,142 +336,114 @@ impl Clone for RootCollectionPtr { impl RootCollection { /// Create an empty collection of roots pub fn new() -> RootCollection { - let addr = unsafe { - return_address() as *const libc::c_void - }; - RootCollection { - roots: UnsafeCell::new(RootedVec::new_with_destination_address(addr)), + roots: UnsafeCell::new(vec!()), } } - /// Track a stack-based root as a pointer to ensure LIFO root ordering. - fn root<'b>(&self, untracked_js_ptr: *mut JSObject) { + /// Start tracking a stack-based root + fn root<'b>(&self, untracked_reflector: *const Reflector) { unsafe { - let roots = self.roots.get(); - (*roots).push(untracked_js_ptr); - debug!(" rooting {:?}", untracked_js_ptr); + let mut roots = &mut *self.roots.get(); + roots.push(untracked_reflector); + assert!(!(*untracked_reflector).get_jsobject().is_null()) } } - /// Stop tracking a stack-based root, asserting if LIFO root ordering has - /// been violated + /// Stop tracking a stack-based root, asserting if the reflector isn't found fn unroot<'b, T: Reflectable>(&self, rooted: &Root<T>) { unsafe { - let roots = self.roots.get(); - let unrooted = (*roots).pop().unwrap(); - debug!("unrooted {:?} (expecting {:?}", unrooted, rooted.js_ptr); - assert!(unrooted == rooted.js_ptr); + let mut roots = &mut *self.roots.get(); + let old_reflector = &*rooted.r().reflector(); + match roots.iter().rposition(|r| *r == old_reflector) { + Some(idx) => { + roots.remove(idx); + }, + None => panic!("Can't remove a root that was never rooted!") + } } } } +/// SM Callback that traces the rooted reflectors +pub unsafe fn trace_roots(tracer: *mut JSTracer) { + STACK_ROOTS.with(|ref collection| { + let RootCollectionPtr(collection) = collection.get().unwrap(); + let collection = &*(*collection).roots.get(); + for root in collection.iter() { + trace_reflector(tracer, "reflector", &**root); + } + }); +} + /// 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. Attempts to transfer ownership of a `Root` via -/// moving will trigger dynamic unrooting failures due to incorrect ordering. -#[no_move] +/// `RootCollection` object. pub struct Root<T: Reflectable> { - /// List that ensures correct dynamic root ordering - root_list: &'static RootCollection, /// Reference to rooted value that must not outlive this container ptr: NonZero<*const T>, - /// On-stack JS pointer to assuage conservative stack scanner - js_ptr: *mut JSObject, + /// List that ensures correct dynamic root ordering + root_list: *const RootCollection, } impl<T: Reflectable> Root<T> { /// Create a new stack-bounded root for the provided JS-owned value. - /// It cannot not outlive its associated `RootCollection`, and it contains - /// a `JSRef` which cannot outlive this new `Root`. - #[inline] - fn new(roots: &'static RootCollection, unrooted: NonZero<*const T>) - -> Root<T> { - let js_ptr = unsafe { - (**unrooted).reflector().get_jsobject() - }; - roots.root(js_ptr); - Root { - root_list: roots, - ptr: unrooted, - js_ptr: js_ptr, - } + /// It cannot not outlive its associated `RootCollection`, and it gives + /// out references which cannot outlive this new `Root`. + pub fn new(unrooted: NonZero<*const T>) + -> Root<T> { + STACK_ROOTS.with(|ref collection| { + let RootCollectionPtr(collection) = collection.get().unwrap(); + unsafe { (*collection).root(&*(**unrooted).reflector()) } + Root { + ptr: unrooted, + root_list: collection, + } + }) } - /// Obtain a safe reference to the wrapped JS owned-value that cannot - /// outlive the lifetime of this root. - pub fn r<'b>(&'b self) -> JSRef<'b, T> { - JSRef { - ptr: self.ptr, - chain: PhantomData, - } + /// Generate a new root from a reference + pub fn from_ref(unrooted: &T) -> Root<T> { + Root::new(unsafe { NonZero::new(&*unrooted) }) } - /// Obtain an unsafe reference to the wrapped JS owned-value that can + /// Obtain a safe reference to the wrapped JS owned-value that cannot /// outlive the lifetime of this root. - /// - /// DO NOT CALL. - pub fn get_unsound_ref_forever<'b>(&self) -> JSRef<'b, T> { - JSRef { - ptr: self.ptr, - chain: PhantomData, - } + pub fn r<'a>(&'a self) -> &'a T { + &**self } -} -impl<T: Reflectable> Drop for Root<T> { - fn drop(&mut self) { - self.root_list.unroot(self); + /// Don't use this. Don't make me find you. + pub fn get_unsound_ref_forever<'a, 'b>(&'a self) -> &'b T { + unsafe { &**self.ptr } } -} -impl<'a, T: Reflectable> Deref for JSRef<'a, T> { - type Target = T; - fn deref<'b>(&'b self) -> &'b T { - unsafe { - &**self.ptr - } + /// Generate a new root from a JS<T> reference + #[allow(unrooted_must_root)] + pub fn from_rooted(js: JS<T>) -> Root<T> { + js.root() } } -/// A reference to a DOM object that is guaranteed to be alive. This is freely -/// copyable. -pub struct JSRef<'a, T> { - ptr: NonZero<*const T>, - chain: PhantomData<&'a ()>, -} - -impl<'a, T> Copy for JSRef<'a, T> {} - -impl<'a, T> Clone for JSRef<'a, T> { - fn clone(&self) -> JSRef<'a, T> { - JSRef { - ptr: self.ptr.clone(), - chain: self.chain, - } +impl<T: Reflectable> Deref for Root<T> { + type Target = T; + fn deref<'a>(&'a self) -> &'a T { + unsafe { &**self.ptr.deref() } } } -impl<'a, 'b, T> PartialEq<JSRef<'b, T>> for JSRef<'a, T> { - fn eq(&self, other: &JSRef<T>) -> bool { +impl<T: Reflectable> PartialEq for Root<T> { + fn eq(&self, other: &Root<T>) -> bool { self.ptr == other.ptr } } -impl<'a, T: Reflectable> JSRef<'a, T> { - /// Returns the inner pointer directly. - pub fn extended_deref(self) -> &'a T { - unsafe { - &**self.ptr - } +impl<T: Reflectable> Drop for Root<T> { + fn drop(&mut self) { + unsafe { (*self.root_list).unroot(self); } } } -impl<'a, T: Reflectable> Reflectable for JSRef<'a, T> { - fn reflector<'b>(&'b self) -> &'b Reflector { - (**self).reflector() - } -} |