Root Temporary values for the duration of their lifetime.

This commit is contained in:
Josh Matthews 2014-04-17 20:28:01 -04:00
parent 522d3f167b
commit a09a4bd297
3 changed files with 30 additions and 15 deletions

View file

@ -2,20 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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 dom::window::Window;
use js::jsapi::{JSObject, JSContext}; use js::jsapi::{JSObject, JSContext, JS_AddObjectRoot, JS_RemoveObjectRoot};
use layout_interface::TrustedNodeAddress; use layout_interface::TrustedNodeAddress;
use std::cast; use std::cast;
use std::cell::RefCell; use std::cell::RefCell;
/// A type that represents a JS-owned value that may or may not be rooted. /// A type that represents a JS-owned value that is rooted for the lifetime of this value.
/// Importantly, it requires rooting in order to interact with the value in any way. /// 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 /// 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). /// `JS<T>::assign` method or `OptionalAssignable::assign` (for Option<JS<T>> fields).
pub struct Temporary<T> { pub struct Temporary<T> {
inner: JS<T> inner: JS<T>,
} }
impl<T> Eq for Temporary<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> { impl<T: Reflectable> Temporary<T> {
/// Create a new Temporary value from a JS-owned value. /// Create a new Temporary value from a JS-owned value.
pub fn new(inner: JS<T>) -> Temporary<T> { pub fn new(inner: JS<T>) -> Temporary<T> {
let cx = cx_for_dom_object(&inner);
unsafe {
JS_AddObjectRoot(cx, inner.reflector().rootable());
}
Temporary { Temporary {
inner: inner inner: inner,
} }
} }
/// Create a new Temporary value from a rooted value. /// Create a new Temporary value from a rooted value.
pub fn new_rooted<'a>(root: &JSRef<'a, T>) -> Temporary<T> { pub fn new_rooted<'a>(root: &JSRef<'a, T>) -> Temporary<T> {
Temporary { Temporary::new(root.unrooted())
inner: root.unrooted()
}
} }
/// Root this unrooted value. /// Root this unrooted value.

View file

@ -412,6 +412,10 @@ impl Reflector {
self.object = object; self.object = object;
} }
pub fn rootable(&self) -> **JSObject {
&self.object as **JSObject
}
pub fn new() -> Reflector { pub fn new() -> Reflector {
Reflector { Reflector {
object: ptr::null(), 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. /// 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 { unsafe {
let global = GetGlobalForObjectCrossCompartment(obj); let global = GetGlobalForObjectCrossCompartment(obj);
let clasp = JS_GetClass(global); let clasp = JS_GetClass(global);
assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0); assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0);
Temporary::new(
FromJSValConvertible::from_jsval(ptr::null(), ObjectOrNullValue(global), ()) FromJSValConvertible::from_jsval(ptr::null(), ObjectOrNullValue(global), ())
.ok().expect("found DOM global that doesn't unwrap to Window")) .ok().expect("found DOM global that doesn't unwrap to Window")
} }
} }

View file

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