diff --git a/components/script/build.rs b/components/script/build.rs index bf496fb48f3..1e98ab5382c 100644 --- a/components/script/build.rs +++ b/components/script/build.rs @@ -50,7 +50,7 @@ fn main() { let mut phf = File::create(&phf).unwrap(); write!( &mut phf, - "pub static MAP: phf::Map<&'static [u8], unsafe fn(JSContext, HandleObject)> = " + "pub static MAP: phf::Map<&'static [u8], fn(JSContext, HandleObject)> = " ) .unwrap(); map.build(&mut phf).unwrap(); diff --git a/components/script/compartments.rs b/components/script/compartments.rs index c26e72ccd1a..7b45f38c56a 100644 --- a/components/script/compartments.rs +++ b/components/script/compartments.rs @@ -4,7 +4,8 @@ use crate::dom::bindings::reflector::DomObject; use crate::dom::globalscope::GlobalScope; -use js::jsapi::{GetCurrentRealmOrNull, JSAutoRealm, JSContext}; +use crate::script_runtime::JSContext; +use js::jsapi::{GetCurrentRealmOrNull, JSAutoRealm}; pub struct AlreadyInCompartment(()); @@ -17,9 +18,9 @@ impl AlreadyInCompartment { AlreadyInCompartment(()) } - pub fn assert_for_cx(cx: *mut JSContext) -> AlreadyInCompartment { + pub fn assert_for_cx(cx: JSContext) -> AlreadyInCompartment { unsafe { - assert!(!GetCurrentRealmOrNull(cx).is_null()); + assert!(!GetCurrentRealmOrNull(*cx).is_null()); } AlreadyInCompartment(()) } diff --git a/components/script/dom/audiobuffer.rs b/components/script/dom/audiobuffer.rs index 4b113a200fe..b0772d8b2af 100644 --- a/components/script/dom/audiobuffer.rs +++ b/components/script/dom/audiobuffer.rs @@ -13,10 +13,10 @@ use crate::dom::bindings::num::Finite; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::window::Window; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::JSContext; use dom_struct::dom_struct; use js::jsapi::JS_GetArrayBufferViewBuffer; -use js::jsapi::{Heap, JSContext, JSObject}; +use js::jsapi::{Heap, JSObject}; use js::rust::wrappers::DetachArrayBuffer; use js::rust::CustomAutoRooterGuard; use js::typedarray::{CreateWith, Float32Array}; @@ -127,7 +127,7 @@ impl AudioBuffer { } #[allow(unsafe_code)] - unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool { + fn restore_js_channel_data(&self, cx: JSContext) -> bool { let _ac = enter_realm(&*self); for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() { if !channel.get().is_null() { @@ -135,20 +135,22 @@ impl AudioBuffer { continue; } - rooted!(in (cx) let mut array = ptr::null_mut::()); + rooted!(in (*cx) let mut array = ptr::null_mut::()); if let Some(ref shared_channels) = *self.shared_channels.borrow() { // Step 4. of // https://webaudio.github.io/web-audio-api/#acquire-the-content // "Attach ArrayBuffers containing copies of the data to the AudioBuffer, // to be returned by the next call to getChannelData()". - if Float32Array::create( - cx, - CreateWith::Slice(&shared_channels.buffers[i]), - array.handle_mut(), - ) - .is_err() - { - return false; + unsafe { + if Float32Array::create( + *cx, + CreateWith::Slice(&shared_channels.buffers[i]), + array.handle_mut(), + ) + .is_err() + { + return false; + } } } channel.set(array.get()); @@ -231,16 +233,15 @@ impl AudioBufferMethods for AudioBuffer { // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata #[allow(unsafe_code)] - fn GetChannelData(&self, cx: SafeJSContext, channel: u32) -> Fallible> { + fn GetChannelData(&self, cx: JSContext, channel: u32) -> Fallible> { if channel >= self.number_of_channels { return Err(Error::IndexSize); } + if !self.restore_js_channel_data(cx) { + return Err(Error::JSFailed); + } unsafe { - if !self.restore_js_channel_data(*cx) { - return Err(Error::JSFailed); - } - Ok(NonNull::new_unchecked( self.js_channels.borrow()[channel as usize].get(), )) @@ -307,7 +308,7 @@ impl AudioBufferMethods for AudioBuffer { } let cx = self.global().get_cx(); - if unsafe { !self.restore_js_channel_data(*cx) } { + if !self.restore_js_channel_data(cx) { return Err(Error::JSFailed); } diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs index 03b8f326f55..6059d75605a 100644 --- a/components/script/dom/bindings/callback.rs +++ b/components/script/dom/bindings/callback.rs @@ -13,10 +13,10 @@ use crate::dom::bindings::settings_stack::{AutoEntryScript, AutoIncumbentScript} use crate::dom::bindings::utils::AsCCharPtrPtr; use crate::dom::globalscope::GlobalScope; use crate::dom::window::Window; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::JSContext; use js::jsapi::Heap; use js::jsapi::JSAutoRealm; -use js::jsapi::{AddRawValueRoot, IsCallable, JSContext, JSObject}; +use js::jsapi::{AddRawValueRoot, IsCallable, JSObject}; use js::jsapi::{EnterRealm, LeaveRealm, Realm, RemoveRawValueRoot}; use js::jsval::{JSVal, ObjectValue, UndefinedValue}; use js::rust::wrappers::{JS_GetProperty, JS_WrapObject}; @@ -82,11 +82,11 @@ impl CallbackObject { } #[allow(unsafe_code)] - unsafe fn init(&mut self, cx: *mut JSContext, callback: *mut JSObject) { + unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) { self.callback.set(callback); self.permanent_js_root.set(ObjectValue(callback)); assert!(AddRawValueRoot( - cx, + *cx, self.permanent_js_root.get_unsafe(), b"CallbackObject::root\n".as_c_char_ptr() )); @@ -113,7 +113,7 @@ impl PartialEq for CallbackObject { /// callback interface types. pub trait CallbackContainer { /// Create a new CallbackContainer object for the given `JSObject`. - unsafe fn new(cx: SafeJSContext, callback: *mut JSObject) -> Rc; + unsafe fn new(cx: JSContext, callback: *mut JSObject) -> Rc; /// Returns the underlying `CallbackObject`. fn callback_holder(&self) -> &CallbackObject; /// Returns the underlying `JSObject`. @@ -152,8 +152,8 @@ impl CallbackFunction { /// Initialize the callback function with a value. /// Should be called once this object is done moving. - pub unsafe fn init(&mut self, cx: SafeJSContext, callback: *mut JSObject) { - self.object.init(*cx, callback); + pub unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) { + self.object.init(cx, callback); } } @@ -179,18 +179,18 @@ impl CallbackInterface { /// Initialize the callback function with a value. /// Should be called once this object is done moving. - pub unsafe fn init(&mut self, cx: SafeJSContext, callback: *mut JSObject) { - self.object.init(*cx, callback); + pub unsafe fn init(&mut self, cx: JSContext, callback: *mut JSObject) { + self.object.init(cx, callback); } /// Returns the property with the given `name`, if it is a callable object, /// or an error otherwise. - pub fn get_callable_property(&self, cx: *mut JSContext, name: &str) -> Fallible { - rooted!(in(cx) let mut callable = UndefinedValue()); - rooted!(in(cx) let obj = self.callback_holder().get()); + pub fn get_callable_property(&self, cx: JSContext, name: &str) -> Fallible { + rooted!(in(*cx) let mut callable = UndefinedValue()); + rooted!(in(*cx) let obj = self.callback_holder().get()); unsafe { let c_name = CString::new(name).unwrap(); - if !JS_GetProperty(cx, obj.handle(), c_name.as_ptr(), callable.handle_mut()) { + if !JS_GetProperty(*cx, obj.handle(), c_name.as_ptr(), callable.handle_mut()) { return Err(Error::JSFailed); } @@ -206,16 +206,12 @@ impl CallbackInterface { } /// Wraps the reflector for `p` into the compartment of `cx`. -pub fn wrap_call_this_object( - cx: *mut JSContext, - p: &T, - mut rval: MutableHandleObject, -) { +pub fn wrap_call_this_object(cx: JSContext, p: &T, mut rval: MutableHandleObject) { rval.set(p.reflector().get_jsobject().get()); assert!(!rval.get().is_null()); unsafe { - if !JS_WrapObject(cx, rval) { + if !JS_WrapObject(*cx, rval) { rval.set(ptr::null_mut()); } } @@ -228,7 +224,7 @@ pub struct CallSetup { /// (possibly wrapped) callback object. exception_global: DomRoot, /// The `JSContext` used for the call. - cx: *mut JSContext, + cx: JSContext, /// The compartment we were in before the call. old_realm: *mut Realm, /// The exception handling used for the call. @@ -255,7 +251,7 @@ impl CallSetup { let ais = callback.incumbent().map(AutoIncumbentScript::new); CallSetup { exception_global: global, - cx: *cx, + cx: cx, old_realm: unsafe { EnterRealm(*cx, callback.callback()) }, handling: handling, entry_script: Some(aes), @@ -264,7 +260,7 @@ impl CallSetup { } /// Returns the `JSContext` used for the call. - pub fn get_context(&self) -> *mut JSContext { + pub fn get_context(&self) -> JSContext { self.cx } } @@ -272,13 +268,13 @@ impl CallSetup { impl Drop for CallSetup { fn drop(&mut self) { unsafe { - LeaveRealm(self.cx, self.old_realm); + LeaveRealm(*self.cx, self.old_realm); if self.handling == ExceptionHandling::Report { let _ac = JSAutoRealm::new( - self.cx, + *self.cx, self.exception_global.reflector().get_jsobject().get(), ); - report_pending_exception(self.cx, true); + report_pending_exception(*self.cx, true); } drop(self.incumbent_script.take()); drop(self.entry_script.take().unwrap()); diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ca041fdddeb..4bea65388b6 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -810,10 +810,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if !JS_WrapValue(*cx, valueToResolve.handle_mut()) { $*{exceptionCode} } - match Promise::new_resolved(&promiseGlobal, *cx, valueToResolve.handle()) { + match Promise::new_resolved(&promiseGlobal, cx, valueToResolve.handle()) { Ok(value) => value, Err(error) => { - throw_dom_exception(*cx, &promiseGlobal, error); + throw_dom_exception(cx, &promiseGlobal, error); $*{exceptionCode} } } @@ -2588,8 +2588,7 @@ class CGConstructorEnabled(CGAbstractMethod): CGAbstractMethod.__init__(self, descriptor, 'ConstructorEnabled', 'bool', [Argument("SafeJSContext", "aCx"), - Argument("HandleObject", "aObj")], - unsafe=True) + Argument("HandleObject", "aObj")]) def definition_body(self): conditions = [] @@ -2651,8 +2650,8 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties): """ unforgeables = [] - defineUnforgeableAttrs = "define_guarded_properties(*cx, unforgeable_holder.handle(), %s, global);" - defineUnforgeableMethods = "define_guarded_methods(*cx, unforgeable_holder.handle(), %s, global);" + defineUnforgeableAttrs = "define_guarded_properties(cx, unforgeable_holder.handle(), %s, global);" + defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s, global);" unforgeableMembers = [ (defineUnforgeableAttrs, properties.unforgeable_attrs), @@ -2762,7 +2761,7 @@ class CGWrapGlobalMethod(CGAbstractMethod): ("define_guarded_methods", self.properties.methods), ("define_guarded_constants", self.properties.consts) ] - members = ["%s(*cx, obj.handle(), %s, obj.handle());" % (function, array.variableName()) + members = ["%s(cx, obj.handle(), %s, obj.handle());" % (function, array.variableName()) for (function, array) in pairs if array.length() > 0] values["members"] = "\n".join(members) @@ -2772,7 +2771,7 @@ let _rt = RootedTraceable::new(&*raw); rooted!(in(*cx) let mut obj = ptr::null_mut::()); create_global_object( - *cx, + cx, &Class.base, raw as *const libc::c_void, _trace, @@ -2911,7 +2910,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): rooted!(in(*cx) let proto = %(proto)s); assert!(!proto.is_null()); rooted!(in(*cx) let mut namespace = ptr::null_mut::()); -create_namespace_object(*cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS, +create_namespace_object(cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS, %(methods)s, %(name)s, namespace.handle_mut()); assert!(!namespace.is_null()); assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); @@ -2924,7 +2923,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants() return CGGeneric("""\ rooted!(in(*cx) let mut interface = ptr::null_mut::()); -create_callback_interface_object(*cx, global, sConstants, %(name)s, interface.handle_mut()); +create_callback_interface_object(cx, global, sConstants, %(name)s, interface.handle_mut()); assert!(!interface.is_null()); assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); (*cache)[PrototypeList::Constructor::%(id)s as usize] = interface.get(); @@ -2976,7 +2975,7 @@ assert!(!prototype_proto.is_null());""" % getPrototypeProto)] code.append(CGGeneric(""" rooted!(in(*cx) let mut prototype = ptr::null_mut::()); -create_interface_prototype_object(*cx, +create_interface_prototype_object(cx, global.into(), prototype_proto.handle().into(), &PrototypeClass, @@ -3011,7 +3010,7 @@ assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null()); assert!(!interface_proto.is_null()); rooted!(in(*cx) let mut interface = ptr::null_mut::()); -create_noncallback_interface_object(*cx, +create_noncallback_interface_object(cx, global.into(), interface_proto.handle(), &INTERFACE_OBJECT_CLASS, @@ -3093,7 +3092,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); specs.append(CGGeneric("(%s as ConstructorClassHook, %s, %d)" % (hook, name, length))) values = CGIndenter(CGList(specs, "\n"), 4) code.append(CGWrapper(values, pre="%s = [\n" % decl, post="\n];")) - code.append(CGGeneric("create_named_constructors(*cx, global, &named_constructors, prototype.handle());")) + code.append(CGGeneric("create_named_constructors(cx, global, &named_constructors, prototype.handle());")) if self.descriptor.hasUnforgeableMembers: # We want to use the same JSClass and prototype as the object we'll @@ -3137,23 +3136,25 @@ class CGGetPerInterfaceObject(CGAbstractMethod): Argument('HandleObject', 'global'), Argument('MutableHandleObject', 'mut rval')] CGAbstractMethod.__init__(self, descriptor, name, - 'void', args, pub=pub, unsafe=True) + 'void', args, pub=pub) self.id = idPrefix + "::" + MakeNativeName(self.descriptor.name) def definition_body(self): return CGGeneric(""" -assert!(((*get_object_class(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0); +unsafe { + assert!(((*get_object_class(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0); -/* Check to see whether the interface objects are already installed */ -let proto_or_iface_array = get_proto_or_iface_array(global.get()); -rval.set((*proto_or_iface_array)[%(id)s as usize]); -if !rval.get().is_null() { - return; + /* Check to see whether the interface objects are already installed */ + let proto_or_iface_array = get_proto_or_iface_array(global.get()); + rval.set((*proto_or_iface_array)[%(id)s as usize]); + if !rval.get().is_null() { + return; + } + + CreateInterfaceObjects(cx, global, proto_or_iface_array); + rval.set((*proto_or_iface_array)[%(id)s as usize]); + assert!(!rval.get().is_null()); } - -CreateInterfaceObjects(cx, global, proto_or_iface_array); -rval.set((*proto_or_iface_array)[%(id)s as usize]); -assert!(!rval.get().is_null()); """ % {"id": self.id}) @@ -3274,7 +3275,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): Argument('HandleObject', 'global'), ] CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', - 'void', args, pub=True, unsafe=True) + 'void', args, pub=True) def define(self): return CGAbstractMethod.define(self) @@ -3335,7 +3336,7 @@ class CGCallGenerator(CGThing): if "cx" not in argsPre and needsCx: args.prepend(CGGeneric("cx")) if nativeMethodName in descriptor.inCompartmentMethods: - args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(*cx))")) + args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(cx))")) # Build up our actual call self.cgRoot = CGList([], "\n") @@ -3371,7 +3372,7 @@ class CGCallGenerator(CGThing): "let result = match result {\n" " Ok(result) => result,\n" " Err(e) => {\n" - " throw_dom_exception(*cx, %s, e);\n" + " throw_dom_exception(cx, %s, e);\n" " return%s;\n" " },\n" "};" % (glob, errorResult))) @@ -5555,12 +5556,12 @@ let global = DomRoot::downcast::(global).unwrap(); // so we can do the spec's object-identity checks. rooted!(in(*cx) let new_target = UnwrapObjectDynamic(args.new_target().to_object(), *cx, 1)); if new_target.is_null() { - throw_dom_exception(*cx, global.upcast::(), Error::Type("new.target is null".to_owned())); + throw_dom_exception(cx, global.upcast::(), Error::Type("new.target is null".to_owned())); return false; } if args.callee() == new_target.get() { - throw_dom_exception(*cx, global.upcast::(), + throw_dom_exception(cx, global.upcast::(), Error::Type("new.target must not be the active function object".to_owned())); return false; } @@ -5601,7 +5602,7 @@ let result: Result, Error> = html_constructor(&global, &args); let result = match result { Ok(result) => result, Err(e) => { - throw_dom_exception(*cx, global.upcast::(), e); + throw_dom_exception(cx, global.upcast::(), e); return false; }, }; @@ -6355,21 +6356,23 @@ class CGDictionary(CGThing): return string.Template( "impl ${selfName} {\n" "${empty}\n" - " pub unsafe fn new(cx: SafeJSContext, val: HandleValue) \n" + " pub fn new(cx: SafeJSContext, val: HandleValue) \n" " -> Result, ()> {\n" - " let object = if val.get().is_null_or_undefined() {\n" - " ptr::null_mut()\n" - " } else if val.get().is_object() {\n" - " val.get().to_object()\n" - " } else {\n" - " return Ok(ConversionResult::Failure(\"Value is not an object.\".into()));\n" - " };\n" - " rooted!(in(*cx) let object = object);\n" + " unsafe {\n" + " let object = if val.get().is_null_or_undefined() {\n" + " ptr::null_mut()\n" + " } else if val.get().is_object() {\n" + " val.get().to_object()\n" + " } else {\n" + " return Ok(ConversionResult::Failure(\"Value is not an object.\".into()));\n" + " };\n" + " rooted!(in(*cx) let object = object);\n" "${preInitial}" "${initParent}" "${initMembers}" "${postInitial}" - " Ok(ConversionResult::Success(dictionary))\n" + " Ok(ConversionResult::Success(dictionary))\n" + " }\n" " }\n" "}\n" "\n" @@ -6391,11 +6394,11 @@ class CGDictionary(CGThing): "selfName": selfName, "actualType": actualType, "empty": CGIndenter(CGGeneric(self.makeEmpty()), indentLevel=4).define(), - "initParent": CGIndenter(CGGeneric(initParent), indentLevel=12).define(), - "initMembers": CGIndenter(memberInits, indentLevel=12).define(), + "initParent": CGIndenter(CGGeneric(initParent), indentLevel=16).define(), + "initMembers": CGIndenter(memberInits, indentLevel=16).define(), "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(), - "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=12).define(), - "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=12).define(), + "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=16).define(), + "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=16).define(), }) def membersNeedTracing(self): @@ -6825,8 +6828,8 @@ class CGCallback(CGClass): # Record the names of all the arguments, so we can use them when we call # the private method. argnames = [arg.name for arg in args] - argnamesWithThis = ["SafeJSContext::from_ptr(s.get_context())", "thisObjJS.handle()"] + argnames - argnamesWithoutThis = ["SafeJSContext::from_ptr(s.get_context())", "thisObjJS.handle()"] + argnames + argnamesWithThis = ["s.get_context()", "thisObjJS.handle()"] + argnames + argnamesWithoutThis = ["s.get_context()", "thisObjJS.handle()"] + argnames # Now that we've recorded the argnames for our call to our private # method, insert our optional argument for deciding whether the # CallSetup should re-throw exceptions on aRv. @@ -6846,7 +6849,7 @@ class CGCallback(CGClass): bodyWithThis = string.Template( setupCall + - "rooted!(in(s.get_context()) let mut thisObjJS = ptr::null_mut::());\n" + "rooted!(in(*s.get_context()) let mut thisObjJS = ptr::null_mut::());\n" "wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n" "if thisObjJS.is_null() {\n" " return Err(JSFailed);\n" @@ -6857,7 +6860,7 @@ class CGCallback(CGClass): }) bodyWithoutThis = string.Template( setupCall + - "rooted!(in(s.get_context()) let thisObjJS = ptr::null_mut::());\n" + "rooted!(in(*s.get_context()) let thisObjJS = ptr::null_mut::());\n" "unsafe { ${methodName}(${callArgs}) }").substitute({ "callArgs": ", ".join(argnamesWithoutThis), "methodName": 'self.' + method.name, @@ -7115,7 +7118,7 @@ class CallbackMember(CGNativeMember): return "" return ( "CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n" - "JSContext* cx = s.get_context();\n" + "JSContext* cx = *s.get_context();\n" "if (!cx) {\n" " return Err(JSFailed);\n" "}\n") @@ -7216,7 +7219,7 @@ class CallbackOperationBase(CallbackMethod): "methodName": self.methodName } getCallableFromProp = string.Template( - 'r#try!(self.parent.get_callable_property(*cx, "${methodName}"))' + 'r#try!(self.parent.get_callable_property(cx, "${methodName}"))' ).substitute(replacements) if not self.singleOperation: return 'rooted!(in(*cx) let callable =\n' + getCallableFromProp + ');\n' diff --git a/components/script/dom/bindings/constant.rs b/components/script/dom/bindings/constant.rs index 951b7f2a550..bce6e3d7844 100644 --- a/components/script/dom/bindings/constant.rs +++ b/components/script/dom/bindings/constant.rs @@ -4,8 +4,9 @@ //! WebIDL constants. +use crate::script_runtime::JSContext; use js::jsapi::JSPROP_READONLY; -use js::jsapi::{JSContext, JSPROP_ENUMERATE, JSPROP_PERMANENT}; +use js::jsapi::{JSPROP_ENUMERATE, JSPROP_PERMANENT}; use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, UInt32Value}; use js::rust::wrappers::JS_DefineProperty; use js::rust::HandleObject; @@ -50,15 +51,17 @@ impl ConstantSpec { /// Defines constants on `obj`. /// Fails on JSAPI failure. -pub unsafe fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &[ConstantSpec]) { +pub fn define_constants(cx: JSContext, obj: HandleObject, constants: &[ConstantSpec]) { for spec in constants { - rooted!(in(cx) let value = spec.get_value()); - assert!(JS_DefineProperty( - cx, - obj, - spec.name.as_ptr() as *const libc::c_char, - value.handle(), - (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) as u32 - )); + rooted!(in(*cx) let value = spec.get_value()); + unsafe { + assert!(JS_DefineProperty( + *cx, + obj, + spec.name.as_ptr() as *const libc::c_char, + value.handle(), + (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) as u32 + )); + } } } diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index 40d690ff8d0..b0b6ca1f685 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -15,6 +15,7 @@ use crate::dom::bindings::conversions::{ use crate::dom::bindings::str::USVString; use crate::dom::domexception::{DOMErrorName, DOMException}; use crate::dom::globalscope::GlobalScope; +use crate::script_runtime::JSContext as SafeJSContext; #[cfg(feature = "js_backtrace")] use backtrace::Backtrace; use js::error::{throw_range_error, throw_type_error}; @@ -104,10 +105,10 @@ pub type Fallible = Result; pub type ErrorResult = Fallible<()>; /// Set a pending exception for the given `result` on `cx`. -pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: &GlobalScope, result: Error) { +pub fn throw_dom_exception(cx: SafeJSContext, global: &GlobalScope, result: Error) { #[cfg(feature = "js_backtrace")] { - capture_stack!(in(cx) let stack); + capture_stack!(in(*cx) let stack); let js_stack = stack.and_then(|s| s.as_string(None)); let rust_stack = Backtrace::new(); LAST_EXCEPTION_BACKTRACE.with(|backtrace| { @@ -139,27 +140,29 @@ pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: &GlobalScope, resu Error::InvalidModification => DOMErrorName::InvalidModificationError, Error::NotReadable => DOMErrorName::NotReadableError, Error::Operation => DOMErrorName::OperationError, - Error::Type(message) => { - assert!(!JS_IsExceptionPending(cx)); - throw_type_error(cx, &message); + Error::Type(message) => unsafe { + assert!(!JS_IsExceptionPending(*cx)); + throw_type_error(*cx, &message); return; }, - Error::Range(message) => { - assert!(!JS_IsExceptionPending(cx)); - throw_range_error(cx, &message); + Error::Range(message) => unsafe { + assert!(!JS_IsExceptionPending(*cx)); + throw_range_error(*cx, &message); return; }, - Error::JSFailed => { - assert!(JS_IsExceptionPending(cx)); + Error::JSFailed => unsafe { + assert!(JS_IsExceptionPending(*cx)); return; }, }; - assert!(!JS_IsExceptionPending(cx)); - let exception = DOMException::new(global, code); - rooted!(in(cx) let mut thrown = UndefinedValue()); - exception.to_jsval(cx, thrown.handle_mut()); - JS_SetPendingException(cx, thrown.handle()); + unsafe { + assert!(!JS_IsExceptionPending(*cx)); + let exception = DOMException::new(global, code); + rooted!(in(*cx) let mut thrown = UndefinedValue()); + exception.to_jsval(*cx, thrown.handle_mut()); + JS_SetPendingException(*cx, thrown.handle()); + } } /// A struct encapsulating information about a runtime script error. @@ -310,7 +313,7 @@ impl Error { Error::JSFailed => (), _ => assert!(!JS_IsExceptionPending(cx)), } - throw_dom_exception(cx, global, self); + throw_dom_exception(SafeJSContext::from_ptr(cx), global, self); assert!(JS_IsExceptionPending(cx)); assert!(JS_GetPendingException(cx, rval)); JS_ClearPendingException(cx); diff --git a/components/script/dom/bindings/guard.rs b/components/script/dom/bindings/guard.rs index 40052c7098e..bba30e1581c 100644 --- a/components/script/dom/bindings/guard.rs +++ b/components/script/dom/bindings/guard.rs @@ -6,7 +6,7 @@ use crate::dom::bindings::codegen::InterfaceObjectMap; use crate::dom::bindings::interface::is_exposed_in; -use js::jsapi::JSContext; +use crate::script_runtime::JSContext; use js::rust::HandleObject; use servo_config::prefs; @@ -28,12 +28,7 @@ impl Guard { /// Expose the value if the condition is satisfied. /// /// The passed handle is the object on which the value may be exposed. - pub unsafe fn expose( - &self, - cx: *mut JSContext, - obj: HandleObject, - global: HandleObject, - ) -> Option { + pub fn expose(&self, cx: JSContext, obj: HandleObject, global: HandleObject) -> Option { if self.condition.is_satisfied(cx, obj, global) { Some(self.value) } else { @@ -45,7 +40,7 @@ impl Guard { /// A condition to expose things. pub enum Condition { /// The condition is satisfied if the function returns true. - Func(unsafe fn(*mut JSContext, HandleObject) -> bool), + Func(fn(JSContext, HandleObject) -> bool), /// The condition is satisfied if the preference is set. Pref(&'static str), // The condition is satisfied if the interface is exposed in the global. @@ -55,12 +50,7 @@ pub enum Condition { } impl Condition { - unsafe fn is_satisfied( - &self, - cx: *mut JSContext, - obj: HandleObject, - global: HandleObject, - ) -> bool { + fn is_satisfied(&self, cx: JSContext, obj: HandleObject, global: HandleObject) -> bool { match *self { Condition::Pref(name) => prefs::pref_map().get(name).as_bool().unwrap_or(false), Condition::Func(f) => f(cx, obj), diff --git a/components/script/dom/bindings/htmlconstructor.rs b/components/script/dom/bindings/htmlconstructor.rs index 6faa4f6211c..1937f400fda 100644 --- a/components/script/dom/bindings/htmlconstructor.rs +++ b/components/script/dom/bindings/htmlconstructor.rs @@ -76,13 +76,13 @@ use crate::dom::customelementregistry::{ConstructionStackEntry, CustomElementSta use crate::dom::element::{Element, ElementCreator}; use crate::dom::htmlelement::HTMLElement; use crate::dom::window::Window; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::JSContext; use crate::script_thread::ScriptThread; use html5ever::interface::QualName; use html5ever::LocalName; use js::glue::UnwrapObjectStatic; use js::jsapi::{CallArgs, CurrentGlobalOrNull}; -use js::jsapi::{JSAutoRealm, JSContext, JSObject}; +use js::jsapi::{JSAutoRealm, JSObject}; use js::rust::HandleObject; use js::rust::MutableHandleObject; use std::ptr; @@ -134,7 +134,7 @@ where // Step 5 get_constructor_object_from_local_name( definition.local_name.clone(), - *window.get_cx(), + window.get_cx(), global_object.handle(), constructor.handle_mut(), ); @@ -196,13 +196,13 @@ where /// This list should only include elements marked with the [HTMLConstructor] extended attribute. pub fn get_constructor_object_from_local_name( name: LocalName, - cx: *mut JSContext, + cx: JSContext, global: HandleObject, rval: MutableHandleObject, ) -> bool { macro_rules! get_constructor( ($binding:ident) => ({ - unsafe { $binding::GetConstructorObject(SafeJSContext::from_ptr(cx), global, rval); } + $binding::GetConstructorObject(cx, global, rval); true }) ); diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 6f2183339af..0a5ee24fb23 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -12,6 +12,7 @@ use crate::dom::bindings::guard::Guard; use crate::dom::bindings::utils::{ get_proto_or_iface_array, ProtoOrIfaceArray, DOM_PROTOTYPE_SLOT, }; +use crate::script_runtime::JSContext as SafeJSContext; use js::error::throw_type_error; use js::glue::UncheckedUnwrapObject; use js::jsapi::HandleObject as RawHandleObject; @@ -129,7 +130,7 @@ pub type TraceHook = unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject /// Create a global object with the given class. pub unsafe fn create_global_object( - cx: *mut JSContext, + cx: SafeJSContext, class: &'static JSClass, private: *const libc::c_void, trace: TraceHook, @@ -142,7 +143,7 @@ pub unsafe fn create_global_object( options.creationOptions_.sharedMemoryAndAtomics_ = true; rval.set(JS_NewGlobalObject( - cx, + *cx, class, ptr::null_mut(), OnNewGlobalHookOption::DontFireOnNewGlobalHook, @@ -159,20 +160,22 @@ pub unsafe fn create_global_object( let val = PrivateValue(Box::into_raw(proto_array) as *const libc::c_void); JS_SetReservedSlot(rval.get(), DOM_PROTOTYPE_SLOT, &val); - let _ac = JSAutoRealm::new(cx, rval.get()); - JS_FireOnNewGlobalObject(cx, rval.handle()); + let _ac = JSAutoRealm::new(*cx, rval.get()); + JS_FireOnNewGlobalObject(*cx, rval.handle()); } /// Create and define the interface object of a callback interface. -pub unsafe fn create_callback_interface_object( - cx: *mut JSContext, +pub fn create_callback_interface_object( + cx: SafeJSContext, global: HandleObject, constants: &[Guard<&[ConstantSpec]>], name: &[u8], mut rval: MutableHandleObject, ) { assert!(!constants.is_empty()); - rval.set(JS_NewObject(cx, ptr::null())); + unsafe { + rval.set(JS_NewObject(*cx, ptr::null())); + } assert!(!rval.is_null()); define_guarded_constants(cx, rval.handle(), constants, global); define_name(cx, rval.handle(), name); @@ -180,8 +183,8 @@ pub unsafe fn create_callback_interface_object( } /// Create the interface prototype object of a non-callback interface. -pub unsafe fn create_interface_prototype_object( - cx: *mut JSContext, +pub fn create_interface_prototype_object( + cx: SafeJSContext, global: HandleObject, proto: HandleObject, class: &'static JSClass, @@ -203,27 +206,29 @@ pub unsafe fn create_interface_prototype_object( ); if !unscopable_names.is_empty() { - rooted!(in(cx) let mut unscopable_obj = ptr::null_mut::()); + rooted!(in(*cx) let mut unscopable_obj = ptr::null_mut::()); create_unscopable_object(cx, unscopable_names, unscopable_obj.handle_mut()); + unsafe { + let unscopable_symbol = GetWellKnownSymbol(*cx, SymbolCode::unscopables); + assert!(!unscopable_symbol.is_null()); - let unscopable_symbol = GetWellKnownSymbol(cx, SymbolCode::unscopables); - assert!(!unscopable_symbol.is_null()); + rooted!(in(*cx) let mut unscopable_id: jsid); + RUST_SYMBOL_TO_JSID(unscopable_symbol, unscopable_id.handle_mut()); - rooted!(in(cx) let mut unscopable_id: jsid); - RUST_SYMBOL_TO_JSID(unscopable_symbol, unscopable_id.handle_mut()); - assert!(JS_DefinePropertyById5( - cx, - rval.handle(), - unscopable_id.handle(), - unscopable_obj.handle(), - JSPROP_READONLY as u32 - )) + assert!(JS_DefinePropertyById5( + *cx, + rval.handle(), + unscopable_id.handle(), + unscopable_obj.handle(), + JSPROP_READONLY as u32 + )) + } } } /// Create and define the interface object of a non-callback interface. -pub unsafe fn create_noncallback_interface_object( - cx: *mut JSContext, +pub fn create_noncallback_interface_object( + cx: SafeJSContext, global: HandleObject, proto: HandleObject, class: &'static NonCallbackInterfaceObjectClass, @@ -245,54 +250,58 @@ pub unsafe fn create_noncallback_interface_object( constants, rval, ); - assert!(JS_LinkConstructorAndPrototype( - cx, - rval.handle(), - interface_prototype_object - )); + unsafe { + assert!(JS_LinkConstructorAndPrototype( + *cx, + rval.handle(), + interface_prototype_object + )); + } define_name(cx, rval.handle(), name); define_length(cx, rval.handle(), i32::try_from(length).expect("overflow")); define_on_global_object(cx, global, name, rval.handle()); } /// Create and define the named constructors of a non-callback interface. -pub unsafe fn create_named_constructors( - cx: *mut JSContext, +pub fn create_named_constructors( + cx: SafeJSContext, global: HandleObject, named_constructors: &[(ConstructorClassHook, &[u8], u32)], interface_prototype_object: HandleObject, ) { - rooted!(in(cx) let mut constructor = ptr::null_mut::()); + rooted!(in(*cx) let mut constructor = ptr::null_mut::()); for &(native, name, arity) in named_constructors { assert_eq!(*name.last().unwrap(), b'\0'); - let fun = JS_NewFunction( - cx, - Some(native), - arity, - JSFUN_CONSTRUCTOR, - name.as_ptr() as *const libc::c_char, - ); - assert!(!fun.is_null()); - constructor.set(JS_GetFunctionObject(fun)); - assert!(!constructor.is_null()); + unsafe { + let fun = JS_NewFunction( + *cx, + Some(native), + arity, + JSFUN_CONSTRUCTOR, + name.as_ptr() as *const libc::c_char, + ); + assert!(!fun.is_null()); + constructor.set(JS_GetFunctionObject(fun)); + assert!(!constructor.is_null()); - assert!(JS_DefineProperty3( - cx, - constructor.handle(), - b"prototype\0".as_ptr() as *const libc::c_char, - interface_prototype_object, - (JSPROP_PERMANENT | JSPROP_READONLY) as u32 - )); + assert!(JS_DefineProperty3( + *cx, + constructor.handle(), + b"prototype\0".as_ptr() as *const libc::c_char, + interface_prototype_object, + (JSPROP_PERMANENT | JSPROP_READONLY) as u32 + )); + } define_on_global_object(cx, global, name, constructor.handle()); } } /// Create a new object with a unique type. -pub unsafe fn create_object( - cx: *mut JSContext, +pub fn create_object( + cx: SafeJSContext, global: HandleObject, proto: HandleObject, class: &'static JSClass, @@ -301,7 +310,9 @@ pub unsafe fn create_object( constants: &[Guard<&[ConstantSpec]>], mut rval: MutableHandleObject, ) { - rval.set(JS_NewObjectWithUniqueType(cx, class, proto)); + unsafe { + rval.set(JS_NewObjectWithUniqueType(*cx, class, proto)); + } assert!(!rval.is_null()); define_guarded_methods(cx, rval.handle(), methods, global); define_guarded_properties(cx, rval.handle(), properties, global); @@ -309,8 +320,8 @@ pub unsafe fn create_object( } /// Conditionally define constants on an object. -pub unsafe fn define_guarded_constants( - cx: *mut JSContext, +pub fn define_guarded_constants( + cx: SafeJSContext, obj: HandleObject, constants: &[Guard<&[ConstantSpec]>], global: HandleObject, @@ -323,57 +334,65 @@ pub unsafe fn define_guarded_constants( } /// Conditionally define methods on an object. -pub unsafe fn define_guarded_methods( - cx: *mut JSContext, +pub fn define_guarded_methods( + cx: SafeJSContext, obj: HandleObject, methods: &[Guard<&'static [JSFunctionSpec]>], global: HandleObject, ) { for guard in methods { if let Some(specs) = guard.expose(cx, obj, global) { - define_methods(cx, obj, specs).unwrap(); + unsafe { + define_methods(*cx, obj, specs).unwrap(); + } } } } /// Conditionally define properties on an object. -pub unsafe fn define_guarded_properties( - cx: *mut JSContext, +pub fn define_guarded_properties( + cx: SafeJSContext, obj: HandleObject, properties: &[Guard<&'static [JSPropertySpec]>], global: HandleObject, ) { for guard in properties { if let Some(specs) = guard.expose(cx, obj, global) { - define_properties(cx, obj, specs).unwrap(); + unsafe { + define_properties(*cx, obj, specs).unwrap(); + } } } } /// Returns whether an interface with exposure set given by `globals` should /// be exposed in the global object `obj`. -pub unsafe fn is_exposed_in(object: HandleObject, globals: Globals) -> bool { - let unwrapped = UncheckedUnwrapObject(object.get(), /* stopAtWindowProxy = */ 0); - let dom_class = get_dom_class(unwrapped).unwrap(); - globals.contains(dom_class.global) +pub fn is_exposed_in(object: HandleObject, globals: Globals) -> bool { + unsafe { + let unwrapped = UncheckedUnwrapObject(object.get(), /* stopAtWindowProxy = */ 0); + let dom_class = get_dom_class(unwrapped).unwrap(); + globals.contains(dom_class.global) + } } /// Define a property with a given name on the global object. Should be called /// through the resolve hook. -pub unsafe fn define_on_global_object( - cx: *mut JSContext, +pub fn define_on_global_object( + cx: SafeJSContext, global: HandleObject, name: &[u8], obj: HandleObject, ) { assert_eq!(*name.last().unwrap(), b'\0'); - assert!(JS_DefineProperty3( - cx, - global, - name.as_ptr() as *const libc::c_char, - obj, - JSPROP_RESOLVING - )); + unsafe { + assert!(JS_DefineProperty3( + *cx, + global, + name.as_ptr() as *const libc::c_char, + obj, + JSPROP_RESOLVING + )); + } } const OBJECT_OPS: ObjectOps = ObjectOps { @@ -409,6 +428,7 @@ unsafe extern "C" fn has_instance_hook( value: RawMutableHandleValue, rval: *mut bool, ) -> bool { + let cx = SafeJSContext::from_ptr(cx); let obj_raw = HandleObject::from_raw(obj); let val_raw = HandleValue::from_raw(value.handle()); match has_instance(cx, obj_raw, val_raw) { @@ -422,8 +442,8 @@ unsafe extern "C" fn has_instance_hook( /// Return whether a value is an instance of a given prototype. /// -unsafe fn has_instance( - cx: *mut JSContext, +fn has_instance( + cx: SafeJSContext, interface_object: HandleObject, value: HandleValue, ) -> Result { @@ -432,86 +452,91 @@ unsafe fn has_instance( return Ok(false); } - rooted!(in(cx) let mut value_out = value.to_object()); - rooted!(in(cx) let mut value = value.to_object()); + rooted!(in(*cx) let mut value_out = value.to_object()); + rooted!(in(*cx) let mut value = value.to_object()); - let js_class = get_object_class(interface_object.get()); - let object_class = &*(js_class as *const NonCallbackInterfaceObjectClass); + unsafe { + let js_class = get_object_class(interface_object.get()); + let object_class = &*(js_class as *const NonCallbackInterfaceObjectClass); - if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject( - value.get(), - /* stopAtWindowProxy = */ 0, - )) { - if dom_class.interface_chain[object_class.proto_depth as usize] == object_class.proto_id { - // Step 4. - return Ok(true); + if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject( + value.get(), + /* stopAtWindowProxy = */ 0, + )) { + if dom_class.interface_chain[object_class.proto_depth as usize] == object_class.proto_id + { + // Step 4. + return Ok(true); + } } - } - // Step 2. - let global = GetNonCCWObjectGlobal(interface_object.get()); - assert!(!global.is_null()); - let proto_or_iface_array = get_proto_or_iface_array(global); - rooted!(in(cx) let prototype = (*proto_or_iface_array)[object_class.proto_id as usize]); - assert!(!prototype.is_null()); - // Step 3 only concern legacy callback interface objects (i.e. NodeFilter). + // Step 2. + let global = GetNonCCWObjectGlobal(interface_object.get()); + assert!(!global.is_null()); + let proto_or_iface_array = get_proto_or_iface_array(global); + rooted!(in(*cx) let prototype = (*proto_or_iface_array)[object_class.proto_id as usize]); + assert!(!prototype.is_null()); + // Step 3 only concern legacy callback interface objects (i.e. NodeFilter). - while JS_GetPrototype(cx, value.handle(), value_out.handle_mut()) { - *value = *value_out; - if value.is_null() { - // Step 5.2. - return Ok(false); - } else if value.get() as *const _ == prototype.get() { - // Step 5.3. - return Ok(true); + while JS_GetPrototype(*cx, value.handle(), value_out.handle_mut()) { + *value = *value_out; + if value.is_null() { + // Step 5.2. + return Ok(false); + } else if value.get() as *const _ == prototype.get() { + // Step 5.3. + return Ok(true); + } } } // JS_GetPrototype threw an exception. Err(()) } -unsafe fn create_unscopable_object( - cx: *mut JSContext, - names: &[&[u8]], - mut rval: MutableHandleObject, -) { +fn create_unscopable_object(cx: SafeJSContext, names: &[&[u8]], mut rval: MutableHandleObject) { assert!(!names.is_empty()); assert!(rval.is_null()); - rval.set(JS_NewPlainObject(cx)); - assert!(!rval.is_null()); - for &name in names { - assert_eq!(*name.last().unwrap(), b'\0'); - assert!(JS_DefineProperty( - cx, - rval.handle(), - name.as_ptr() as *const libc::c_char, - HandleValue::from_raw(TrueHandleValue), - JSPROP_READONLY as u32, + unsafe { + rval.set(JS_NewPlainObject(*cx)); + assert!(!rval.is_null()); + for &name in names { + assert_eq!(*name.last().unwrap(), b'\0'); + assert!(JS_DefineProperty( + *cx, + rval.handle(), + name.as_ptr() as *const libc::c_char, + HandleValue::from_raw(TrueHandleValue), + JSPROP_READONLY as u32, + )); + } + } +} + +fn define_name(cx: SafeJSContext, obj: HandleObject, name: &[u8]) { + assert_eq!(*name.last().unwrap(), b'\0'); + unsafe { + rooted!(in(*cx) let name = JS_AtomizeAndPinString(*cx, name.as_ptr() as *const libc::c_char)); + assert!(!name.is_null()); + assert!(JS_DefineProperty4( + *cx, + obj, + b"name\0".as_ptr() as *const libc::c_char, + name.handle().into(), + JSPROP_READONLY as u32 )); } } -unsafe fn define_name(cx: *mut JSContext, obj: HandleObject, name: &[u8]) { - assert_eq!(*name.last().unwrap(), b'\0'); - rooted!(in(cx) let name = JS_AtomizeAndPinString(cx, name.as_ptr() as *const libc::c_char)); - assert!(!name.is_null()); - assert!(JS_DefineProperty4( - cx, - obj, - b"name\0".as_ptr() as *const libc::c_char, - name.handle().into(), - JSPROP_READONLY as u32 - )); -} - -unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: i32) { - assert!(JS_DefineProperty5( - cx, - obj, - b"length\0".as_ptr() as *const libc::c_char, - length, - JSPROP_READONLY as u32 - )); +fn define_length(cx: SafeJSContext, obj: HandleObject, length: i32) { + unsafe { + assert!(JS_DefineProperty5( + *cx, + obj, + b"length\0".as_ptr() as *const libc::c_char, + length, + JSPROP_READONLY as u32 + )); + } } unsafe extern "C" fn invalid_constructor( diff --git a/components/script/dom/bindings/iterable.rs b/components/script/dom/bindings/iterable.rs index 5ee790cf2d3..17c5f2fb1ae 100644 --- a/components/script/dom/bindings/iterable.rs +++ b/components/script/dom/bindings/iterable.rs @@ -13,10 +13,10 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::trace::{JSTraceable, RootedTraceableBox}; use crate::dom::globalscope::GlobalScope; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::JSContext; use dom_struct::dom_struct; use js::conversions::ToJSValConvertible; -use js::jsapi::{Heap, JSContext, JSObject}; +use js::jsapi::{Heap, JSObject}; use js::jsval::UndefinedValue; use js::rust::{HandleValue, MutableHandleObject}; use std::cell::Cell; @@ -63,7 +63,7 @@ impl IterableIterator { pub fn new( iterable: &T, type_: IteratorType, - wrap: unsafe fn(SafeJSContext, &GlobalScope, Box>) -> DomRoot, + wrap: unsafe fn(JSContext, &GlobalScope, Box>) -> DomRoot, ) -> DomRoot { let iterator = Box::new(IterableIterator { reflector: Reflector::new(), @@ -76,12 +76,12 @@ impl IterableIterator { /// Return the next value from the iterable object. #[allow(non_snake_case)] - pub fn Next(&self, cx: SafeJSContext) -> Fallible> { + pub fn Next(&self, cx: JSContext) -> Fallible> { let index = self.index.get(); rooted!(in(*cx) let mut value = UndefinedValue()); rooted!(in(*cx) let mut rval = ptr::null_mut::()); let result = if index >= self.iterable.get_iterable_length() { - dict_return(*cx, rval.handle_mut(), true, value.handle()) + dict_return(cx, rval.handle_mut(), true, value.handle()) } else { match self.type_ { IteratorType::Keys => { @@ -90,7 +90,7 @@ impl IterableIterator { .get_key_at_index(index) .to_jsval(*cx, value.handle_mut()); } - dict_return(*cx, rval.handle_mut(), false, value.handle()) + dict_return(cx, rval.handle_mut(), false, value.handle()) }, IteratorType::Values => { unsafe { @@ -98,7 +98,7 @@ impl IterableIterator { .get_value_at_index(index) .to_jsval(*cx, value.handle_mut()); } - dict_return(*cx, rval.handle_mut(), false, value.handle()) + dict_return(cx, rval.handle_mut(), false, value.handle()) }, IteratorType::Entries => { rooted!(in(*cx) let mut key = UndefinedValue()); @@ -110,7 +110,7 @@ impl IterableIterator { .get_value_at_index(index) .to_jsval(*cx, value.handle_mut()); } - key_and_value_return(*cx, rval.handle_mut(), key.handle(), value.handle()) + key_and_value_return(cx, rval.handle_mut(), key.handle(), value.handle()) }, } }; @@ -120,7 +120,7 @@ impl IterableIterator { } fn dict_return( - cx: *mut JSContext, + cx: JSContext, mut result: MutableHandleObject, done: bool, value: HandleValue, @@ -128,16 +128,16 @@ fn dict_return( let mut dict = IterableKeyOrValueResult::empty(); dict.done = done; dict.value.set(value.get()); - rooted!(in(cx) let mut dict_value = UndefinedValue()); + rooted!(in(*cx) let mut dict_value = UndefinedValue()); unsafe { - dict.to_jsval(cx, dict_value.handle_mut()); + dict.to_jsval(*cx, dict_value.handle_mut()); } result.set(dict_value.to_object()); Ok(()) } fn key_and_value_return( - cx: *mut JSContext, + cx: JSContext, mut result: MutableHandleObject, key: HandleValue, value: HandleValue, @@ -150,9 +150,9 @@ fn key_and_value_return( .map(|handle| RootedTraceableBox::from_box(Heap::boxed(handle.get()))) .collect(), ); - rooted!(in(cx) let mut dict_value = UndefinedValue()); + rooted!(in(*cx) let mut dict_value = UndefinedValue()); unsafe { - dict.to_jsval(cx, dict_value.handle_mut()); + dict.to_jsval(*cx, dict_value.handle_mut()); } result.set(dict_value.to_object()); Ok(()) diff --git a/components/script/dom/bindings/namespace.rs b/components/script/dom/bindings/namespace.rs index a6539c83de6..82b7bd8834e 100644 --- a/components/script/dom/bindings/namespace.rs +++ b/components/script/dom/bindings/namespace.rs @@ -6,7 +6,8 @@ use crate::dom::bindings::guard::Guard; use crate::dom::bindings::interface::{create_object, define_on_global_object}; -use js::jsapi::{JSClass, JSContext, JSFunctionSpec}; +use crate::script_runtime::JSContext; +use js::jsapi::{JSClass, JSFunctionSpec}; use js::rust::{HandleObject, MutableHandleObject}; /// The class of a namespace object. @@ -28,8 +29,8 @@ impl NamespaceObjectClass { } /// Create a new namespace object. -pub unsafe fn create_namespace_object( - cx: *mut JSContext, +pub fn create_namespace_object( + cx: JSContext, global: HandleObject, proto: HandleObject, class: &'static NamespaceObjectClass, diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs index 4a5a9af9c43..989bcce27b7 100644 --- a/components/script/dom/bluetooth.rs +++ b/components/script/dom/bluetooth.rs @@ -30,13 +30,13 @@ use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::permissions::{get_descriptor_permission_state, PermissionAlgorithm}; use crate::dom::promise::Promise; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::JSContext; use crate::task::TaskOnce; use dom_struct::dom_struct; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use js::conversions::ConversionResult; -use js::jsapi::{JSContext, JSObject}; +use js::jsapi::JSObject; use js::jsval::{ObjectValue, UndefinedValue}; use profile_traits::ipc as ProfiledIpc; use std::cell::Ref; @@ -616,28 +616,24 @@ impl PermissionAlgorithm for Bluetooth { type Descriptor = BluetoothPermissionDescriptor; type Status = BluetoothPermissionResult; - #[allow(unsafe_code)] fn create_descriptor( - cx: *mut JSContext, + cx: JSContext, permission_descriptor_obj: *mut JSObject, ) -> Result { - rooted!(in(cx) let mut property = UndefinedValue()); + rooted!(in(*cx) let mut property = UndefinedValue()); property .handle_mut() .set(ObjectValue(permission_descriptor_obj)); - unsafe { - match BluetoothPermissionDescriptor::new(SafeJSContext::from_ptr(cx), property.handle()) - { - Ok(ConversionResult::Success(descriptor)) => Ok(descriptor), - Ok(ConversionResult::Failure(error)) => Err(Error::Type(error.into_owned())), - Err(_) => Err(Error::Type(String::from(BT_DESC_CONVERSION_ERROR))), - } + match BluetoothPermissionDescriptor::new(cx, property.handle()) { + Ok(ConversionResult::Success(descriptor)) => Ok(descriptor), + Ok(ConversionResult::Failure(error)) => Err(Error::Type(error.into_owned())), + Err(_) => Err(Error::Type(String::from(BT_DESC_CONVERSION_ERROR))), } } // https://webbluetoothcg.github.io/web-bluetooth/#query-the-bluetooth-permission fn permission_query( - _cx: *mut JSContext, + _cx: JSContext, promise: &Rc, descriptor: &BluetoothPermissionDescriptor, status: &BluetoothPermissionResult, @@ -727,7 +723,7 @@ impl PermissionAlgorithm for Bluetooth { // https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission fn permission_request( - _cx: *mut JSContext, + _cx: JSContext, promise: &Rc, descriptor: &BluetoothPermissionDescriptor, status: &BluetoothPermissionResult, diff --git a/components/script/dom/create.rs b/components/script/dom/create.rs index 18c9504a245..e992a8707dd 100644 --- a/components/script/dom/create.rs +++ b/components/script/dom/create.rs @@ -158,7 +158,7 @@ fn create_html_element( unsafe { let _ac = JSAutoRealm::new(*cx, global.reflector().get_jsobject().get()); - throw_dom_exception(*cx, &global, error); + throw_dom_exception(cx, &global, error); report_pending_exception(*cx, true); } diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs index 2603768ed83..64117959500 100644 --- a/components/script/dom/customelementregistry.rs +++ b/components/script/dom/customelementregistry.rs @@ -31,14 +31,14 @@ use crate::dom::node::{document_from_node, window_from_node, Node, ShadowIncludi use crate::dom::promise::Promise; use crate::dom::window::Window; use crate::microtask::Microtask; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::JSContext; use crate::script_thread::ScriptThread; use dom_struct::dom_struct; use html5ever::{LocalName, Namespace, Prefix}; use js::conversions::ToJSValConvertible; use js::glue::UnwrapObjectStatic; use js::jsapi::{HandleValueArray, Heap, IsCallable, IsConstructor}; -use js::jsapi::{JSAutoRealm, JSContext, JSObject}; +use js::jsapi::{JSAutoRealm, JSObject}; use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue}; use js::rust::wrappers::{Construct1, JS_GetProperty, SameValue}; use js::rust::{HandleObject, HandleValue, MutableHandleValue}; @@ -171,14 +171,10 @@ impl CustomElementRegistry { // Step 4 Ok(LifecycleCallbacks { - connected_callback: get_callback(*cx, prototype, b"connectedCallback\0")?, - disconnected_callback: get_callback(*cx, prototype, b"disconnectedCallback\0")?, - adopted_callback: get_callback(*cx, prototype, b"adoptedCallback\0")?, - attribute_changed_callback: get_callback( - *cx, - prototype, - b"attributeChangedCallback\0", - )?, + connected_callback: get_callback(cx, prototype, b"connectedCallback\0")?, + disconnected_callback: get_callback(cx, prototype, b"disconnectedCallback\0")?, + adopted_callback: get_callback(cx, prototype, b"adoptedCallback\0")?, + attribute_changed_callback: get_callback(cx, prototype, b"attributeChangedCallback\0")?, }) } @@ -221,34 +217,32 @@ impl CustomElementRegistry { /// /// Step 10.4 #[allow(unsafe_code)] -unsafe fn get_callback( - cx: *mut JSContext, +fn get_callback( + cx: JSContext, prototype: HandleObject, name: &[u8], ) -> Fallible>> { - rooted!(in(cx) let mut callback = UndefinedValue()); - - // Step 10.4.1 - if !JS_GetProperty( - cx, - prototype, - name.as_ptr() as *const _, - callback.handle_mut(), - ) { - return Err(Error::JSFailed); - } - - // Step 10.4.2 - if !callback.is_undefined() { - if !callback.is_object() || !IsCallable(callback.to_object()) { - return Err(Error::Type("Lifecycle callback is not callable".to_owned())); + rooted!(in(*cx) let mut callback = UndefinedValue()); + unsafe { + // Step 10.4.1 + if !JS_GetProperty( + *cx, + prototype, + name.as_ptr() as *const _, + callback.handle_mut(), + ) { + return Err(Error::JSFailed); + } + + // Step 10.4.2 + if !callback.is_undefined() { + if !callback.is_object() || !IsCallable(callback.to_object()) { + return Err(Error::Type("Lifecycle callback is not callable".to_owned())); + } + Ok(Some(Function::new(cx, callback.to_object()))) + } else { + Ok(None) } - Ok(Some(Function::new( - SafeJSContext::from_ptr(cx), - callback.to_object(), - ))) - } else { - Ok(None) } } @@ -409,7 +403,7 @@ impl CustomElementRegistryMethods for CustomElementRegistry { /// #[allow(unsafe_code)] - fn Get(&self, cx: SafeJSContext, name: DOMString) -> JSVal { + fn Get(&self, cx: JSContext, name: DOMString) -> JSVal { match self.definitions.borrow().get(&LocalName::from(&*name)) { Some(definition) => unsafe { rooted!(in(*cx) let mut constructor = UndefinedValue()); @@ -631,7 +625,7 @@ pub fn upgrade_element(definition: Rc, element: &Elemen let global = GlobalScope::current().expect("No current global"); let cx = global.get_cx(); unsafe { - throw_dom_exception(*cx, &global, error); + throw_dom_exception(cx, &global, error); report_pending_exception(*cx, true); } return; diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs index fdba0e0aa75..1a1a734d5b0 100644 --- a/components/script/dom/filereader.rs +++ b/components/script/dom/filereader.rs @@ -22,7 +22,7 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable}; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::progressevent::ProgressEvent; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::JSContext; use crate::task::TaskCanceller; use crate::task_source::file_reading::{FileReadingTask, FileReadingTaskSource}; use crate::task_source::{TaskSource, TaskSourceName}; @@ -30,7 +30,6 @@ use base64; use dom_struct::dom_struct; use encoding_rs::{Encoding, UTF_8}; use js::jsapi::Heap; -use js::jsapi::JSContext; use js::jsapi::JSObject; use js::jsval::{self, JSVal}; use js::typedarray::{ArrayBuffer, CreateWith}; @@ -233,7 +232,6 @@ impl FileReader { } // https://w3c.github.io/FileAPI/#dfn-readAsText - #[allow(unsafe_code)] pub fn process_read_eof( filereader: TrustedFileReader, gen_id: GenerationId, @@ -266,7 +264,7 @@ impl FileReader { let _ac = enter_realm(&*fr); FileReader::perform_readasarraybuffer( &fr.result, - *fr.global().get_cx(), + fr.global().get_cx(), data, &blob_contents, ) @@ -313,14 +311,14 @@ impl FileReader { #[allow(unsafe_code)] fn perform_readasarraybuffer( result: &DomRefCell>, - cx: *mut JSContext, + cx: JSContext, _: ReadMetaData, bytes: &[u8], ) { unsafe { - rooted!(in(cx) let mut array_buffer = ptr::null_mut::()); + rooted!(in(*cx) let mut array_buffer = ptr::null_mut::()); assert!( - ArrayBuffer::create(cx, CreateWith::Slice(bytes), array_buffer.handle_mut()) + ArrayBuffer::create(*cx, CreateWith::Slice(bytes), array_buffer.handle_mut()) .is_ok() ); @@ -392,7 +390,7 @@ impl FileReaderMethods for FileReader { #[allow(unsafe_code)] // https://w3c.github.io/FileAPI/#dfn-result - fn GetResult(&self, _: SafeJSContext) -> Option { + fn GetResult(&self, _: JSContext) -> Option { self.result.borrow().as_ref().map(|r| match *r { FileReaderResult::String(ref string) => StringOrObject::String(string.clone()), FileReaderResult::ArrayBuffer(ref arr_buffer) => { diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index ddf7dfc61cc..2ae306e25be 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -677,23 +677,17 @@ impl GlobalScope { } /// Perform a microtask checkpoint. - #[allow(unsafe_code)] pub fn perform_a_microtask_checkpoint(&self) { - unsafe { - self.microtask_queue.checkpoint( - *self.get_cx(), - |_| Some(DomRoot::from_ref(self)), - vec![DomRoot::from_ref(self)], - ); - } + self.microtask_queue.checkpoint( + self.get_cx(), + |_| Some(DomRoot::from_ref(self)), + vec![DomRoot::from_ref(self)], + ); } /// Enqueue a microtask for subsequent execution. - #[allow(unsafe_code)] pub fn enqueue_microtask(&self, job: Microtask) { - unsafe { - self.microtask_queue.enqueue(job, *self.get_cx()); - } + self.microtask_queue.enqueue(job, self.get_cx()); } /// Create a new sender/receiver pair that can be used to implement an on-demand diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs index 583c58a00f1..92c27dfb82d 100644 --- a/components/script/dom/history.rs +++ b/components/script/dom/history.rs @@ -18,9 +18,9 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::hashchangeevent::HashChangeEvent; use crate::dom::popstateevent::PopStateEvent; use crate::dom::window::Window; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::JSContext; use dom_struct::dom_struct; -use js::jsapi::{Heap, JSContext}; +use js::jsapi::Heap; use js::jsval::{JSVal, NullValue, UndefinedValue}; use js::rust::HandleValue; use msg::constellation_msg::{HistoryStateId, TraversalDirection}; @@ -165,7 +165,7 @@ impl History { // https://html.spec.whatwg.org/multipage/#dom-history-replacestate fn push_or_replace_state( &self, - cx: *mut JSContext, + cx: JSContext, data: HandleValue, _title: DOMString, url: Option, @@ -185,7 +185,7 @@ impl History { // TODO: Step 4 // Step 5 - let serialized_data = StructuredCloneData::write(cx, data)?.move_to_arraybuffer(); + let serialized_data = StructuredCloneData::write(*cx, data)?.move_to_arraybuffer(); let new_url: ServoUrl = match url { // Step 6 @@ -265,7 +265,7 @@ impl History { // Step 11 let global_scope = self.window.upcast::(); - rooted!(in(cx) let mut state = UndefinedValue()); + rooted!(in(*cx) let mut state = UndefinedValue()); StructuredCloneData::Vector(serialized_data).read(&global_scope, state.handle_mut()); // Step 12 @@ -280,7 +280,7 @@ impl History { impl HistoryMethods for History { // https://html.spec.whatwg.org/multipage/#dom-history-state - fn GetState(&self, _cx: SafeJSContext) -> Fallible { + fn GetState(&self, _cx: JSContext) -> Fallible { if !self.window.Document().is_fully_active() { return Err(Error::Security); } @@ -329,22 +329,22 @@ impl HistoryMethods for History { // https://html.spec.whatwg.org/multipage/#dom-history-pushstate fn PushState( &self, - cx: SafeJSContext, + cx: JSContext, data: HandleValue, title: DOMString, url: Option, ) -> ErrorResult { - self.push_or_replace_state(*cx, data, title, url, PushOrReplace::Push) + self.push_or_replace_state(cx, data, title, url, PushOrReplace::Push) } // https://html.spec.whatwg.org/multipage/#dom-history-replacestate fn ReplaceState( &self, - cx: SafeJSContext, + cx: JSContext, data: HandleValue, title: DOMString, url: Option, ) -> ErrorResult { - self.push_or_replace_state(*cx, data, title, url, PushOrReplace::Replace) + self.push_or_replace_state(cx, data, title, url, PushOrReplace::Replace) } } diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 4e9abe5f3c9..1c07a88cc1c 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -28,7 +28,7 @@ use crate::dom::webgl2renderingcontext::WebGL2RenderingContext; use crate::dom::webglrenderingcontext::{ LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext, }; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::JSContext; use base64; use canvas_traits::canvas::{CanvasId, CanvasMsg, FromScriptMsg}; use canvas_traits::webgl::{GLContextAttributes, WebGLVersion}; @@ -39,7 +39,6 @@ use image::png::PNGEncoder; use image::ColorType; use ipc_channel::ipc::IpcSharedMemory; use js::error::throw_type_error; -use js::jsapi::JSContext; use js::rust::HandleValue; use profile_traits::ipc; use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource}; @@ -207,10 +206,9 @@ impl HTMLCanvasElement { Some(context) } - #[allow(unsafe_code)] - unsafe fn get_or_init_webgl_context( + fn get_or_init_webgl_context( &self, - cx: *mut JSContext, + cx: JSContext, options: HandleValue, ) -> Option> { if let Some(ctx) = self.context() { @@ -227,10 +225,9 @@ impl HTMLCanvasElement { Some(context) } - #[allow(unsafe_code)] - unsafe fn get_or_init_webgl2_context( + fn get_or_init_webgl2_context( &self, - cx: *mut JSContext, + cx: JSContext, options: HandleValue, ) -> Option> { if !pref!(dom.webgl2.enabled) { @@ -260,20 +257,19 @@ impl HTMLCanvasElement { } #[allow(unsafe_code)] - unsafe fn get_gl_attributes( - cx: *mut JSContext, - options: HandleValue, - ) -> Option { - match WebGLContextAttributes::new(SafeJSContext::from_ptr(cx), options) { - Ok(ConversionResult::Success(ref attrs)) => Some(From::from(attrs)), - Ok(ConversionResult::Failure(ref error)) => { - throw_type_error(cx, &error); - None - }, - _ => { - debug!("Unexpected error on conversion of WebGLContextAttributes"); - None - }, + fn get_gl_attributes(cx: JSContext, options: HandleValue) -> Option { + unsafe { + match WebGLContextAttributes::new(cx, options) { + Ok(ConversionResult::Success(ref attrs)) => Some(From::from(attrs)), + Ok(ConversionResult::Failure(ref error)) => { + throw_type_error(*cx, &error); + None + }, + _ => { + debug!("Unexpected error on conversion of WebGLContextAttributes"); + None + }, + } } } @@ -329,10 +325,9 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { make_uint_setter!(SetHeight, "height", DEFAULT_HEIGHT); // https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext - #[allow(unsafe_code)] fn GetContext( &self, - cx: SafeJSContext, + cx: JSContext, id: DOMString, options: HandleValue, ) -> Option { @@ -340,14 +335,12 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { "2d" => self .get_or_init_2d_context() .map(RenderingContext::CanvasRenderingContext2D), - "webgl" | "experimental-webgl" => unsafe { - self.get_or_init_webgl_context(*cx, options) - .map(RenderingContext::WebGLRenderingContext) - }, - "webgl2" | "experimental-webgl2" => unsafe { - self.get_or_init_webgl2_context(*cx, options) - .map(RenderingContext::WebGL2RenderingContext) - }, + "webgl" | "experimental-webgl" => self + .get_or_init_webgl_context(cx, options) + .map(RenderingContext::WebGLRenderingContext), + "webgl2" | "experimental-webgl2" => self + .get_or_init_webgl2_context(cx, options) + .map(RenderingContext::WebGL2RenderingContext), _ => None, } } @@ -355,7 +348,7 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { // https://html.spec.whatwg.org/multipage/#dom-canvas-todataurl fn ToDataURL( &self, - _context: SafeJSContext, + _context: JSContext, _mime_type: Option, _quality: HandleValue, ) -> Fallible { diff --git a/components/script/dom/permissions.rs b/components/script/dom/permissions.rs index 419115d1240..fba7965eee1 100644 --- a/components/script/dom/permissions.rs +++ b/components/script/dom/permissions.rs @@ -17,10 +17,10 @@ use crate::dom::bluetoothpermissionresult::BluetoothPermissionResult; use crate::dom::globalscope::GlobalScope; use crate::dom::permissionstatus::PermissionStatus; use crate::dom::promise::Promise; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::JSContext; use dom_struct::dom_struct; use js::conversions::ConversionResult; -use js::jsapi::{JSContext, JSObject}; +use js::jsapi::JSObject; use js::jsval::{ObjectValue, UndefinedValue}; use servo_config::pref; use std::rc::Rc; @@ -37,17 +37,17 @@ pub trait PermissionAlgorithm { type Descriptor; type Status; fn create_descriptor( - cx: *mut JSContext, + cx: JSContext, permission_descriptor_obj: *mut JSObject, ) -> Result; fn permission_query( - cx: *mut JSContext, + cx: JSContext, promise: &Rc, descriptor: &Self::Descriptor, status: &Self::Status, ); fn permission_request( - cx: *mut JSContext, + cx: JSContext, promise: &Rc, descriptor: &Self::Descriptor, status: &Self::Status, @@ -88,7 +88,7 @@ impl Permissions { fn manipulate( &self, op: Operation, - cx: *mut JSContext, + cx: JSContext, permissionDesc: *mut JSObject, promise: Option>, ) -> Rc { @@ -201,18 +201,18 @@ impl Permissions { impl PermissionsMethods for Permissions { // https://w3c.github.io/permissions/#dom-permissions-query - fn Query(&self, cx: SafeJSContext, permissionDesc: *mut JSObject) -> Rc { - self.manipulate(Operation::Query, *cx, permissionDesc, None) + fn Query(&self, cx: JSContext, permissionDesc: *mut JSObject) -> Rc { + self.manipulate(Operation::Query, cx, permissionDesc, None) } // https://w3c.github.io/permissions/#dom-permissions-request - fn Request(&self, cx: SafeJSContext, permissionDesc: *mut JSObject) -> Rc { - self.manipulate(Operation::Request, *cx, permissionDesc, None) + fn Request(&self, cx: JSContext, permissionDesc: *mut JSObject) -> Rc { + self.manipulate(Operation::Request, cx, permissionDesc, None) } // https://w3c.github.io/permissions/#dom-permissions-revoke - fn Revoke(&self, cx: SafeJSContext, permissionDesc: *mut JSObject) -> Rc { - self.manipulate(Operation::Revoke, *cx, permissionDesc, None) + fn Revoke(&self, cx: JSContext, permissionDesc: *mut JSObject) -> Rc { + self.manipulate(Operation::Revoke, cx, permissionDesc, None) } } @@ -220,27 +220,24 @@ impl PermissionAlgorithm for Permissions { type Descriptor = PermissionDescriptor; type Status = PermissionStatus; - #[allow(unsafe_code)] fn create_descriptor( - cx: *mut JSContext, + cx: JSContext, permission_descriptor_obj: *mut JSObject, ) -> Result { - rooted!(in(cx) let mut property = UndefinedValue()); + rooted!(in(*cx) let mut property = UndefinedValue()); property .handle_mut() .set(ObjectValue(permission_descriptor_obj)); - unsafe { - match PermissionDescriptor::new(SafeJSContext::from_ptr(cx), property.handle()) { - Ok(ConversionResult::Success(descriptor)) => Ok(descriptor), - Ok(ConversionResult::Failure(error)) => Err(Error::Type(error.into_owned())), - Err(_) => Err(Error::JSFailed), - } + match PermissionDescriptor::new(cx, property.handle()) { + Ok(ConversionResult::Success(descriptor)) => Ok(descriptor), + Ok(ConversionResult::Failure(error)) => Err(Error::Type(error.into_owned())), + Err(_) => Err(Error::JSFailed), } } // https://w3c.github.io/permissions/#boolean-permission-query-algorithm fn permission_query( - _cx: *mut JSContext, + _cx: JSContext, _promise: &Rc, _descriptor: &PermissionDescriptor, status: &PermissionStatus, @@ -251,7 +248,7 @@ impl PermissionAlgorithm for Permissions { // https://w3c.github.io/permissions/#boolean-permission-request-algorithm fn permission_request( - cx: *mut JSContext, + cx: JSContext, promise: &Rc, descriptor: &PermissionDescriptor, status: &PermissionStatus, diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs index 4dd6f53e711..b101c449348 100644 --- a/components/script/dom/promise.rs +++ b/components/script/dom/promise.rs @@ -18,6 +18,7 @@ use crate::dom::bindings::reflector::{DomObject, MutDomObject, Reflector}; use crate::dom::bindings::utils::AsCCharPtrPtr; use crate::dom::globalscope::GlobalScope; use crate::dom::promisenativehandler::PromiseNativeHandler; +use crate::script_runtime::JSContext as SafeJSContext; use dom_struct::dom_struct; use js::conversions::ToJSValConvertible; use js::jsapi::{AddRawValueRoot, CallArgs, GetFunctionNativeReserved}; @@ -49,20 +50,21 @@ pub struct Promise { /// Private helper to enable adding new methods to Rc. trait PromiseHelper { - #[allow(unsafe_code)] - unsafe fn initialize(&self, cx: *mut JSContext); + fn initialize(&self, cx: SafeJSContext); } impl PromiseHelper for Rc { #[allow(unsafe_code)] - unsafe fn initialize(&self, cx: *mut JSContext) { + fn initialize(&self, cx: SafeJSContext) { let obj = self.reflector().get_jsobject(); self.permanent_js_root.set(ObjectValue(*obj)); - assert!(AddRawValueRoot( - cx, - self.permanent_js_root.get_unsafe(), - b"Promise::root\0".as_c_char_ptr() - )); + unsafe { + assert!(AddRawValueRoot( + *cx, + self.permanent_js_root.get_unsafe(), + b"Promise::root\0".as_c_char_ptr() + )); + } } } @@ -86,75 +88,72 @@ impl Promise { Promise::new_in_current_compartment(global, comp) } - #[allow(unsafe_code)] pub fn new_in_current_compartment(global: &GlobalScope, _comp: InCompartment) -> Rc { let cx = global.get_cx(); rooted!(in(*cx) let mut obj = ptr::null_mut::()); - unsafe { - Promise::create_js_promise(*cx, HandleObject::null(), obj.handle_mut()); - Promise::new_with_js_promise(obj.handle(), *cx) - } + Promise::create_js_promise(cx, HandleObject::null(), obj.handle_mut()); + Promise::new_with_js_promise(obj.handle(), cx) } #[allow(unsafe_code)] pub fn duplicate(&self) -> Rc { let cx = self.global().get_cx(); - unsafe { Promise::new_with_js_promise(self.reflector().get_jsobject(), *cx) } + Promise::new_with_js_promise(self.reflector().get_jsobject(), cx) } #[allow(unsafe_code, unrooted_must_root)] - pub unsafe fn new_with_js_promise(obj: HandleObject, cx: *mut JSContext) -> Rc { - assert!(IsPromiseObject(obj)); - let promise = Promise { - reflector: Reflector::new(), - permanent_js_root: Heap::default(), - }; - let mut promise = Rc::new(promise); - Rc::get_mut(&mut promise).unwrap().init_reflector(obj.get()); - promise.initialize(cx); - promise + pub fn new_with_js_promise(obj: HandleObject, cx: SafeJSContext) -> Rc { + unsafe { + assert!(IsPromiseObject(obj)); + let promise = Promise { + reflector: Reflector::new(), + permanent_js_root: Heap::default(), + }; + let mut promise = Rc::new(promise); + Rc::get_mut(&mut promise).unwrap().init_reflector(obj.get()); + promise.initialize(cx); + promise + } } #[allow(unsafe_code)] - unsafe fn create_js_promise( - cx: *mut JSContext, - proto: HandleObject, - mut obj: MutableHandleObject, - ) { - let do_nothing_func = JS_NewFunction( - cx, - Some(do_nothing_promise_executor), - /* nargs = */ 2, - /* flags = */ 0, - ptr::null(), - ); - assert!(!do_nothing_func.is_null()); - rooted!(in(cx) let do_nothing_obj = JS_GetFunctionObject(do_nothing_func)); - assert!(!do_nothing_obj.is_null()); - obj.set(NewPromiseObject(cx, do_nothing_obj.handle(), proto)); - assert!(!obj.is_null()); + fn create_js_promise(cx: SafeJSContext, proto: HandleObject, mut obj: MutableHandleObject) { + unsafe { + let do_nothing_func = JS_NewFunction( + *cx, + Some(do_nothing_promise_executor), + /* nargs = */ 2, + /* flags = */ 0, + ptr::null(), + ); + assert!(!do_nothing_func.is_null()); + rooted!(in(*cx) let do_nothing_obj = JS_GetFunctionObject(do_nothing_func)); + assert!(!do_nothing_obj.is_null()); + obj.set(NewPromiseObject(*cx, do_nothing_obj.handle(), proto)); + assert!(!obj.is_null()); + } } #[allow(unrooted_must_root, unsafe_code)] - pub unsafe fn new_resolved( + pub fn new_resolved( global: &GlobalScope, - cx: *mut JSContext, + cx: SafeJSContext, value: HandleValue, ) -> Fallible> { - let _ac = JSAutoRealm::new(cx, global.reflector().get_jsobject().get()); - rooted!(in(cx) let p = CallOriginalPromiseResolve(cx, value)); + let _ac = JSAutoRealm::new(*cx, global.reflector().get_jsobject().get()); + rooted!(in(*cx) let p = unsafe { CallOriginalPromiseResolve(*cx, value) }); assert!(!p.handle().is_null()); Ok(Promise::new_with_js_promise(p.handle(), cx)) } #[allow(unrooted_must_root, unsafe_code)] - pub unsafe fn new_rejected( + pub fn new_rejected( global: &GlobalScope, - cx: *mut JSContext, + cx: SafeJSContext, value: HandleValue, ) -> Fallible> { - let _ac = JSAutoRealm::new(cx, global.reflector().get_jsobject().get()); - rooted!(in(cx) let p = CallOriginalPromiseReject(cx, value)); + let _ac = JSAutoRealm::new(*cx, global.reflector().get_jsobject().get()); + rooted!(in(*cx) let p = unsafe { CallOriginalPromiseReject(*cx, value) }); assert!(!p.handle().is_null()); Ok(Promise::new_with_js_promise(p.handle(), cx)) } @@ -169,14 +168,16 @@ impl Promise { rooted!(in(*cx) let mut v = UndefinedValue()); unsafe { val.to_jsval(*cx, v.handle_mut()); - self.resolve(*cx, v.handle()); } + self.resolve(cx, v.handle()); } #[allow(unrooted_must_root, unsafe_code)] - pub unsafe fn resolve(&self, cx: *mut JSContext, value: HandleValue) { - if !ResolvePromise(cx, self.promise_obj(), value) { - JS_ClearPendingException(cx); + pub fn resolve(&self, cx: SafeJSContext, value: HandleValue) { + unsafe { + if !ResolvePromise(*cx, self.promise_obj(), value) { + JS_ClearPendingException(*cx); + } } } @@ -190,8 +191,8 @@ impl Promise { rooted!(in(*cx) let mut v = UndefinedValue()); unsafe { val.to_jsval(*cx, v.handle_mut()); - self.reject(*cx, v.handle()); } + self.reject(cx, v.handle()); } #[allow(unsafe_code)] @@ -201,14 +202,16 @@ impl Promise { rooted!(in(*cx) let mut v = UndefinedValue()); unsafe { error.to_jsval(*cx, &self.global(), v.handle_mut()); - self.reject(*cx, v.handle()); } + self.reject(cx, v.handle()); } #[allow(unrooted_must_root, unsafe_code)] - pub unsafe fn reject(&self, cx: *mut JSContext, value: HandleValue) { - if !RejectPromise(cx, self.promise_obj(), value) { - JS_ClearPendingException(cx); + pub fn reject(&self, cx: SafeJSContext, value: HandleValue) { + unsafe { + if !RejectPromise(*cx, self.promise_obj(), value) { + JS_ClearPendingException(*cx); + } } } diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index dfa148e5c11..607c97085f1 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -941,29 +941,21 @@ impl TestBindingMethods for TestBinding { } #[allow(unrooted_must_root)] - #[allow(unsafe_code)] fn ReturnResolvedPromise(&self, cx: SafeJSContext, v: HandleValue) -> Fallible> { - unsafe { Promise::new_resolved(&self.global(), *cx, v) } + Promise::new_resolved(&self.global(), cx, v) } #[allow(unrooted_must_root)] - #[allow(unsafe_code)] fn ReturnRejectedPromise(&self, cx: SafeJSContext, v: HandleValue) -> Fallible> { - unsafe { Promise::new_rejected(&self.global(), *cx, v) } + Promise::new_rejected(&self.global(), cx, v) } - #[allow(unsafe_code)] fn PromiseResolveNative(&self, cx: SafeJSContext, p: &Promise, v: HandleValue) { - unsafe { - p.resolve(*cx, v); - } + p.resolve(cx, v); } - #[allow(unsafe_code)] fn PromiseRejectNative(&self, cx: SafeJSContext, p: &Promise, v: HandleValue) { - unsafe { - p.reject(*cx, v); - } + p.reject(cx, v); } fn PromiseRejectWithTypeError(&self, p: &Promise, s: USVString) { @@ -1098,12 +1090,11 @@ impl TestBinding { pub fn FuncControlledStaticMethodEnabled(_: &GlobalScope) {} } -#[allow(unsafe_code)] impl TestBinding { - pub unsafe fn condition_satisfied(_: *mut JSContext, _: HandleObject) -> bool { + pub fn condition_satisfied(_: SafeJSContext, _: HandleObject) -> bool { true } - pub unsafe fn condition_unsatisfied(_: *mut JSContext, _: HandleObject) -> bool { + pub fn condition_unsatisfied(_: SafeJSContext, _: HandleObject) -> bool { false } } diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index dbdd09eabb9..99336ec7f66 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -18,6 +18,7 @@ use crate::dom::document::Document; use crate::dom::element::Element; use crate::dom::globalscope::GlobalScope; use crate::dom::window::Window; +use crate::script_runtime::JSContext as SafeJSContext; use crate::script_thread::ScriptThread; use dom_struct::dom_struct; use embedder_traits::EmbedderMsg; @@ -959,7 +960,7 @@ pub fn new_window_proxy_handler() -> WindowProxyHandler { unsafe fn throw_security_error(cx: *mut JSContext) -> bool { if !JS_IsExceptionPending(cx) { let global = GlobalScope::from_context(cx); - throw_dom_exception(cx, &*global, Error::Security); + throw_dom_exception(SafeJSContext::from_ptr(cx), &*global, Error::Security); } false } diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 082973345c9..7f0dbdf68a2 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -38,7 +38,7 @@ use crate::dom::xmlhttprequesteventtarget::XMLHttpRequestEventTarget; use crate::dom::xmlhttprequestupload::XMLHttpRequestUpload; use crate::fetch::FetchCanceller; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::JSContext; use crate::task_source::networking::NetworkingTaskSource; use crate::task_source::TaskSourceName; use crate::timers::{OneshotTimerCallback, OneshotTimerHandle}; @@ -54,7 +54,7 @@ use hyper_serde::Serde; use ipc_channel::ipc; use ipc_channel::router::ROUTER; use js::jsapi::JS_ClearPendingException; -use js::jsapi::{Heap, JSContext, JSObject}; +use js::jsapi::{Heap, JSObject}; use js::jsval::{JSVal, NullValue, UndefinedValue}; use js::rust::wrappers::JS_ParseJSON; use js::typedarray::{ArrayBuffer, CreateWith}; @@ -878,7 +878,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest { #[allow(unsafe_code)] // https://xhr.spec.whatwg.org/#the-response-attribute - fn Response(&self, cx: SafeJSContext) -> JSVal { + fn Response(&self, cx: JSContext) -> JSVal { rooted!(in(*cx) let mut rval = UndefinedValue()); match self.response_type.get() { XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Text => unsafe { @@ -902,16 +902,14 @@ impl XMLHttpRequestMethods for XMLHttpRequest { self.document_response().to_jsval(*cx, rval.handle_mut()); }, XMLHttpRequestResponseType::Json => unsafe { - self.json_response(*cx).to_jsval(*cx, rval.handle_mut()); + self.json_response(cx).to_jsval(*cx, rval.handle_mut()); }, XMLHttpRequestResponseType::Blob => unsafe { self.blob_response().to_jsval(*cx, rval.handle_mut()); }, - XMLHttpRequestResponseType::Arraybuffer => unsafe { - match self.arraybuffer_response(*cx) { - Some(js_object) => js_object.to_jsval(*cx, rval.handle_mut()), - None => return NullValue(), - } + XMLHttpRequestResponseType::Arraybuffer => match self.arraybuffer_response(cx) { + Some(js_object) => unsafe { js_object.to_jsval(*cx, rval.handle_mut()) }, + None => return NullValue(), }, } rval.get() @@ -1278,7 +1276,7 @@ impl XMLHttpRequest { // https://xhr.spec.whatwg.org/#arraybuffer-response #[allow(unsafe_code)] - unsafe fn arraybuffer_response(&self, cx: *mut JSContext) -> Option> { + fn arraybuffer_response(&self, cx: JSContext) -> Option> { // Step 1 let created = self.response_arraybuffer.get(); if let Some(nonnull) = NonNull::new(created) { @@ -1287,13 +1285,15 @@ impl XMLHttpRequest { // Step 2 let bytes = self.response.borrow(); - rooted!(in(cx) let mut array_buffer = ptr::null_mut::()); - ArrayBuffer::create(cx, CreateWith::Slice(&bytes), array_buffer.handle_mut()) - .ok() - .and_then(|()| { - self.response_arraybuffer.set(array_buffer.get()); - Some(NonNull::new_unchecked(array_buffer.get())) - }) + rooted!(in(*cx) let mut array_buffer = ptr::null_mut::()); + unsafe { + ArrayBuffer::create(*cx, CreateWith::Slice(&bytes), array_buffer.handle_mut()) + .ok() + .and_then(|()| { + self.response_arraybuffer.set(array_buffer.get()); + Some(NonNull::new_unchecked(array_buffer.get())) + }) + } } // https://xhr.spec.whatwg.org/#document-response @@ -1345,7 +1345,7 @@ impl XMLHttpRequest { #[allow(unsafe_code)] // https://xhr.spec.whatwg.org/#json-response - fn json_response(&self, cx: *mut JSContext) -> JSVal { + fn json_response(&self, cx: JSContext) -> JSVal { // Step 1 let response_json = self.response_json.get(); if !response_json.is_null_or_undefined() { @@ -1378,15 +1378,15 @@ 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()); + rooted!(in(*cx) let mut rval = UndefinedValue()); unsafe { if !JS_ParseJSON( - cx, + *cx, json_text.as_ptr(), json_text.len() as u32, rval.handle_mut(), ) { - JS_ClearPendingException(cx); + JS_ClearPendingException(*cx); return NullValue(); } } diff --git a/components/script/microtask.rs b/components/script/microtask.rs index db420e20eaa..001262c05e1 100644 --- a/components/script/microtask.rs +++ b/components/script/microtask.rs @@ -14,9 +14,9 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::htmlimageelement::ImageElementMicrotask; use crate::dom::htmlmediaelement::MediaElementMicrotask; use crate::dom::mutationobserver::MutationObserver; -use crate::script_runtime::notify_about_rejected_promises; +use crate::script_runtime::{notify_about_rejected_promises, JSContext}; use crate::script_thread::ScriptThread; -use js::jsapi::{JSContext, JobQueueIsEmpty, JobQueueMayNotBeEmpty}; +use js::jsapi::{JobQueueIsEmpty, JobQueueMayNotBeEmpty}; use msg::constellation_msg::PipelineId; use std::cell::Cell; use std::mem; @@ -56,17 +56,17 @@ impl MicrotaskQueue { /// Add a new microtask to this queue. It will be invoked as part of the next /// microtask checkpoint. #[allow(unsafe_code)] - pub unsafe fn enqueue(&self, job: Microtask, cx: *mut JSContext) { + pub fn enqueue(&self, job: Microtask, cx: JSContext) { self.microtask_queue.borrow_mut().push(job); - JobQueueMayNotBeEmpty(cx); + unsafe { JobQueueMayNotBeEmpty(*cx) }; } /// /// Perform a microtask checkpoint, executing all queued microtasks until the queue is empty. #[allow(unsafe_code)] - pub unsafe fn checkpoint( + pub fn checkpoint( &self, - cx: *mut JSContext, + cx: JSContext, target_provider: F, globalscopes: Vec>, ) where @@ -86,7 +86,7 @@ impl MicrotaskQueue { for (idx, job) in pending_queue.iter().enumerate() { if idx == pending_queue.len() - 1 && self.microtask_queue.borrow().is_empty() { - JobQueueIsEmpty(cx); + unsafe { JobQueueIsEmpty(*cx) }; } match *job { diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index fb94d30fafd..a460d1af1b5 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -172,6 +172,7 @@ unsafe extern "C" fn enqueue_promise_job( _allocation_site: HandleObject, incumbent_global: HandleObject, ) -> bool { + let cx = JSContext::from_ptr(cx); wrap_panic( AssertUnwindSafe(|| { let microtask_queue = &*(extra as *const MicrotaskQueue); @@ -179,7 +180,7 @@ unsafe extern "C" fn enqueue_promise_job( let pipeline = global.pipeline_id(); microtask_queue.enqueue( Microtask::Promise(EnqueuedPromiseCallback { - callback: PromiseJobCallback::new(JSContext::from_ptr(cx), job.get()), + callback: PromiseJobCallback::new(cx, job.get()), pipeline, }), cx, @@ -201,7 +202,8 @@ unsafe extern "C" fn promise_rejection_tracker( // TODO: Step 2 - If script's muted errors is true, terminate these steps. // Step 3. - let global = GlobalScope::from_context(cx); + let cx = JSContext::from_ptr(cx); + let global = GlobalScope::from_context(*cx); wrap_panic( AssertUnwindSafe(|| { @@ -281,7 +283,7 @@ pub fn notify_about_rejected_promises(global: &GlobalScope) { .iter() .map(|promise| { let promise = - Promise::new_with_js_promise(Handle::from_raw(promise.handle()), *cx); + Promise::new_with_js_promise(Handle::from_raw(promise.handle()), cx); TrustedPromise::new(promise) }) diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index da5d8f2e7aa..06442d3042a 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -910,16 +910,13 @@ impl ScriptThread { } // https://html.spec.whatwg.org/multipage/#await-a-stable-state - #[allow(unsafe_code)] pub fn await_stable_state(task: Microtask) { SCRIPT_THREAD_ROOT.with(|root| { if let Some(script_thread) = root.get() { - unsafe { - let script_thread = &*script_thread; - script_thread - .microtask_queue - .enqueue(task, *script_thread.get_cx()); - } + let script_thread = unsafe { &*script_thread }; + script_thread + .microtask_queue + .enqueue(task, script_thread.get_cx()); } }); } @@ -3776,17 +3773,15 @@ impl ScriptThread { } } - #[allow(unsafe_code)] pub fn enqueue_microtask(job: Microtask) { - SCRIPT_THREAD_ROOT.with(|root| unsafe { - let script_thread = &*root.get().unwrap(); + SCRIPT_THREAD_ROOT.with(|root| { + let script_thread = unsafe { &*root.get().unwrap() }; script_thread .microtask_queue - .enqueue(job, *script_thread.get_cx()); + .enqueue(job, script_thread.get_cx()); }); } - #[allow(unsafe_code)] fn perform_a_microtask_checkpoint(&self) { let globals = self .documents @@ -3795,13 +3790,11 @@ impl ScriptThread { .map(|(_id, document)| document.global()) .collect(); - unsafe { - self.microtask_queue.checkpoint( - *self.get_cx(), - |id| self.documents.borrow().find_global(id), - globals, - ) - } + self.microtask_queue.checkpoint( + self.get_cx(), + |id| self.documents.borrow().find_global(id), + globals, + ) } } diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index c8aad9a6b4c..874f707a739 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -739,7 +739,7 @@ pub fn handle_get_property( Err(_) => Ok(WebDriverJSValue::Undefined), }, Err(error) => { - unsafe { throw_dom_exception(*cx, &node.reflector().global(), error) }; + throw_dom_exception(cx, &node.reflector().global(), error); Ok(WebDriverJSValue::Undefined) }, }