mirror of
https://github.com/servo/servo.git
synced 2025-10-17 16:59:27 +01:00
Turn on GC all the time. Fix rooting errors during parsing and storing timers. Fix borrow errors during tracing.
This commit is contained in:
parent
4051a8096d
commit
ffdc3f5b32
109 changed files with 1567 additions and 996 deletions
|
@ -281,6 +281,7 @@ class CGMethodCall(CGThing):
|
|||
isDefinitelyObject=True),
|
||||
{
|
||||
"declName" : "arg%d" % distinguishingIndex,
|
||||
"simpleDeclName" : "arg%d" % distinguishingIndex,
|
||||
"holderName" : ("arg%d" % distinguishingIndex) + "_holder",
|
||||
"val" : distinguishingArg
|
||||
})
|
||||
|
@ -551,12 +552,21 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
|||
templateBody += (
|
||||
"} else {\n" +
|
||||
CGIndenter(onFailureNotAnObject(failureCode)).define() +
|
||||
"}")
|
||||
"}\n")
|
||||
if type.nullable():
|
||||
templateBody = handleDefaultNull(templateBody, "None")
|
||||
else:
|
||||
assert(defaultValue is None)
|
||||
|
||||
#if type.isGeckoInterface() and not type.unroll().inner.isCallback():
|
||||
# if type.nullable() or isOptional:
|
||||
#
|
||||
# else:
|
||||
#
|
||||
# templateBody = CGList([CGGeneric(templateBody),
|
||||
# CGGeneric("\n"),
|
||||
# CGGeneric(rootBody)]).define()
|
||||
|
||||
return templateBody
|
||||
|
||||
assert not (isEnforceRange and isClamp) # These are mutually exclusive
|
||||
|
@ -888,6 +898,18 @@ def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
|
|||
# Add an empty CGGeneric to get an extra newline after the argument
|
||||
# conversion.
|
||||
result.append(CGGeneric(""))
|
||||
|
||||
type = declType.define() if declType else None
|
||||
if type and 'JS<' in type:
|
||||
if dealWithOptional or 'Option<' in type:
|
||||
rootBody = """let ${simpleDeclName} = ${declName}.as_ref().map(|inner| {
|
||||
inner.root(&roots) //second root code
|
||||
});"""
|
||||
else:
|
||||
rootBody = "let ${simpleDeclName} = ${declName}.root(&roots); //third root code"
|
||||
result.append(CGGeneric(string.Template(rootBody).substitute(replacements)))
|
||||
result.append(CGGeneric(""))
|
||||
|
||||
return result;
|
||||
|
||||
def convertConstIDLValueToJSVal(value):
|
||||
|
@ -929,6 +951,7 @@ class CGArgumentConverter(CGThing):
|
|||
}
|
||||
self.replacementVariables = {
|
||||
"declName" : "arg%d" % index,
|
||||
"simpleDeclName" : "arg%d" % index,
|
||||
"holderName" : ("arg%d" % index) + "_holder"
|
||||
}
|
||||
self.replacementVariables["val"] = string.Template(
|
||||
|
@ -1691,6 +1714,8 @@ class Argument():
|
|||
A class for outputting the type and name of an argument
|
||||
"""
|
||||
def __init__(self, argType, name, default=None, mutable=False):
|
||||
if argType and 'JS<' in argType:
|
||||
argType = argType.replace('JS<', 'JSRef<')
|
||||
self.argType = argType
|
||||
self.name = name
|
||||
self.default = default
|
||||
|
@ -1763,7 +1788,7 @@ class CGAbstractMethod(CGThing):
|
|||
def _returnType(self):
|
||||
return (" -> %s" % self.returnType) if self.returnType != "void" else ""
|
||||
def _unsafe_open(self):
|
||||
return "\n unsafe {" if self.unsafe else ""
|
||||
return "\n unsafe {\n let roots = RootCollection::new();\n" if self.unsafe else ""
|
||||
def _unsafe_close(self):
|
||||
return "\n }\n" if self.unsafe else ""
|
||||
|
||||
|
@ -1809,7 +1834,7 @@ class CGWrapMethod(CGAbstractMethod):
|
|||
def __init__(self, descriptor):
|
||||
assert descriptor.interface.hasInterfacePrototypeObject()
|
||||
if not descriptor.createGlobal:
|
||||
args = [Argument('*JSContext', 'aCx'), Argument('&JS<Window>', 'aScope'),
|
||||
args = [Argument('*JSContext', 'aCx'), Argument('&JSRef<Window>', 'aScope'),
|
||||
Argument("~" + descriptor.concreteType, 'aObject', mutable=True)]
|
||||
else:
|
||||
args = [Argument('*JSContext', 'aCx'),
|
||||
|
@ -2277,7 +2302,12 @@ class CGPerSignatureCall(CGThing):
|
|||
def getArgc(self):
|
||||
return "argc"
|
||||
def getArguments(self):
|
||||
return [(a, "arg" + str(i)) for (i, a) in enumerate(self.arguments)]
|
||||
def process(arg, i):
|
||||
argVal = "arg" + str(i)
|
||||
if arg.type.isGeckoInterface() and not arg.type.unroll().inner.isCallback():
|
||||
argVal += ".root_ref()"
|
||||
return argVal
|
||||
return [(a, process(a, i)) for (i, a) in enumerate(self.arguments)]
|
||||
|
||||
def isFallible(self):
|
||||
return not 'infallible' in self.extendedAttributes
|
||||
|
@ -2452,8 +2482,10 @@ class CGSpecializedMethod(CGAbstractExternMethod):
|
|||
argsPre = []
|
||||
if name in self.descriptor.needsAbstract:
|
||||
abstractName = re.sub(r'<\w+>', '', self.descriptor.nativeType)
|
||||
extraPre = ' let mut abstract_this = %s::from_raw(this);\n' % abstractName
|
||||
argsPre = ['&mut abstract_this']
|
||||
extraPre = """ let mut abstract_this = %s::from_raw(this);
|
||||
let abstract_this = abstract_this.root(&roots);
|
||||
""" % abstractName
|
||||
argsPre = ['&mut abstract_this.root_ref()']
|
||||
return CGWrapper(CGMethodCall(argsPre, nativeName, self.method.isStatic(),
|
||||
self.descriptor, self.method),
|
||||
pre=extraPre +
|
||||
|
@ -2480,10 +2512,8 @@ class CGGenericGetter(CGAbstractBindingMethod):
|
|||
|
||||
def generate_code(self):
|
||||
return CGIndenter(CGGeneric(
|
||||
"return with_gc_disabled(cx, || {\n"
|
||||
" let info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, &*vp));\n"
|
||||
" CallJitPropertyOp(info, cx, obj, this.unsafe_get() as *libc::c_void, &*vp)\n"
|
||||
"});\n"))
|
||||
"let info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, &*vp));\n"
|
||||
"return CallJitPropertyOp(info, cx, obj, this.unsafe_get() as *libc::c_void, &*vp);\n"))
|
||||
|
||||
class CGSpecializedGetter(CGAbstractExternMethod):
|
||||
"""
|
||||
|
@ -2509,8 +2539,10 @@ class CGSpecializedGetter(CGAbstractExternMethod):
|
|||
getter=True))
|
||||
if name in self.descriptor.needsAbstract:
|
||||
abstractName = re.sub(r'<\w+>', '', self.descriptor.nativeType)
|
||||
extraPre = ' let mut abstract_this = %s::from_raw(this);\n' % abstractName
|
||||
argsPre = ['&mut abstract_this']
|
||||
extraPre = """ let mut abstract_this = %s::from_raw(this);
|
||||
let abstract_this = abstract_this.root(&roots);
|
||||
""" % abstractName
|
||||
argsPre = ['&mut abstract_this.root_ref()']
|
||||
if self.attr.type.nullable() or not infallible:
|
||||
nativeName = "Get" + nativeName
|
||||
return CGWrapper(CGIndenter(CGGetterCall(argsPre, self.attr.type, nativeName,
|
||||
|
@ -2541,10 +2573,7 @@ class CGGenericSetter(CGAbstractBindingMethod):
|
|||
"let undef = UndefinedValue();\n"
|
||||
"let argv: *JSVal = if argc != 0 { JS_ARGV(cx, vp as *JSVal) } else { &undef as *JSVal };\n"
|
||||
"let info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp as *JSVal));\n"
|
||||
"let ok = with_gc_disabled(cx, || {\n"
|
||||
" CallJitPropertyOp(info, cx, obj, this.unsafe_get() as *libc::c_void, argv)\n"
|
||||
"});\n"
|
||||
"if ok == 0 {\n"
|
||||
"if CallJitPropertyOp(info, cx, obj, this.unsafe_get() as *libc::c_void, argv) == 0 {\n"
|
||||
" return 0;\n"
|
||||
"}\n"
|
||||
"*vp = UndefinedValue();\n"
|
||||
|
@ -2571,8 +2600,10 @@ class CGSpecializedSetter(CGAbstractExternMethod):
|
|||
extraPre = ''
|
||||
if name in self.descriptor.needsAbstract:
|
||||
abstractName = re.sub(r'<\w+>', '', self.descriptor.nativeType)
|
||||
extraPre = ' let mut abstract_this = %s::from_raw(this);\n' % abstractName
|
||||
argsPre = ['&mut abstract_this']
|
||||
extraPre = """ let mut abstract_this = %s::from_raw(this);
|
||||
let abstract_this = abstract_this.root(&roots);
|
||||
""" % abstractName
|
||||
argsPre = ['&mut abstract_this.root_ref()']
|
||||
return CGWrapper(CGIndenter(CGSetterCall(argsPre, self.attr.type, nativeName,
|
||||
self.descriptor, self.attr)),
|
||||
pre=extraPre +
|
||||
|
@ -3402,6 +3433,7 @@ class CGProxySpecialOperation(CGPerSignatureCall):
|
|||
treatNullAs=argument.treatNullAs)
|
||||
templateValues = {
|
||||
"declName": argument.identifier.name,
|
||||
"simpleDeclName": argument.identifier.name,
|
||||
"holderName": argument.identifier.name + "_holder",
|
||||
"val": "(*desc).value",
|
||||
"valPtr": "&(*desc).value"
|
||||
|
@ -3411,7 +3443,12 @@ class CGProxySpecialOperation(CGPerSignatureCall):
|
|||
self.cgRoot.prepend(CGGeneric("let mut found = false;"))
|
||||
|
||||
def getArguments(self):
|
||||
args = [(a, a.identifier.name) for a in self.arguments]
|
||||
def process(arg):
|
||||
argVal = arg.identifier.name
|
||||
if arg.type.isGeckoInterface() and not arg.type.unroll().inner.isCallback():
|
||||
argVal += ".root_ref()"
|
||||
return argVal
|
||||
args = [(a, process(a)) for a in self.arguments]
|
||||
if self.idlNode.isGetter():
|
||||
args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean],
|
||||
self.idlNode),
|
||||
|
@ -3825,11 +3862,13 @@ class CGClassConstructHook(CGAbstractExternMethod):
|
|||
|
||||
def generate_code(self):
|
||||
preamble = """
|
||||
let roots = RootCollection::new();
|
||||
let global = global_object_for_js_object(JS_CALLEE(cx, &*vp).to_object());
|
||||
let global = global.root(&roots);
|
||||
let obj = global.reflector().get_jsobject();
|
||||
"""
|
||||
nativeName = MakeNativeName(self._ctor.identifier.name)
|
||||
callGenerator = CGMethodCall(["&global"], nativeName, True,
|
||||
callGenerator = CGMethodCall(["&global.root_ref()"], nativeName, True,
|
||||
self.descriptor, self._ctor)
|
||||
return preamble + callGenerator.define();
|
||||
|
||||
|
@ -4067,6 +4106,7 @@ class CGDictionary(CGThing):
|
|||
return string.Template(
|
||||
"impl ${selfName} {\n"
|
||||
" pub fn new(cx: *JSContext, val: JSVal) -> Result<${selfName}, ()> {\n"
|
||||
" let roots = RootCollection::new();\n" # XXXjdm need to root dict members outside of Init
|
||||
" let object = if val.is_null_or_undefined() {\n"
|
||||
" ptr::null()\n"
|
||||
" } else if val.is_object() {\n"
|
||||
|
@ -4266,7 +4306,7 @@ class CGBindingRoot(CGThing):
|
|||
'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING}',
|
||||
'dom::types::*',
|
||||
'dom::bindings',
|
||||
'dom::bindings::js::JS',
|
||||
'dom::bindings::js::{JS, JSRef, RootCollection, RootedReference}',
|
||||
'dom::bindings::utils::{CreateDOMGlobal, CreateInterfaceObjects2}',
|
||||
'dom::bindings::utils::{ConstantSpec, cx_for_dom_object, Default}',
|
||||
'dom::bindings::utils::{dom_object_slot, DOM_OBJECT_SLOT, DOMClass}',
|
||||
|
@ -4279,8 +4319,7 @@ class CGBindingRoot(CGThing):
|
|||
'dom::bindings::utils::{Reflectable}',
|
||||
'dom::bindings::utils::{squirrel_away_unique}',
|
||||
'dom::bindings::utils::{ThrowingConstructor, unwrap, unwrap_jsmanaged}',
|
||||
'dom::bindings::utils::{VoidVal, with_gc_disabled}',
|
||||
'dom::bindings::utils::{with_gc_enabled}',
|
||||
'dom::bindings::utils::VoidVal',
|
||||
'dom::bindings::utils::get_dictionary_property',
|
||||
'dom::bindings::trace::JSTraceable',
|
||||
'dom::bindings::callback::{CallbackContainer,CallbackInterface}',
|
||||
|
@ -5057,11 +5096,8 @@ class CallbackMethod(CallbackMember):
|
|||
replacements["argc"] = "0"
|
||||
return string.Template("${getCallable}"
|
||||
"let ok = unsafe {\n"
|
||||
" //JS_AllowGC(cx); // It's unsafe to enable GC at arbitrary points during Rust execution; leave it disabled\n"
|
||||
" let ok = JS_CallFunctionValue(cx, ${thisObj}, callable,\n"
|
||||
" ${argc}, ${argv}, &rval);\n"
|
||||
" //JS_InhibitGC(cx);\n"
|
||||
" ok\n"
|
||||
" JS_CallFunctionValue(cx, ${thisObj}, callable,\n"
|
||||
" ${argc}, ${argv}, &rval)\n"
|
||||
"};\n"
|
||||
"if ok == 0 {\n"
|
||||
" return${errorReturn};\n"
|
||||
|
@ -5209,7 +5245,7 @@ class GlobalGenRoots():
|
|||
# TODO - Generate the methods we want
|
||||
return CGImports(CGRegisterProtos(config), [
|
||||
'dom::bindings::codegen',
|
||||
'dom::bindings::js::JS',
|
||||
'dom::bindings::js::{JS, JSRef}',
|
||||
'dom::window::Window',
|
||||
'script_task::JSPageInfo',
|
||||
])
|
||||
|
@ -5241,7 +5277,7 @@ class GlobalGenRoots():
|
|||
descriptors = config.getDescriptors(register=True, hasInterfaceObject=True)
|
||||
allprotos = [CGGeneric("#![allow(unused_imports)]\n"),
|
||||
CGGeneric("use dom::types::*;\n"),
|
||||
CGGeneric("use dom::bindings::js::JS;\n"),
|
||||
CGGeneric("use dom::bindings::js::{JS, JSRef};\n"),
|
||||
CGGeneric("use dom::bindings::trace::JSTraceable;\n"),
|
||||
CGGeneric("use serialize::{Encodable, Encoder};\n"),
|
||||
CGGeneric("use js::jsapi::JSTracer;\n\n")]
|
||||
|
@ -5286,6 +5322,14 @@ class GlobalGenRoots():
|
|||
assert!(base.get().${checkFn}());
|
||||
base.clone().transmute()
|
||||
}
|
||||
|
||||
fn from_ref<'a, 'b, T: ${fromBound}>(derived: &'a JSRef<'b, T>) -> &'a JSRef<'b, Self> {
|
||||
unsafe { derived.transmute() }
|
||||
}
|
||||
|
||||
fn from_mut_ref<'a, 'b, T: ${fromBound}>(derived: &'a mut JSRef<'b, T>) -> &'a mut JSRef<'b, Self> {
|
||||
unsafe { derived.transmute_mut() }
|
||||
}
|
||||
}
|
||||
''').substitute({'checkFn': 'is_' + name.lower(),
|
||||
'castTraitName': name + 'Cast',
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
* 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;
|
||||
use dom::bindings::js::{JS, JSRef};
|
||||
use dom::bindings::str::ByteString;
|
||||
use dom::bindings::utils::Reflectable;
|
||||
use dom::bindings::utils::{Reflectable, Reflector};
|
||||
use dom::bindings::utils::jsstring_to_str;
|
||||
use dom::bindings::utils::unwrap_jsmanaged;
|
||||
use servo_util::str::DOMString;
|
||||
|
@ -293,9 +293,9 @@ impl FromJSValConvertible<()> for ByteString {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Reflectable> ToJSValConvertible for JS<T> {
|
||||
impl ToJSValConvertible for Reflector {
|
||||
fn to_jsval(&self, cx: *JSContext) -> JSVal {
|
||||
let obj = self.reflector().get_jsobject();
|
||||
let obj = self.get_jsobject();
|
||||
assert!(obj.is_not_null());
|
||||
let mut value = ObjectValue(unsafe { &*obj });
|
||||
if unsafe { JS_WrapValue(cx, &mut value as *mut JSVal as *JSVal) } == 0 {
|
||||
|
@ -316,6 +316,18 @@ impl<T: Reflectable+IDLInterface> FromJSValConvertible<()> for JS<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Reflectable> ToJSValConvertible for JS<T> {
|
||||
fn to_jsval(&self, cx: *JSContext) -> JSVal {
|
||||
self.reflector().to_jsval(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Reflectable> ToJSValConvertible for JSRef<'a, T> {
|
||||
fn to_jsval(&self, cx: *JSContext) -> JSVal {
|
||||
self.reflector().to_jsval(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
|
||||
fn to_jsval(&self, cx: *JSContext) -> JSVal {
|
||||
match self {
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
|
||||
use dom::bindings::utils::{Reflector, Reflectable};
|
||||
use dom::window::Window;
|
||||
use js::jsapi::JSContext;
|
||||
use js::jsapi::{JSObject, JSContext};
|
||||
use layout_interface::TrustedNodeAddress;
|
||||
|
||||
use std::cast;
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::ptr;
|
||||
//use std::ops::{Deref, DerefMut};
|
||||
|
||||
pub struct JS<T> {
|
||||
ptr: RefCell<*mut T>
|
||||
|
@ -31,8 +33,8 @@ impl <T> Clone for JS<T> {
|
|||
|
||||
impl<T: Reflectable> JS<T> {
|
||||
pub fn new(obj: ~T,
|
||||
window: &JS<Window>,
|
||||
wrap_fn: extern "Rust" fn(*JSContext, &JS<Window>, ~T) -> JS<T>) -> JS<T> {
|
||||
window: &JSRef<Window>,
|
||||
wrap_fn: extern "Rust" fn(*JSContext, &JSRef<Window>, ~T) -> JS<T>) -> JS<T> {
|
||||
wrap_fn(window.get().get_cx(), window, obj)
|
||||
}
|
||||
|
||||
|
@ -49,6 +51,10 @@ impl<T: Reflectable> JS<T> {
|
|||
ptr: RefCell::new(addr as *mut T)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn root<'a>(&self, collection: &'a RootCollection) -> Root<'a, T> {
|
||||
collection.new_root(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Reflectable> Reflectable for JS<T> {
|
||||
|
@ -94,3 +100,213 @@ impl<From, To> JS<From> {
|
|||
cast::transmute_copy(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RootedReference<T> {
|
||||
fn root_ref<'a>(&'a self) -> Option<JSRef<'a, T>>;
|
||||
}
|
||||
|
||||
impl<'a, T: Reflectable> RootedReference<T> for Option<Root<'a, T>> {
|
||||
fn root_ref<'a>(&'a self) -> Option<JSRef<'a, T>> {
|
||||
self.as_ref().map(|root| root.root_ref())
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Eq, Clone)]
|
||||
struct RootReference(*JSObject);
|
||||
|
||||
impl RootReference {
|
||||
fn new<'a, T: Reflectable>(unrooted: &Root<'a, T>) -> RootReference {
|
||||
RootReference(unrooted.rooted())
|
||||
}
|
||||
|
||||
fn null() -> RootReference {
|
||||
RootReference(ptr::null())
|
||||
}
|
||||
}
|
||||
|
||||
static MAX_STACK_ROOTS: uint = 10;
|
||||
|
||||
pub struct RootCollection {
|
||||
roots: [Cell<RootReference>, ..MAX_STACK_ROOTS],
|
||||
current: Cell<uint>,
|
||||
}
|
||||
|
||||
impl RootCollection {
|
||||
pub fn new() -> RootCollection {
|
||||
RootCollection {
|
||||
roots: [Cell::new(RootReference::null()), ..MAX_STACK_ROOTS],
|
||||
current: Cell::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn new_root<'a, T: Reflectable>(&'a self, unrooted: &JS<T>) -> Root<'a, T> {
|
||||
Root::new(self, unrooted)
|
||||
}
|
||||
|
||||
fn root_impl(&self, unrooted: RootReference) {
|
||||
let current = self.current.get();
|
||||
assert!(current < MAX_STACK_ROOTS);
|
||||
self.roots[current].set(unrooted);
|
||||
self.current.set(current + 1);
|
||||
}
|
||||
|
||||
fn root<'a, T: Reflectable>(&self, unrooted: &Root<'a, T>) {
|
||||
self.root_impl(RootReference::new(unrooted));
|
||||
}
|
||||
|
||||
pub fn root_raw(&self, unrooted: *JSObject) {
|
||||
self.root_impl(RootReference(unrooted));
|
||||
}
|
||||
|
||||
fn unroot_impl(&self, rooted: RootReference) {
|
||||
let mut current = self.current.get();
|
||||
assert!(current != 0);
|
||||
current -= 1;
|
||||
assert!(self.roots[current].get() == rooted);
|
||||
self.roots[current].set(RootReference::null());
|
||||
self.current.set(current);
|
||||
}
|
||||
|
||||
fn unroot<'a, T: Reflectable>(&self, rooted: &Root<'a, T>) {
|
||||
self.unroot_impl(RootReference::new(rooted));
|
||||
}
|
||||
|
||||
pub fn unroot_raw(&self, rooted: *JSObject) {
|
||||
self.unroot_impl(RootReference(rooted));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Root<'a, T> {
|
||||
root_list: &'a RootCollection,
|
||||
ptr: RefCell<*mut T>,
|
||||
}
|
||||
|
||||
impl<'a, T: Reflectable> Root<'a, T> {
|
||||
fn new(roots: &'a RootCollection, unrooted: &JS<T>) -> Root<'a, T> {
|
||||
let root = Root {
|
||||
root_list: roots,
|
||||
ptr: unrooted.ptr.clone()
|
||||
};
|
||||
roots.root(&root);
|
||||
root
|
||||
}
|
||||
|
||||
pub fn get<'a>(&'a self) -> &'a T {
|
||||
unsafe {
|
||||
let borrow = self.ptr.borrow();
|
||||
&**borrow
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
|
||||
unsafe {
|
||||
let mut borrow = self.ptr.borrow_mut();
|
||||
&mut **borrow
|
||||
}
|
||||
}
|
||||
|
||||
fn rooted(&self) -> *JSObject {
|
||||
self.reflector().get_jsobject()
|
||||
}
|
||||
|
||||
pub fn root_ref<'b>(&'b self) -> JSRef<'b,T> {
|
||||
unsafe {
|
||||
JSRef {
|
||||
ptr: self.ptr.clone(),
|
||||
chain: ::std::cast::transmute_region(&()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<'a, T: Reflectable> Drop for Root<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
self.root_list.unroot(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Reflectable> Reflectable for Root<'a, T> {
|
||||
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||
self.get().reflector()
|
||||
}
|
||||
|
||||
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
|
||||
self.get_mut().mut_reflector()
|
||||
}
|
||||
}
|
||||
|
||||
/*impl<'a, T> Deref for Root<'a, T> {
|
||||
fn deref<'a>(&'a self) -> &'a T {
|
||||
self.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> DerefMut for Root<'a, T> {
|
||||
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
|
||||
self.get_mut()
|
||||
}
|
||||
}*/
|
||||
|
||||
/// Encapsulates a reference to something that is guaranteed to be alive. This is freely copyable.
|
||||
pub struct JSRef<'a, T> {
|
||||
ptr: RefCell<*mut T>,
|
||||
chain: &'a (),
|
||||
}
|
||||
|
||||
impl<'a, T> Clone for JSRef<'a, T> {
|
||||
fn clone(&self) -> JSRef<'a, T> {
|
||||
JSRef {
|
||||
ptr: self.ptr.clone(),
|
||||
chain: self.chain
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Eq for JSRef<'a, T> {
|
||||
fn eq(&self, other: &JSRef<T>) -> bool {
|
||||
self.ptr == other.ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,T> JSRef<'a,T> {
|
||||
pub fn get<'a>(&'a self) -> &'a T {
|
||||
unsafe {
|
||||
let borrow = self.ptr.borrow();
|
||||
&**borrow
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
|
||||
let mut borrowed = self.ptr.borrow_mut();
|
||||
unsafe {
|
||||
&mut **borrowed
|
||||
}
|
||||
}
|
||||
|
||||
//XXXjdm It would be lovely if this could be private.
|
||||
pub unsafe fn transmute<'b, To>(&'b self) -> &'b JSRef<'a, To> {
|
||||
cast::transmute(self)
|
||||
}
|
||||
|
||||
//XXXjdm It would be lovely if this could be private.
|
||||
pub unsafe fn transmute_mut<'b, To>(&'b mut self) -> &'b mut JSRef<'a, To> {
|
||||
cast::transmute(self)
|
||||
}
|
||||
|
||||
pub fn unrooted(&self) -> JS<T> {
|
||||
JS {
|
||||
ptr: self.ptr.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Reflectable> Reflectable for JSRef<'a, T> {
|
||||
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||
self.get().reflector()
|
||||
}
|
||||
|
||||
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
|
||||
self.get_mut().mut_reflector()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use dom::bindings::js::JS;
|
|||
use dom::bindings::utils::{Reflectable, Reflector};
|
||||
|
||||
use js::jsapi::{JSObject, JSTracer, JS_CallTracer, JSTRACE_OBJECT};
|
||||
use js::jsval::JSVal;
|
||||
|
||||
use libc;
|
||||
use std::cast;
|
||||
|
@ -42,6 +43,22 @@ pub trait JSTraceable {
|
|||
fn trace(&self, trc: *mut JSTracer);
|
||||
}
|
||||
|
||||
pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: JSVal) {
|
||||
if !val.is_gcthing() {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
description.to_c_str().with_ref(|name| {
|
||||
(*tracer).debugPrinter = ptr::null();
|
||||
(*tracer).debugPrintIndex = -1;
|
||||
(*tracer).debugPrintArg = name as *libc::c_void;
|
||||
debug!("tracing value {:s}", description);
|
||||
JS_CallTracer(tracer as *JSTracer, val.to_gcthing(), val.trace_kind());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
|
||||
trace_object(tracer, description, reflector.get_jsobject())
|
||||
}
|
||||
|
@ -132,3 +149,10 @@ impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<*JSObject> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<JSVal> {
|
||||
fn encode(&self, s: &mut S) -> Result<(), E> {
|
||||
trace_jsval(get_jstracer(s), "val", **self);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
use dom::bindings::js::{JS, JSRef};
|
||||
use dom::bindings::trace::Untraceable;
|
||||
use dom::browsercontext;
|
||||
use dom::window;
|
||||
|
@ -37,7 +37,6 @@ use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative};
|
|||
use js::jsapi::{JSFunctionSpec, JSPropertySpec};
|
||||
use js::jsapi::{JS_NewGlobalObject, JS_InitStandardClasses};
|
||||
use js::jsapi::{JSString};
|
||||
use js::jsapi::{JS_AllowGC, JS_InhibitGC};
|
||||
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
||||
use js::jsval::JSVal;
|
||||
use js::jsval::{PrivateValue, ObjectValue, NullValue, ObjectOrNullValue};
|
||||
|
@ -390,8 +389,8 @@ pub trait Reflectable {
|
|||
|
||||
pub fn reflect_dom_object<T: Reflectable>
|
||||
(obj: ~T,
|
||||
window: &JS<window::Window>,
|
||||
wrap_fn: extern "Rust" fn(*JSContext, &JS<window::Window>, ~T) -> JS<T>)
|
||||
window: &JSRef<window::Window>,
|
||||
wrap_fn: extern "Rust" fn(*JSContext, &JSRef<window::Window>, ~T) -> JS<T>)
|
||||
-> JS<T> {
|
||||
JS::new(obj, window, wrap_fn)
|
||||
}
|
||||
|
@ -637,26 +636,6 @@ pub fn cx_for_dom_object<T: Reflectable>(obj: &T) -> *JSContext {
|
|||
cx_for_dom_reflector(obj.reflector().get_jsobject())
|
||||
}
|
||||
|
||||
/// Execute arbitrary code with the JS GC enabled, then disable it afterwards.
|
||||
pub fn with_gc_enabled<R>(cx: *JSContext, f: || -> R) -> R {
|
||||
unsafe {
|
||||
JS_AllowGC(cx);
|
||||
let rv = f();
|
||||
JS_InhibitGC(cx);
|
||||
rv
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute arbitrary code with the JS GC disabled, then enable it afterwards.
|
||||
pub fn with_gc_disabled<R>(cx: *JSContext, f: || -> R) -> R {
|
||||
unsafe {
|
||||
JS_InhibitGC(cx);
|
||||
let rv = f();
|
||||
JS_AllowGC(cx);
|
||||
rv
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if an element name is valid. See http://www.w3.org/TR/xml/#NT-Name
|
||||
/// for details.
|
||||
#[deriving(Eq)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue