mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Implement an Unrooted smart pointer to replace JS when it is not traced.
This commit is contained in:
parent
f451291782
commit
147dadce89
11 changed files with 137 additions and 63 deletions
|
@ -34,6 +34,7 @@ For supporting SpiderMonkey’s exact GC rooting, we introduce [some types](http
|
||||||
|
|
||||||
- `JS<T>` is used for the DOM typed field in a DOM type structure. The GC can trace them recursively while the enclosing DOM object (maybe root) is alive.
|
- `JS<T>` is used for the DOM typed field in a DOM type structure. The GC can trace them recursively while the enclosing DOM object (maybe root) is alive.
|
||||||
- `LayoutJS<T>` is specialized `JS<T>` to use in layout. `Layout*Helper` must be implemented on this type to prevent calling methods from non layout code.
|
- `LayoutJS<T>` is specialized `JS<T>` to use in layout. `Layout*Helper` must be implemented on this type to prevent calling methods from non layout code.
|
||||||
|
- `Unrooted<T>` is used to wrap raw pointers to DOM objects extracted from their reflectors.
|
||||||
- `Temporary<T>` is used as a return value for functions returning a DOM type. They are rooted for the duration of their lifetime. But a retun value gets moved around which can break the LIFO ordering constraint. Thus we need to introduce `Root<T>`.
|
- `Temporary<T>` is used as a return value for functions returning a DOM type. They are rooted for the duration of their lifetime. But a retun value gets moved around which can break the LIFO ordering constraint. Thus we need to introduce `Root<T>`.
|
||||||
- `Root<T>` contains the pointer to `JSObject` which the represented DOM type has. SpiderMonkey's conservative stack scanner scans it's pointers and marks a pointed `JSObject` as GC root.
|
- `Root<T>` contains the pointer to `JSObject` which the represented DOM type has. SpiderMonkey's conservative stack scanner scans it's pointers and marks a pointed `JSObject` as GC root.
|
||||||
- `JSRef` is just a reference to the value rooted by `Root<T>`.
|
- `JSRef` is just a reference to the value rooted by `Root<T>`.
|
||||||
|
|
|
@ -1673,7 +1673,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, config):
|
||||||
'dom::bindings::conversions::unwrap_jsmanaged',
|
'dom::bindings::conversions::unwrap_jsmanaged',
|
||||||
'dom::bindings::conversions::StringificationBehavior::Default',
|
'dom::bindings::conversions::StringificationBehavior::Default',
|
||||||
'dom::bindings::error::throw_not_in_union',
|
'dom::bindings::error::throw_not_in_union',
|
||||||
'dom::bindings::js::JS',
|
'dom::bindings::js::Unrooted',
|
||||||
'dom::types::*',
|
'dom::types::*',
|
||||||
'js::jsapi::JSContext',
|
'js::jsapi::JSContext',
|
||||||
'js::jsval::JSVal',
|
'js::jsval::JSVal',
|
||||||
|
@ -1795,7 +1795,7 @@ class CGAbstractMethod(CGThing):
|
||||||
assert(False) # Override me!
|
assert(False) # Override me!
|
||||||
|
|
||||||
def CreateBindingJSObject(descriptor, parent=None):
|
def CreateBindingJSObject(descriptor, parent=None):
|
||||||
create = "let mut raw: JS<%s> = JS::from_raw(&*object);\n" % descriptor.concreteType
|
create = "let mut raw: Unrooted<%s> = Unrooted::from_raw(&*object);\n" % descriptor.concreteType
|
||||||
if descriptor.proxy:
|
if descriptor.proxy:
|
||||||
assert not descriptor.isGlobal()
|
assert not descriptor.isGlobal()
|
||||||
create += """
|
create += """
|
||||||
|
@ -1853,7 +1853,7 @@ assert!(!proto.is_null());
|
||||||
|
|
||||||
raw.reflector().set_jsobject(obj);
|
raw.reflector().set_jsobject(obj);
|
||||||
|
|
||||||
Temporary::new(raw)""" % CreateBindingJSObject(self.descriptor, "scope"))
|
Temporary::from_unrooted(raw)""" % CreateBindingJSObject(self.descriptor, "scope"))
|
||||||
else:
|
else:
|
||||||
return CGGeneric("""\
|
return CGGeneric("""\
|
||||||
%s
|
%s
|
||||||
|
@ -1866,7 +1866,7 @@ with_compartment(cx, obj, || {
|
||||||
RegisterBindings::Register(cx, obj);
|
RegisterBindings::Register(cx, obj);
|
||||||
});
|
});
|
||||||
|
|
||||||
Temporary::new(raw)""" % CreateBindingJSObject(self.descriptor))
|
Temporary::from_unrooted(raw)""" % CreateBindingJSObject(self.descriptor))
|
||||||
|
|
||||||
|
|
||||||
class CGIDLInterface(CGThing):
|
class CGIDLInterface(CGThing):
|
||||||
|
@ -2447,7 +2447,7 @@ class CGAbstractBindingMethod(CGAbstractExternMethod):
|
||||||
" return false as JSBool;\n"
|
" return false as JSBool;\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"let this: JS<%s> = %s;\n" % (self.descriptor.concreteType, unwrapThis))
|
"let this: Unrooted<%s> = %s;\n" % (self.descriptor.concreteType, unwrapThis))
|
||||||
return CGList([ unwrapThis, self.generate_code() ], "\n")
|
return CGList([ unwrapThis, self.generate_code() ], "\n")
|
||||||
|
|
||||||
def generate_code(self):
|
def generate_code(self):
|
||||||
|
@ -2509,7 +2509,7 @@ class CGSpecializedMethod(CGAbstractExternMethod):
|
||||||
self.method)
|
self.method)
|
||||||
return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(),
|
return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(),
|
||||||
self.descriptor, self.method),
|
self.descriptor, self.method),
|
||||||
pre="let this = JS::from_raw(this);\n"
|
pre="let this = Unrooted::from_raw(this);\n"
|
||||||
"let this = this.root();\n")
|
"let this = this.root();\n")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -2575,7 +2575,7 @@ class CGSpecializedGetter(CGAbstractExternMethod):
|
||||||
|
|
||||||
return CGWrapper(CGGetterCall([], self.attr.type, nativeName,
|
return CGWrapper(CGGetterCall([], self.attr.type, nativeName,
|
||||||
self.descriptor, self.attr),
|
self.descriptor, self.attr),
|
||||||
pre="let this = JS::from_raw(this);\n"
|
pre="let this = Unrooted::from_raw(this);\n"
|
||||||
"let this = this.root();\n")
|
"let this = this.root();\n")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -2653,7 +2653,7 @@ class CGSpecializedSetter(CGAbstractExternMethod):
|
||||||
self.attr)
|
self.attr)
|
||||||
return CGWrapper(CGSetterCall([], self.attr.type, nativeName,
|
return CGWrapper(CGSetterCall([], self.attr.type, nativeName,
|
||||||
self.descriptor, self.attr),
|
self.descriptor, self.attr),
|
||||||
pre="let this = JS::from_raw(this);\n"
|
pre="let this = Unrooted::from_raw(this);\n"
|
||||||
"let this = this.root();\n")
|
"let this = this.root();\n")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -3636,7 +3636,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
|
||||||
get = ("if index.is_some() {\n" +
|
get = ("if index.is_some() {\n" +
|
||||||
" let index = index.unwrap();\n" +
|
" let index = index.unwrap();\n" +
|
||||||
" let this = UnwrapProxy(proxy);\n" +
|
" let this = UnwrapProxy(proxy);\n" +
|
||||||
" let this = JS::from_raw(this);\n" +
|
" let this = Unrooted::from_raw(this);\n" +
|
||||||
" let this = this.root();\n" +
|
" let this = this.root();\n" +
|
||||||
CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
|
CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
|
||||||
"}\n")
|
"}\n")
|
||||||
|
@ -3683,7 +3683,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
|
||||||
"if !set && RUST_JSID_IS_STRING(id) != 0 && !has_property_on_prototype(cx, proxy, id) {\n" +
|
"if !set && RUST_JSID_IS_STRING(id) != 0 && !has_property_on_prototype(cx, proxy, id) {\n" +
|
||||||
" let name = jsid_to_str(cx, id);\n" +
|
" let name = jsid_to_str(cx, id);\n" +
|
||||||
" let this = UnwrapProxy(proxy);\n" +
|
" let this = UnwrapProxy(proxy);\n" +
|
||||||
" let this = JS::from_raw(this);\n" +
|
" let this = Unrooted::from_raw(this);\n" +
|
||||||
" let this = this.root();\n" +
|
" let this = this.root();\n" +
|
||||||
CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" +
|
CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" +
|
||||||
"}\n")
|
"}\n")
|
||||||
|
@ -3729,7 +3729,7 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
|
||||||
"if index.is_some() {\n" +
|
"if index.is_some() {\n" +
|
||||||
" let index = index.unwrap();\n" +
|
" let index = index.unwrap();\n" +
|
||||||
" let this = UnwrapProxy(proxy);\n" +
|
" let this = UnwrapProxy(proxy);\n" +
|
||||||
" let this = JS::from_raw(this);\n" +
|
" let this = Unrooted::from_raw(this);\n" +
|
||||||
" let this = this.root();\n" +
|
" let this = this.root();\n" +
|
||||||
CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
|
CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
|
||||||
" return true;\n" +
|
" return true;\n" +
|
||||||
|
@ -3747,7 +3747,7 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
|
||||||
set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" +
|
set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" +
|
||||||
" let name = jsid_to_str(cx, id);\n" +
|
" let name = jsid_to_str(cx, id);\n" +
|
||||||
" let this = UnwrapProxy(proxy);\n" +
|
" let this = UnwrapProxy(proxy);\n" +
|
||||||
" let this = JS::from_raw(this);\n" +
|
" let this = Unrooted::from_raw(this);\n" +
|
||||||
" let this = this.root();\n" +
|
" let this = this.root();\n" +
|
||||||
CGIndenter(CGProxyNamedSetter(self.descriptor)).define() +
|
CGIndenter(CGProxyNamedSetter(self.descriptor)).define() +
|
||||||
"}\n")
|
"}\n")
|
||||||
|
@ -3755,7 +3755,7 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
|
||||||
set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" +
|
set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" +
|
||||||
" let name = jsid_to_str(cx, id);\n" +
|
" let name = jsid_to_str(cx, id);\n" +
|
||||||
" let this = UnwrapProxy(proxy);\n" +
|
" let this = UnwrapProxy(proxy);\n" +
|
||||||
" let this = JS::from_raw(this);\n" +
|
" let this = Unrooted::from_raw(this);\n" +
|
||||||
" let this = this.root();\n" +
|
" let this = this.root();\n" +
|
||||||
CGIndenter(CGProxyNamedGetter(self.descriptor)).define() +
|
CGIndenter(CGProxyNamedGetter(self.descriptor)).define() +
|
||||||
" if (found) {\n"
|
" if (found) {\n"
|
||||||
|
@ -3782,7 +3782,7 @@ class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
|
||||||
if self.descriptor.operations['NamedDeleter']:
|
if self.descriptor.operations['NamedDeleter']:
|
||||||
set += ("let name = jsid_to_str(cx, id);\n" +
|
set += ("let name = jsid_to_str(cx, id);\n" +
|
||||||
"let this = UnwrapProxy(proxy);\n" +
|
"let this = UnwrapProxy(proxy);\n" +
|
||||||
"let this = JS::from_raw(this);\n" +
|
"let this = Unrooted::from_raw(this);\n" +
|
||||||
"let this = this.root();\n" +
|
"let this = this.root();\n" +
|
||||||
"%s") % (CGProxyNamedDeleter(self.descriptor).define())
|
"%s") % (CGProxyNamedDeleter(self.descriptor).define())
|
||||||
set += "return proxyhandler::delete(%s);" % ", ".join(a.name for a in self.args)
|
set += "return proxyhandler::delete(%s);" % ", ".join(a.name for a in self.args)
|
||||||
|
@ -3804,7 +3804,7 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
|
||||||
"if index.is_some() {\n" +
|
"if index.is_some() {\n" +
|
||||||
" let index = index.unwrap();\n" +
|
" let index = index.unwrap();\n" +
|
||||||
" let this = UnwrapProxy(proxy);\n" +
|
" let this = UnwrapProxy(proxy);\n" +
|
||||||
" let this = JS::from_raw(this);\n" +
|
" let this = Unrooted::from_raw(this);\n" +
|
||||||
" let this = this.root();\n" +
|
" let this = this.root();\n" +
|
||||||
CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" +
|
CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" +
|
||||||
" *bp = found;\n" +
|
" *bp = found;\n" +
|
||||||
|
@ -3818,7 +3818,7 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
|
||||||
named = ("if RUST_JSID_IS_STRING(id) != 0 && !has_property_on_prototype(cx, proxy, id) {\n" +
|
named = ("if RUST_JSID_IS_STRING(id) != 0 && !has_property_on_prototype(cx, proxy, id) {\n" +
|
||||||
" let name = jsid_to_str(cx, id);\n" +
|
" let name = jsid_to_str(cx, id);\n" +
|
||||||
" let this = UnwrapProxy(proxy);\n" +
|
" let this = UnwrapProxy(proxy);\n" +
|
||||||
" let this = JS::from_raw(this);\n" +
|
" let this = Unrooted::from_raw(this);\n" +
|
||||||
" let this = this.root();\n" +
|
" let this = this.root();\n" +
|
||||||
CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" +
|
CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" +
|
||||||
" *bp = found;\n"
|
" *bp = found;\n"
|
||||||
|
@ -3877,7 +3877,7 @@ if !expando.is_null() {
|
||||||
"if index.is_some() {\n" +
|
"if index.is_some() {\n" +
|
||||||
" let index = index.unwrap();\n" +
|
" let index = index.unwrap();\n" +
|
||||||
" let this = UnwrapProxy(proxy);\n" +
|
" let this = UnwrapProxy(proxy);\n" +
|
||||||
" let this = JS::from_raw(this);\n" +
|
" let this = Unrooted::from_raw(this);\n" +
|
||||||
" let this = this.root();\n" +
|
" let this = this.root();\n" +
|
||||||
CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define())
|
CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define())
|
||||||
getIndexedOrExpando += """\
|
getIndexedOrExpando += """\
|
||||||
|
@ -3895,7 +3895,7 @@ if !expando.is_null() {
|
||||||
getNamed = ("if (RUST_JSID_IS_STRING(id) != 0) {\n" +
|
getNamed = ("if (RUST_JSID_IS_STRING(id) != 0) {\n" +
|
||||||
" let name = jsid_to_str(cx, id);\n" +
|
" let name = jsid_to_str(cx, id);\n" +
|
||||||
" let this = UnwrapProxy(proxy);\n" +
|
" let this = UnwrapProxy(proxy);\n" +
|
||||||
" let this = JS::from_raw(this);\n" +
|
" let this = Unrooted::from_raw(this);\n" +
|
||||||
" let this = this.root();\n" +
|
" let this = this.root();\n" +
|
||||||
CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
|
CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
|
||||||
"}\n")
|
"}\n")
|
||||||
|
@ -4545,7 +4545,7 @@ class CGBindingRoot(CGThing):
|
||||||
'dom::bindings',
|
'dom::bindings',
|
||||||
'dom::bindings::global::GlobalRef',
|
'dom::bindings::global::GlobalRef',
|
||||||
'dom::bindings::global::global_object_for_js_object',
|
'dom::bindings::global::global_object_for_js_object',
|
||||||
'dom::bindings::js::{JS, JSRef, Root, RootedReference, Temporary}',
|
'dom::bindings::js::{JS, JSRef, Root, RootedReference, Temporary, Unrooted}',
|
||||||
'dom::bindings::js::{OptionalRootable, OptionalRootedRootable, ResultRootable}',
|
'dom::bindings::js::{OptionalRootable, OptionalRootedRootable, ResultRootable}',
|
||||||
'dom::bindings::js::{OptionalRootedReference, OptionalOptionalRootedRootable}',
|
'dom::bindings::js::{OptionalRootedReference, OptionalOptionalRootedRootable}',
|
||||||
'dom::bindings::utils::{create_dom_global, do_create_interface_objects}',
|
'dom::bindings::utils::{create_dom_global, do_create_interface_objects}',
|
||||||
|
|
|
@ -157,7 +157,7 @@ class Descriptor(DescriptorProvider):
|
||||||
self.returnType = "Temporary<%s>" % ifaceName
|
self.returnType = "Temporary<%s>" % ifaceName
|
||||||
self.argumentType = "JSRef<%s>" % ifaceName
|
self.argumentType = "JSRef<%s>" % ifaceName
|
||||||
self.memberType = "Root<%s>" % ifaceName
|
self.memberType = "Root<%s>" % ifaceName
|
||||||
self.nativeType = "JS<%s>" % ifaceName
|
self.nativeType = "Unrooted<%s>" % ifaceName
|
||||||
|
|
||||||
self.concreteType = ifaceName
|
self.concreteType = ifaceName
|
||||||
self.register = desc.get('register', True)
|
self.register = desc.get('register', True)
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
//! | union types | `T` |
|
//! | union types | `T` |
|
||||||
|
|
||||||
use dom::bindings::codegen::PrototypeList;
|
use dom::bindings::codegen::PrototypeList;
|
||||||
use dom::bindings::js::{JS, JSRef, Root};
|
use dom::bindings::js::{JS, JSRef, Root, Unrooted};
|
||||||
use dom::bindings::str::ByteString;
|
use dom::bindings::str::ByteString;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, DOMClass};
|
use dom::bindings::utils::{Reflectable, Reflector, DOMClass};
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
@ -458,13 +458,13 @@ unsafe fn get_dom_class(obj: *mut JSObject) -> Result<DOMClass, ()> {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a `JS<T>` for the given DOM object, unwrapping any wrapper around it
|
/// Get an `Unrooted<T>` for the given DOM object, unwrapping any wrapper
|
||||||
/// first, and checking if the object is of the correct type.
|
/// around it first, and checking if the object is of the correct type.
|
||||||
///
|
///
|
||||||
/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is
|
/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is
|
||||||
/// not a reflector for a DOM object of the given type (as defined by the
|
/// not a reflector for a DOM object of the given type (as defined by the
|
||||||
/// proto_id and proto_depth).
|
/// proto_id and proto_depth).
|
||||||
pub fn unwrap_jsmanaged<T>(mut obj: *mut JSObject) -> Result<JS<T>, ()>
|
pub fn unwrap_jsmanaged<T>(mut obj: *mut JSObject) -> Result<Unrooted<T>, ()>
|
||||||
where T: Reflectable + IDLInterface
|
where T: Reflectable + IDLInterface
|
||||||
{
|
{
|
||||||
use js::glue::{IsWrapper, UnwrapObject};
|
use js::glue::{IsWrapper, UnwrapObject};
|
||||||
|
@ -493,7 +493,7 @@ pub fn unwrap_jsmanaged<T>(mut obj: *mut JSObject) -> Result<JS<T>, ()>
|
||||||
let proto_depth = IDLInterface::get_prototype_depth(None::<T>);
|
let proto_depth = IDLInterface::get_prototype_depth(None::<T>);
|
||||||
if dom_class.interface_chain[proto_depth] == proto_id {
|
if dom_class.interface_chain[proto_depth] == proto_id {
|
||||||
debug!("good prototype");
|
debug!("good prototype");
|
||||||
Ok(JS::from_raw(unwrap(obj)))
|
Ok(Unrooted::from_raw(unwrap(obj)))
|
||||||
} else {
|
} else {
|
||||||
debug!("bad prototype");
|
debug!("bad prototype");
|
||||||
Err(())
|
Err(())
|
||||||
|
@ -501,9 +501,10 @@ pub fn unwrap_jsmanaged<T>(mut obj: *mut JSObject) -> Result<JS<T>, ()>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Reflectable+IDLInterface> FromJSValConvertible for JS<T> {
|
impl<T: Reflectable+IDLInterface> FromJSValConvertible for Unrooted<T> {
|
||||||
type Config = ();
|
type Config = ();
|
||||||
fn from_jsval(_cx: *mut JSContext, value: JSVal, _option: ()) -> Result<JS<T>, ()> {
|
fn from_jsval(_cx: *mut JSContext, value: JSVal, _option: ())
|
||||||
|
-> Result<Unrooted<T>, ()> {
|
||||||
if !value.is_object() {
|
if !value.is_object() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -529,6 +530,12 @@ impl<'a, T: Reflectable> ToJSValConvertible for JS<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Reflectable> ToJSValConvertible for Unrooted<T> {
|
||||||
|
fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
|
||||||
|
self.reflector().to_jsval(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
|
impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
|
||||||
fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
|
fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//! code that works in workers as well as window scopes.
|
//! code that works in workers as well as window scopes.
|
||||||
|
|
||||||
use dom::bindings::conversions::FromJSValConvertible;
|
use dom::bindings::conversions::FromJSValConvertible;
|
||||||
use dom::bindings::js::{JS, JSRef, Root};
|
use dom::bindings::js::{JS, JSRef, Root, Unrooted};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers};
|
use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers};
|
||||||
use dom::window;
|
use dom::window;
|
||||||
|
@ -53,6 +53,15 @@ pub enum GlobalField {
|
||||||
Worker(JS<WorkerGlobalScope>),
|
Worker(JS<WorkerGlobalScope>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An unrooted reference to a global object.
|
||||||
|
#[must_root]
|
||||||
|
pub enum GlobalUnrooted {
|
||||||
|
/// An unrooted reference to a `Window` object.
|
||||||
|
Window(Unrooted<window::Window>),
|
||||||
|
/// An unrooted reference to a `WorkerGlobalScope` object.
|
||||||
|
Worker(Unrooted<WorkerGlobalScope>),
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> GlobalRef<'a> {
|
impl<'a> GlobalRef<'a> {
|
||||||
/// Get the `JSContext` for the `JSRuntime` associated with the thread
|
/// Get the `JSContext` for the `JSRuntime` associated with the thread
|
||||||
/// this global object is on.
|
/// this global object is on.
|
||||||
|
@ -136,20 +145,30 @@ impl GlobalField {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GlobalUnrooted {
|
||||||
|
/// Create a stack-bounded root for this reference.
|
||||||
|
pub fn root(&self) -> GlobalRoot {
|
||||||
|
match *self {
|
||||||
|
GlobalUnrooted::Window(ref window) => GlobalRoot::Window(window.root()),
|
||||||
|
GlobalUnrooted::Worker(ref worker) => GlobalRoot::Worker(worker.root()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn global_object_for_js_object(obj: *mut JSObject) -> GlobalField {
|
pub fn global_object_for_js_object(obj: *mut JSObject) -> GlobalUnrooted {
|
||||||
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);
|
||||||
match FromJSValConvertible::from_jsval(ptr::null_mut(), ObjectOrNullValue(global), ()) {
|
match FromJSValConvertible::from_jsval(ptr::null_mut(), ObjectOrNullValue(global), ()) {
|
||||||
Ok(window) => return GlobalField::Window(window),
|
Ok(window) => return GlobalUnrooted::Window(window),
|
||||||
Err(_) => (),
|
Err(_) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
match FromJSValConvertible::from_jsval(ptr::null_mut(), ObjectOrNullValue(global), ()) {
|
match FromJSValConvertible::from_jsval(ptr::null_mut(), ObjectOrNullValue(global), ()) {
|
||||||
Ok(worker) => return GlobalField::Worker(worker),
|
Ok(worker) => return GlobalUnrooted::Worker(worker),
|
||||||
Err(_) => (),
|
Err(_) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,46 @@ use std::marker::ContravariantLifetime;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
/// An unrooted, JS-owned value. Must not be held across a GC.
|
||||||
|
#[must_root]
|
||||||
|
pub struct Unrooted<T> {
|
||||||
|
ptr: NonZero<*const T>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Reflectable> Unrooted<T> {
|
||||||
|
/// Create a new JS-owned value wrapped from a raw Rust pointer.
|
||||||
|
pub unsafe fn from_raw(raw: *const T) -> Unrooted<T> {
|
||||||
|
assert!(!raw.is_null());
|
||||||
|
Unrooted {
|
||||||
|
ptr: NonZero::new(raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `Reflector` for this pointer.
|
||||||
|
pub fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||||
|
unsafe {
|
||||||
|
(**self.ptr).reflector()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an unsafe pointer to the interior of this object.
|
||||||
|
pub unsafe fn unsafe_get(&self) -> *const T {
|
||||||
|
*self.ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a stack-bounded root for this value.
|
||||||
|
pub fn root(self) -> Root<T> {
|
||||||
|
STACK_ROOTS.with(|ref collection| {
|
||||||
|
let RootCollectionPtr(collection) = collection.get().unwrap();
|
||||||
|
unsafe {
|
||||||
|
Root::new(&*collection, self.ptr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Copy for Unrooted<T> {}
|
||||||
|
|
||||||
/// A type that represents a JS-owned value that is rooted for the lifetime of this value.
|
/// 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.
|
/// Importantly, it requires explicit rooting in order to interact with the inner value.
|
||||||
/// Can be assigned into JS-owned member fields (i.e. `JS<T>` types) safely via the
|
/// Can be assigned into JS-owned member fields (i.e. `JS<T>` types) safely via the
|
||||||
|
@ -96,6 +136,15 @@ impl<T: Reflectable> Temporary<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new `Temporary` value from an unrooted value.
|
||||||
|
#[allow(unrooted_must_root)]
|
||||||
|
pub fn from_unrooted(unrooted: Unrooted<T>) -> Temporary<T> {
|
||||||
|
Temporary {
|
||||||
|
inner: JS { ptr: unrooted.ptr },
|
||||||
|
_js_ptr: unrooted.reflector().get_jsobject(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new `Temporary` value from a rooted value.
|
/// Create a new `Temporary` value from a rooted value.
|
||||||
pub fn from_rooted<'a>(root: JSRef<'a, T>) -> Temporary<T> {
|
pub fn from_rooted<'a>(root: JSRef<'a, T>) -> Temporary<T> {
|
||||||
Temporary::new(JS::from_rooted(root))
|
Temporary::new(JS::from_rooted(root))
|
||||||
|
@ -106,7 +155,7 @@ impl<T: Reflectable> Temporary<T> {
|
||||||
STACK_ROOTS.with(|ref collection| {
|
STACK_ROOTS.with(|ref collection| {
|
||||||
let RootCollectionPtr(collection) = collection.get().unwrap();
|
let RootCollectionPtr(collection) = collection.get().unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
Root::new(&*collection, &self.inner)
|
Root::new(&*collection, self.inner.ptr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -198,21 +247,12 @@ impl LayoutJS<Node> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Reflectable> JS<T> {
|
impl<T: Reflectable> JS<T> {
|
||||||
/// Create a new JS-owned value wrapped from a raw Rust pointer.
|
|
||||||
pub unsafe fn from_raw(raw: *const T) -> JS<T> {
|
|
||||||
assert!(!raw.is_null());
|
|
||||||
JS {
|
|
||||||
ptr: NonZero::new(raw)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Root this JS-owned value to prevent its collection as garbage.
|
/// Root this JS-owned value to prevent its collection as garbage.
|
||||||
pub fn root(&self) -> Root<T> {
|
pub fn root(&self) -> Root<T> {
|
||||||
STACK_ROOTS.with(|ref collection| {
|
STACK_ROOTS.with(|ref collection| {
|
||||||
let RootCollectionPtr(collection) = collection.get().unwrap();
|
let RootCollectionPtr(collection) = collection.get().unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
Root::new(&*collection, self)
|
Root::new(&*collection, self.ptr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -484,6 +524,12 @@ impl<T: Reflectable> OptionalRootedRootable<T> for Option<JS<T>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Reflectable> OptionalRootedRootable<T> for Option<Unrooted<T>> {
|
||||||
|
fn root(&self) -> Option<Root<T>> {
|
||||||
|
self.as_ref().map(|inner| inner.root())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Root a rootable `Option<Option>` type (used for `Option<Option<JS<T>>>`)
|
/// Root a rootable `Option<Option>` type (used for `Option<Option<JS<T>>>`)
|
||||||
pub trait OptionalOptionalRootedRootable<T> {
|
pub trait OptionalOptionalRootedRootable<T> {
|
||||||
/// Root the inner value, if it exists.
|
/// Root the inner value, if it exists.
|
||||||
|
@ -496,6 +542,12 @@ impl<T: Reflectable> OptionalOptionalRootedRootable<T> for Option<Option<JS<T>>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Reflectable> OptionalOptionalRootedRootable<T> for Option<Option<Unrooted<T>>> {
|
||||||
|
fn root(&self) -> Option<Option<Root<T>>> {
|
||||||
|
self.as_ref().map(|inner| inner.root())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Root a rootable `Result` type (any of `Temporary<T>` or `JS<T>`)
|
/// Root a rootable `Result` type (any of `Temporary<T>` or `JS<T>`)
|
||||||
pub trait ResultRootable<T,U> {
|
pub trait ResultRootable<T,U> {
|
||||||
|
@ -593,11 +645,12 @@ impl<T: Reflectable> Root<T> {
|
||||||
/// Create a new stack-bounded root for the provided JS-owned value.
|
/// Create a new stack-bounded root for the provided JS-owned value.
|
||||||
/// It cannot not outlive its associated `RootCollection`, and it contains a `JSRef`
|
/// It cannot not outlive its associated `RootCollection`, and it contains a `JSRef`
|
||||||
/// which cannot outlive this new `Root`.
|
/// which cannot outlive this new `Root`.
|
||||||
fn new(roots: &'static RootCollection, unrooted: &JS<T>) -> Root<T> {
|
fn new(roots: &'static RootCollection, unrooted: NonZero<*const T>)
|
||||||
|
-> Root<T> {
|
||||||
let root = Root {
|
let root = Root {
|
||||||
root_list: roots,
|
root_list: roots,
|
||||||
ptr: unrooted.ptr,
|
ptr: unrooted,
|
||||||
js_ptr: unrooted.reflector().get_jsobject(),
|
js_ptr: unsafe { (**unrooted).reflector().get_jsobject() },
|
||||||
};
|
};
|
||||||
roots.root(&root);
|
roots.root(&root);
|
||||||
root
|
root
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
//! is rooted when a hashmap entry is first created, and unrooted when the hashmap entry
|
//! is rooted when a hashmap entry is first created, and unrooted when the hashmap entry
|
||||||
//! is removed.
|
//! is removed.
|
||||||
|
|
||||||
use dom::bindings::js::{Temporary, JS, JSRef};
|
use dom::bindings::js::{Temporary, JSRef, Unrooted};
|
||||||
use dom::bindings::utils::{Reflector, Reflectable};
|
use dom::bindings::utils::{Reflector, Reflectable};
|
||||||
use script_task::{ScriptMsg, ScriptChan};
|
use script_task::{ScriptMsg, ScriptChan};
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ impl<T: Reflectable> Trusted<T> {
|
||||||
self.owner_thread == (&*live_references) as *const _ as *const libc::c_void
|
self.owner_thread == (&*live_references) as *const _ as *const libc::c_void
|
||||||
}));
|
}));
|
||||||
unsafe {
|
unsafe {
|
||||||
Temporary::new(JS::from_raw(self.ptr as *const T))
|
Temporary::from_unrooted(Unrooted::from_raw(self.ptr as *const T))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
use dom::bindings::js::JS;
|
use dom::bindings::js::JS;
|
||||||
use dom::bindings::refcounted::Trusted;
|
use dom::bindings::refcounted::Trusted;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, WindowProxyHandler};
|
use dom::bindings::utils::{Reflectable, Reflector, WindowProxyHandler};
|
||||||
use dom::node::{Node, TrustedNodeAddress};
|
|
||||||
use script_task::ScriptChan;
|
use script_task::ScriptChan;
|
||||||
|
|
||||||
use cssparser::RGBA;
|
use cssparser::RGBA;
|
||||||
|
@ -257,13 +256,3 @@ impl JSTraceable for Box<LayoutRPC+'static> {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JSTraceable for TrustedNodeAddress {
|
|
||||||
fn trace(&self, s: *mut JSTracer) {
|
|
||||||
let TrustedNodeAddress(addr) = *self;
|
|
||||||
let node = addr as *const Node;
|
|
||||||
unsafe {
|
|
||||||
JS::from_raw(node).trace(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use dom::bindings::codegen::UnionTypes::FileOrString;
|
||||||
use dom::bindings::codegen::UnionTypes::FileOrString::{eFile, eString};
|
use dom::bindings::codegen::UnionTypes::FileOrString::{eFile, eString};
|
||||||
use dom::bindings::error::{Fallible};
|
use dom::bindings::error::{Fallible};
|
||||||
use dom::bindings::global::{GlobalRef, GlobalField};
|
use dom::bindings::global::{GlobalRef, GlobalField};
|
||||||
use dom::bindings::js::{JS, JSRef, Temporary};
|
use dom::bindings::js::{JS, JSRef, Temporary, Unrooted};
|
||||||
use dom::bindings::utils::{Reflector, reflect_dom_object};
|
use dom::bindings::utils::{Reflector, reflect_dom_object};
|
||||||
use dom::blob::Blob;
|
use dom::blob::Blob;
|
||||||
use dom::file::File;
|
use dom::file::File;
|
||||||
|
@ -82,12 +82,15 @@ impl<'a> FormDataMethods for JSRef<'a, FormData> {
|
||||||
self.data.borrow_mut().remove(&name);
|
self.data.borrow_mut().remove(&name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_blocks)]
|
||||||
fn Get(self, name: DOMString) -> Option<FileOrString> {
|
fn Get(self, name: DOMString) -> Option<FileOrString> {
|
||||||
if self.data.borrow().contains_key(&name) {
|
if self.data.borrow().contains_key(&name) {
|
||||||
match (*self.data.borrow())[name][0].clone() {
|
match (*self.data.borrow())[name][0].clone() {
|
||||||
FormDatum::StringData(ref s) => Some(eString(s.clone())),
|
FormDatum::StringData(ref s) => Some(eString(s.clone())),
|
||||||
FormDatum::FileData(ref f) => {
|
FormDatum::FileData(ref f) => {
|
||||||
Some(eFile(f.clone()))
|
Some(eFile(unsafe {
|
||||||
|
Unrooted::from_raw(f.unsafe_get())
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -38,7 +38,9 @@
|
||||||
//! * returning pointers from functions: the
|
//! * returning pointers from functions: the
|
||||||
//! [`Temporary`](bindings/js/struct.Temporary.html) smart pointer;
|
//! [`Temporary`](bindings/js/struct.Temporary.html) smart pointer;
|
||||||
//! * rooting pointers from across task boundaries or in channels: the
|
//! * rooting pointers from across task boundaries or in channels: the
|
||||||
//! [`Trusted`](bindings/refcounted/struct.Trusted.html) smart pointer.
|
//! [`Trusted`](bindings/refcounted/struct.Trusted.html) smart pointer;
|
||||||
|
//! * extracting pointers to DOM objects from their reflectors: the
|
||||||
|
//! [`Unrooted`](bindings/js/struct.Unrooted.html) smart pointer.
|
||||||
//!
|
//!
|
||||||
//! Inheritance
|
//! Inheritance
|
||||||
//! ===========
|
//! ===========
|
||||||
|
|
|
@ -23,7 +23,7 @@ use dom::bindings::conversions;
|
||||||
use dom::bindings::error::Fallible;
|
use dom::bindings::error::Fallible;
|
||||||
use dom::bindings::error::Error::{NotFound, HierarchyRequest, Syntax};
|
use dom::bindings::error::Error::{NotFound, HierarchyRequest, Syntax};
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::js::{JS, JSRef, LayoutJS, RootedReference, Temporary, Root};
|
use dom::bindings::js::{JS, JSRef, LayoutJS, RootedReference, Temporary, Root, Unrooted};
|
||||||
use dom::bindings::js::{TemporaryPushable, OptionalRootedRootable};
|
use dom::bindings::js::{TemporaryPushable, OptionalRootedRootable};
|
||||||
use dom::bindings::js::{ResultRootable, OptionalRootable, MutNullableJS};
|
use dom::bindings::js::{ResultRootable, OptionalRootable, MutNullableJS};
|
||||||
use dom::bindings::trace::JSTraceable;
|
use dom::bindings::trace::JSTraceable;
|
||||||
|
@ -907,7 +907,7 @@ pub fn from_untrusted_node_address(runtime: *mut JSRuntime, candidate: Untrusted
|
||||||
panic!("Attempted to create a `JS<Node>` from an invalid pointer!")
|
panic!("Attempted to create a `JS<Node>` from an invalid pointer!")
|
||||||
}
|
}
|
||||||
let boxed_node: *const Node = conversions::unwrap(object);
|
let boxed_node: *const Node = conversions::unwrap(object);
|
||||||
Temporary::new(JS::from_raw(boxed_node))
|
Temporary::from_unrooted(Unrooted::from_raw(boxed_node))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue