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
* 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.

View file

@ -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")
}
}

View file

@ -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)
}
}