diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 2d188d411040..e4448ff834c2 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -19,6 +19,7 @@ IDLBuiltinType, IDLNullValue, IDLNullableType, + IDLObject, IDLType, IDLInterfaceMember, IDLUndefinedValue, @@ -1090,6 +1091,12 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, typeName = "%s::%s" % (CGDictionary.makeModuleName(type.inner), CGDictionary.makeDictionaryName(type.inner)) declType = CGGeneric(typeName) + 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::Failure(error)) => {\n" @@ -1098,7 +1105,7 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, " _ => { %s },\n" "}" % (indent(failOrPropagate, 8), exceptionCode)) - return handleOptional(template, declType, handleDefaultNull("%s::empty(cx)" % typeName)) + return handleOptional(template, declType, handleDefaultNull(empty)) if type.isVoid(): # This one only happens for return values, and its easy: Just @@ -3147,7 +3154,7 @@ def __init__(self, errorResult, arguments, argsPre, returnType, args = CGList([CGGeneric(arg) for arg in argsPre], ", ") for (a, name) in arguments: # 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 args.append(CGGeneric(name)) @@ -5577,6 +5584,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::utils::trace_global', 'dom::bindings::trace::JSTraceable', 'dom::bindings::trace::RootedTraceable', + 'dom::bindings::trace::RootedTraceableBox', 'dom::bindings::callback::CallSetup', 'dom::bindings::callback::CallbackContainer', 'dom::bindings::callback::CallbackInterface', @@ -6163,6 +6171,45 @@ def define(self): 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): info = getJSToNativeConversionInfo( ty, descriptorProvider, isArgument=True) @@ -6176,7 +6223,7 @@ def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, var elif optional and not defaultValue: declType = CGWrapper(declType, pre="Option<", post=">") - if ty.isDictionary(): + if ty.isDictionary() and not type_needs_tracing(ty): declType = CGWrapper(declType, pre="&") return declType.define() diff --git a/components/script/dom/customevent.rs b/components/script/dom/customevent.rs index 942253c30dca..f11f2643dad5 100644 --- a/components/script/dom/customevent.rs +++ b/components/script/dom/customevent.rs @@ -10,6 +10,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::{MutHeapJSVal, Root}; use dom::bindings::reflector::reflect_dom_object; use dom::bindings::str::DOMString; +use dom::bindings::trace::RootedTraceableBox; use dom::event::Event; use dom::globalscope::GlobalScope; use js::jsapi::{HandleValue, JSContext}; @@ -51,7 +52,7 @@ impl CustomEvent { #[allow(unsafe_code)] pub fn Constructor(global: &GlobalScope, type_: DOMString, - init: &CustomEventBinding::CustomEventInit) + init: RootedTraceableBox) -> Fallible> { Ok(CustomEvent::new(global, Atom::from(type_), diff --git a/components/script/dom/errorevent.rs b/components/script/dom/errorevent.rs index a89a7b7e5274..37197b6125a9 100644 --- a/components/script/dom/errorevent.rs +++ b/components/script/dom/errorevent.rs @@ -11,6 +11,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::{MutHeapJSVal, Root}; use dom::bindings::reflector::reflect_dom_object; use dom::bindings::str::DOMString; +use dom::bindings::trace::RootedTraceableBox; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::globalscope::GlobalScope; use js::jsapi::{HandleValue, JSContext}; @@ -72,7 +73,8 @@ impl ErrorEvent { pub fn Constructor(global: &GlobalScope, type_: DOMString, - init: &ErrorEventBinding::ErrorEventInit) -> Fallible>{ + init: RootedTraceableBox) + -> Fallible>{ let msg = match init.message.as_ref() { Some(message) => message.clone(), None => DOMString::new(), @@ -91,9 +93,6 @@ impl ErrorEvent { 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.get()); let event = ErrorEvent::new( global, Atom::from(type_), @@ -103,7 +102,7 @@ impl ErrorEvent { file_name, line_num, col_num, - error.handle()); + init.error.handle()); Ok(event) } diff --git a/components/script/dom/extendablemessageevent.rs b/components/script/dom/extendablemessageevent.rs index b070007f8318..dd0360cb408d 100644 --- a/components/script/dom/extendablemessageevent.rs +++ b/components/script/dom/extendablemessageevent.rs @@ -9,6 +9,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::bindings::reflector::reflect_dom_object; use dom::bindings::str::DOMString; +use dom::bindings::trace::RootedTraceableBox; use dom::event::Event; use dom::eventtarget::EventTarget; use dom::extendableevent::ExtendableEvent; @@ -47,15 +48,14 @@ impl ExtendableMessageEvent { pub fn Constructor(worker: &ServiceWorkerGlobalScope, type_: DOMString, - init: &ExtendableMessageEventBinding::ExtendableMessageEventInit) + init: RootedTraceableBox) -> Fallible> { let global = worker.upcast::(); - rooted!(in(global.get_cx()) let data = init.data.get()); let ev = ExtendableMessageEvent::new(global, Atom::from(type_), init.parent.parent.bubbles, init.parent.parent.cancelable, - data.handle(), + init.data.handle(), init.origin.clone().unwrap(), init.lastEventId.clone().unwrap()); Ok(ev) diff --git a/components/script/dom/messageevent.rs b/components/script/dom/messageevent.rs index b066cf810fe2..3df960d0882e 100644 --- a/components/script/dom/messageevent.rs +++ b/components/script/dom/messageevent.rs @@ -10,6 +10,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::bindings::reflector::reflect_dom_object; use dom::bindings::str::DOMString; +use dom::bindings::trace::RootedTraceableBox; use dom::event::Event; use dom::eventtarget::EventTarget; use dom::globalscope::GlobalScope; @@ -60,16 +61,13 @@ impl MessageEvent { pub fn Constructor(global: &GlobalScope, type_: DOMString, - init: &MessageEventBinding::MessageEventInit) + init: RootedTraceableBox) -> Fallible> { - // Dictionaries need to be rooted - // https://github.com/servo/servo/issues/6381 - rooted!(in(global.get_cx()) let data = init.data.get()); let ev = MessageEvent::new(global, Atom::from(type_), init.parent.bubbles, init.parent.cancelable, - data.handle(), + init.data.handle(), init.origin.clone(), init.lastEventId.clone()); Ok(ev) diff --git a/components/script/dom/popstateevent.rs b/components/script/dom/popstateevent.rs index 7db2eea8fe66..1282d847d7c6 100644 --- a/components/script/dom/popstateevent.rs +++ b/components/script/dom/popstateevent.rs @@ -10,6 +10,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::{MutHeapJSVal, Root}; use dom::bindings::reflector::reflect_dom_object; use dom::bindings::str::DOMString; +use dom::bindings::trace::RootedTraceableBox; use dom::event::Event; use dom::window::Window; use js::jsapi::{HandleValue, JSContext}; @@ -55,7 +56,7 @@ impl PopStateEvent { pub fn Constructor(window: &Window, type_: DOMString, - init: &PopStateEventBinding::PopStateEventInit) + init: RootedTraceableBox) -> Fallible> { Ok(PopStateEvent::new(window, Atom::from(type_), diff --git a/components/script/dom/request.rs b/components/script/dom/request.rs index bf4914f82550..a81d9f767b6f 100644 --- a/components/script/dom/request.rs +++ b/components/script/dom/request.rs @@ -20,6 +20,7 @@ use dom::bindings::error::{Error, Fallible}; use dom::bindings::js::{MutNullableJS, Root}; use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; use dom::bindings::str::{ByteString, DOMString, USVString}; +use dom::bindings::trace::RootedTraceableBox; use dom::globalscope::GlobalScope; use dom::headers::{Guard, Headers}; use dom::promise::Promise; @@ -80,7 +81,7 @@ impl Request { // https://fetch.spec.whatwg.org/#dom-request pub fn Constructor(global: &GlobalScope, input: RequestInfo, - init: &RequestInit) + init: RootedTraceableBox) -> Fallible> { // Step 1 let temporary_request: NetTraitsRequest; @@ -311,7 +312,7 @@ impl Request { if let Some(possible_header) = init.headers.as_ref() { match possible_header { &HeadersInit::Headers(ref init_headers) => { - headers_copy = init_headers.clone(); + headers_copy = Root::from_ref(&*init_headers); } &HeadersInit::ByteStringSequenceSequence(ref init_sequence) => { try!(headers_copy.fill(Some( diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index 677d5c611db9..1582647ca335 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -27,6 +27,7 @@ use dom::bindings::num::Finite; use dom::bindings::refcounted::TrustedPromise; use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; use dom::bindings::str::{ByteString, DOMString, USVString}; +use dom::bindings::trace::RootedTraceableBox; use dom::bindings::weakref::MutableWeakRef; use dom::blob::{Blob, BlobImpl}; use dom::globalscope::GlobalScope; @@ -402,7 +403,7 @@ impl TestBindingMethods for TestBinding { } } - fn DictMatchesPassedValues(&self, arg: &TestDictionary) -> bool { + fn DictMatchesPassedValues(&self, arg: RootedTraceableBox) -> bool { arg.type_.as_ref().map(|s| s == "success").unwrap_or(false) && arg.nonRequiredNullable.is_none() && arg.nonRequiredNullable2 == Some(None) diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index b68bd492fd08..d1eba0245e0c 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -26,6 +26,7 @@ use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::DomObject; use dom::bindings::str::DOMString; use dom::bindings::structuredclone::StructuredCloneData; +use dom::bindings::trace::RootedTraceableBox; use dom::bindings::utils::{GlobalStaticData, WindowProxyHandler}; use dom::bluetooth::BluetoothExtraPermissionData; use dom::browsingcontext::BrowsingContext; @@ -921,7 +922,7 @@ impl WindowMethods for Window { #[allow(unrooted_must_root)] // https://fetch.spec.whatwg.org/#fetch-method - fn Fetch(&self, input: RequestOrUSVString, init: &RequestInit) -> Rc { + fn Fetch(&self, input: RequestOrUSVString, init: RootedTraceableBox) -> Rc { fetch::Fetch(&self.upcast(), input, init) } diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 16bd699da7c1..03e531c5f16f 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -14,6 +14,7 @@ use dom::bindings::js::{MutNullableJS, Root}; use dom::bindings::reflector::DomObject; use dom::bindings::settings_stack::AutoEntryScript; use dom::bindings::str::DOMString; +use dom::bindings::trace::RootedTraceableBox; use dom::crypto::Crypto; use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope; use dom::globalscope::GlobalScope; @@ -314,7 +315,7 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope { #[allow(unrooted_must_root)] // https://fetch.spec.whatwg.org/#fetch-method - fn Fetch(&self, input: RequestOrUSVString, init: &RequestInit) -> Rc { + fn Fetch(&self, input: RequestOrUSVString, init: RootedTraceableBox) -> Rc { fetch::Fetch(self.upcast(), input, init) } } diff --git a/components/script/fetch.rs b/components/script/fetch.rs index f1fd49147b7a..0e7cacdfc1a0 100644 --- a/components/script/fetch.rs +++ b/components/script/fetch.rs @@ -10,6 +10,7 @@ use dom::bindings::error::Error; use dom::bindings::js::Root; use dom::bindings::refcounted::{Trusted, TrustedPromise}; use dom::bindings::reflector::DomObject; +use dom::bindings::trace::RootedTraceableBox; use dom::globalscope::GlobalScope; use dom::headers::Guard; use dom::promise::Promise; @@ -68,7 +69,7 @@ fn request_init_from_request(request: NetTraitsRequest) -> NetTraitsRequestInit // https://fetch.spec.whatwg.org/#fetch-method #[allow(unrooted_must_root)] -pub fn Fetch(global: &GlobalScope, input: RequestInfo, init: &RequestInit) -> Rc { +pub fn Fetch(global: &GlobalScope, input: RequestInfo, init: RootedTraceableBox) -> Rc { let core_resource_thread = global.core_resource_thread(); // Step 1