Auto merge of #15544 - servo:RootedTraceable-dict, r=nox

Root dictionaries that contain any or object.

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15544)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-02-16 02:03:54 -08:00 committed by GitHub
commit 0cc6d3e997
18 changed files with 206 additions and 69 deletions

2
Cargo.lock generated
View file

@ -1303,7 +1303,7 @@ dependencies = [
[[package]] [[package]]
name = "js" name = "js"
version = "0.1.4" version = "0.1.4"
source = "git+https://github.com/servo/rust-mozjs#b391ec674babe4a3955f562635ea936180c7eea3" source = "git+https://github.com/servo/rust-mozjs#93e59ef1263e451143d0ed431f1aa564ea101ab8"
dependencies = [ dependencies = [
"cmake 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -19,6 +19,7 @@ from WebIDL import (
IDLBuiltinType, IDLBuiltinType,
IDLNullValue, IDLNullValue,
IDLNullableType, IDLNullableType,
IDLObject,
IDLType, IDLType,
IDLInterfaceMember, IDLInterfaceMember,
IDLUndefinedValue, IDLUndefinedValue,
@ -581,11 +582,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
If isDefinitelyObject is True, that means we know the value If isDefinitelyObject is True, that means we know the value
isObject() and we have no need to recheck that. isObject() and we have no need to recheck that.
if isMember is True, we're being converted from a property of some isMember is `False`, "Dictionary", "Union" or "Variadic", and affects
JS object, not from an actual method argument, so we can't rely on whether this function returns code suitable for an on-stack rooted binding
our jsval being rooted or outliving us in any way. Any caller or suitable for storing in an appropriate larger structure.
passing true needs to ensure that it is handled correctly in
typeIsSequenceOrHasSequenceMember.
invalidEnumValueFatal controls whether an invalid enum value conversion invalidEnumValueFatal controls whether an invalid enum value conversion
attempt will throw (if true) or simply return without doing anything (if attempt will throw (if true) or simply return without doing anything (if
@ -1033,33 +1032,33 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.isAny(): if type.isAny():
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
assert isMember != "Union"
declType = ""
default = ""
if isMember == "Dictionary": if isMember == "Dictionary":
# TODO: Need to properly root dictionaries # TODO: Need to properly root dictionaries
# https://github.com/servo/servo/issues/6381 # https://github.com/servo/servo/issues/6381
declType = CGGeneric("JSVal") declType = CGGeneric("Heap<JSVal>")
if defaultValue is None: if defaultValue is None:
default = None default = None
elif isinstance(defaultValue, IDLNullValue): elif isinstance(defaultValue, IDLNullValue):
default = "NullValue()" default = "Heap::new(NullValue())"
elif isinstance(defaultValue, IDLUndefinedValue): elif isinstance(defaultValue, IDLUndefinedValue):
default = "UndefinedValue()" default = "Heap::new(UndefinedValue())"
else: else:
raise TypeError("Can't handle non-null, non-undefined default value here") raise TypeError("Can't handle non-null, non-undefined default value here")
return handleOptional("Heap::new(${val}.get())", declType, default)
declType = CGGeneric("HandleValue")
if defaultValue is None:
default = None
elif isinstance(defaultValue, IDLNullValue):
default = "HandleValue::null()"
elif isinstance(defaultValue, IDLUndefinedValue):
default = "HandleValue::undefined()"
else: else:
declType = CGGeneric("HandleValue") raise TypeError("Can't handle non-null, non-undefined default value here")
if defaultValue is None:
default = None
elif isinstance(defaultValue, IDLNullValue):
default = "HandleValue::null()"
elif isinstance(defaultValue, IDLUndefinedValue):
default = "HandleValue::undefined()"
else:
raise TypeError("Can't handle non-null, non-undefined default value here")
return handleOptional("${val}", declType, default) return handleOptional("${val}", declType, default)
@ -1068,13 +1067,22 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# TODO: Need to root somehow # TODO: Need to root somehow
# https://github.com/servo/servo/issues/6382 # https://github.com/servo/servo/issues/6382
declType = CGGeneric("*mut JSObject") default = "ptr::null_mut()"
templateBody = wrapObjectTemplate("${val}.get().to_object()", templateBody = wrapObjectTemplate("${val}.get().to_object()",
"ptr::null_mut()", default,
isDefinitelyObject, type, failureCode) isDefinitelyObject, type, failureCode)
if isMember in ("Dictionary", "Union"):
declType = CGGeneric("Heap<*mut JSObject>")
templateBody = "Heap::new(%s)" % templateBody
default = "Heap::new(%s)" % default
else:
# TODO: Need to root somehow
# https://github.com/servo/servo/issues/6382
declType = CGGeneric("*mut JSObject")
return handleOptional(templateBody, declType, return handleOptional(templateBody, declType,
handleDefaultNull("ptr::null_mut()")) handleDefaultNull(default))
if type.isDictionary(): if type.isDictionary():
# There are no nullable dictionaries # There are no nullable dictionaries
@ -1083,15 +1091,21 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
typeName = "%s::%s" % (CGDictionary.makeModuleName(type.inner), typeName = "%s::%s" % (CGDictionary.makeModuleName(type.inner),
CGDictionary.makeDictionaryName(type.inner)) CGDictionary.makeDictionaryName(type.inner))
declType = CGGeneric(typeName) declType = CGGeneric(typeName)
template = ("match %s::new(cx, ${val}) {\n" empty = "%s::empty(cx)" % typeName
if isMember != "Dictionary" and type_needs_tracing(type):
declType = CGTemplatedType("RootedTraceableBox", declType)
empty = "RootedTraceableBox::new(%s)" % empty
template = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
" Ok(ConversionResult::Success(dictionary)) => dictionary,\n" " Ok(ConversionResult::Success(dictionary)) => dictionary,\n"
" Ok(ConversionResult::Failure(error)) => {\n" " Ok(ConversionResult::Failure(error)) => {\n"
"%s\n" "%s\n"
" }\n" " }\n"
" _ => { %s },\n" " _ => { %s },\n"
"}" % (typeName, indent(failOrPropagate, 8), exceptionCode)) "}" % (indent(failOrPropagate, 8), exceptionCode))
return handleOptional(template, declType, handleDefaultNull("%s::empty(cx)" % typeName)) return handleOptional(template, declType, handleDefaultNull(empty))
if type.isVoid(): if type.isVoid():
# This one only happens for return values, and its easy: Just # This one only happens for return values, and its easy: Just
@ -2233,6 +2247,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
'dom::types::*', 'dom::types::*',
'js::error::throw_type_error', 'js::error::throw_type_error',
'js::jsapi::HandleValue', 'js::jsapi::HandleValue',
'js::jsapi::Heap',
'js::jsapi::JSContext', 'js::jsapi::JSContext',
'js::jsapi::JSObject', 'js::jsapi::JSObject',
'js::jsapi::MutableHandleValue', 'js::jsapi::MutableHandleValue',
@ -3139,7 +3154,7 @@ class CGCallGenerator(CGThing):
args = CGList([CGGeneric(arg) for arg in argsPre], ", ") args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
for (a, name) in arguments: for (a, name) in arguments:
# XXXjdm Perhaps we should pass all nontrivial types by borrowed pointer # XXXjdm Perhaps we should pass all nontrivial types by borrowed pointer
if a.type.isDictionary(): if a.type.isDictionary() and not type_needs_tracing(a.type):
name = "&" + name name = "&" + name
args.append(CGGeneric(name)) args.append(CGGeneric(name))
@ -4052,14 +4067,15 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
typeName = builtinNames[type.tag()] typeName = builtinNames[type.tag()]
elif type.isObject(): elif type.isObject():
name = type.name name = type.name
typeName = "*mut JSObject" typeName = "Heap<*mut JSObject>"
else: else:
raise TypeError("Can't handle %s in unions yet" % type) raise TypeError("Can't handle %s in unions yet" % type)
info = getJSToNativeConversionInfo( info = getJSToNativeConversionInfo(
type, descriptorProvider, failureCode="return Ok(None);", type, descriptorProvider, failureCode="return Ok(None);",
exceptionCode='return Err(());', exceptionCode='return Err(());',
isDefinitelyObject=True) isDefinitelyObject=True,
isMember="Union")
template = info.template template = info.template
jsConversion = string.Template(template).substitute({ jsConversion = string.Template(template).substitute({
@ -4094,6 +4110,7 @@ class CGUnionStruct(CGThing):
% (self.type, v["name"]) for v in templateVars % (self.type, v["name"]) for v in templateVars
] ]
return ("""\ return ("""\
#[derive(JSTraceable)]
pub enum %s { pub enum %s {
%s %s
} }
@ -5567,6 +5584,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'dom::bindings::utils::trace_global', 'dom::bindings::utils::trace_global',
'dom::bindings::trace::JSTraceable', 'dom::bindings::trace::JSTraceable',
'dom::bindings::trace::RootedTraceable', 'dom::bindings::trace::RootedTraceable',
'dom::bindings::trace::RootedTraceableBox',
'dom::bindings::callback::CallSetup', 'dom::bindings::callback::CallSetup',
'dom::bindings::callback::CallbackContainer', 'dom::bindings::callback::CallbackContainer',
'dom::bindings::callback::CallbackInterface', 'dom::bindings::callback::CallbackInterface',
@ -5872,6 +5890,7 @@ class CGDictionary(CGThing):
for m in self.memberInfo] for m in self.memberInfo]
return (string.Template( return (string.Template(
"#[derive(JSTraceable)]\n"
"pub struct ${selfName} {\n" + "pub struct ${selfName} {\n" +
"${inheritance}" + "${inheritance}" +
"\n".join(memberDecls) + "\n" + "\n".join(memberDecls) + "\n" +
@ -5995,8 +6014,6 @@ class CGDictionary(CGThing):
default = info.default default = info.default
replacements = {"val": "rval.handle()"} replacements = {"val": "rval.handle()"}
conversion = string.Template(templateBody).substitute(replacements) conversion = string.Template(templateBody).substitute(replacements)
if memberType.isAny():
conversion = "%s.get()" % conversion
assert (member.defaultValue is None) == (default is None) assert (member.defaultValue is None) == (default is None)
if not member.optional: if not member.optional:
@ -6154,6 +6171,45 @@ class CGBindingRoot(CGThing):
return stripTrailingWhitespace(self.root.define()) return stripTrailingWhitespace(self.root.define())
def type_needs_tracing(t):
assert isinstance(t, IDLObject), (t, type(t))
if t.isType():
if isinstance(t, IDLWrapperType):
return type_needs_tracing(t.inner)
if t.nullable():
return type_needs_tracing(t.inner)
if t.isAny():
return True
if t.isObject():
return True
if t.isSequence():
return type_needs_tracing(t.inner)
return False
if t.isDictionary():
if t.parent and type_needs_tracing(t.parent):
return True
if any(type_needs_tracing(member.type) for member in t.members):
return True
return False
if t.isInterface():
return False
if t.isEnum():
return False
assert False, (t, type(t))
def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, variadic=False): def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, variadic=False):
info = getJSToNativeConversionInfo( info = getJSToNativeConversionInfo(
ty, descriptorProvider, isArgument=True) ty, descriptorProvider, isArgument=True)
@ -6167,7 +6223,7 @@ def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, var
elif optional and not defaultValue: elif optional and not defaultValue:
declType = CGWrapper(declType, pre="Option<", post=">") declType = CGWrapper(declType, pre="Option<", post=">")
if ty.isDictionary(): if ty.isDictionary() and not type_needs_tracing(ty):
declType = CGWrapper(declType, pre="&") declType = CGWrapper(declType, pre="&")
return declType.define() return declType.define()

View file

@ -37,6 +37,7 @@ use dom::bindings::js::Root;
use dom::bindings::num::Finite; use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector}; use dom::bindings::reflector::{DomObject, Reflector};
use dom::bindings::str::{ByteString, DOMString, USVString}; use dom::bindings::str::{ByteString, DOMString, USVString};
use dom::bindings::trace::{JSTraceable, RootedTraceableBox};
use dom::bindings::utils::DOMClass; use dom::bindings::utils::DOMClass;
use js; use js;
pub use js::conversions::{FromJSValConvertible, ToJSValConvertible, ConversionResult}; pub use js::conversions::{FromJSValConvertible, ToJSValConvertible, ConversionResult};
@ -117,6 +118,22 @@ impl <T: DomObject + IDLInterface> FromJSValConvertible for Root<T> {
} }
} }
impl <T: FromJSValConvertible + JSTraceable> FromJSValConvertible for RootedTraceableBox<T> {
type Config = T::Config;
unsafe fn from_jsval(cx: *mut JSContext,
value: HandleValue,
config: Self::Config)
-> Result<ConversionResult<Self>, ()> {
T::from_jsval(cx, value, config).map(|result| {
match result {
ConversionResult::Success(v) => ConversionResult::Success(RootedTraceableBox::new(v)),
ConversionResult::Failure(e) => ConversionResult::Failure(e),
}
})
}
}
/// Convert `id` to a `DOMString`, assuming it is string-valued. /// Convert `id` to a `DOMString`, assuming it is string-valued.
/// ///
/// Handling of invalid UTF-16 in strings depends on the relevant option. /// Handling of invalid UTF-16 in strings depends on the relevant option.

View file

@ -15,7 +15,7 @@ use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::trace::JSTraceable; use dom::bindings::trace::JSTraceable;
use dom::globalscope::GlobalScope; use dom::globalscope::GlobalScope;
use js::conversions::ToJSValConvertible; use js::conversions::ToJSValConvertible;
use js::jsapi::{HandleValue, JSContext, JSObject, MutableHandleObject}; use js::jsapi::{HandleValue, Heap, JSContext, JSObject, MutableHandleObject};
use js::jsval::UndefinedValue; use js::jsval::UndefinedValue;
use std::cell::Cell; use std::cell::Cell;
use std::ptr; use std::ptr;
@ -116,7 +116,7 @@ fn dict_return(cx: *mut JSContext,
value: HandleValue) -> Fallible<()> { value: HandleValue) -> Fallible<()> {
let mut dict = unsafe { IterableKeyOrValueResult::empty(cx) }; let mut dict = unsafe { IterableKeyOrValueResult::empty(cx) };
dict.done = done; dict.done = done;
dict.value = value.get(); dict.value.set(value.get());
rooted!(in(cx) let mut dict_value = UndefinedValue()); rooted!(in(cx) let mut dict_value = UndefinedValue());
unsafe { unsafe {
dict.to_jsval(cx, dict_value.handle_mut()); dict.to_jsval(cx, dict_value.handle_mut());
@ -131,7 +131,7 @@ fn key_and_value_return(cx: *mut JSContext,
value: HandleValue) -> Fallible<()> { value: HandleValue) -> Fallible<()> {
let mut dict = unsafe { IterableKeyAndValueResult::empty(cx) }; let mut dict = unsafe { IterableKeyAndValueResult::empty(cx) };
dict.done = false; dict.done = false;
dict.value = Some(vec![key.get(), value.get()]); dict.value = Some(vec![Heap::new(key.get()), Heap::new(value.get())]);
rooted!(in(cx) let mut dict_value = UndefinedValue()); rooted!(in(cx) let mut dict_value = UndefinedValue());
unsafe { unsafe {
dict.to_jsval(cx, dict_value.handle_mut()); dict.to_jsval(cx, dict_value.handle_mut());

View file

@ -642,3 +642,9 @@ impl<T: DomObject> Drop for Root<T> {
} }
} }
} }
unsafe impl<T: DomObject> JSTraceable for Root<T> {
unsafe fn trace(&self, _: *mut JSTracer) {
// Already traced.
}
}

View file

@ -23,7 +23,7 @@ use std::collections::HashMap;
use std::ops::Deref; use std::ops::Deref;
/// The `MozMap` (open-ended dictionary) type. /// The `MozMap` (open-ended dictionary) type.
#[derive(Clone)] #[derive(Clone, JSTraceable)]
pub struct MozMap<T> { pub struct MozMap<T> {
map: HashMap<DOMString, T>, map: HashMap<DOMString, T>,
} }

View file

@ -653,6 +653,61 @@ impl<'a, T: JSTraceable + 'static> Drop for RootedTraceable<'a, T> {
} }
} }
/// Roots any JSTraceable thing
///
/// If you have a valid DomObject, use Root.
/// If you have GC things like *mut JSObject or JSVal, use rooted!.
/// If you have an arbitrary number of DomObjects to root, use rooted_vec!.
/// If you know what you're doing, use this.
pub struct RootedTraceableBox<T: 'static + JSTraceable> {
ptr: *mut T,
}
unsafe impl<T: JSTraceable + 'static> JSTraceable for RootedTraceableBox<T> {
unsafe fn trace(&self, tracer: *mut JSTracer) {
(*self.ptr).trace(tracer);
}
}
impl<T: JSTraceable + 'static> RootedTraceableBox<T> {
/// Root a JSTraceable thing for the life of this RootedTraceable
pub fn new(traceable: T) -> RootedTraceableBox<T> {
let traceable = Box::into_raw(box traceable);
unsafe {
RootedTraceableSet::add(traceable);
}
RootedTraceableBox {
ptr: traceable,
}
}
}
impl<T: JSTraceable> Deref for RootedTraceableBox<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe {
&*self.ptr
}
}
}
impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> {
fn deref_mut(&mut self) -> &mut T {
unsafe {
&mut *self.ptr
}
}
}
impl<T: JSTraceable + 'static> Drop for RootedTraceableBox<T> {
fn drop(&mut self) {
unsafe {
RootedTraceableSet::remove(self.ptr);
let _ = Box::from_raw(self.ptr);
}
}
}
/// A vector of items to be rooted with `RootedVec`. /// A vector of items to be rooted with `RootedVec`.
/// Guaranteed to be empty when not rooted. /// Guaranteed to be empty when not rooted.
/// Usage: `rooted_vec!(let mut v);` or if you have an /// Usage: `rooted_vec!(let mut v);` or if you have an

