/* 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/. */ /// The DOM is made up of Rust types whose lifetime is entirely controlled by the whims of /// the SpiderMonkey garbage collector. The types in this module are designed to ensure /// that any interactions with said Rust types only occur on values that will remain alive /// the entire time. /// /// Here is a brief overview of the important types: /// - JSRef: a freely-copyable reference to a rooted value. /// - JS: a pointer to JS-owned memory that can automatically be traced by the GC when /// encountered as a field of a Rust structure. /// - Temporary: a value that will remain rooted for the duration of its lifetime. /// /// The rule of thumb is as follows: /// - All methods return Temporary, to ensure the value remains alive until it is stored /// somewhere that is reachable by the GC. /// - All functions take &JSRef arguments, to ensure that they will remain uncollected for /// the duration of their usage. /// - All types contain JS fields and derive the Encodable 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, to ensure that the self value /// will not be collected for the duration of the method call. /// /// Both Temporary and JS do not allow access to their inner value without explicitly /// creating a stack-based root via the `root` method. This returns a Root, which causes /// the JS-owned value to be uncollectable for the duration of the Root type's lifetime. /// A JSRef can be obtained from a Root either by dereferencing the Root (`*rooted`) /// or explicitly calling the `root_ref` method. These JSRef values are not allowed to /// outlive their originating Root, 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 OptionalRootedRootable: make rooting Option values easy via a `root` method /// - ResultRootable: make rooting successful Result values easy /// - TemporaryPushable: allows mutating vectors of JS with new elements of JSRef/Temporary /// - OptionalSettable: allows assigning Option values of JSRef/Temporary to fields of Option> /// - RootedReference: makes obtaining an Option> from an Option> easy use dom::bindings::utils::{Reflector, Reflectable, cx_for_dom_object}; use dom::node::Node; use dom::xmlhttprequest::{XMLHttpRequest, TrustedXHRAddress}; use js::jsapi::{JSObject, JS_AddObjectRoot, JS_RemoveObjectRoot}; use layout_interface::TrustedNodeAddress; use script_task::StackRoots; use std::cell::{Cell, RefCell}; use std::kinds::marker::ContravariantLifetime; use std::mem; /// 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 (ie. JS types) safely via the /// `JS::assign` method or `OptionalSettable::assign` (for Option> fields). pub struct Temporary { inner: JS, } impl Eq for Temporary { fn eq(&self, other: &Temporary) -> bool { self.inner == other.inner } } #[unsafe_destructor] impl Drop for Temporary { fn drop(&mut self) { let cx = cx_for_dom_object(&self.inner); unsafe { JS_RemoveObjectRoot(cx, self.inner.mut_reflector().rootable()); } } } impl Temporary { /// Create a new Temporary value from a JS-owned value. pub fn new(mut inner: JS) -> Temporary { let cx = cx_for_dom_object(&inner); unsafe { JS_AddObjectRoot(cx, inner.mut_reflector().rootable()); } Temporary { inner: inner, } } /// Create a new Temporary value from a rooted value. pub fn from_rooted<'a>(root: &JSRef<'a, T>) -> Temporary { Temporary::new(root.unrooted()) } /// Create a stack-bounded root for this value. pub fn root<'a, 'b>(self) -> Root<'a, 'b, T> { let collection = StackRoots.get().unwrap(); unsafe { (**collection).new_root(&self.inner) } } unsafe fn inner(&self) -> JS { self.inner.clone() } //XXXjdm It would be lovely if this could be private. pub unsafe fn transmute(self) -> Temporary { mem::transmute(self) } } /// A rooted, JS-owned value. Must only be used as a field in other JS-owned types. pub struct JS { ptr: *T } impl Eq for JS { fn eq(&self, other: &JS) -> bool { self.ptr == other.ptr } } impl Clone for JS { #[inline] fn clone(&self) -> JS { JS { ptr: self.ptr.clone() } } } impl JS { /// Create a new JS-owned value wrapped from an address known to be a Node pointer. pub unsafe fn from_trusted_node_address(inner: TrustedNodeAddress) -> JS { let TrustedNodeAddress(addr) = inner; JS { ptr: addr as *Node } } } impl JS { pub unsafe fn from_trusted_xhr_address(inner: TrustedXHRAddress) -> JS { let TrustedXHRAddress(addr) = inner; JS { ptr: addr as *XMLHttpRequest } } } impl JS { /// Create a new JS-owned value wrapped from a raw Rust pointer. pub unsafe fn from_raw(raw: *T) -> JS { JS { ptr: raw } } /// Root this JS-owned value to prevent its collection as garbage. pub fn root<'a, 'b>(&self) -> Root<'a, 'b, T> { let collection = StackRoots.get().unwrap(); unsafe { (**collection).new_root(self) } } } impl, U: Reflectable> JS { pub fn from_rooted(root: T) -> JS { 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 Reflectable for JS { fn reflector<'a>(&'a self) -> &'a Reflector { unsafe { (*self.unsafe_get()).reflector() } } fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector { unsafe { (*self.unsafe_get()).mut_reflector() } } } impl JS { /// Returns an unsafe pointer to the interior of this JS object without touching the borrow /// flags. This is the only method that be safely accessed from layout. (The fact that this /// is unsafe is what necessitates the layout wrappers.) pub unsafe fn unsafe_get(&self) -> *mut T { mem::transmute_copy(&self.ptr) } /// Store an unrooted value in this field. This is safe under the assumption that JS /// 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) { *self = unsafe { val.inner() }; } } impl JS { //XXXjdm It would be lovely if this could be private. pub unsafe fn transmute(self) -> JS { mem::transmute(self) } pub unsafe fn transmute_copy(&self) -> JS { mem::transmute_copy(self) } } /// Get an Option> out of an Option> pub trait RootedReference { fn root_ref<'a>(&'a self) -> Option>; } impl<'a, 'b, T: Reflectable> RootedReference for Option> { fn root_ref<'a>(&'a self) -> Option> { self.as_ref().map(|root| root.root_ref()) } } /// Get an Option>> out of an Option>> pub trait OptionalRootedReference { fn root_ref<'a>(&'a self) -> Option>>; } impl<'a, 'b, T: Reflectable> OptionalRootedReference for Option>> { fn root_ref<'a>(&'a self) -> Option>> { self.as_ref().map(|inner| inner.root_ref()) } } /// Trait that allows extracting a JS 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. /*definitely not public*/ trait Assignable { unsafe fn get_js(&self) -> JS; } impl Assignable for JS { unsafe fn get_js(&self) -> JS { self.clone() } } impl<'a, T> Assignable for JSRef<'a, T> { unsafe fn get_js(&self) -> JS { self.unrooted() } } impl Assignable for Temporary { unsafe fn get_js(&self) -> JS { self.inner() } } /// Assign an optional rootable value (either of JS or Temporary) to an optional /// field of a DOM type (ie. Option>) pub trait OptionalSettable { fn assign(&self, val: Option); } impl, U: Reflectable> OptionalSettable for Cell>> { fn assign(&self, val: Option) { self.set(val.map(|val| unsafe { val.get_js() })); } } /// Root a rootable Option type (used for Option>) pub trait OptionalRootable { fn root<'a, 'b>(self) -> Option>; } impl OptionalRootable for Option> { fn root<'a, 'b>(self) -> Option> { self.map(|inner| inner.root()) } } /// Return an unrooted type for storing in optional DOM fields pub trait OptionalUnrootable { fn unrooted(&self) -> Option>; } impl<'a, T: Reflectable> OptionalUnrootable for Option> { fn unrooted(&self) -> Option> { self.as_ref().map(|inner| inner.unrooted()) } } /// Root a rootable Option type (used for Option>) pub trait OptionalRootedRootable { fn root<'a, 'b>(&self) -> Option>; } impl OptionalRootedRootable for Option> { fn root<'a, 'b>(&self) -> Option> { self.as_ref().map(|inner| inner.root()) } } /// Root a rootable Option