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

Next

Turn on GC all the time. Fix rooting errors during parsing and storin…

…g timers. Fix borrow errors during tracing.
  • Loading branch information
jdm committed May 3, 2014
commit ffdc3f5b32a345b88eed774848924e862d47c093
@@ -697,6 +697,7 @@ do
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-android-ndk=${CFG_ANDROID_NDK_PATH}"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-android-toolchain=${CFG_ANDROID_CROSS_PATH}"
fi
CONFIGURE_ARGS="${CONFIGURE_ARGS} --enable-gczeal"
;;
support/skia/skia)
# Right now the skia configure script actually ignores --enable-debug and the
@@ -4,7 +4,7 @@

use dom::bindings::codegen::BindingDeclarations::AttrBinding;
use dom::bindings::codegen::InheritTypes::NodeCast;
use dom::bindings::js::JS;
use dom::bindings::js::{JS, JSRef};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::element::Element;
use dom::node::Node;
@@ -57,7 +57,7 @@ impl Attr {
}
}

pub fn new(window: &JS<Window>, local_name: DOMString, value: DOMString,
pub fn new(window: &JSRef<Window>, local_name: DOMString, value: DOMString,
name: DOMString, namespace: Namespace,
prefix: Option<DOMString>, owner: JS<Element>) -> JS<Attr> {
let attr = Attr::new_inherited(local_name, value, name, namespace, prefix, owner);
@@ -4,7 +4,7 @@

use dom::attr::Attr;
use dom::bindings::codegen::BindingDeclarations::AttrListBinding;
use dom::bindings::js::JS;
use dom::bindings::js::{JS, JSRef};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::element::Element;
use dom::window::Window;
@@ -25,8 +25,8 @@ impl AttrList {
}
}

pub fn new(window: &JS<Window>, elem: &JS<Element>) -> JS<AttrList> {
reflect_dom_object(~AttrList::new_inherited(window.clone(), elem.clone()),
pub fn new(window: &JSRef<Window>, elem: &JSRef<Element>) -> JS<AttrList> {
reflect_dom_object(~AttrList::new_inherited(window.unrooted(), elem.unrooted()),
window, AttrListBinding::Wrap)
}

@@ -281,6 +281,7 @@ def pickFirstSignature(condition, filterLambda):
isDefinitelyObject=True),
{
"declName" : "arg%d" % distinguishingIndex,
"simpleDeclName" : "arg%d" % distinguishingIndex,
"holderName" : ("arg%d" % distinguishingIndex) + "_holder",
"val" : distinguishingArg
})
@@ -551,12 +552,21 @@ def wrapObjectTemplate(templateBody, isDefinitelyObject, type,
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 @@ def __init__(self, argument, index, argv, argc, descriptorProvider,
}
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 @@ def _decorators(self):
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 @@ def getArgvDecl(self):
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 @@ def definition_body(self):
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 @@ def __init__(self, descriptor, lenientThis=False):

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 @@ def definition_body(self):
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 @@ def generate_code(self):
"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 @@ def definition_body(self):
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 @@ def __init__(self, descriptor, operation):
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 @@ def __init__(self, descriptor, operation):
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 @@ def definition_body(self):

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 @@ def memberInit(memberInfo):
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 @@ def __init__(self, config, prefix, webIDLFile):
'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 @@ def __init__(self, config, prefix, webIDLFile):
'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 @@ def getCall(self):
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 @@ def RegisterBindings(config):
# 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 @@ def InheritTypes(config):
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 @@ def InheritTypes(config):
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 {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.