Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a safe, mostly-sound rooting rooting strategy. #2101

Merged
merged 16 commits into from May 3, 2014
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

s/Unrooted/Temporary/g

  • Loading branch information
jdm committed May 3, 2014
commit 522d3f167b12fa79401eea5525c7b6133cae0f06
@@ -4,7 +4,7 @@

use dom::bindings::codegen::BindingDeclarations::AttrBinding;
use dom::bindings::codegen::InheritTypes::NodeCast;
use dom::bindings::js::{JS, JSRef, Unrooted, RootCollection};
use dom::bindings::js::{JS, JSRef, Temporary, RootCollection};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::element::Element;
use dom::node::Node;
@@ -59,7 +59,7 @@ impl Attr {

pub fn new(window: &JSRef<Window>, local_name: DOMString, value: DOMString,
name: DOMString, namespace: Namespace,
prefix: Option<DOMString>, owner: &JSRef<Element>) -> Unrooted<Attr> {
prefix: Option<DOMString>, owner: &JSRef<Element>) -> Temporary<Attr> {
let attr = Attr::new_inherited(local_name, value, name, namespace, prefix, owner);
reflect_dom_object(~attr, window, AttrBinding::Wrap)
}
@@ -4,7 +4,7 @@

use dom::attr::Attr;
use dom::bindings::codegen::BindingDeclarations::AttrListBinding;
use dom::bindings::js::{JS, JSRef, Unrooted, RootCollection};
use dom::bindings::js::{JS, JSRef, Temporary, RootCollection};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::element::Element;
use dom::window::Window;
@@ -25,16 +25,16 @@ impl AttrList {
}
}

pub fn new(window: &JSRef<Window>, elem: &JSRef<Element>) -> Unrooted<AttrList> {
pub fn new(window: &JSRef<Window>, elem: &JSRef<Element>) -> Temporary<AttrList> {
reflect_dom_object(~AttrList::new_inherited(window.unrooted(), elem.unrooted()),
window, AttrListBinding::Wrap)
}
}

pub trait AttrListMethods {
fn Length(&self) -> u32;
fn Item(&self, index: u32) -> Option<Unrooted<Attr>>;
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Unrooted<Attr>>;
fn Item(&self, index: u32) -> Option<Temporary<Attr>>;
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Temporary<Attr>>;
}

