diff options
author | Josh Matthews <josh@joshmatthews.net> | 2024-11-05 03:29:08 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-05 08:29:08 +0000 |
commit | 25a0764a37a585d032ca352923b24995f8cbf1a0 (patch) | |
tree | 1805edc4fc79396de9150f8bc063888926d53d3b /components/script/dom | |
parent | 537958a3ccb57502c558e4da0963307fd7481a14 (diff) | |
download | servo-25a0764a37a585d032ca352923b24995f8cbf1a0.tar.gz servo-25a0764a37a585d032ca352923b24995f8cbf1a0.zip |
Use out parameter for generated methods returning JSVal (#34087)
* Make generated bindings that return a WebIDL `any` value use out parameters.
Returning raw JSVal values makes it easier to create GC hazards in code
that calls these methods. Accepting a MutableHandle argument instead
ensures that the values are rooted by the caller.
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
* Update mozjs.
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
* Fix clippy warnings.
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
---------
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
Diffstat (limited to 'components/script/dom')
36 files changed, 756 insertions, 509 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 6b68c68dc93..f716f4a8be1 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1415,6 +1415,18 @@ def typeNeedsCx(type, retVal=False): return type.isAny() or type.isObject() +def returnTypeNeedsOutparam(type): + if type.nullable(): + type = type.inner + return type.isAny() + + +def outparamTypeFromReturnType(type): + if type.isAny(): + return "MutableHandleValue" + raise f"Don't know how to handle {type} as an outparam" + + # Returns a conversion behavior suitable for a type def getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs): if type.isSequence() or type.isRecord(): @@ -1502,8 +1514,6 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): if returnType.nullable(): result = CGWrapper(result, pre="Option<", post=">") return result - # TODO: Return the value through a MutableHandleValue outparam - # https://github.com/servo/servo/issues/6307 if returnType.isAny(): return CGGeneric("JSVal") if returnType.isObject() or returnType.isSpiderMonkeyInterface(): @@ -3705,6 +3715,12 @@ class CGCallGenerator(CGThing): isFallible = errorResult is not None result = getRetvalDeclarationForType(returnType, descriptor) + if returnType and returnTypeNeedsOutparam(returnType): + rootType = result + result = CGGeneric("()") + else: + rootType = None + if isFallible: result = CGWrapper(result, pre="Result<", post=", Error>") @@ -3723,10 +3739,19 @@ class CGCallGenerator(CGThing): args.append(CGGeneric("InRealm::already(&AlreadyInRealm::assert_for_cx(cx))")) if nativeMethodName in descriptor.canGcMethods: args.append(CGGeneric("CanGc::note()")) + if rootType: + args.append(CGGeneric("retval.handle_mut()")) # Build up our actual call self.cgRoot = CGList([], "\n") + if rootType: + self.cgRoot.append(CGList([ + CGGeneric("rooted!(in(*cx) let mut retval: "), + rootType, + CGGeneric(");"), + ])) + call = CGGeneric(nativeMethodName) if static: call = CGWrapper(call, pre=f"{MakeNativeName(descriptor.interface.identifier.name)}::") @@ -3846,7 +3871,18 @@ class CGPerSignatureCall(CGThing): return 'infallible' not in self.extendedAttributes def wrap_return_value(self): - return wrapForType('MutableHandleValue::from_raw(args.rval())', successCode='return true;') + resultName = "result" + # Maplike methods have `any` return values in WebIDL, but our internal bindings + # use stronger types so we need to exclude them from being handled like other + # generated code. + if returnTypeNeedsOutparam(self.returnType) and ( + not (self.idlNode.isMethod() and self.idlNode.isMaplikeOrSetlikeOrIterableMethod())): + resultName = "retval" + return wrapForType( + 'MutableHandleValue::from_raw(args.rval())', + result=resultName, + successCode='return true;', + ) def define(self): return f"{self.cgRoot.define()}\n{self.wrap_return_value()}" @@ -6303,8 +6339,8 @@ class CGInterfaceTrait(CGThing): def __init__(self, descriptor, descriptorProvider): CGThing.__init__(self) - def attribute_arguments(needCx, argument=None, inRealm=False, canGc=False): - if needCx: + def attribute_arguments(attribute_type, argument=None, inRealm=False, canGc=False, retval=False): + if typeNeedsCx(attribute_type, retval): yield "cx", "SafeJSContext" if argument: @@ -6316,6 +6352,9 @@ class CGInterfaceTrait(CGThing): if canGc: yield "_can_gc", "CanGc" + if retval and returnTypeNeedsOutparam(attribute_type): + yield "retval", outparamTypeFromReturnType(attribute_type) + def members(): for m in descriptor.interface.members: if (m.isMethod() @@ -6335,9 +6374,10 @@ class CGInterfaceTrait(CGThing): infallible = 'infallible' in descriptor.getExtendedAttributes(m, getter=True) yield (name, attribute_arguments( - typeNeedsCx(m.type, True), + m.type, inRealm=name in descriptor.inRealmMethods, - canGc=name in descriptor.canGcMethods + canGc=name in descriptor.canGcMethods, + retval=True ), return_type(descriptor, m.type, infallible), m.isStatic()) @@ -6351,10 +6391,11 @@ class CGInterfaceTrait(CGThing): rettype = "ErrorResult" yield (name, attribute_arguments( - typeNeedsCx(m.type, False), + m.type, m.type, inRealm=name in descriptor.inRealmMethods, - canGc=name in descriptor.canGcMethods + canGc=name in descriptor.canGcMethods, + retval=False, ), rettype, m.isStatic()) @@ -7240,9 +7281,14 @@ def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, if canGc: yield "_can_gc", "CanGc" + if returnTypeNeedsOutparam(returnType): + yield "rval", outparamTypeFromReturnType(returnType), + def return_type(descriptorProvider, rettype, infallible): result = getRetvalDeclarationForType(rettype, descriptorProvider) + if rettype and returnTypeNeedsOutparam(rettype): + result = CGGeneric("()") if not infallible: result = CGWrapper(result, pre="Fallible<", post=">") return result.define() @@ -7466,6 +7512,7 @@ class CallbackMember(CGNativeMember): f"{self.argCount - 1} + {lastArg.identifier.name}.len()").removeprefix("0 + ") else: self.argCountStr = f"{self.argCount}" + self.usingOutparam = returnTypeNeedsOutparam(self.retvalType) self.needThisHandling = needThisHandling # If needThisHandling, we generate ourselves as private and the caller # will handle generating public versions that handle the "this" stuff. @@ -7518,15 +7565,16 @@ class CallbackMember(CGNativeMember): template = info.template declType = info.declType - convertType = instantiateJSToNativeConversionTemplate( - template, replacements, declType, "rvalDecl") + if self.usingOutparam: + convertType = CGGeneric("") + else: + convertType = instantiateJSToNativeConversionTemplate( + template, replacements, declType, "retval") - if self.retvalType is None or self.retvalType.isUndefined(): + if self.retvalType is None or self.retvalType.isUndefined() or self.usingOutparam: retval = "()" - elif self.retvalType.isAny(): - retval = "rvalDecl.get()" else: - retval = "rvalDecl" + retval = "retval" return f"{convertType.define()}\nOk({retval})\n" @@ -7633,7 +7681,10 @@ class CallbackMethod(CallbackMember): needThisHandling) def getRvalDecl(self): - return "rooted!(in(*cx) let mut rval = UndefinedValue());\n" + if self.usingOutparam: + return "" + else: + return "rooted!(in(*cx) let mut rval = UndefinedValue());\n" def getCall(self): if self.argCount > 0: @@ -7642,6 +7693,7 @@ class CallbackMethod(CallbackMember): else: argv = "ptr::null_mut()" argc = "0" + suffix = "" if self.usingOutparam else ".handle_mut()" return (f"{self.getCallableDecl()}" f"rooted!(in(*cx) let rootedThis = {self.getThisObj()});\n" f"let ok = {self.getCallGuard()}JS_CallFunctionValue(\n" @@ -7649,7 +7701,7 @@ class CallbackMethod(CallbackMember): " &HandleValueArray {\n" f" length_: {argc} as ::libc::size_t,\n" f" elements_: {argv}\n" - " }, rval.handle_mut());\n" + f" }}, rval{suffix});\n" "maybe_resume_unwind();\n" "if !ok {\n" " return Err(JSFailed);\n" diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index c9cbbae2723..cd7d8d4e6e5 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -117,13 +117,15 @@ impl Clone for DOMJSClass { unsafe impl Sync for DOMJSClass {} /// Returns a JSVal representing the frozen JavaScript array -pub fn to_frozen_array<T: ToJSValConvertible>(convertibles: &[T], cx: SafeJSContext) -> JSVal { - rooted!(in(*cx) let mut ports = UndefinedValue()); - unsafe { convertibles.to_jsval(*cx, ports.handle_mut()) }; +pub fn to_frozen_array<T: ToJSValConvertible>( + convertibles: &[T], + cx: SafeJSContext, + rval: MutableHandleValue, +) { + unsafe { convertibles.to_jsval(*cx, rval) }; - rooted!(in(*cx) let obj = ports.to_object()); + rooted!(in(*cx) let obj = rval.to_object()); unsafe { JS_FreezeObject(*cx, RawHandleObject::from(obj.handle())) }; - *ports } /// Returns the ProtoOrIfaceArray for the given global object. diff --git a/components/script/dom/csslayerstatementrule.rs b/components/script/dom/csslayerstatementrule.rs index 9a4aa5a0dc9..dd9e632701d 100644 --- a/components/script/dom/csslayerstatementrule.rs +++ b/components/script/dom/csslayerstatementrule.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use dom_struct::dom_struct; -use js::jsval::JSVal; +use js::rust::MutableHandleValue; use servo_arc::Arc; use style::shared_lock::ToCssWithGuard; use style::stylesheets::{CssRuleType, LayerStatementRule}; @@ -67,13 +67,13 @@ impl SpecificCSSRule for CSSLayerStatementRule { impl CSSLayerStatementRuleMethods for CSSLayerStatementRule { /// <https://drafts.csswg.org/css-cascade-5/#dom-csslayerstatementrule-namelist> - fn NameList(&self, cx: SafeJSContext) -> JSVal { + fn NameList(&self, cx: SafeJSContext, retval: MutableHandleValue) { let names: Vec<DOMString> = self .layerstatementrule .names .iter() .map(|name| DOMString::from_string(name.to_css_string())) .collect(); - to_frozen_array(names.as_slice(), cx) + to_frozen_array(names.as_slice(), cx, retval) } } diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs index dfbbe5e5d79..dd8675b066d 100644 --- a/components/script/dom/customelementregistry.rs +++ b/components/script/dom/customelementregistry.rs @@ -548,16 +548,12 @@ impl CustomElementRegistryMethods for CustomElementRegistry { /// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-get> #[allow(unsafe_code)] - fn Get(&self, cx: JSContext, name: DOMString) -> JSVal { + fn Get(&self, cx: JSContext, name: DOMString, mut retval: MutableHandleValue) { match self.definitions.borrow().get(&LocalName::from(&*name)) { Some(definition) => unsafe { - rooted!(in(*cx) let mut constructor = UndefinedValue()); - definition - .constructor - .to_jsval(*cx, constructor.handle_mut()); - constructor.get() + definition.constructor.to_jsval(*cx, retval); }, - None => UndefinedValue(), + None => retval.set(UndefinedValue()), } } @@ -994,7 +990,13 @@ impl CustomElementReaction { .iter() .map(|arg| unsafe { HandleValue::from_raw(arg.handle()) }) .collect(); - let _ = callback.Call_(element, arguments, ExceptionHandling::Report); + rooted!(in(*GlobalScope::get_cx()) let mut value: JSVal); + let _ = callback.Call_( + element, + arguments, + value.handle_mut(), + ExceptionHandling::Report, + ); }, } } diff --git a/components/script/dom/customevent.rs b/components/script/dom/customevent.rs index cb99468e00e..459747b6ca4 100644 --- a/components/script/dom/customevent.rs +++ b/components/script/dom/customevent.rs @@ -5,7 +5,7 @@ use dom_struct::dom_struct; use js::jsapi::Heap; use js::jsval::JSVal; -use js::rust::{HandleObject, HandleValue}; +use js::rust::{HandleObject, HandleValue, MutableHandleValue}; use servo_atoms::Atom; use crate::dom::bindings::codegen::Bindings::CustomEventBinding; @@ -105,8 +105,8 @@ impl CustomEventMethods for CustomEvent { } // https://dom.spec.whatwg.org/#dom-customevent-detail - fn Detail(&self, _cx: JSContext) -> JSVal { - self.detail.get() + fn Detail(&self, _cx: JSContext, mut retval: MutableHandleValue) { + retval.set(self.detail.get()) } // https://dom.spec.whatwg.org/#dom-customevent-initcustomevent diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs index 51cad369282..65a8039e261 100644 --- a/components/script/dom/dissimilaroriginwindow.rs +++ b/components/script/dom/dissimilaroriginwindow.rs @@ -5,8 +5,8 @@ use base::id::PipelineId; use dom_struct::dom_struct; use js::jsapi::{Heap, JSObject}; -use js::jsval::{JSVal, UndefinedValue}; -use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue}; +use js::jsval::UndefinedValue; +use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue, MutableHandleValue}; use script_traits::{ScriptMsg, StructuredSerializedData}; use servo_url::ServoUrl; @@ -167,9 +167,9 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow { } // https://html.spec.whatwg.org/multipage/#dom-opener - fn Opener(&self, _: JSContext) -> JSVal { + fn Opener(&self, _: JSContext, mut retval: MutableHandleValue) { // TODO: Implement x-origin opener - UndefinedValue() + retval.set(UndefinedValue()); } // https://html.spec.whatwg.org/multipage/#dom-opener diff --git a/components/script/dom/errorevent.rs b/components/script/dom/errorevent.rs index 012a2cde343..1bd0f9f3af8 100644 --- a/components/script/dom/errorevent.rs +++ b/components/script/dom/errorevent.rs @@ -7,7 +7,7 @@ use std::cell::Cell; use dom_struct::dom_struct; use js::jsapi::Heap; use js::jsval::JSVal; -use js::rust::{HandleObject, HandleValue}; +use js::rust::{HandleObject, HandleValue, MutableHandleValue}; use servo_atoms::Atom; use crate::dom::bindings::cell::DomRefCell; @@ -166,8 +166,8 @@ impl ErrorEventMethods for ErrorEvent { } // https://html.spec.whatwg.org/multipage/#dom-errorevent-error - fn Error(&self, _cx: JSContext) -> JSVal { - self.error.get() + fn Error(&self, _cx: JSContext, mut retval: MutableHandleValue) { + retval.set(self.error.get()); } // https://dom.spec.whatwg.org/#dom-event-istrusted diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs index 98d1b912416..b097080bbc4 100644 --- a/components/script/dom/eventtarget.rs +++ b/components/script/dom/eventtarget.rs @@ -15,6 +15,7 @@ use deny_public_fields::DenyPublicFields; use dom_struct::dom_struct; use fnv::FnvHasher; use js::jsapi::JS_GetFunctionObject; +use js::jsval::JSVal; use js::rust::wrappers::CompileFunction; use js::rust::{ transform_u16_to_source_text, CompileOptionsWrapper, HandleObject, RootedObjectVectorWrapper, @@ -194,7 +195,9 @@ impl CompiledEventListener { if let Some(event) = event.downcast::<ErrorEvent>() { if object.is::<Window>() || object.is::<WorkerGlobalScope>() { let cx = GlobalScope::get_cx(); - rooted!(in(*cx) let error = event.Error(cx)); + rooted!(in(*cx) let mut error: JSVal); + event.Error(cx, error.handle_mut()); + rooted!(in(*cx) let mut rooted_return_value: JSVal); let return_value = handler.Call_( object, EventOrString::String(event.Message()), @@ -202,13 +205,13 @@ impl CompiledEventListener { Some(event.Lineno()), Some(event.Colno()), Some(error.handle()), + rooted_return_value.handle_mut(), exception_handle, ); // Step 4 - if let Ok(return_value) = return_value { - rooted!(in(*cx) let return_value = return_value); - if return_value.handle().is_boolean() && - return_value.handle().to_boolean() + if let Ok(()) = return_value { + if rooted_return_value.handle().is_boolean() && + rooted_return_value.handle().to_boolean() { event.upcast::<Event>().PreventDefault(); } @@ -217,6 +220,7 @@ impl CompiledEventListener { } } + rooted!(in(*GlobalScope::get_cx()) let mut rooted_return_value: JSVal); let _ = handler.Call_( object, EventOrString::Event(DomRoot::from_ref(event)), @@ -224,6 +228,7 @@ impl CompiledEventListener { None, None, None, + rooted_return_value.handle_mut(), exception_handle, ); }, @@ -250,10 +255,15 @@ impl CompiledEventListener { }, CommonEventHandler::EventHandler(ref handler) => { - if let Ok(value) = handler.Call_(object, event, exception_handle) { - let cx = GlobalScope::get_cx(); - rooted!(in(*cx) let value = value); - let value = value.handle(); + let cx = GlobalScope::get_cx(); + rooted!(in(*cx) let mut rooted_return_value: JSVal); + if let Ok(()) = handler.Call_( + object, + event, + rooted_return_value.handle_mut(), + exception_handle, + ) { + let value = rooted_return_value.handle(); //Step 5 let should_cancel = value.is_boolean() && !value.to_boolean(); diff --git a/components/script/dom/extendablemessageevent.rs b/components/script/dom/extendablemessageevent.rs index 6b08077e77d..c4f0ccb8249 100644 --- a/components/script/dom/extendablemessageevent.rs +++ b/components/script/dom/extendablemessageevent.rs @@ -5,7 +5,7 @@ use dom_struct::dom_struct; use js::jsapi::Heap; use js::jsval::JSVal; -use js::rust::{HandleObject, HandleValue}; +use js::rust::{HandleObject, HandleValue, MutableHandleValue}; use servo_atoms::Atom; use crate::dom::bindings::cell::DomRefCell; @@ -188,8 +188,8 @@ impl ExtendableMessageEventMethods for ExtendableMessageEvent { } /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-data> - fn Data(&self, _cx: JSContext) -> JSVal { - self.data.get() + fn Data(&self, _cx: JSContext, mut retval: MutableHandleValue) { + retval.set(self.data.get()) } /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-origin> @@ -208,9 +208,10 @@ impl ExtendableMessageEventMethods for ExtendableMessageEvent { } /// <https://w3c.github.io/ServiceWorker/#extendablemessage-event-ports> - fn Ports(&self, cx: JSContext) -> JSVal { + fn Ports(&self, cx: JSContext, mut retval: MutableHandleValue) { if let Some(ports) = &*self.frozen_ports.borrow() { - return ports.get(); + retval.set(ports.get()); + return; } let ports: Vec<DomRoot<MessagePort>> = self @@ -218,7 +219,7 @@ impl ExtendableMessageEventMethods for ExtendableMessageEvent { .iter() .map(|port| DomRoot::from_ref(&**port)) .collect(); - let frozen_ports = to_frozen_array(ports.as_slice(), cx); + to_frozen_array(ports.as_slice(), cx, retval); // Safety: need to create the Heap value in its final memory location before setting it. *self.frozen_ports.borrow_mut() = Some(Heap::default()); @@ -226,8 +227,6 @@ impl ExtendableMessageEventMethods for ExtendableMessageEvent { .borrow() .as_ref() .unwrap() - .set(frozen_ports); - - frozen_ports + .set(retval.get()); } } diff --git a/components/script/dom/gamepadhapticactuator.rs b/components/script/dom/gamepadhapticactuator.rs index 3f7513b29ce..10be49dcfee 100644 --- a/components/script/dom/gamepadhapticactuator.rs +++ b/components/script/dom/gamepadhapticactuator.rs @@ -9,7 +9,7 @@ use dom_struct::dom_struct; use embedder_traits::{DualRumbleEffectParams, EmbedderMsg}; use ipc_channel::ipc; use ipc_channel::router::ROUTER; -use js::jsval::JSVal; +use js::rust::MutableHandleValue; use script_traits::GamepadSupportedHapticEffects; use crate::dom::bindings::cell::DomRefCell; @@ -134,8 +134,8 @@ impl GamepadHapticActuator { impl GamepadHapticActuatorMethods for GamepadHapticActuator { /// <https://www.w3.org/TR/gamepad/#dom-gamepadhapticactuator-effects> - fn Effects(&self, cx: JSContext) -> JSVal { - to_frozen_array(self.effects.as_slice(), cx) + fn Effects(&self, cx: JSContext, retval: MutableHandleValue) { + to_frozen_array(self.effects.as_slice(), cx, retval) } /// <https://www.w3.org/TR/gamepad/#dom-gamepadhapticactuator-playeffect> diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index d18813a74f8..4cac0ca870f 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -3072,16 +3072,21 @@ impl GlobalScope { } /// <https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute> - pub fn supported_performance_entry_types(&self, cx: SafeJSContext) -> JSVal { + pub fn supported_performance_entry_types( + &self, + cx: SafeJSContext, + mut retval: MutableHandleValue, + ) { if let Some(types) = &*self.frozen_supported_performance_entry_types.borrow() { - return types.get(); + retval.set(types.get()); + return; } let types: Vec<DOMString> = VALID_ENTRY_TYPES .iter() .map(|t| DOMString::from(t.to_string())) .collect(); - let frozen_types = to_frozen_array(types.as_slice(), cx); + to_frozen_array(types.as_slice(), cx, retval); // Safety: need to create the Heap value in its final memory location before setting it. *self.frozen_supported_performance_entry_types.borrow_mut() = Some(Heap::default()); @@ -3089,9 +3094,7 @@ impl GlobalScope { .borrow() .as_ref() .unwrap() - .set(frozen_types); - - frozen_types + .set(retval.get()); } pub fn is_headless(&self) -> bool { @@ -3372,7 +3375,8 @@ impl GlobalScope { cx: SafeJSContext, value: HandleValue, options: RootedTraceableBox<StructuredSerializeOptions>, - ) -> Fallible<js::jsval::JSVal> { + retval: MutableHandleValue, + ) -> Fallible<()> { let mut rooted = CustomAutoRooter::new( options .transfer @@ -3384,12 +3388,9 @@ impl GlobalScope { let data = structuredclone::write(cx, value, Some(guard))?; - rooted!(in(*cx) let mut message_clone = UndefinedValue()); - - structuredclone::read(self, data, message_clone.handle_mut()) - .map_err(|_| Error::DataClone)?; + structuredclone::read(self, data, retval).map_err(|_| Error::DataClone)?; - Ok(message_clone.get()) + Ok(()) } pub(crate) fn fetch<Listener: FetchResponseListener + PreInvoke + Send + 'static>( diff --git a/components/script/dom/gpucompilationinfo.rs b/components/script/dom/gpucompilationinfo.rs index ee0049260db..a54b3e81e41 100644 --- a/components/script/dom/gpucompilationinfo.rs +++ b/components/script/dom/gpucompilationinfo.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use dom_struct::dom_struct; -use js::jsval::JSVal; +use js::rust::MutableHandleValue; use webgpu::ShaderCompilationInfo; use super::bindings::codegen::Bindings::WebGPUBinding::GPUCompilationInfoMethods; @@ -58,7 +58,7 @@ impl GPUCompilationInfo { impl GPUCompilationInfoMethods for GPUCompilationInfo { /// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationinfo-messages> - fn Messages(&self, cx: JSContext) -> JSVal { - to_frozen_array(self.msg.as_slice(), cx) + fn Messages(&self, cx: JSContext, retval: MutableHandleValue) { + to_frozen_array(self.msg.as_slice(), cx, retval) } } diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs index 67354cb0dc9..039bf15d5ed 100644 --- a/components/script/dom/history.rs +++ b/components/script/dom/history.rs @@ -9,7 +9,7 @@ use base::id::HistoryStateId; use dom_struct::dom_struct; use js::jsapi::Heap; use js::jsval::{JSVal, NullValue, UndefinedValue}; -use js::rust::HandleValue; +use js::rust::{HandleValue, MutableHandleValue}; use net_traits::{CoreResourceMsg, IpcSend}; use profile_traits::ipc; use profile_traits::ipc::channel; @@ -289,11 +289,12 @@ impl History { impl HistoryMethods for History { /// <https://html.spec.whatwg.org/multipage/#dom-history-state> - fn GetState(&self, _cx: JSContext) -> Fallible<JSVal> { + fn GetState(&self, _cx: JSContext, mut retval: MutableHandleValue) -> Fallible<()> { if !self.window.Document().is_fully_active() { return Err(Error::Security); } - Ok(self.state.get()) + retval.set(self.state.get()); + Ok(()) } /// <https://html.spec.whatwg.org/multipage/#dom-history-length> diff --git a/components/script/dom/intersectionobserver.rs b/components/script/dom/intersectionobserver.rs index 3c02238f52f..7b926e4909a 100644 --- a/components/script/dom/intersectionobserver.rs +++ b/components/script/dom/intersectionobserver.rs @@ -5,8 +5,7 @@ use std::rc::Rc; use dom_struct::dom_struct; -use js::jsval::{JSVal, NullValue}; -use js::rust::HandleObject; +use js::rust::{HandleObject, MutableHandleValue}; use super::bindings::codegen::Bindings::IntersectionObserverBinding::{ IntersectionObserverCallback, IntersectionObserverMethods, @@ -93,9 +92,7 @@ impl IntersectionObserverMethods for IntersectionObserver { /// > constructor, or the sequence is empty, the value of this attribute will be [0]. /// /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-thresholds> - fn Thresholds(&self, _context: JSContext) -> JSVal { - NullValue() - } + fn Thresholds(&self, _context: JSContext, _retval: MutableHandleValue) {} /// > A number indicating the minimum delay in milliseconds between notifications from /// > this observer for a given target. diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index 52731fd654b..f5268e72945 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -666,14 +666,3 @@ macro_rules! impl_rare_data ( } ); ); - -#[macro_export] -macro_rules! optional_root_object_to_js_or_null { - ($cx: expr, $binding:expr) => {{ - rooted!(in($cx) let mut rval = NullValue()); - if let Some(object) = $binding { - object.to_jsval($cx, rval.handle_mut()); - } - rval.get() - }}; -} diff --git a/components/script/dom/messageevent.rs b/components/script/dom/messageevent.rs index 99f8603973e..004c80aad31 100644 --- a/components/script/dom/messageevent.rs +++ b/components/script/dom/messageevent.rs @@ -5,7 +5,7 @@ use dom_struct::dom_struct; use js::jsapi::Heap; use js::jsval::JSVal; -use js::rust::{HandleObject, HandleValue}; +use js::rust::{HandleObject, HandleValue, MutableHandleValue}; use servo_atoms::Atom; use crate::dom::bindings::cell::DomRefCell; @@ -266,8 +266,8 @@ impl MessageEventMethods for MessageEvent { } /// <https://html.spec.whatwg.org/multipage/#dom-messageevent-data> - fn Data(&self, _cx: JSContext) -> JSVal { - self.data.get() + fn Data(&self, _cx: JSContext, mut retval: MutableHandleValue) { + retval.set(self.data.get()) } /// <https://html.spec.whatwg.org/multipage/#dom-messageevent-origin> @@ -302,9 +302,10 @@ impl MessageEventMethods for MessageEvent { } /// <https://html.spec.whatwg.org/multipage/#dom-messageevent-ports> - fn Ports(&self, cx: JSContext) -> JSVal { + fn Ports(&self, cx: JSContext, mut retval: MutableHandleValue) { if let Some(ports) = &*self.frozen_ports.borrow() { - return ports.get(); + retval.set(ports.get()); + return; } let ports: Vec<DomRoot<MessagePort>> = self @@ -313,7 +314,7 @@ impl MessageEventMethods for MessageEvent { .iter() .map(|port| DomRoot::from_ref(&**port)) .collect(); - let frozen_ports = to_frozen_array(ports.as_slice(), cx); + to_frozen_array(ports.as_slice(), cx, retval); // Safety: need to create the Heap value in its final memory location before setting it. *self.frozen_ports.borrow_mut() = Some(Heap::default()); @@ -321,9 +322,7 @@ impl MessageEventMethods for MessageEvent { .borrow() .as_ref() .unwrap() - .set(frozen_ports); - - frozen_ports + .set(retval.get()); } /// <https://html.spec.whatwg.org/multipage/#dom-messageevent-initmessageevent> diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs index 9ef543bfb68..969f006dd76 100644 --- a/components/script/dom/navigator.rs +++ b/components/script/dom/navigator.rs @@ -7,7 +7,7 @@ use std::convert::TryInto; use std::sync::LazyLock; use dom_struct::dom_struct; -use js::jsval::JSVal; +use js::rust::MutableHandleValue; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods; @@ -199,8 +199,8 @@ impl NavigatorMethods for Navigator { // https://html.spec.whatwg.org/multipage/#dom-navigator-languages #[allow(unsafe_code)] - fn Languages(&self, cx: JSContext) -> JSVal { - to_frozen_array(&[self.Language()], cx) + fn Languages(&self, cx: JSContext, retval: MutableHandleValue) { + to_frozen_array(&[self.Language()], cx, retval) } // https://html.spec.whatwg.org/multipage/#dom-navigator-plugins diff --git a/components/script/dom/performanceobserver.rs b/components/script/dom/performanceobserver.rs index 339941ffbf6..f6d83d496dd 100644 --- a/components/script/dom/performanceobserver.rs +++ b/components/script/dom/performanceobserver.rs @@ -6,8 +6,7 @@ use std::cell::Cell; use std::rc::Rc; use dom_struct::dom_struct; -use js::jsval::JSVal; -use js::rust::HandleObject; +use js::rust::{HandleObject, MutableHandleValue}; use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::cell::DomRefCell; @@ -137,10 +136,10 @@ impl PerformanceObserverMethods for PerformanceObserver { } // https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute - fn SupportedEntryTypes(cx: JSContext, global: &GlobalScope) -> JSVal { + fn SupportedEntryTypes(cx: JSContext, global: &GlobalScope, retval: MutableHandleValue) { // While this is exposed through a method of PerformanceObserver, // it is specified as associated with the global scope. - global.supported_performance_entry_types(cx) + global.supported_performance_entry_types(cx, retval) } // https://w3c.github.io/performance-timeline/#dom-performanceobserver-observe() diff --git a/components/script/dom/popstateevent.rs b/components/script/dom/popstateevent.rs index d241c273116..d0a8afe2048 100644 --- a/components/script/dom/popstateevent.rs +++ b/components/script/dom/popstateevent.rs @@ -5,7 +5,7 @@ use dom_struct::dom_struct; use js::jsapi::Heap; use js::jsval::JSVal; -use js::rust::{HandleObject, HandleValue}; +use js::rust::{HandleObject, HandleValue, MutableHandleValue}; use servo_atoms::Atom; use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; @@ -102,8 +102,8 @@ impl PopStateEventMethods for PopStateEvent { } // https://html.spec.whatwg.org/multipage/#dom-popstateevent-state - fn State(&self, _cx: JSContext) -> JSVal { - self.state.get() + fn State(&self, _cx: JSContext, mut retval: MutableHandleValue) { + retval.set(self.state.get()) } // https://dom.spec.whatwg.org/#dom-event-istrusted diff --git a/components/script/dom/promiserejectionevent.rs b/components/script/dom/promiserejectionevent.rs index 7aec0e2cd49..1a45790b7e1 100644 --- a/components/script/dom/promiserejectionevent.rs +++ b/components/script/dom/promiserejectionevent.rs @@ -8,7 +8,7 @@ use std::rc::Rc; use dom_struct::dom_struct; use js::jsapi::{Heap, JSObject}; use js::jsval::JSVal; -use js::rust::{HandleObject, HandleValue}; +use js::rust::{HandleObject, HandleValue, MutableHandleValue}; use servo_atoms::Atom; use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; @@ -127,8 +127,8 @@ impl PromiseRejectionEventMethods for PromiseRejectionEvent { } // https://html.spec.whatwg.org/multipage/#dom-promiserejectionevent-reason - fn Reason(&self, _cx: JSContext) -> JSVal { - self.reason.get() + fn Reason(&self, _cx: JSContext, mut retval: MutableHandleValue) { + retval.set(self.reason.get()) } // https://dom.spec.whatwg.org/#dom-event-istrusted diff --git a/components/script/dom/resizeobserverentry.rs b/components/script/dom/resizeobserverentry.rs index 5d94db2abab..a5017c4868c 100644 --- a/components/script/dom/resizeobserverentry.rs +++ b/components/script/dom/resizeobserverentry.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use dom_struct::dom_struct; -use js::jsval::JSVal; +use js::rust::MutableHandleValue; use crate::dom::bindings::codegen::Bindings::ResizeObserverEntryBinding::ResizeObserverEntryMethods; use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, Reflector}; @@ -90,32 +90,32 @@ impl ResizeObserverEntryMethods for ResizeObserverEntry { } /// <https://drafts.csswg.org/resize-observer/#dom-resizeobserverentry-borderboxsize> - fn BorderBoxSize(&self, cx: SafeJSContext) -> JSVal { + fn BorderBoxSize(&self, cx: SafeJSContext, retval: MutableHandleValue) { let sizes: Vec<DomRoot<ResizeObserverSize>> = self .border_box_size .iter() .map(|size| DomRoot::from_ref(&**size)) .collect(); - to_frozen_array(sizes.as_slice(), cx) + to_frozen_array(sizes.as_slice(), cx, retval) } /// <https://drafts.csswg.org/resize-observer/#dom-resizeobserverentry-contentboxsize> - fn ContentBoxSize(&self, cx: SafeJSContext) -> JSVal { + fn ContentBoxSize(&self, cx: SafeJSContext, retval: MutableHandleValue) { let sizes: Vec<DomRoot<ResizeObserverSize>> = self .content_box_size .iter() .map(|size| DomRoot::from_ref(&**size)) .collect(); - to_frozen_array(sizes.as_slice(), cx) + to_frozen_array(sizes.as_slice(), cx, retval); } /// <https://drafts.csswg.org/resize-observer/#dom-resizeobserverentry-devicepixelcontentboxsize> - fn DevicePixelContentBoxSize(&self, cx: SafeJSContext) -> JSVal { + fn DevicePixelContentBoxSize(&self, cx: SafeJSContext, retval: MutableHandleValue) { let sizes: Vec<DomRoot<ResizeObserverSize>> = self .device_pixel_content_box_size .iter() .map(|size| DomRoot::from_ref(&**size)) .collect(); - to_frozen_array(sizes.as_slice(), cx) + to_frozen_array(sizes.as_slice(), cx, retval); } } diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index 2c91ce7fac5..1fc70eac60d 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -11,8 +11,8 @@ use std::time::Duration; use dom_struct::dom_struct; use js::jsapi::{Heap, JSObject, JS_NewPlainObject}; -use js::jsval::{JSVal, NullValue}; -use js::rust::{CustomAutoRooterGuard, HandleObject, HandleValue}; +use js::jsval::JSVal; +use js::rust::{CustomAutoRooterGuard, HandleObject, HandleValue, MutableHandleValue}; use js::typedarray::{self, Uint8ClampedArray}; use script_traits::serializable::BlobImpl; use servo_config::prefs; @@ -229,9 +229,7 @@ impl TestBindingMethods for TestBinding { create_buffer_source(cx, &data, array.handle_mut()) .expect("Creating ClampedU8 array should never fail") } - fn AnyAttribute(&self, _: SafeJSContext) -> JSVal { - NullValue() - } + fn AnyAttribute(&self, _: SafeJSContext, _: MutableHandleValue) {} fn SetAnyAttribute(&self, _: SafeJSContext, _: HandleValue) {} #[allow(unsafe_code)] fn ObjectAttribute(&self, cx: SafeJSContext) -> NonNull<JSObject> { @@ -426,9 +424,7 @@ impl TestBindingMethods for TestBinding { can_gc, ) } - fn ReceiveAny(&self, _: SafeJSContext) -> JSVal { - NullValue() - } + fn ReceiveAny(&self, _: SafeJSContext, _: MutableHandleValue) {} fn ReceiveObject(&self, cx: SafeJSContext) -> NonNull<JSObject> { self.ObjectAttribute(cx) } diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs index 038f00df9df..ffe7dec15a5 100644 --- a/components/script/dom/webgl2renderingcontext.rs +++ b/components/script/dom/webgl2renderingcontext.rs @@ -16,11 +16,8 @@ use dom_struct::dom_struct; use euclid::default::{Point2D, Rect, Size2D}; use ipc_channel::ipc::{self, IpcSharedMemory}; use js::jsapi::{JSObject, Type}; -use js::jsval::{ - BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, ObjectValue, UInt32Value, - UndefinedValue, -}; -use js::rust::{CustomAutoRooterGuard, HandleObject}; +use js::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, ObjectValue, UInt32Value}; +use js::rust::{CustomAutoRooterGuard, HandleObject, MutableHandleValue}; use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, Uint32Array}; use script_layout_interface::HTMLCanvasDataSource; use servo_config::pref; @@ -591,14 +588,20 @@ impl WebGL2RenderingContext { } #[allow(unsafe_code)] - fn get_default_fb_attachment_param(&self, attachment: u32, pname: u32) -> WebGLResult<JSVal> { + fn get_default_fb_attachment_param( + &self, + attachment: u32, + pname: u32, + mut retval: MutableHandleValue, + ) -> WebGLResult<()> { match attachment { constants::BACK | constants::DEPTH | constants::STENCIL => {}, _ => return Err(InvalidEnum), } if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME { - return Ok(NullValue()); + retval.set(NullValue()); + return Ok(()); } let attrs = self @@ -646,7 +649,8 @@ impl WebGL2RenderingContext { }, _ => return Err(InvalidEnum), }; - Ok(Int32Value(intval)) + retval.set(Int32Value(intval)); + Ok(()) } #[allow(unsafe_code)] @@ -657,7 +661,8 @@ impl WebGL2RenderingContext { target: u32, attachment: u32, pname: u32, - ) -> WebGLResult<JSVal> { + mut rval: MutableHandleValue, + ) -> WebGLResult<()> { use crate::dom::webglframebuffer::WebGLFramebufferAttachmentRoot::{Renderbuffer, Texture}; match attachment { @@ -692,17 +697,16 @@ impl WebGL2RenderingContext { }; if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME { - rooted!(in(*cx) let mut rval = NullValue()); match fb.attachment(attachment) { Some(Renderbuffer(rb)) => unsafe { - rb.to_jsval(*cx, rval.handle_mut()); + rb.to_jsval(*cx, rval); }, Some(Texture(texture)) => unsafe { - texture.to_jsval(*cx, rval.handle_mut()); + texture.to_jsval(*cx, rval); }, - _ => {}, + _ => rval.set(NullValue()), } - return Ok(rval.get()); + return Ok(()); } match pname { @@ -738,7 +742,8 @@ impl WebGL2RenderingContext { )); let retval = receiver.recv().unwrap(); - Ok(Int32Value(retval)) + rval.set(Int32Value(retval)); + Ok(()) } fn clearbuffer_array_size(&self, buffer: u32, draw_buffer: i32) -> WebGLResult<usize> { @@ -931,101 +936,108 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { } /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5> - fn GetBufferParameter(&self, _cx: JSContext, target: u32, parameter: u32) -> JSVal { - let buffer = - handle_potential_webgl_error!(self.base, self.bound_buffer(target), return NullValue()); - self.base.get_buffer_param(buffer, parameter) + fn GetBufferParameter( + &self, + _cx: JSContext, + target: u32, + parameter: u32, + mut retval: MutableHandleValue, + ) { + let buffer = handle_potential_webgl_error!( + self.base, + self.bound_buffer(target), + return retval.set(NullValue()) + ); + self.base.get_buffer_param(buffer, parameter, retval) } #[allow(unsafe_code)] /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3> - fn GetParameter(&self, cx: JSContext, parameter: u32) -> JSVal { + fn GetParameter(&self, cx: JSContext, parameter: u32, mut rval: MutableHandleValue) { match parameter { constants::VERSION => unsafe { - rooted!(in(*cx) let mut rval = UndefinedValue()); - "WebGL 2.0".to_jsval(*cx, rval.handle_mut()); - return rval.get(); + "WebGL 2.0".to_jsval(*cx, rval); + return; }, constants::SHADING_LANGUAGE_VERSION => unsafe { - rooted!(in(*cx) let mut rval = UndefinedValue()); - "WebGL GLSL ES 3.00".to_jsval(*cx, rval.handle_mut()); - return rval.get(); + "WebGL GLSL ES 3.00".to_jsval(*cx, rval); + return; }, constants::MAX_CLIENT_WAIT_TIMEOUT_WEBGL => { - return DoubleValue( - self.base.limits().max_client_wait_timeout_webgl.as_nanos() as f64 - ); + rval.set(DoubleValue( + self.base.limits().max_client_wait_timeout_webgl.as_nanos() as f64, + )); + return; }, constants::MAX_SERVER_WAIT_TIMEOUT => { - return DoubleValue(self.base.limits().max_server_wait_timeout.as_nanos() as f64); + rval.set(DoubleValue( + self.base.limits().max_server_wait_timeout.as_nanos() as f64, + )); + return; }, constants::SAMPLER_BINDING => unsafe { let idx = (self.base.textures().active_unit_enum() - constants::TEXTURE0) as usize; assert!(idx < self.samplers.len()); let sampler = self.samplers[idx].get(); - return optional_root_object_to_js_or_null!(*cx, sampler); + sampler.to_jsval(*cx, rval); + return; }, constants::COPY_READ_BUFFER_BINDING => unsafe { - return optional_root_object_to_js_or_null!( - *cx, - &self.bound_copy_read_buffer.get() - ); + self.bound_copy_read_buffer.get().to_jsval(*cx, rval); + return; }, constants::COPY_WRITE_BUFFER_BINDING => unsafe { - return optional_root_object_to_js_or_null!( - *cx, - &self.bound_copy_write_buffer.get() - ); + self.bound_copy_write_buffer.get().to_jsval(*cx, rval); + return; }, constants::PIXEL_PACK_BUFFER_BINDING => unsafe { - return optional_root_object_to_js_or_null!( - *cx, - &self.bound_pixel_pack_buffer.get() - ); + self.bound_pixel_pack_buffer.get().to_jsval(*cx, rval); + return; }, constants::PIXEL_UNPACK_BUFFER_BINDING => unsafe { - return optional_root_object_to_js_or_null!( - *cx, - &self.bound_pixel_unpack_buffer.get() - ); + self.bound_pixel_unpack_buffer.get().to_jsval(*cx, rval); + return; }, constants::TRANSFORM_FEEDBACK_BUFFER_BINDING => unsafe { - return optional_root_object_to_js_or_null!( - *cx, - &self.bound_transform_feedback_buffer.get() - ); + self.bound_transform_feedback_buffer + .get() + .to_jsval(*cx, rval); + return; }, constants::UNIFORM_BUFFER_BINDING => unsafe { - return optional_root_object_to_js_or_null!(*cx, &self.bound_uniform_buffer.get()); + self.bound_uniform_buffer.get().to_jsval(*cx, rval); + return; }, constants::TRANSFORM_FEEDBACK_BINDING => unsafe { - return optional_root_object_to_js_or_null!( - *cx, - self.current_transform_feedback.get() - ); + self.current_transform_feedback.get().to_jsval(*cx, rval); + return; }, constants::ELEMENT_ARRAY_BUFFER_BINDING => unsafe { let buffer = self.current_vao().element_array_buffer().get(); - return optional_root_object_to_js_or_null!(*cx, buffer); + buffer.to_jsval(*cx, rval); + return; }, constants::VERTEX_ARRAY_BINDING => unsafe { let vao = self.current_vao(); let vao = vao.id().map(|_| &*vao); - return optional_root_object_to_js_or_null!(*cx, vao); + vao.to_jsval(*cx, rval); + return; }, // NOTE: DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING, handled on the WebGL1 side constants::READ_FRAMEBUFFER_BINDING => unsafe { - return optional_root_object_to_js_or_null!( - *cx, - &self.base.get_read_framebuffer_slot().get() - ); + self.base + .get_read_framebuffer_slot() + .get() + .to_jsval(*cx, rval); + return; }, constants::READ_BUFFER => { let buffer = match self.base.get_read_framebuffer_slot().get() { Some(fb) => fb.read_buffer(), None => self.default_fb_readbuffer.get(), }; - return UInt32Value(buffer); + rval.set(UInt32Value(buffer)); + return; }, constants::DRAW_BUFFER0..=constants::DRAW_BUFFER15 => { let buffer = match self.base.get_read_framebuffer_slot().get() { @@ -1038,29 +1050,38 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { }, None => constants::NONE, }; - return UInt32Value(buffer); + rval.set(UInt32Value(buffer)); + return; }, constants::MAX_TEXTURE_LOD_BIAS => { - return DoubleValue(self.base.limits().max_texture_lod_bias as f64) + rval.set(DoubleValue(self.base.limits().max_texture_lod_bias as f64)); + return; }, constants::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS => { - return DoubleValue( + rval.set(DoubleValue( self.base.limits().max_combined_fragment_uniform_components as f64, - ) + )); + return; }, constants::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS => { - return DoubleValue( + rval.set(DoubleValue( self.base.limits().max_combined_vertex_uniform_components as f64, - ) + )); + return; }, constants::MAX_ELEMENT_INDEX => { - return DoubleValue(self.base.limits().max_element_index as f64) + rval.set(DoubleValue(self.base.limits().max_element_index as f64)); + return; }, constants::MAX_UNIFORM_BLOCK_SIZE => { - return DoubleValue(self.base.limits().max_uniform_block_size as f64) + rval.set(DoubleValue( + self.base.limits().max_uniform_block_size as f64, + )); + return; }, constants::MIN_PROGRAM_TEXEL_OFFSET => { - return Int32Value(self.base.limits().min_program_texel_offset) + rval.set(Int32Value(self.base.limits().min_program_texel_offset)); + return; }, _ => {}, } @@ -1109,15 +1130,16 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { _ => None, }; if let Some(limit) = limit { - return UInt32Value(limit); + rval.set(UInt32Value(limit)); + return; } - self.base.GetParameter(cx, parameter) + self.base.GetParameter(cx, parameter, rval) } /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8> - fn GetTexParameter(&self, cx: JSContext, target: u32, pname: u32) -> JSVal { - self.base.GetTexParameter(cx, target, pname) + fn GetTexParameter(&self, cx: JSContext, target: u32, pname: u32, retval: MutableHandleValue) { + self.base.GetTexParameter(cx, target, pname, retval) } /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3> @@ -1152,7 +1174,8 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { target: u32, attachment: u32, pname: u32, - ) -> JSVal { + mut rval: MutableHandleValue, + ) { let fb_slot = match target { constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => { self.base.get_draw_framebuffer_slot() @@ -1160,31 +1183,43 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(), _ => { self.base.webgl_error(InvalidEnum); - return NullValue(); + rval.set(NullValue()); + return; }, }; if let Some(fb) = fb_slot.get() { // A selected framebuffer is bound to the target - handle_potential_webgl_error!(self.base, fb.validate_transparent(), return NullValue()); handle_potential_webgl_error!( self.base, - self.get_specific_fb_attachment_param(cx, &fb, target, attachment, pname), - NullValue() + fb.validate_transparent(), + return rval.set(NullValue()) + ); + handle_potential_webgl_error!( + self.base, + self.get_specific_fb_attachment_param(cx, &fb, target, attachment, pname, rval), + rval.set(NullValue()) ) } else { // The default framebuffer is bound to the target handle_potential_webgl_error!( self.base, - self.get_default_fb_attachment_param(attachment, pname), - NullValue() + self.get_default_fb_attachment_param(attachment, pname, rval), + rval.set(NullValue()) ) } } /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7> - fn GetRenderbufferParameter(&self, cx: JSContext, target: u32, pname: u32) -> JSVal { - self.base.GetRenderbufferParameter(cx, target, pname) + fn GetRenderbufferParameter( + &self, + cx: JSContext, + target: u32, + pname: u32, + retval: MutableHandleValue, + ) { + self.base + .GetRenderbufferParameter(cx, target, pname, retval) } /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3> @@ -1856,24 +1891,30 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { } /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9> - fn GetProgramParameter(&self, cx: JSContext, program: &WebGLProgram, param_id: u32) -> JSVal { + fn GetProgramParameter( + &self, + cx: JSContext, + program: &WebGLProgram, + param_id: u32, + mut retval: MutableHandleValue, + ) { handle_potential_webgl_error!( self.base, self.base.validate_ownership(program), - return NullValue() + return retval.set(NullValue()) ); if program.is_deleted() { self.base.webgl_error(InvalidOperation); - return NullValue(); + return retval.set(NullValue()); } match param_id { constants::TRANSFORM_FEEDBACK_VARYINGS => { - Int32Value(program.transform_feedback_varyings_length()) + retval.set(Int32Value(program.transform_feedback_varyings_length())) }, constants::TRANSFORM_FEEDBACK_BUFFER_MODE => { - Int32Value(program.transform_feedback_buffer_mode()) + retval.set(Int32Value(program.transform_feedback_buffer_mode())) }, - _ => self.base.GetProgramParameter(cx, program, param_id), + _ => self.base.GetProgramParameter(cx, program, param_id, retval), } } @@ -1883,8 +1924,14 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { } /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9> - fn GetShaderParameter(&self, cx: JSContext, shader: &WebGLShader, param_id: u32) -> JSVal { - self.base.GetShaderParameter(cx, shader, param_id) + fn GetShaderParameter( + &self, + cx: JSContext, + shader: &WebGLShader, + param_id: u32, + retval: MutableHandleValue, + ) { + self.base.GetShaderParameter(cx, shader, param_id, retval) } /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9> @@ -1899,7 +1946,13 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2> #[allow(unsafe_code)] - fn GetIndexedParameter(&self, cx: JSContext, target: u32, index: u32) -> JSVal { + fn GetIndexedParameter( + &self, + cx: JSContext, + target: u32, + index: u32, + mut retval: MutableHandleValue, + ) { let bindings = match target { constants::TRANSFORM_FEEDBACK_BUFFER_BINDING | constants::TRANSFORM_FEEDBACK_BUFFER_SIZE | @@ -1911,7 +1964,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { constants::UNIFORM_BUFFER_START => &self.indexed_uniform_buffer_bindings, _ => { self.base.webgl_error(InvalidEnum); - return NullValue(); + return retval.set(NullValue()); }, }; @@ -1919,19 +1972,19 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { Some(binding) => binding, None => { self.base.webgl_error(InvalidValue); - return NullValue(); + return retval.set(NullValue()); }, }; match target { constants::TRANSFORM_FEEDBACK_BUFFER_BINDING | constants::UNIFORM_BUFFER_BINDING => unsafe { - optional_root_object_to_js_or_null!(*cx, binding.buffer.get()) + binding.buffer.get().to_jsval(*cx, retval) }, constants::TRANSFORM_FEEDBACK_BUFFER_START | constants::UNIFORM_BUFFER_START => { - Int32Value(binding.start.get() as _) + retval.set(Int32Value(binding.start.get() as _)) }, constants::TRANSFORM_FEEDBACK_BUFFER_SIZE | constants::UNIFORM_BUFFER_SIZE => { - Int32Value(binding.size.get() as _) + retval.set(Int32Value(binding.size.get() as _)) }, _ => unreachable!(), } @@ -1947,8 +2000,8 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { } /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9> - fn GetVertexAttrib(&self, cx: JSContext, index: u32, pname: u32) -> JSVal { - self.base.GetVertexAttrib(cx, index, pname) + fn GetVertexAttrib(&self, cx: JSContext, index: u32, pname: u32, retval: MutableHandleValue) { + self.base.GetVertexAttrib(cx, index, pname, retval) } /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10> @@ -2709,68 +2762,88 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { cx: JSContext, program: &WebGLProgram, location: &WebGLUniformLocation, - ) -> JSVal { + mut retval: MutableHandleValue, + ) { handle_potential_webgl_error!( self.base, self.base.uniform_check_program(program, location), - return NullValue() + return retval.set(NullValue()) ); let triple = (&*self.base, program.id(), location.id()); match location.type_() { - constants::UNSIGNED_INT => { - UInt32Value(uniform_get(triple, WebGLCommand::GetUniformUint)) - }, + constants::UNSIGNED_INT => retval.set(UInt32Value(uniform_get( + triple, + WebGLCommand::GetUniformUint, + ))), constants::UNSIGNED_INT_VEC2 => unsafe { - uniform_typed::<Uint32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformUint2)) + uniform_typed::<Uint32>( + *cx, + &uniform_get(triple, WebGLCommand::GetUniformUint2), + retval, + ) }, constants::UNSIGNED_INT_VEC3 => unsafe { - uniform_typed::<Uint32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformUint3)) + uniform_typed::<Uint32>( + *cx, + &uniform_get(triple, WebGLCommand::GetUniformUint3), + retval, + ) }, constants::UNSIGNED_INT_VEC4 => unsafe { - uniform_typed::<Uint32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformUint4)) + uniform_typed::<Uint32>( + *cx, + &uniform_get(triple, WebGLCommand::GetUniformUint4), + retval, + ) }, constants::FLOAT_MAT2x3 => unsafe { uniform_typed::<Float32>( *cx, &uniform_get(triple, WebGLCommand::GetUniformFloat2x3), + retval, ) }, constants::FLOAT_MAT2x4 => unsafe { uniform_typed::<Float32>( *cx, &uniform_get(triple, WebGLCommand::GetUniformFloat2x4), + retval, ) }, constants::FLOAT_MAT3x2 => unsafe { uniform_typed::<Float32>( *cx, &uniform_get(triple, WebGLCommand::GetUniformFloat3x2), + retval, ) }, constants::FLOAT_MAT3x4 => unsafe { uniform_typed::<Float32>( *cx, &uniform_get(triple, WebGLCommand::GetUniformFloat3x4), + retval, ) }, constants::FLOAT_MAT4x2 => unsafe { uniform_typed::<Float32>( *cx, &uniform_get(triple, WebGLCommand::GetUniformFloat4x2), + retval, ) }, constants::FLOAT_MAT4x3 => unsafe { uniform_typed::<Float32>( *cx, &uniform_get(triple, WebGLCommand::GetUniformFloat4x3), + retval, ) }, constants::SAMPLER_3D | constants::SAMPLER_2D_ARRAY => { - Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)) + retval.set(Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt))) }, - _ => self.base.GetUniform(cx, program, location), + _ => self.base.GetUniform(cx, program, location, retval), } } @@ -3530,21 +3603,21 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12> #[rustfmt::skip] - fn GetQueryParameter(&self, _cx: JSContext, query: &WebGLQuery, pname: u32) -> JSVal { + fn GetQueryParameter(&self, _cx: JSContext, query: &WebGLQuery, pname: u32, mut retval: MutableHandleValue) { handle_potential_webgl_error!( self.base, self.base.validate_ownership(query), - return NullValue() + return retval.set(NullValue()) ); match query.get_parameter(&self.base, pname) { Ok(value) => match pname { - constants::QUERY_RESULT => UInt32Value(value), - constants::QUERY_RESULT_AVAILABLE => BooleanValue(value != 0), + constants::QUERY_RESULT => retval.set(UInt32Value(value)), + constants::QUERY_RESULT_AVAILABLE => retval.set(BooleanValue(value != 0)), _ => unreachable!(), }, Err(error) => { self.base.webgl_error(error); - NullValue() + retval.set(NullValue()) }, } } @@ -3631,30 +3704,36 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { } /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14> - fn GetSyncParameter(&self, _cx: JSContext, sync: &WebGLSync, pname: u32) -> JSVal { + fn GetSyncParameter( + &self, + _cx: JSContext, + sync: &WebGLSync, + pname: u32, + mut retval: MutableHandleValue, + ) { if !sync.is_valid() { self.base.webgl_error(InvalidOperation); - return NullValue(); + return retval.set(NullValue()); } handle_potential_webgl_error!( self.base, self.base.validate_ownership(sync), - return NullValue() + return retval.set(NullValue()) ); match pname { constants::OBJECT_TYPE | constants::SYNC_CONDITION | constants::SYNC_FLAGS => { let (sender, receiver) = webgl_channel().unwrap(); self.base .send_command(WebGLCommand::GetSyncParameter(sync.id(), pname, sender)); - UInt32Value(receiver.recv().unwrap()) + retval.set(UInt32Value(receiver.recv().unwrap())) }, constants::SYNC_STATUS => match sync.get_sync_status(pname, &self.base) { - Some(status) => UInt32Value(status), - None => UInt32Value(constants::UNSIGNALED), + Some(status) => retval.set(UInt32Value(status)), + None => retval.set(UInt32Value(constants::UNSIGNALED)), }, _ => { self.base.webgl_error(InvalidEnum); - NullValue() + retval.set(NullValue()) }, } } @@ -3711,20 +3790,26 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { } /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13> - fn GetSamplerParameter(&self, _cx: JSContext, sampler: &WebGLSampler, pname: u32) -> JSVal { + fn GetSamplerParameter( + &self, + _cx: JSContext, + sampler: &WebGLSampler, + pname: u32, + mut retval: MutableHandleValue, + ) { handle_potential_webgl_error!( self.base, self.base.validate_ownership(sampler), - return NullValue() + return retval.set(NullValue()) ); match sampler.get_parameter(&self.base, pname) { Ok(value) => match value { - WebGLSamplerValue::GLenum(value) => UInt32Value(value), - WebGLSamplerValue::Float(value) => DoubleValue(value as f64), + WebGLSamplerValue::GLenum(value) => retval.set(UInt32Value(value)), + WebGLSamplerValue::Float(value) => retval.set(DoubleValue(value as f64)), }, Err(error) => { self.base.webgl_error(error); - NullValue() + retval.set(NullValue()) }, } } @@ -4085,19 +4170,19 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { program: &WebGLProgram, indices: Vec<u32>, pname: u32, - ) -> JSVal { + mut rval: MutableHandleValue, + ) { handle_potential_webgl_error!( self.base, self.base.validate_ownership(program), - return NullValue() + return rval.set(NullValue()) ); let values = handle_potential_webgl_error!( self.base, program.get_active_uniforms(indices, pname), - return NullValue() + return rval.set(NullValue()) ); - rooted!(in(*cx) let mut rval = UndefinedValue()); match pname { constants::UNIFORM_SIZE | constants::UNIFORM_TYPE | @@ -4105,15 +4190,14 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { constants::UNIFORM_OFFSET | constants::UNIFORM_ARRAY_STRIDE | constants::UNIFORM_MATRIX_STRIDE => unsafe { - values.to_jsval(*cx, rval.handle_mut()); + values.to_jsval(*cx, rval); }, constants::UNIFORM_IS_ROW_MAJOR => unsafe { let values = values.iter().map(|&v| v != 0).collect::<Vec<_>>(); - values.to_jsval(*cx, rval.handle_mut()); + values.to_jsval(*cx, rval); }, _ => unreachable!(), } - rval.get() } /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16> @@ -4138,34 +4222,35 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { program: &WebGLProgram, block_index: u32, pname: u32, - ) -> JSVal { + mut retval: MutableHandleValue, + ) { handle_potential_webgl_error!( self.base, self.base.validate_ownership(program), - return NullValue() + return retval.set(NullValue()) ); let values = handle_potential_webgl_error!( self.base, program.get_active_uniform_block_parameter(block_index, pname), - return NullValue() + return retval.set(NullValue()) ); match pname { constants::UNIFORM_BLOCK_BINDING | constants::UNIFORM_BLOCK_DATA_SIZE | constants::UNIFORM_BLOCK_ACTIVE_UNIFORMS => { assert!(values.len() == 1); - UInt32Value(values[0] as u32) + retval.set(UInt32Value(values[0] as u32)) }, constants::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES => unsafe { let values = values.iter().map(|&v| v as u32).collect::<Vec<_>>(); rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>()); Uint32Array::create(*cx, CreateWith::Slice(&values), result.handle_mut()).unwrap(); - ObjectValue(result.get()) + retval.set(ObjectValue(result.get())) }, constants::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER | constants::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => { assert!(values.len() == 1); - BooleanValue(values[0] != 0) + retval.set(BooleanValue(values[0] != 0)) }, _ => unreachable!(), } @@ -4367,16 +4452,17 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { target: u32, internal_format: u32, pname: u32, - ) -> JSVal { + mut retval: MutableHandleValue, + ) { if target != constants::RENDERBUFFER { self.base.webgl_error(InvalidEnum); - return NullValue(); + return retval.set(NullValue()); } match handle_potential_webgl_error!( self.base, InternalFormatParameter::from_u32(pname), - return NullValue() + return retval.set(NullValue()) ) { InternalFormatParameter::IntVec(param) => unsafe { let (sender, receiver) = webgl_channel().unwrap(); @@ -4395,7 +4481,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext { rval.handle_mut(), ) .unwrap(); - ObjectValue(rval.get()) + retval.set(ObjectValue(rval.get())) }, } } diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index d662b52254d..7751bce87ce 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -22,11 +22,8 @@ use dom_struct::dom_struct; use euclid::default::{Point2D, Rect, Size2D}; use ipc_channel::ipc::{self, IpcSharedMemory}; use js::jsapi::{JSContext, JSObject, Type}; -use js::jsval::{ - BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, ObjectValue, UInt32Value, - UndefinedValue, -}; -use js::rust::CustomAutoRooterGuard; +use js::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, ObjectValue, UInt32Value}; +use js::rust::{CustomAutoRooterGuard, MutableHandleValue}; use js::typedarray::{ ArrayBufferView, CreateWith, Float32, Float32Array, Int32, Int32Array, TypedArray, TypedArrayElementCreator, Uint32Array, @@ -131,14 +128,17 @@ where } #[allow(unsafe_code)] -pub unsafe fn uniform_typed<T>(cx: *mut JSContext, value: &[T::Element]) -> JSVal -where +pub unsafe fn uniform_typed<T>( + cx: *mut JSContext, + value: &[T::Element], + mut retval: MutableHandleValue, +) where T: TypedArrayElementCreator, { rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>()); <TypedArray<T, *mut JSObject>>::create(cx, CreateWith::Slice(value), rval.handle_mut()) .unwrap(); - ObjectValue(rval.get()) + retval.set(ObjectValue(rval.get())); } /// Set of bitflags for texture unpacking (texImage2d, etc...) @@ -1946,18 +1946,26 @@ impl WebGLRenderingContext { }); } - pub fn get_buffer_param(&self, buffer: Option<DomRoot<WebGLBuffer>>, parameter: u32) -> JSVal { - let buffer = - handle_potential_webgl_error!(self, buffer.ok_or(InvalidOperation), return NullValue()); + pub fn get_buffer_param( + &self, + buffer: Option<DomRoot<WebGLBuffer>>, + parameter: u32, + mut retval: MutableHandleValue, + ) { + let buffer = handle_potential_webgl_error!( + self, + buffer.ok_or(InvalidOperation), + return retval.set(NullValue()) + ); - match parameter { + retval.set(match parameter { constants::BUFFER_SIZE => Int32Value(buffer.capacity() as i32), constants::BUFFER_USAGE => Int32Value(buffer.usage() as i32), _ => { self.webgl_error(InvalidEnum); NullValue() }, - } + }) } } @@ -2019,42 +2027,53 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 - fn GetBufferParameter(&self, _cx: SafeJSContext, target: u32, parameter: u32) -> JSVal { - let buffer = - handle_potential_webgl_error!(self, self.bound_buffer(target), return NullValue()); - self.get_buffer_param(buffer, parameter) + fn GetBufferParameter( + &self, + _cx: SafeJSContext, + target: u32, + parameter: u32, + mut retval: MutableHandleValue, + ) { + let buffer = handle_potential_webgl_error!( + self, + self.bound_buffer(target), + return retval.set(NullValue()) + ); + self.get_buffer_param(buffer, parameter, retval) } #[allow(unsafe_code)] // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 - fn GetParameter(&self, cx: SafeJSContext, parameter: u32) -> JSVal { + fn GetParameter(&self, cx: SafeJSContext, parameter: u32, mut retval: MutableHandleValue) { if !self .extension_manager .is_get_parameter_name_enabled(parameter) { self.webgl_error(WebGLError::InvalidEnum); - return NullValue(); + return retval.set(NullValue()); } match parameter { constants::ARRAY_BUFFER_BINDING => unsafe { - return optional_root_object_to_js_or_null!(*cx, &self.bound_buffer_array.get()); + self.bound_buffer_array.get().to_jsval(*cx, retval); + return; }, constants::CURRENT_PROGRAM => unsafe { - return optional_root_object_to_js_or_null!(*cx, &self.current_program.get()); + self.current_program.get().to_jsval(*cx, retval); + return; }, constants::ELEMENT_ARRAY_BUFFER_BINDING => unsafe { let buffer = self.current_vao().element_array_buffer().get(); - return optional_root_object_to_js_or_null!(*cx, buffer); + buffer.to_jsval(*cx, retval); + return; }, constants::FRAMEBUFFER_BINDING => unsafe { - return optional_root_object_to_js_or_null!( - *cx, - &self.bound_draw_framebuffer.get() - ); + self.bound_draw_framebuffer.get().to_jsval(*cx, retval); + return; }, constants::RENDERBUFFER_BINDING => unsafe { - return optional_root_object_to_js_or_null!(*cx, &self.bound_renderbuffer.get()); + self.bound_renderbuffer.get().to_jsval(*cx, retval); + return; }, constants::TEXTURE_BINDING_2D => unsafe { let texture = self @@ -2062,7 +2081,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { .active_texture_slot(constants::TEXTURE_2D, self.webgl_version()) .unwrap() .get(); - return optional_root_object_to_js_or_null!(*cx, texture); + texture.to_jsval(*cx, retval); + return; }, constants::TEXTURE_BINDING_CUBE_MAP => unsafe { let texture = self @@ -2070,11 +2090,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { .active_texture_slot(constants::TEXTURE_CUBE_MAP, self.webgl_version()) .unwrap() .get(); - return optional_root_object_to_js_or_null!(*cx, texture); + texture.to_jsval(*cx, retval); + return; }, OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES => unsafe { let vao = self.current_vao.get().filter(|vao| vao.id().is_some()); - return optional_root_object_to_js_or_null!(*cx, vao); + vao.to_jsval(*cx, retval); + return; }, // In readPixels we currently support RGBA/UBYTE only. If // we wanted to support other formats, we could ask the @@ -2084,16 +2106,16 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { constants::IMPLEMENTATION_COLOR_READ_FORMAT => { if self.validate_framebuffer().is_err() { self.webgl_error(InvalidOperation); - return NullValue(); + return retval.set(NullValue()); } - return Int32Value(constants::RGBA as i32); + return retval.set(Int32Value(constants::RGBA as i32)); }, constants::IMPLEMENTATION_COLOR_READ_TYPE => { if self.validate_framebuffer().is_err() { self.webgl_error(InvalidOperation); - return NullValue(); + return retval.set(NullValue()); } - return Int32Value(constants::UNSIGNED_BYTE as i32); + return retval.set(Int32Value(constants::UNSIGNED_BYTE as i32)); }, constants::COMPRESSED_TEXTURE_FORMATS => unsafe { let format_ids = self.extension_manager.get_tex_compression_ids(); @@ -2101,44 +2123,50 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>()); Uint32Array::create(*cx, CreateWith::Slice(&format_ids), rval.handle_mut()) .unwrap(); - return ObjectValue(rval.get()); + return retval.set(ObjectValue(rval.get())); }, constants::VERSION => unsafe { - rooted!(in(*cx) let mut rval = UndefinedValue()); - "WebGL 1.0".to_jsval(*cx, rval.handle_mut()); - return rval.get(); + "WebGL 1.0".to_jsval(*cx, retval); + return; }, constants::RENDERER | constants::VENDOR => unsafe { - rooted!(in(*cx) let mut rval = UndefinedValue()); - "Mozilla/Servo".to_jsval(*cx, rval.handle_mut()); - return rval.get(); + "Mozilla/Servo".to_jsval(*cx, retval); + return; }, constants::SHADING_LANGUAGE_VERSION => unsafe { - rooted!(in(*cx) let mut rval = UndefinedValue()); - "WebGL GLSL ES 1.0".to_jsval(*cx, rval.handle_mut()); - return rval.get(); + "WebGL GLSL ES 1.0".to_jsval(*cx, retval); + return; }, constants::UNPACK_FLIP_Y_WEBGL => { let unpack = self.texture_unpacking_settings.get(); - return BooleanValue(unpack.contains(TextureUnpacking::FLIP_Y_AXIS)); + retval.set(BooleanValue(unpack.contains(TextureUnpacking::FLIP_Y_AXIS))); + return; }, constants::UNPACK_PREMULTIPLY_ALPHA_WEBGL => { let unpack = self.texture_unpacking_settings.get(); - return BooleanValue(unpack.contains(TextureUnpacking::PREMULTIPLY_ALPHA)); + retval.set(BooleanValue( + unpack.contains(TextureUnpacking::PREMULTIPLY_ALPHA), + )); + return; }, constants::PACK_ALIGNMENT => { - return UInt32Value(self.texture_packing_alignment.get() as u32); + retval.set(UInt32Value(self.texture_packing_alignment.get() as u32)); + return; }, constants::UNPACK_ALIGNMENT => { - return UInt32Value(self.texture_unpacking_alignment.get()); + retval.set(UInt32Value(self.texture_unpacking_alignment.get())); + return; }, constants::UNPACK_COLORSPACE_CONVERSION_WEBGL => { let unpack = self.texture_unpacking_settings.get(); - return UInt32Value(if unpack.contains(TextureUnpacking::CONVERT_COLORSPACE) { - constants::BROWSER_DEFAULT_WEBGL - } else { - constants::NONE - }); + retval.set(UInt32Value( + if unpack.contains(TextureUnpacking::CONVERT_COLORSPACE) { + constants::BROWSER_DEFAULT_WEBGL + } else { + constants::NONE + }, + )); + return; }, _ => {}, } @@ -2165,34 +2193,34 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { _ => None, }; if let Some(limit) = limit { - return UInt32Value(limit); + retval.set(UInt32Value(limit)); + return; } if let Ok(value) = self.capabilities.is_enabled(parameter) { - return BooleanValue(value); + retval.set(BooleanValue(value)); + return; } match handle_potential_webgl_error!( self, Parameter::from_u32(parameter), - return NullValue() + return retval.set(NullValue()) ) { Parameter::Bool(param) => { let (sender, receiver) = webgl_channel().unwrap(); self.send_command(WebGLCommand::GetParameterBool(param, sender)); - BooleanValue(receiver.recv().unwrap()) + retval.set(BooleanValue(receiver.recv().unwrap())) }, Parameter::Bool4(param) => unsafe { let (sender, receiver) = webgl_channel().unwrap(); self.send_command(WebGLCommand::GetParameterBool4(param, sender)); - rooted!(in(*cx) let mut rval = UndefinedValue()); - receiver.recv().unwrap().to_jsval(*cx, rval.handle_mut()); - rval.get() + receiver.recv().unwrap().to_jsval(*cx, retval); }, Parameter::Int(param) => { let (sender, receiver) = webgl_channel().unwrap(); self.send_command(WebGLCommand::GetParameterInt(param, sender)); - Int32Value(receiver.recv().unwrap()) + retval.set(Int32Value(receiver.recv().unwrap())) }, Parameter::Int2(param) => unsafe { let (sender, receiver) = webgl_channel().unwrap(); @@ -2204,7 +2232,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { rval.handle_mut(), ) .unwrap(); - ObjectValue(rval.get()) + retval.set(ObjectValue(rval.get())) }, Parameter::Int4(param) => unsafe { let (sender, receiver) = webgl_channel().unwrap(); @@ -2216,12 +2244,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { rval.handle_mut(), ) .unwrap(); - ObjectValue(rval.get()) + retval.set(ObjectValue(rval.get())) }, Parameter::Float(param) => { let (sender, receiver) = webgl_channel().unwrap(); self.send_command(WebGLCommand::GetParameterFloat(param, sender)); - DoubleValue(receiver.recv().unwrap() as f64) + retval.set(DoubleValue(receiver.recv().unwrap() as f64)) }, Parameter::Float2(param) => unsafe { let (sender, receiver) = webgl_channel().unwrap(); @@ -2233,7 +2261,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { rval.handle_mut(), ) .unwrap(); - ObjectValue(rval.get()) + retval.set(ObjectValue(rval.get())) }, Parameter::Float4(param) => unsafe { let (sender, receiver) = webgl_channel().unwrap(); @@ -2245,23 +2273,29 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { rval.handle_mut(), ) .unwrap(); - ObjectValue(rval.get()) + retval.set(ObjectValue(rval.get())) }, } } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 - fn GetTexParameter(&self, _cx: SafeJSContext, target: u32, pname: u32) -> JSVal { + fn GetTexParameter( + &self, + _cx: SafeJSContext, + target: u32, + pname: u32, + mut retval: MutableHandleValue, + ) { let texture_slot = handle_potential_webgl_error!( self, self.textures .active_texture_slot(target, self.webgl_version()), - return NullValue() + return retval.set(NullValue()) ); let texture = handle_potential_webgl_error!( self, texture_slot.get().ok_or(InvalidOperation), - return NullValue() + return retval.set(NullValue()) ); if !self @@ -2269,45 +2303,49 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { .is_get_tex_parameter_name_enabled(pname) { self.webgl_error(InvalidEnum); - return NullValue(); + return retval.set(NullValue()); } match pname { - constants::TEXTURE_MAG_FILTER => return UInt32Value(texture.mag_filter()), - constants::TEXTURE_MIN_FILTER => return UInt32Value(texture.min_filter()), + constants::TEXTURE_MAG_FILTER => return retval.set(UInt32Value(texture.mag_filter())), + constants::TEXTURE_MIN_FILTER => return retval.set(UInt32Value(texture.min_filter())), _ => {}, } - let texparam = - handle_potential_webgl_error!(self, TexParameter::from_u32(pname), return NullValue()); + let texparam = handle_potential_webgl_error!( + self, + TexParameter::from_u32(pname), + return retval.set(NullValue()) + ); if self.webgl_version() < texparam.required_webgl_version() { self.webgl_error(InvalidEnum); - return NullValue(); + return retval.set(NullValue()); } if let Some(value) = texture.maybe_get_tex_parameter(texparam) { match value { - TexParameterValue::Float(v) => return DoubleValue(v as f64), - TexParameterValue::Int(v) => return Int32Value(v), - TexParameterValue::Bool(v) => return BooleanValue(v), + TexParameterValue::Float(v) => retval.set(DoubleValue(v as f64)), + TexParameterValue::Int(v) => retval.set(Int32Value(v)), + TexParameterValue::Bool(v) => retval.set(BooleanValue(v)), } + return; } match texparam { TexParameter::Float(param) => { let (sender, receiver) = webgl_channel().unwrap(); self.send_command(WebGLCommand::GetTexParameterFloat(target, param, sender)); - DoubleValue(receiver.recv().unwrap() as f64) + retval.set(DoubleValue(receiver.recv().unwrap() as f64)) }, TexParameter::Int(param) => { let (sender, receiver) = webgl_channel().unwrap(); self.send_command(WebGLCommand::GetTexParameterInt(target, param, sender)); - Int32Value(receiver.recv().unwrap()) + retval.set(Int32Value(receiver.recv().unwrap())) }, TexParameter::Bool(param) => { let (sender, receiver) = webgl_channel().unwrap(); self.send_command(WebGLCommand::GetTexParameterBool(target, param, sender)); - BooleanValue(receiver.recv().unwrap()) + retval.set(BooleanValue(receiver.recv().unwrap())) }, } } @@ -3123,15 +3161,20 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { target: u32, attachment: u32, pname: u32, - ) -> JSVal { + mut retval: MutableHandleValue, + ) { // Check if currently bound framebuffer is non-zero as per spec. if let Some(fb) = self.bound_draw_framebuffer.get() { // Opaque framebuffers cannot have their attachments inspected // https://immersive-web.github.io/webxr/#opaque-framebuffer - handle_potential_webgl_error!(self, fb.validate_transparent(), return NullValue()); + handle_potential_webgl_error!( + self, + fb.validate_transparent(), + return retval.set(NullValue()) + ); } else { self.webgl_error(InvalidOperation); - return NullValue(); + return retval.set(NullValue()); } // Note: commented out stuff is for the WebGL2 standard. @@ -3192,7 +3235,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if !target_matches || !attachment_matches || !pname_matches || !bound_attachment_matches { self.webgl_error(InvalidEnum); - return NullValue(); + return retval.set(NullValue()); } // From the GLES2 spec: @@ -3208,19 +3251,17 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if let Some(webgl_attachment) = fb.attachment(attachment) { match webgl_attachment { WebGLFramebufferAttachmentRoot::Renderbuffer(rb) => unsafe { - rooted!(in(*cx) let mut rval = NullValue()); - rb.to_jsval(*cx, rval.handle_mut()); - return rval.get(); + rb.to_jsval(*cx, retval); + return; }, WebGLFramebufferAttachmentRoot::Texture(texture) => unsafe { - rooted!(in(*cx) let mut rval = NullValue()); - texture.to_jsval(*cx, rval.handle_mut()); - return rval.get(); + texture.to_jsval(*cx, retval); + return; }, } } self.webgl_error(InvalidEnum); - return NullValue(); + return retval.set(NullValue()); } let (sender, receiver) = webgl_channel().unwrap(); @@ -3228,11 +3269,17 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { target, attachment, pname, sender, )); - Int32Value(receiver.recv().unwrap()) + retval.set(Int32Value(receiver.recv().unwrap())) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7 - fn GetRenderbufferParameter(&self, _cx: SafeJSContext, target: u32, pname: u32) -> JSVal { + fn GetRenderbufferParameter( + &self, + _cx: SafeJSContext, + target: u32, + pname: u32, + mut retval: MutableHandleValue, + ) { // We do not check to see if the renderbuffer came from an opaque framebuffer // https://github.com/immersive-web/webxr/issues/862 let target_matches = target == constants::RENDERBUFFER; @@ -3252,12 +3299,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if !target_matches || !pname_matches { self.webgl_error(InvalidEnum); - return NullValue(); + return retval.set(NullValue()); } if self.bound_renderbuffer.get().is_none() { self.webgl_error(InvalidOperation); - return NullValue(); + return retval.set(NullValue()); } let result = if pname == constants::RENDERBUFFER_INTERNAL_FORMAT { @@ -3271,7 +3318,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { receiver.recv().unwrap() }; - Int32Value(result) + retval.set(Int32Value(result)) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 @@ -3287,13 +3334,23 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 - fn GetProgramParameter(&self, _: SafeJSContext, program: &WebGLProgram, param: u32) -> JSVal { - handle_potential_webgl_error!(self, self.validate_ownership(program), return NullValue()); + fn GetProgramParameter( + &self, + _: SafeJSContext, + program: &WebGLProgram, + param: u32, + mut retval: MutableHandleValue, + ) { + handle_potential_webgl_error!( + self, + self.validate_ownership(program), + return retval.set(NullValue()) + ); if program.is_deleted() { self.webgl_error(InvalidOperation); - return NullValue(); + return retval.set(NullValue()); } - match param { + retval.set(match param { constants::DELETE_STATUS => BooleanValue(program.is_marked_for_deletion()), constants::LINK_STATUS => BooleanValue(program.is_linked()), constants::VALIDATE_STATUS => { @@ -3318,7 +3375,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { self.webgl_error(InvalidEnum); NullValue() }, - } + }) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 @@ -3328,13 +3385,23 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 - fn GetShaderParameter(&self, _: SafeJSContext, shader: &WebGLShader, param: u32) -> JSVal { - handle_potential_webgl_error!(self, self.validate_ownership(shader), return NullValue()); + fn GetShaderParameter( + &self, + _: SafeJSContext, + shader: &WebGLShader, + param: u32, + mut retval: MutableHandleValue, + ) { + handle_potential_webgl_error!( + self, + self.validate_ownership(shader), + return retval.set(NullValue()) + ); if shader.is_deleted() { self.webgl_error(InvalidValue); - return NullValue(); + return retval.set(NullValue()); } - match param { + retval.set(match param { constants::DELETE_STATUS => BooleanValue(shader.is_marked_for_deletion()), constants::COMPILE_STATUS => BooleanValue(shader.successfully_compiled()), constants::SHADER_TYPE => UInt32Value(shader.gl_type()), @@ -3342,7 +3409,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { self.webgl_error(InvalidEnum); NullValue() }, - } + }) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 @@ -3400,8 +3467,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { #[allow(unsafe_code)] // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 - fn GetVertexAttrib(&self, cx: SafeJSContext, index: u32, param: u32) -> JSVal { - let get_attrib = |data: Ref<VertexAttribData>| -> JSVal { + fn GetVertexAttrib( + &self, + cx: SafeJSContext, + index: u32, + param: u32, + mut retval: MutableHandleValue, + ) { + let mut get_attrib = |data: Ref<VertexAttribData>| { if param == constants::CURRENT_VERTEX_ATTRIB { let attrib = self.current_vertex_attribs.borrow()[index as usize]; match attrib { @@ -3415,7 +3488,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { result.handle_mut(), ) .unwrap(); - return ObjectValue(result.get()); + return retval.set(ObjectValue(result.get())); } }, VertexAttrib::Int(x, y, z, w) => { @@ -3424,7 +3497,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>()); Int32Array::create(*cx, CreateWith::Slice(&value), result.handle_mut()) .unwrap(); - return ObjectValue(result.get()); + return retval.set(ObjectValue(result.get())); } }, VertexAttrib::Uint(x, y, z, w) => { @@ -3437,7 +3510,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { result.handle_mut(), ) .unwrap(); - return ObjectValue(result.get()); + return retval.set(ObjectValue(result.get())); } }, }; @@ -3447,28 +3520,32 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { .is_get_vertex_attrib_name_enabled(param) { self.webgl_error(WebGLError::InvalidEnum); - return NullValue(); + return retval.set(NullValue()); } match param { - constants::VERTEX_ATTRIB_ARRAY_ENABLED => BooleanValue(data.enabled_as_array), - constants::VERTEX_ATTRIB_ARRAY_SIZE => Int32Value(data.size as i32), - constants::VERTEX_ATTRIB_ARRAY_TYPE => Int32Value(data.type_ as i32), - constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => BooleanValue(data.normalized), - constants::VERTEX_ATTRIB_ARRAY_STRIDE => Int32Value(data.stride as i32), + constants::VERTEX_ATTRIB_ARRAY_ENABLED => { + retval.set(BooleanValue(data.enabled_as_array)) + }, + constants::VERTEX_ATTRIB_ARRAY_SIZE => retval.set(Int32Value(data.size as i32)), + constants::VERTEX_ATTRIB_ARRAY_TYPE => retval.set(Int32Value(data.type_ as i32)), + constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => { + retval.set(BooleanValue(data.normalized)) + }, + constants::VERTEX_ATTRIB_ARRAY_STRIDE => retval.set(Int32Value(data.stride as i32)), constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING => unsafe { - rooted!(in(*cx) let mut jsval = NullValue()); if let Some(buffer) = data.buffer() { - buffer.to_jsval(*cx, jsval.handle_mut()); + buffer.to_jsval(*cx, retval); + } else { + retval.set(NullValue()); } - jsval.get() }, ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE => { - UInt32Value(data.divisor) + retval.set(UInt32Value(data.divisor)) }, _ => { self.webgl_error(InvalidEnum); - NullValue() + retval.set(NullValue()) }, } }; @@ -3479,7 +3556,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let data = handle_potential_webgl_error!( self, current_vao.get_vertex_attrib(index).ok_or(InvalidValue), - return NullValue() + return retval.set(NullValue()) ); get_attrib(data) }, @@ -3488,7 +3565,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let data = handle_potential_webgl_error!( self, current_vao.get_vertex_attrib(index).ok_or(InvalidValue), - return NullValue() + return retval.set(NullValue()) ); get_attrib(data) }, @@ -4062,61 +4139,92 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { cx: SafeJSContext, program: &WebGLProgram, location: &WebGLUniformLocation, - ) -> JSVal { + mut rval: MutableHandleValue, + ) { handle_potential_webgl_error!( self, self.uniform_check_program(program, location), - return NullValue() + return rval.set(NullValue()) ); let triple = (self, program.id(), location.id()); match location.type_() { - constants::BOOL => BooleanValue(uniform_get(triple, WebGLCommand::GetUniformBool)), + constants::BOOL => rval.set(BooleanValue(uniform_get( + triple, + WebGLCommand::GetUniformBool, + ))), constants::BOOL_VEC2 => unsafe { - rooted!(in(*cx) let mut rval = NullValue()); - uniform_get(triple, WebGLCommand::GetUniformBool2).to_jsval(*cx, rval.handle_mut()); - rval.get() + uniform_get(triple, WebGLCommand::GetUniformBool2).to_jsval(*cx, rval); }, constants::BOOL_VEC3 => unsafe { - rooted!(in(*cx) let mut rval = NullValue()); - uniform_get(triple, WebGLCommand::GetUniformBool3).to_jsval(*cx, rval.handle_mut()); - rval.get() + uniform_get(triple, WebGLCommand::GetUniformBool3).to_jsval(*cx, rval); }, constants::BOOL_VEC4 => unsafe { - rooted!(in(*cx) let mut rval = NullValue()); - uniform_get(triple, WebGLCommand::GetUniformBool4).to_jsval(*cx, rval.handle_mut()); - rval.get() + uniform_get(triple, WebGLCommand::GetUniformBool4).to_jsval(*cx, rval); }, constants::INT | constants::SAMPLER_2D | constants::SAMPLER_CUBE => { - Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)) + rval.set(Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt))) }, constants::INT_VEC2 => unsafe { - uniform_typed::<Int32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformInt2)) + uniform_typed::<Int32>( + *cx, + &uniform_get(triple, WebGLCommand::GetUniformInt2), + rval, + ) }, constants::INT_VEC3 => unsafe { - uniform_typed::<Int32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformInt3)) + uniform_typed::<Int32>( + *cx, + &uniform_get(triple, WebGLCommand::GetUniformInt3), + rval, + ) }, constants::INT_VEC4 => unsafe { - uniform_typed::<Int32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformInt4)) - }, - constants::FLOAT => { - DoubleValue(uniform_get(triple, WebGLCommand::GetUniformFloat) as f64) + uniform_typed::<Int32>( + *cx, + &uniform_get(triple, WebGLCommand::GetUniformInt4), + rval, + ) }, + constants::FLOAT => rval + .set(DoubleValue( + uniform_get(triple, WebGLCommand::GetUniformFloat) as f64, + )), constants::FLOAT_VEC2 => unsafe { - uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat2)) + uniform_typed::<Float32>( + *cx, + &uniform_get(triple, WebGLCommand::GetUniformFloat2), + rval, + ) }, constants::FLOAT_VEC3 => unsafe { - uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat3)) + uniform_typed::<Float32>( + *cx, + &uniform_get(triple, WebGLCommand::GetUniformFloat3), + rval, + ) }, constants::FLOAT_VEC4 | constants::FLOAT_MAT2 => unsafe { - uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat4)) + uniform_typed::<Float32>( + *cx, + &uniform_get(triple, WebGLCommand::GetUniformFloat4), + rval, + ) }, constants::FLOAT_MAT3 => unsafe { - uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat9)) + uniform_typed::<Float32>( + *cx, + &uniform_get(triple, WebGLCommand::GetUniformFloat9), + rval, + ) }, constants::FLOAT_MAT4 => unsafe { - uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat16)) + uniform_typed::<Float32>( + *cx, + &uniform_get(triple, WebGLCommand::GetUniformFloat16), + rval, + ) }, _ => panic!("wrong uniform type"), } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index e133eb6cb46..9121fa75fc0 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -33,10 +33,11 @@ use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use js::conversions::ToJSValConvertible; use js::jsapi::{GCReason, Heap, JSAutoRealm, JSObject, StackFormat, JSPROP_ENUMERATE, JS_GC}; -use js::jsval::{JSVal, NullValue, UndefinedValue}; +use js::jsval::{NullValue, UndefinedValue}; use js::rust::wrappers::JS_DefineProperty; use js::rust::{ CustomAutoRooter, CustomAutoRooterGuard, HandleObject, HandleValue, MutableHandleObject, + MutableHandleValue, }; use malloc_size_of::MallocSizeOf; use media::WindowGLContext; @@ -697,22 +698,32 @@ impl WindowMethods for Window { } // https://html.spec.whatwg.org/multipage/#dom-opener - fn GetOpener(&self, cx: JSContext, in_realm_proof: InRealm) -> Fallible<JSVal> { + fn GetOpener( + &self, + cx: JSContext, + in_realm_proof: InRealm, + mut retval: MutableHandleValue, + ) -> Fallible<()> { // Step 1, Let current be this Window object's browsing context. let current = match self.window_proxy.get() { Some(proxy) => proxy, // Step 2, If current is null, then return null. - None => return Ok(NullValue()), + None => { + retval.set(NullValue()); + return Ok(()); + }, }; // Still step 2, since the window's BC is the associated doc's BC, // see https://html.spec.whatwg.org/multipage/#window-bc // and a doc's BC is null if it has been discarded. // see https://html.spec.whatwg.org/multipage/#concept-document-bc if current.is_browsing_context_discarded() { - return Ok(NullValue()); + retval.set(NullValue()); + return Ok(()); } // Step 3 to 5. - Ok(current.opener(*cx, in_realm_proof)) + current.opener(*cx, in_realm_proof, retval); + Ok(()) } #[allow(unsafe_code)] @@ -1388,17 +1399,12 @@ impl WindowMethods for Window { // https://dom.spec.whatwg.org/#dom-window-event #[allow(unsafe_code)] - fn Event(&self, cx: JSContext) -> JSVal { - rooted!(in(*cx) let mut rval = UndefinedValue()); + fn Event(&self, cx: JSContext, rval: MutableHandleValue) { if let Some(ref event) = *self.current_event.borrow() { unsafe { - event - .reflector() - .get_jsobject() - .to_jsval(*cx, rval.handle_mut()); + event.reflector().get_jsobject().to_jsval(*cx, rval); } } - rval.get() } fn IsSecureContext(&self) -> bool { @@ -1571,9 +1577,10 @@ impl WindowMethods for Window { cx: JSContext, value: HandleValue, options: RootedTraceableBox<StructuredSerializeOptions>, - ) -> Fallible<js::jsval::JSVal> { + retval: MutableHandleValue, + ) -> Fallible<()> { self.upcast::<GlobalScope>() - .structured_clone(cx, value, options) + .structured_clone(cx, value, options, retval) } } diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index 4d080881ba8..02267471930 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -24,9 +24,9 @@ use js::jsapi::{ MutableHandleObject as RawMutableHandleObject, MutableHandleValue as RawMutableHandleValue, ObjectOpResult, PropertyDescriptor, JSPROP_ENUMERATE, JSPROP_READONLY, }; -use js::jsval::{JSVal, NullValue, PrivateValue, UndefinedValue}; +use js::jsval::{NullValue, PrivateValue, UndefinedValue}; use js::rust::wrappers::{JS_TransplantObject, NewWindowProxy, SetWindowProxy}; -use js::rust::{get_object_class, Handle, MutableHandle}; +use js::rust::{get_object_class, Handle, MutableHandle, MutableHandleValue}; use js::JSCLASS_IS_GLOBAL; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use net_traits::request::Referrer; @@ -416,13 +416,18 @@ impl WindowProxy { #[allow(unsafe_code)] // https://html.spec.whatwg.org/multipage/#dom-opener - pub fn opener(&self, cx: *mut JSContext, in_realm_proof: InRealm) -> JSVal { + pub fn opener( + &self, + cx: *mut JSContext, + in_realm_proof: InRealm, + mut retval: MutableHandleValue, + ) { if self.disowned.get() { - return NullValue(); + return retval.set(NullValue()); } let opener_id = match self.opener { Some(opener_browsing_context_id) => opener_browsing_context_id, - None => return NullValue(), + None => return retval.set(NullValue()), }; let parent_browsing_context = self.parent.as_deref(); let opener_proxy = match ScriptThread::find_window_proxy(opener_id) { @@ -447,16 +452,14 @@ impl WindowProxy { creator, ) }, - None => return NullValue(), + None => return retval.set(NullValue()), } }, }; if opener_proxy.is_browsing_context_discarded() { - return NullValue(); + return retval.set(NullValue()); } - rooted!(in(cx) let mut val = UndefinedValue()); - unsafe { opener_proxy.to_jsval(cx, val.handle_mut()) }; - val.get() + unsafe { opener_proxy.to_jsval(cx, retval) }; } // https://html.spec.whatwg.org/multipage/#window-open-steps diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index f89ff975322..b08cf0abc38 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -16,7 +16,7 @@ use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; use js::jsval::UndefinedValue; use js::panic::maybe_resume_unwind; -use js::rust::{HandleValue, ParentRuntime}; +use js::rust::{HandleValue, MutableHandleValue, ParentRuntime}; use net_traits::request::{ CredentialsMode, Destination, ParserMetadata, RequestBuilder as NetRequestInit, }; @@ -439,9 +439,10 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope { cx: JSContext, value: HandleValue, options: RootedTraceableBox<StructuredSerializeOptions>, - ) -> Fallible<js::jsval::JSVal> { + retval: MutableHandleValue, + ) -> Fallible<()> { self.upcast::<GlobalScope>() - .structured_clone(cx, value, options) + .structured_clone(cx, value, options, retval) } } diff --git a/components/script/dom/workernavigator.rs b/components/script/dom/workernavigator.rs index aae6a59f733..795c764b8c6 100644 --- a/components/script/dom/workernavigator.rs +++ b/components/script/dom/workernavigator.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use dom_struct::dom_struct; -use js::jsval::JSVal; +use js::rust::MutableHandleValue; use crate::dom::bindings::codegen::Bindings::WorkerNavigatorBinding::WorkerNavigatorMethods; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; @@ -97,8 +97,8 @@ impl WorkerNavigatorMethods for WorkerNavigator { // https://html.spec.whatwg.org/multipage/#dom-navigator-languages #[allow(unsafe_code)] - fn Languages(&self, cx: JSContext) -> JSVal { - to_frozen_array(&[self.Language()], cx) + fn Languages(&self, cx: JSContext, retval: MutableHandleValue) { + to_frozen_array(&[self.Language()], cx, retval) } // https://w3c.github.io/permissions/#navigator-and-workernavigator-extension diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 74d99176f26..04327945313 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -20,9 +20,9 @@ use http::Method; use hyper_serde::Serde; use ipc_channel::ipc; use js::jsapi::{Heap, JS_ClearPendingException}; -use js::jsval::{JSVal, NullValue, UndefinedValue}; +use js::jsval::{JSVal, NullValue}; use js::rust::wrappers::JS_ParseJSON; -use js::rust::HandleObject; +use js::rust::{HandleObject, MutableHandleValue}; use js::typedarray::{ArrayBuffer, ArrayBufferU8}; use mime::{self, Mime, Name}; use net_traits::http_status::HttpStatus; @@ -935,8 +935,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest { #[allow(unsafe_code)] /// <https://xhr.spec.whatwg.org/#the-response-attribute> - fn Response(&self, cx: JSContext, can_gc: CanGc) -> JSVal { - rooted!(in(*cx) let mut rval = UndefinedValue()); + fn Response(&self, cx: JSContext, can_gc: CanGc, mut rval: MutableHandleValue) { match self.response_type.get() { XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Text => unsafe { let ready_state = self.ready_state.get(); @@ -944,33 +943,29 @@ impl XMLHttpRequestMethods for XMLHttpRequest { if ready_state == XMLHttpRequestState::Done || ready_state == XMLHttpRequestState::Loading { - self.text_response().to_jsval(*cx, rval.handle_mut()); + self.text_response().to_jsval(*cx, rval); } else { // Step 1 - "".to_jsval(*cx, rval.handle_mut()); + "".to_jsval(*cx, rval); } }, // Step 1 _ if self.ready_state.get() != XMLHttpRequestState::Done => { - return NullValue(); + rval.set(NullValue()); }, // Step 2 XMLHttpRequestResponseType::Document => unsafe { - self.document_response(can_gc) - .to_jsval(*cx, rval.handle_mut()); - }, - XMLHttpRequestResponseType::Json => unsafe { - self.json_response(cx).to_jsval(*cx, rval.handle_mut()); + self.document_response(can_gc).to_jsval(*cx, rval); }, + XMLHttpRequestResponseType::Json => self.json_response(cx, rval), XMLHttpRequestResponseType::Blob => unsafe { - self.blob_response(can_gc).to_jsval(*cx, rval.handle_mut()); + self.blob_response(can_gc).to_jsval(*cx, rval); }, XMLHttpRequestResponseType::Arraybuffer => match self.arraybuffer_response(cx) { - Some(array_buffer) => unsafe { array_buffer.to_jsval(*cx, rval.handle_mut()) }, - None => return NullValue(), + Some(array_buffer) => unsafe { array_buffer.to_jsval(*cx, rval) }, + None => rval.set(NullValue()), }, } - rval.get() } /// <https://xhr.spec.whatwg.org/#the-responsetext-attribute> @@ -1447,17 +1442,17 @@ impl XMLHttpRequest { #[allow(unsafe_code)] /// <https://xhr.spec.whatwg.org/#json-response> - fn json_response(&self, cx: JSContext) -> JSVal { + fn json_response(&self, cx: JSContext, mut rval: MutableHandleValue) { // Step 1 let response_json = self.response_json.get(); if !response_json.is_null_or_undefined() { - return response_json; + return rval.set(response_json); } // Step 2 let bytes = self.response.borrow(); // Step 3 if bytes.len() == 0 { - return NullValue(); + return rval.set(NullValue()); } // Step 4 fn decode_to_utf16_with_bom_removal(bytes: &[u8], encoding: &'static Encoding) -> Vec<u16> { @@ -1480,21 +1475,14 @@ impl XMLHttpRequest { // if present, but UTF-16BE/LE BOM must not be honored. let json_text = decode_to_utf16_with_bom_removal(&bytes, UTF_8); // Step 5 - rooted!(in(*cx) let mut rval = UndefinedValue()); unsafe { - if !JS_ParseJSON( - *cx, - json_text.as_ptr(), - json_text.len() as u32, - rval.handle_mut(), - ) { + if !JS_ParseJSON(*cx, json_text.as_ptr(), json_text.len() as u32, rval) { JS_ClearPendingException(*cx); - return NullValue(); + return rval.set(NullValue()); } } // Step 6 self.response_json.set(rval.get()); - self.response_json.get() } fn document_text_html(&self, can_gc: CanGc) -> DomRoot<Document> { diff --git a/components/script/dom/xrboundedreferencespace.rs b/components/script/dom/xrboundedreferencespace.rs index 93d3d5d10c7..87c267152c1 100644 --- a/components/script/dom/xrboundedreferencespace.rs +++ b/components/script/dom/xrboundedreferencespace.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use dom_struct::dom_struct; -use js::jsval::JSVal; +use js::rust::MutableHandleValue; use crate::dom::bindings::codegen::Bindings::XRBoundedReferenceSpaceBinding::XRBoundedReferenceSpaceMethods; use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType; @@ -67,7 +67,7 @@ impl XRBoundedReferenceSpace { impl XRBoundedReferenceSpaceMethods for XRBoundedReferenceSpace { /// <https://www.w3.org/TR/webxr/#dom-xrboundedreferencespace-boundsgeometry> - fn BoundsGeometry(&self, cx: JSContext, can_gc: CanGc) -> JSVal { + fn BoundsGeometry(&self, cx: JSContext, can_gc: CanGc, retval: MutableHandleValue) { if let Some(bounds) = self.reference_space.get_bounds() { let points: Vec<DomRoot<DOMPointReadOnly>> = bounds .into_iter() @@ -83,9 +83,9 @@ impl XRBoundedReferenceSpaceMethods for XRBoundedReferenceSpace { }) .collect(); - to_frozen_array(&points, cx) + to_frozen_array(&points, cx, retval) } else { - to_frozen_array::<DomRoot<DOMPointReadOnly>>(&[], cx) + to_frozen_array::<DomRoot<DOMPointReadOnly>>(&[], cx, retval) } } } diff --git a/components/script/dom/xrinputsource.rs b/components/script/dom/xrinputsource.rs index a260e2e6780..abbb65bdc9b 100644 --- a/components/script/dom/xrinputsource.rs +++ b/components/script/dom/xrinputsource.rs @@ -6,6 +6,7 @@ use dom_struct::dom_struct; use js::conversions::ToJSValConvertible; use js::jsapi::Heap; use js::jsval::{JSVal, UndefinedValue}; +use js::rust::MutableHandleValue; use script_traits::GamepadSupportedHapticEffects; use webxr_api::{Handedness, InputFrame, InputId, InputSource, TargetRayMode}; @@ -159,8 +160,8 @@ impl XRInputSourceMethods for XRInputSource { } } // https://immersive-web.github.io/webxr/#dom-xrinputsource-profiles - fn Profiles(&self, _cx: JSContext) -> JSVal { - self.profiles.get() + fn Profiles(&self, _cx: JSContext, mut retval: MutableHandleValue) { + retval.set(self.profiles.get()) } /// <https://www.w3.org/TR/webxr/#dom-xrinputsource-skiprendering> diff --git a/components/script/dom/xrinputsourceschangeevent.rs b/components/script/dom/xrinputsourceschangeevent.rs index dc28cefa812..1ae14b3a47c 100644 --- a/components/script/dom/xrinputsourceschangeevent.rs +++ b/components/script/dom/xrinputsourceschangeevent.rs @@ -5,7 +5,7 @@ use dom_struct::dom_struct; use js::jsapi::Heap; use js::jsval::JSVal; -use js::rust::HandleObject; +use js::rust::{HandleObject, MutableHandleValue}; use servo_atoms::Atom; use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods; @@ -87,8 +87,11 @@ impl XRInputSourcesChangeEvent { } let _ac = enter_realm(global); let cx = GlobalScope::get_cx(); - changeevent.added.set(to_frozen_array(added, cx)); - changeevent.removed.set(to_frozen_array(removed, cx)); + rooted!(in(*cx) let mut frozen_val: JSVal); + to_frozen_array(added, cx, frozen_val.handle_mut()); + changeevent.added.set(*frozen_val); + to_frozen_array(removed, cx, frozen_val.handle_mut()); + changeevent.removed.set(*frozen_val); changeevent } } @@ -121,13 +124,13 @@ impl XRInputSourcesChangeEventMethods for XRInputSourcesChangeEvent { } // https://immersive-web.github.io/webxr/#dom-xrinputsourceschangeevent-added - fn Added(&self, _cx: JSContext) -> JSVal { - self.added.get() + fn Added(&self, _cx: JSContext, mut retval: MutableHandleValue) { + retval.set(self.added.get()) } // https://immersive-web.github.io/webxr/#dom-xrinputsourceschangeevent-removed - fn Removed(&self, _cx: JSContext) -> JSVal { - self.removed.get() + fn Removed(&self, _cx: JSContext, mut retval: MutableHandleValue) { + retval.set(self.removed.get()) } // https://dom.spec.whatwg.org/#dom-event-istrusted diff --git a/components/script/dom/xrrenderstate.rs b/components/script/dom/xrrenderstate.rs index cabe248d0a2..e189710ead2 100644 --- a/components/script/dom/xrrenderstate.rs +++ b/components/script/dom/xrrenderstate.rs @@ -5,7 +5,7 @@ use std::cell::Cell; use dom_struct::dom_struct; -use js::jsval::JSVal; +use js::rust::MutableHandleValue; use webxr_api::SubImages; use crate::dom::bindings::cell::DomRefCell; @@ -146,10 +146,10 @@ impl XRRenderStateMethods for XRRenderState { } /// <https://immersive-web.github.io/layers/#dom-xrrenderstate-layers> - fn Layers(&self, cx: JSContext) -> JSVal { + fn Layers(&self, cx: JSContext, retval: MutableHandleValue) { // TODO: cache this array? let layers = self.layers.borrow(); let layers: Vec<&XRLayer> = layers.iter().map(|x| &**x).collect(); - to_frozen_array(&layers[..], cx) + to_frozen_array(&layers[..], cx, retval) } } diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 85a7ec7ae41..6ba00e003a7 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -14,7 +14,7 @@ use euclid::{RigidTransform3D, Transform3D, Vector3D}; use ipc_channel::ipc::IpcReceiver; use ipc_channel::router::ROUTER; use js::jsapi::JSObject; -use js::jsval::JSVal; +use js::rust::MutableHandleValue; use js::typedarray::Float32Array; use profile_traits::ipc; use servo_atoms::Atom; @@ -1011,10 +1011,10 @@ impl XRSessionMethods for XRSession { } /// <https://www.w3.org/TR/webxr/#dom-xrsession-enabledfeatures> - fn EnabledFeatures(&self, cx: JSContext) -> JSVal { + fn EnabledFeatures(&self, cx: JSContext, retval: MutableHandleValue) { let session = self.session.borrow(); let features = session.granted_features(); - to_frozen_array(features, cx) + to_frozen_array(features, cx, retval) } /// <https://www.w3.org/TR/webxr/#dom-xrsession-issystemkeyboardsupported> diff --git a/components/script/dom/xrtest.rs b/components/script/dom/xrtest.rs index b50549d8be2..c6cc3a3ee7c 100644 --- a/components/script/dom/xrtest.rs +++ b/components/script/dom/xrtest.rs @@ -11,6 +11,7 @@ use std::rc::Rc; use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; use ipc_channel::router::ROUTER; +use js::jsval::JSVal; use profile_traits::ipc; use webxr_api::{self, Error as XRError, MockDeviceInit, MockDeviceMsg}; @@ -184,7 +185,8 @@ impl XRTestMethods for XRTest { /// <https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md> fn SimulateUserActivation(&self, f: Rc<Function>) { ScriptThread::set_user_interacting(true); - let _ = f.Call__(vec![], ExceptionHandling::Rethrow); + rooted!(in(*GlobalScope::get_cx()) let mut value: JSVal); + let _ = f.Call__(vec![], value.handle_mut(), ExceptionHandling::Rethrow); ScriptThread::set_user_interacting(false); } diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs index 92d2b03b54d..9c8774c7855 100644 --- a/components/script/dom/xrviewerpose.rs +++ b/components/script/dom/xrviewerpose.rs @@ -7,6 +7,7 @@ use euclid::RigidTransform3D; use js::conversions::ToJSValConvertible; use js::jsapi::Heap; use js::jsval::{JSVal, UndefinedValue}; +use js::rust::MutableHandleValue; use webxr_api::{Viewer, ViewerPose, Views}; use crate::dom::bindings::codegen::Bindings::XRViewBinding::XREye; @@ -189,7 +190,7 @@ impl XRViewerPose { impl XRViewerPoseMethods for XRViewerPose { /// <https://immersive-web.github.io/webxr/#dom-xrviewerpose-views> - fn Views(&self, _cx: JSContext) -> JSVal { - self.views.get() + fn Views(&self, _cx: JSContext, mut retval: MutableHandleValue) { + retval.set(self.views.get()) } } |