View file

@ -10,6 +10,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::{MutHeapJSVal, Root}; use dom::bindings::js::{MutHeapJSVal, Root};
use dom::bindings::reflector::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::bindings::trace::RootedTraceableBox;
use dom::event::Event; use dom::event::Event;
use dom::globalscope::GlobalScope; use dom::globalscope::GlobalScope;
use js::jsapi::{HandleValue, JSContext}; use js::jsapi::{HandleValue, JSContext};
@ -51,13 +52,13 @@ impl CustomEvent {
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn Constructor(global: &GlobalScope, pub fn Constructor(global: &GlobalScope,
type_: DOMString, type_: DOMString,
init: &CustomEventBinding::CustomEventInit) init: RootedTraceableBox<CustomEventBinding::CustomEventInit>)
-> Fallible<Root<CustomEvent>> { -> Fallible<Root<CustomEvent>> {
Ok(CustomEvent::new(global, Ok(CustomEvent::new(global,
Atom::from(type_), Atom::from(type_),
init.parent.bubbles, init.parent.bubbles,
init.parent.cancelable, init.parent.cancelable,
unsafe { HandleValue::from_marked_location(&init.detail) })) init.detail.handle()))
} }
fn init_custom_event(&self, fn init_custom_event(&self,

View file

@ -11,6 +11,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::{MutHeapJSVal, Root}; use dom::bindings::js::{MutHeapJSVal, Root};
use dom::bindings::reflector::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::bindings::trace::RootedTraceableBox;
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
use dom::globalscope::GlobalScope; use dom::globalscope::GlobalScope;
use js::jsapi::{HandleValue, JSContext}; use js::jsapi::{HandleValue, JSContext};
@ -72,7 +73,8 @@ impl ErrorEvent {
pub fn Constructor(global: &GlobalScope, pub fn Constructor(global: &GlobalScope,
type_: DOMString, type_: DOMString,
init: &ErrorEventBinding::ErrorEventInit) -> Fallible<Root<ErrorEvent>>{ init: RootedTraceableBox<ErrorEventBinding::ErrorEventInit>)
-> Fallible<Root<ErrorEvent>>{
let msg = match init.message.as_ref() { let msg = match init.message.as_ref() {
Some(message) => message.clone(), Some(message) => message.clone(),
None => DOMString::new(), None => DOMString::new(),
@ -91,9 +93,6 @@ impl ErrorEvent {
let cancelable = EventCancelable::from(init.parent.cancelable); let cancelable = EventCancelable::from(init.parent.cancelable);
// Dictionaries need to be rooted
// https://github.com/servo/servo/issues/6381
rooted!(in(global.get_cx()) let error = init.error);
let event = ErrorEvent::new( let event = ErrorEvent::new(
global, global,
Atom::from(type_), Atom::from(type_),
@ -103,7 +102,7 @@ impl ErrorEvent {
file_name, file_name,
line_num, line_num,
col_num, col_num,
error.handle()); init.error.handle());
Ok(event) Ok(event)
} }

View file

@ -9,6 +9,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::bindings::trace::RootedTraceableBox;
use dom::event::Event; use dom::event::Event;
use dom::eventtarget::EventTarget; use dom::eventtarget::EventTarget;
use dom::extendableevent::ExtendableEvent; use dom::extendableevent::ExtendableEvent;
@ -47,15 +48,14 @@ impl ExtendableMessageEvent {
pub fn Constructor(worker: &ServiceWorkerGlobalScope, pub fn Constructor(worker: &ServiceWorkerGlobalScope,
type_: DOMString, type_: DOMString,
init: &ExtendableMessageEventBinding::ExtendableMessageEventInit) init: RootedTraceableBox<ExtendableMessageEventBinding::ExtendableMessageEventInit>)
-> Fallible<Root<ExtendableMessageEvent>> { -> Fallible<Root<ExtendableMessageEvent>> {
let global = worker.upcast::<GlobalScope>(); let global = worker.upcast::<GlobalScope>();
rooted!(in(global.get_cx()) let data = init.data);
let ev = ExtendableMessageEvent::new(global, let ev = ExtendableMessageEvent::new(global,
Atom::from(type_), Atom::from(type_),
init.parent.parent.bubbles, init.parent.parent.bubbles,
init.parent.parent.cancelable, init.parent.parent.cancelable,
data.handle(), init.data.handle(),
init.origin.clone().unwrap(), init.origin.clone().unwrap(),
init.lastEventId.clone().unwrap()); init.lastEventId.clone().unwrap());
Ok(ev) Ok(ev)

View file

@ -344,7 +344,7 @@ impl FileReaderMethods for FileReader {
FileReaderResult::String(ref string) => FileReaderResult::String(ref string) =>
StringOrObject::String(string.clone()), StringOrObject::String(string.clone()),
FileReaderResult::ArrayBuffer(ref arr_buffer) => { FileReaderResult::ArrayBuffer(ref arr_buffer) => {
StringOrObject::Object((*arr_buffer.ptr.get()).to_object()) StringOrObject::Object(Heap::new((*arr_buffer.ptr.get()).to_object()))
} }
}) })
} }

View file

@ -10,6 +10,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::bindings::trace::RootedTraceableBox;
use dom::event::Event; use dom::event::Event;
use dom::eventtarget::EventTarget; use dom::eventtarget::EventTarget;
use dom::globalscope::GlobalScope; use dom::globalscope::GlobalScope;
@ -60,16 +61,13 @@ impl MessageEvent {
pub fn Constructor(global: &GlobalScope, pub fn Constructor(global: &GlobalScope,
type_: DOMString, type_: DOMString,
init: &MessageEventBinding::MessageEventInit) init: RootedTraceableBox<MessageEventBinding::MessageEventInit>)
-> Fallible<Root<MessageEvent>> { -> Fallible<Root<MessageEvent>> {
// Dictionaries need to be rooted
// https://github.com/servo/servo/issues/6381
rooted!(in(global.get_cx()) let data = init.data);
let ev = MessageEvent::new(global, let ev = MessageEvent::new(global,
Atom::from(type_), Atom::from(type_),
init.parent.bubbles, init.parent.bubbles,
init.parent.cancelable, init.parent.cancelable,
data.handle(), init.data.handle(),
init.origin.clone(), init.origin.clone(),
init.lastEventId.clone()); init.lastEventId.clone());
Ok(ev) Ok(ev)

View file

@ -10,6 +10,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::{MutHeapJSVal, Root}; use dom::bindings::js::{MutHeapJSVal, Root};
use dom::bindings::reflector::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::bindings::trace::RootedTraceableBox;
use dom::event::Event; use dom::event::Event;
use dom::window::Window; use dom::window::Window;
use js::jsapi::{HandleValue, JSContext}; use js::jsapi::{HandleValue, JSContext};
@ -53,16 +54,15 @@ impl PopStateEvent {
ev ev
} }
#[allow(unsafe_code)]
pub fn Constructor(window: &Window, pub fn Constructor(window: &Window,
type_: DOMString, type_: DOMString,
init: &PopStateEventBinding::PopStateEventInit) init: RootedTraceableBox<PopStateEventBinding::PopStateEventInit>)
-> Fallible<Root<PopStateEvent>> { -> Fallible<Root<PopStateEvent>> {
Ok(PopStateEvent::new(window, Ok(PopStateEvent::new(window,
Atom::from(type_), Atom::from(type_),
init.parent.bubbles, init.parent.bubbles,
init.parent.cancelable, init.parent.cancelable,
unsafe { HandleValue::from_marked_location(&init.state) })) init.state.handle()))
} }
} }

View file

@ -20,6 +20,7 @@ use dom::bindings::error::{Error, Fallible};
use dom::bindings::js::{MutNullableJS, Root}; use dom::bindings::js::{MutNullableJS, Root};
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::str::{ByteString, DOMString, USVString}; use dom::bindings::str::{ByteString, DOMString, USVString};
use dom::bindings::trace::RootedTraceableBox;
use dom::globalscope::GlobalScope; use dom::globalscope::GlobalScope;
use dom::headers::{Guard, Headers}; use dom::headers::{Guard, Headers};
use dom::promise::Promise; use dom::promise::Promise;
@ -80,7 +81,7 @@ impl Request {
// https://fetch.spec.whatwg.org/#dom-request // https://fetch.spec.whatwg.org/#dom-request
pub fn Constructor(global: &GlobalScope, pub fn Constructor(global: &GlobalScope,
input: RequestInfo, input: RequestInfo,
init: &RequestInit) init: RootedTraceableBox<RequestInit>)
-> Fallible<Root<Request>> { -> Fallible<Root<Request>> {
// Step 1 // Step 1
let temporary_request: NetTraitsRequest; let temporary_request: NetTraitsRequest;
@ -139,12 +140,12 @@ impl Request {
// TODO: `environment settings object` is not implemented in Servo yet. // TODO: `environment settings object` is not implemented in Servo yet.
// Step 10 // Step 10
if !init.window.is_undefined() && !init.window.is_null() { if !init.window.handle().is_null_or_undefined() {
return Err(Error::Type("Window is present and is not null".to_string())) return Err(Error::Type("Window is present and is not null".to_string()))
} }
// Step 11 // Step 11
if !init.window.is_undefined() { if !init.window.handle().is_undefined() {
window = Window::NoWindow; window = Window::NoWindow;
} }
@ -179,7 +180,7 @@ impl Request {
init.redirect.is_some() || init.redirect.is_some() ||
init.referrer.is_some() || init.referrer.is_some() ||
init.referrerPolicy.is_some() || init.referrerPolicy.is_some() ||
!init.window.is_undefined() { !init.window.handle().is_undefined() {
// Step 13.1 // Step 13.1
if request.mode == NetTraitsRequestMode::Navigate { if request.mode == NetTraitsRequestMode::Navigate {
return Err(Error::Type( return Err(Error::Type(
@ -311,7 +312,7 @@ impl Request {
if let Some(possible_header) = init.headers.as_ref() { if let Some(possible_header) = init.headers.as_ref() {
match possible_header { match possible_header {
&HeadersInit::Headers(ref init_headers) => { &HeadersInit::Headers(ref init_headers) => {
headers_copy = init_headers.clone(); headers_copy = Root::from_ref(&*init_headers);
} }
&HeadersInit::ByteStringSequenceSequence(ref init_sequence) => { &HeadersInit::ByteStringSequenceSequence(ref init_sequence) => {
try!(headers_copy.fill(Some( try!(headers_copy.fill(Some(

View file

@ -27,13 +27,14 @@ use dom::bindings::num::Finite;
use dom::bindings::refcounted::TrustedPromise; use dom::bindings::refcounted::TrustedPromise;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::str::{ByteString, DOMString, USVString}; use dom::bindings::str::{ByteString, DOMString, USVString};
use dom::bindings::trace::RootedTraceableBox;
use dom::bindings::weakref::MutableWeakRef; use dom::bindings::weakref::MutableWeakRef;
use dom::blob::{Blob, BlobImpl}; use dom::blob::{Blob, BlobImpl};
use dom::globalscope::GlobalScope; use dom::globalscope::GlobalScope;
use dom::promise::Promise; use dom::promise::Promise;
use dom::promisenativehandler::{PromiseNativeHandler, Callback}; use dom::promisenativehandler::{PromiseNativeHandler, Callback};
use dom::url::URL; use dom::url::URL;
use js::jsapi::{HandleObject, HandleValue, JSContext, JSObject, JSAutoCompartment}; use js::jsapi::{HandleObject, HandleValue, Heap, JSContext, JSObject, JSAutoCompartment};
use js::jsapi::{JS_NewPlainObject, JS_NewUint8ClampedArray}; use js::jsapi::{JS_NewPlainObject, JS_NewUint8ClampedArray};
use js::jsval::{JSVal, NullValue}; use js::jsval::{JSVal, NullValue};
use script_traits::MsDuration; use script_traits::MsDuration;
@ -338,12 +339,12 @@ impl TestBindingMethods for TestBinding {
fn ReceiveNullableSequence(&self) -> Option<Vec<i32>> { Some(vec![1]) } fn ReceiveNullableSequence(&self) -> Option<Vec<i32>> { Some(vec![1]) }
fn ReceiveTestDictionaryWithSuccessOnKeyword(&self) -> TestDictionary { fn ReceiveTestDictionaryWithSuccessOnKeyword(&self) -> TestDictionary {
TestDictionary { TestDictionary {
anyValue: NullValue(), anyValue: Heap::new(NullValue()),
booleanValue: None, booleanValue: None,
byteValue: None, byteValue: None,
dict: TestDictionaryDefaults { dict: TestDictionaryDefaults {
UnrestrictedDoubleValue: 0.0, UnrestrictedDoubleValue: 0.0,
anyValue: NullValue(), anyValue: Heap::new(NullValue()),
booleanValue: false, booleanValue: false,
bytestringValue: ByteString::new(vec![]), bytestringValue: ByteString::new(vec![]),
byteValue: 0, byteValue: 0,
@ -359,7 +360,7 @@ impl TestBindingMethods for TestBinding {
nullableFloatValue: None, nullableFloatValue: None,
nullableLongLongValue: None, nullableLongLongValue: None,
nullableLongValue: None, nullableLongValue: None,
nullableObjectValue: ptr::null_mut(), nullableObjectValue: Heap::new(ptr::null_mut()),
nullableOctetValue: None, nullableOctetValue: None,
nullableShortValue: None, nullableShortValue: None,
nullableStringValue: None, nullableStringValue: None,
@ -402,7 +403,7 @@ impl TestBindingMethods for TestBinding {
} }
} }
fn DictMatchesPassedValues(&self, arg: &TestDictionary) -> bool { fn DictMatchesPassedValues(&self, arg: RootedTraceableBox<TestDictionary>) -> bool {
arg.type_.as_ref().map(|s| s == "success").unwrap_or(false) && arg.type_.as_ref().map(|s| s == "success").unwrap_or(false) &&
arg.nonRequiredNullable.is_none() && arg.nonRequiredNullable.is_none() &&
arg.nonRequiredNullable2 == Some(None) arg.nonRequiredNullable2 == Some(None)

View file

@ -26,6 +26,7 @@ use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::DomObject; use dom::bindings::reflector::DomObject;
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::bindings::structuredclone::StructuredCloneData; use dom::bindings::structuredclone::StructuredCloneData;
use dom::bindings::trace::RootedTraceableBox;
use dom::bindings::utils::{GlobalStaticData, WindowProxyHandler}; use dom::bindings::utils::{GlobalStaticData, WindowProxyHandler};
use dom::bluetooth::BluetoothExtraPermissionData; use dom::bluetooth::BluetoothExtraPermissionData;
use dom::browsingcontext::BrowsingContext; use dom::browsingcontext::BrowsingContext;
@ -921,7 +922,7 @@ impl WindowMethods for Window {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://fetch.spec.whatwg.org/#fetch-method // https://fetch.spec.whatwg.org/#fetch-method
fn Fetch(&self, input: RequestOrUSVString, init: &RequestInit) -> Rc<Promise> { fn Fetch(&self, input: RequestOrUSVString, init: RootedTraceableBox<RequestInit>) -> Rc<Promise> {
fetch::Fetch(&self.upcast(), input, init) fetch::Fetch(&self.upcast(), input, init)
} }

View file

@ -14,6 +14,7 @@ use dom::bindings::js::{MutNullableJS, Root};
use dom::bindings::reflector::DomObject; use dom::bindings::reflector::DomObject;
use dom::bindings::settings_stack::AutoEntryScript; use dom::bindings::settings_stack::AutoEntryScript;
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::bindings::trace::RootedTraceableBox;
use dom::crypto::Crypto; use dom::crypto::Crypto;
use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope; use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
use dom::globalscope::GlobalScope; use dom::globalscope::GlobalScope;
@ -314,7 +315,7 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://fetch.spec.whatwg.org/#fetch-method // https://fetch.spec.whatwg.org/#fetch-method
fn Fetch(&self, input: RequestOrUSVString, init: &RequestInit) -> Rc<Promise> { fn Fetch(&self, input: RequestOrUSVString, init: RootedTraceableBox<RequestInit>) -> Rc<Promise> {
fetch::Fetch(self.upcast(), input, init) fetch::Fetch(self.upcast(), input, init)
} }
} }

View file

@ -10,6 +10,7 @@ use dom::bindings::error::Error;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::refcounted::{Trusted, TrustedPromise}; use dom::bindings::refcounted::{Trusted, TrustedPromise};
use dom::bindings::reflector::DomObject; use dom::bindings::reflector::DomObject;
use dom::bindings::trace::RootedTraceableBox;
use dom::globalscope::GlobalScope; use dom::globalscope::GlobalScope;
use dom::headers::Guard; use dom::headers::Guard;
use dom::promise::Promise; use dom::promise::Promise;
@ -68,7 +69,7 @@ fn request_init_from_request(request: NetTraitsRequest) -> NetTraitsRequestInit
// https://fetch.spec.whatwg.org/#fetch-method // https://fetch.spec.whatwg.org/#fetch-method
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn Fetch(global: &GlobalScope, input: RequestInfo, init: &RequestInit) -> Rc<Promise> { pub fn Fetch(global: &GlobalScope, input: RequestInfo, init: RootedTraceableBox<RequestInit>) -> Rc<Promise> {
let core_resource_thread = global.core_resource_thread(); let core_resource_thread = global.core_resource_thread();
// Step 1 // Step 1