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

Root Temporary values for the duration of their lifetime.

  • Loading branch information
jdm committed May 3, 2014
commit a09a4bd297d48c2702e1e15a901b1fdec32dda83
@@ -2,20 +2,20 @@
* 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::utils::{Reflector, Reflectable};
use dom::bindings::utils::{Reflector, Reflectable, cx_for_dom_object};
use dom::window::Window;
use js::jsapi::{JSObject, JSContext};
use js::jsapi::{JSObject, JSContext, JS_AddObjectRoot, JS_RemoveObjectRoot};
use layout_interface::TrustedNodeAddress;

use std::cast;
use std::cell::RefCell;

/// A type that represents a JS-owned value that may or may not be rooted.
/// Importantly, it requires rooting in order to interact with the value in any way.
/// 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<T> types) safely via the
/// `JS<T>::assign` method or `OptionalAssignable::assign` (for Option<JS<T>> fields).
pub struct Temporary<T> {
inner: JS<T>
inner: JS<T>,
}

impl<T> Eq for Temporary<T> {
@@ -24,19 +24,31 @@ impl<T> Eq for Temporary<T> {
}
}

#[unsafe_destructor]
impl<T: Reflectable> Drop for Temporary<T> {
fn drop(&mut self) {
let cx = cx_for_dom_object(&self.inner);
unsafe {
JS_RemoveObjectRoot(cx, self.inner.reflector().rootable());
}
}
}

impl<T: Reflectable> Temporary<T> {
/// Create a new Temporary value from a JS-owned value.
pub fn new(inner: JS<T>) -> Temporary<T> {
let cx = cx_for_dom_object(&inner);
unsafe {
JS_AddObjectRoot(cx, inner.reflector().rootable());
}
Temporary {
inner: inner
inner: inner,
}
}

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

/// Root this unrooted value.
@@ -412,6 +412,10 @@ impl Reflector {
self.object = object;
}

pub fn rootable(&self) -> **JSObject {
&self.object as **JSObject
}

pub fn new() -> Reflector {
Reflector {
object: ptr::null(),
@@ -616,14 +620,13 @@ 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) -> Temporary<window::Window> {
pub fn global_object_for_js_object(obj: *JSObject) -> JS<window::Window> {
unsafe {
let global = GetGlobalForObjectCrossCompartment(obj);
let clasp = JS_GetClass(global);
assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0);
Temporary::new(
FromJSValConvertible::from_jsval(ptr::null(), ObjectOrNullValue(global), ())
.ok().expect("found DOM global that doesn't unwrap to Window"))
FromJSValConvertible::from_jsval(ptr::null(), ObjectOrNullValue(global), ())
.ok().expect("found DOM global that doesn't unwrap to Window")
}
}

@@ -342,7 +342,7 @@ impl Window {
script_chan: ScriptChan,
compositor: ~ScriptListener,
image_cache_task: ImageCacheTask)
-> Temporary<Window> {
-> JS<Window> {
let win = ~Window {
eventtarget: EventTarget::new_inherited(WindowTypeId),
script_chan: script_chan,
@@ -357,6 +357,6 @@ impl Window {
browser_context: None,
};

Temporary::new(WindowBinding::Wrap(cx, win))
WindowBinding::Wrap(cx, win)
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.