impl<'a> AttrListMethods for JSRef<'a, AttrList> {
@@ -43,12 +43,12 @@ impl<'a> AttrListMethods for JSRef<'a, AttrList> {
self.owner.root(&roots).attrs.len() as u32
}

fn Item(&self, index: u32) -> Option<Unrooted<Attr>> {
fn Item(&self, index: u32) -> Option<Temporary<Attr>> {
let roots = RootCollection::new();
self.owner.root(&roots).attrs.as_slice().get(index as uint).map(|x| Unrooted::new(x.clone()))
self.owner.root(&roots).attrs.as_slice().get(index as uint).map(|x| Temporary::new(x.clone()))
}

fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Unrooted<Attr>> {
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Temporary<Attr>> {
let item = self.Item(index);
*found = item.is_some();
item
@@ -4323,7 +4323,7 @@ def __init__(self, config, prefix, webIDLFile):
'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING}',
'dom::types::*',
'dom::bindings',
'dom::bindings::js::{JS, JSRef, RootCollection, RootedReference, Unrooted, OptionalRootable}',
'dom::bindings::js::{JS, JSRef, RootCollection, RootedReference, Temporary, OptionalRootable}',
'dom::bindings::utils::{CreateDOMGlobal, CreateInterfaceObjects2}',
'dom::bindings::utils::{ConstantSpec, cx_for_dom_object, Default}',
'dom::bindings::utils::{dom_object_slot, DOM_OBJECT_SLOT, DOMClass}',
@@ -5294,7 +5294,7 @@ def InheritTypes(config):
descriptors = config.getDescriptors(register=True, hasInterfaceObject=True)
allprotos = [CGGeneric("#![allow(unused_imports)]\n"),
CGGeneric("use dom::types::*;\n"),
CGGeneric("use dom::bindings::js::{JS, JSRef, Unrooted};\n"),
CGGeneric("use dom::bindings::js::{JS, JSRef, Temporary};\n"),
CGGeneric("use dom::bindings::trace::JSTraceable;\n"),
CGGeneric("use dom::bindings::utils::Reflectable;\n"),
CGGeneric("use serialize::{Encodable, Encoder};\n"),
@@ -5349,7 +5349,7 @@ def InheritTypes(config):
}
#[inline(always)]
fn from_unrooted<T: ${fromBound}+Reflectable>(derived: Unrooted<T>) -> Unrooted<Self> {
fn from_unrooted<T: ${fromBound}+Reflectable>(derived: Temporary<T>) -> Temporary<Self> {
unsafe { derived.transmute() }
}
}
@@ -133,7 +133,7 @@ def __init__(self, config, interface, desc):
else:
nativeTypeDefault = 'JS<%s>' % ifaceName

self.returnType = "Unrooted<%s>" % ifaceName
self.returnType = "Temporary<%s>" % ifaceName
self.nativeType = desc.get('nativeType', nativeTypeDefault)
self.concreteType = desc.get('concreteType', ifaceName)
self.createGlobal = desc.get('createGlobal', False)
@@ -14,27 +14,27 @@ use std::cell::RefCell;
/// Importantly, it requires rooting in order to interact with the value in any way.
/// Can be assigned into JS-owned member fields (ie. JS<T> types) safely via the
/// `JS<T>::assign` method or `OptionalAssignable::assign` (for Option<JS<T>> fields).
pub struct Unrooted<T> {
pub struct Temporary<T> {
inner: JS<T>
}

impl<T> Eq for Unrooted<T> {
fn eq(&self, other: &Unrooted<T>) -> bool {
impl<T> Eq for Temporary<T> {
fn eq(&self, other: &Temporary<T>) -> bool {
self.inner == other.inner
}
}

impl<T: Reflectable> Unrooted<T> {
/// Create a new Unrooted value from a JS-owned value.
pub fn new(inner: JS<T>) -> Unrooted<T> {
Unrooted {
impl<T: Reflectable> Temporary<T> {
/// Create a new Temporary value from a JS-owned value.
pub fn new(inner: JS<T>) -> Temporary<T> {
Temporary {
inner: inner
}
}

/// Create a new Unrooted value from a rooted value.
pub fn new_rooted<'a>(root: &JSRef<'a, T>) -> Unrooted<T> {
Unrooted {
/// Create a new Temporary value from a rooted value.
pub fn new_rooted<'a>(root: &JSRef<'a, T>) -> Temporary<T> {
Temporary {
inner: root.unrooted()
}
}
@@ -49,7 +49,7 @@ impl<T: Reflectable> Unrooted<T> {
}

//XXXjdm It would be lovely if this could be private.
pub unsafe fn transmute<To>(self) -> Unrooted<To> {
pub unsafe fn transmute<To>(self) -> Temporary<To> {
cast::transmute(self)
}
}
@@ -75,12 +75,12 @@ impl <T> Clone for JS<T> {
}

impl<T: Reflectable> JS<T> {
/// Create a new JS-reflected DOM object; returns an Unrooted type because the new value
/// Create a new JS-reflected DOM object; returns an Temporary type because the new value
/// is not safe to use until it is rooted.
pub fn new(obj: ~T,
window: &JSRef<Window>,
wrap_fn: extern "Rust" fn(*JSContext, &JSRef<Window>, ~T) -> JS<T>) -> Unrooted<T> {
Unrooted::new(wrap_fn(window.get().get_cx(), window, obj))
wrap_fn: extern "Rust" fn(*JSContext, &JSRef<Window>, ~T) -> JS<T>) -> Temporary<T> {
Temporary::new(wrap_fn(window.get().get_cx(), window, obj))
}

/// Create a new JS-owned value wrapped from a raw Rust pointer.
@@ -132,7 +132,7 @@ 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: Unrooted<T>) {
pub fn assign(&mut self, val: Temporary<T>) {
*self = unsafe { val.inner() };
}
}
@@ -178,7 +178,7 @@ impl<'a, T> Assignable<T> for JSRef<'a, T> {

// Assignable should not be exposed publically, since it's used to
// extract unrooted values in a safe way WHEN USED CORRECTLY.
impl<T: Reflectable> Assignable<T> for Unrooted<T> {
impl<T: Reflectable> Assignable<T> for Temporary<T> {
fn get_js(&self) -> JS<T> {
unsafe { self.inner() }
}
@@ -198,7 +198,7 @@ pub trait OptionalRootable<T> {
fn root<'a, 'b>(self, roots: &'a RootCollection) -> Option<Root<'a, 'b, T>>;
}

impl<T: Reflectable> OptionalRootable<T> for Option<Unrooted<T>> {
impl<T: Reflectable> OptionalRootable<T> for Option<Temporary<T>> {
fn root<'a, 'b>(self, roots: &'a RootCollection) -> Option<Root<'a, 'b, T>> {
self.map(|inner| inner.root(roots))
}
@@ -218,7 +218,7 @@ pub trait ResultRootable<T,U> {
fn root<'a, 'b>(self, roots: &'a RootCollection) -> Result<Root<'a, 'b, T>, U>;
}

impl<T: Reflectable, U> ResultRootable<T, U> for Result<Unrooted<T>, U> {
impl<T: Reflectable, U> ResultRootable<T, U> for Result<Temporary<T>, U> {
fn root<'a, 'b>(self, roots: &'a RootCollection) -> Result<Root<'a, 'b, T>, U> {
self.map(|inner| inner.root(roots))
}
@@ -227,12 +227,12 @@ impl<T: Reflectable, U> ResultRootable<T, U> for Result<Unrooted<T>, U> {
/// 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 UnrootedPushable<T> {
fn push_unrooted(&mut self, val: Unrooted<T>);
pub trait TemporaryPushable<T> {
fn push_unrooted(&mut self, val: Temporary<T>);
}

impl<T: Reflectable> UnrootedPushable<T> for Vec<JS<T>> {
fn push_unrooted(&mut self, val: Unrooted<T>) {
impl<T: Reflectable> TemporaryPushable<T> for Vec<JS<T>> {
fn push_unrooted(&mut self, val: Temporary<T>) {
unsafe { self.push(val.inner()) };
}
}
@@ -5,7 +5,7 @@
use dom::bindings::codegen::PrototypeList;
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
use dom::bindings::conversions::{FromJSValConvertible, IDLInterface};
use dom::bindings::js::{JS, JSRef, RootCollection, Unrooted, Root};
use dom::bindings::js::{JS, JSRef, RootCollection, Temporary, Root};
use dom::bindings::trace::Untraceable;
use dom::browsercontext;
use dom::window;
@@ -391,7 +391,7 @@ pub fn reflect_dom_object<T: Reflectable>
(obj: ~T,
window: &JSRef<window::Window>,
wrap_fn: extern "Rust" fn(*JSContext, &JSRef<window::Window>, ~T) -> JS<T>)
-> Unrooted<T> {
-> Temporary<T> {
JS::new(obj, window, wrap_fn)
}

@@ -616,12 +616,12 @@ pub extern fn outerize_global(_cx: *JSContext, obj: JSHandleObject) -> *JSObject
}

/// Returns the global object of the realm that the given JS object was created in.
pub fn global_object_for_js_object(obj: *JSObject) -> Unrooted<window::Window> {
pub fn global_object_for_js_object(obj: *JSObject) -> Temporary<window::Window> {
unsafe {
let global = GetGlobalForObjectCrossCompartment(obj);
let clasp = JS_GetClass(global);
assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0);
Unrooted::new(
Temporary::new(
FromJSValConvertible::from_jsval(ptr::null(), ObjectOrNullValue(global), ())
.ok().expect("found DOM global that doesn't unwrap to Window"))
}
@@ -2,7 +2,7 @@
* 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/. */

use dom::bindings::js::{JS, JSRef, RootCollection, Unrooted};
use dom::bindings::js::{JS, JSRef, RootCollection, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::error::Fallible;
use dom::bindings::codegen::BindingDeclarations::BlobBinding;
@@ -23,21 +23,21 @@ impl Blob {
}
}

pub fn new(window: &JSRef<Window>) -> Unrooted<Blob> {
pub fn new(window: &JSRef<Window>) -> Temporary<Blob> {
reflect_dom_object(~Blob::new_inherited(window.unrooted()),
window,
BlobBinding::Wrap)
}

pub fn Constructor(window: &JSRef<Window>) -> Fallible<Unrooted<Blob>> {
pub fn Constructor(window: &JSRef<Window>) -> Fallible<Temporary<Blob>> {
Ok(Blob::new(window))
}
}

pub trait BlobMethods {
fn Size(&self) -> u64;
fn Type(&self) -> DOMString;
fn Slice(&self, _start: Option<i64>, _end: Option<i64>, _contentType: Option<DOMString>) -> Unrooted<Blob>;
fn Slice(&self, _start: Option<i64>, _end: Option<i64>, _contentType: Option<DOMString>) -> Temporary<Blob>;
fn Close(&self);
}

@@ -50,7 +50,7 @@ impl<'a> BlobMethods for JSRef<'a, Blob> {
~""
}

fn Slice(&self, _start: Option<i64>, _end: Option<i64>, _contentType: Option<DOMString>) -> Unrooted<Blob> {
fn Slice(&self, _start: Option<i64>, _end: Option<i64>, _contentType: Option<DOMString>) -> Temporary<Blob> {
let roots = RootCollection::new();
let window = self.window.root(&roots);
Blob::new(&window.root_ref())
@@ -2,7 +2,7 @@
* 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/. */

use dom::bindings::js::{JS, JSRef, Unrooted, RootCollection};
use dom::bindings::js::{JS, JSRef, Temporary, RootCollection};
use dom::bindings::trace::Traceable;
use dom::bindings::utils::Reflectable;
use dom::document::Document;
@@ -32,14 +32,14 @@ impl BrowserContext {
context
}

pub fn active_document(&self) -> Unrooted<Document> {
Unrooted::new(self.history.get(self.active_index).document.clone())
pub fn active_document(&self) -> Temporary<Document> {
Temporary::new(self.history.get(self.active_index).document.clone())
}

pub fn active_window(&self) -> Unrooted<Window> {
pub fn active_window(&self) -> Temporary<Window> {
let roots = RootCollection::new();
let doc = self.active_document().root(&roots);
Unrooted::new(doc.deref().window.clone())
Temporary::new(doc.deref().window.clone())
}

pub fn window_proxy(&self) -> *JSObject {
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::ClientRectBinding;
use dom::bindings::js::{JS, JSRef, Unrooted};
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::window::Window;
use servo_util::geometry::Au;
@@ -34,7 +34,7 @@ impl ClientRect {

pub fn new(window: &JSRef<Window>,
top: Au, bottom: Au,
left: Au, right: Au) -> Unrooted<ClientRect> {
left: Au, right: Au) -> Temporary<ClientRect> {
let rect = ClientRect::new_inherited(window.unrooted(), top, bottom, left, right);
reflect_dom_object(~rect, window, ClientRectBinding::Wrap)
}
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::ClientRectListBinding;
use dom::bindings::js::{JS, JSRef, Unrooted};
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::clientrect::ClientRect;
use dom::window::Window;
@@ -26,32 +26,32 @@ impl ClientRectList {
}

pub fn new(window: &JSRef<Window>,
rects: Vec<JSRef<ClientRect>>) -> Unrooted<ClientRectList> {
rects: Vec<JSRef<ClientRect>>) -> Temporary<ClientRectList> {
reflect_dom_object(~ClientRectList::new_inherited(window.unrooted(), rects),
window, ClientRectListBinding::Wrap)
}
}

pub trait ClientRectListMethods {
fn Length(&self) -> u32;
fn Item(&self, index: u32) -> Option<Unrooted<ClientRect>>;
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Unrooted<ClientRect>>;
fn Item(&self, index: u32) -> Option<Temporary<ClientRect>>;
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Temporary<ClientRect>>;
}

impl<'a> ClientRectListMethods for JSRef<'a, ClientRectList> {
fn Length(&self) -> u32 {
self.rects.len() as u32
}

fn Item(&self, index: u32) -> Option<Unrooted<ClientRect>> {
fn Item(&self, index: u32) -> Option<Temporary<ClientRect>> {
if index < self.rects.len() as u32 {
Some(Unrooted::new(self.rects.get(index as uint).clone()))
Some(Temporary::new(self.rects.get(index as uint).clone()))
} else {
None
}
}

fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Unrooted<ClientRect>> {
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Temporary<ClientRect>> {
*found = index < self.rects.len() as u32;
self.Item(index)
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.