Auto merge of #23872 - marmeladema:issue-20377, r=jdm

Make DOM bindings methods not take raw JSContext pointers. Part 2.

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [ ] `./mach build -d` does not report any errors
- [ ] `./mach test-tidy` does not report any errors
- [ ] These changes fix #20377

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because ___

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23872)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-08-08 22:21:19 -04:00 committed by GitHub
commit da559d47b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 543 additions and 558 deletions

View file

@ -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();

View file

@ -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(())
}

View file

@ -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::<JSObject>());
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
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<NonNull<JSObject>> {
fn GetChannelData(&self, cx: JSContext, channel: u32) -> Fallible<NonNull<JSObject>> {
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);
}

View file

@ -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<Self>;
unsafe fn new(cx: JSContext, callback: *mut JSObject) -> Rc<Self>;
/// 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<JSVal> {
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<JSVal> {
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<T: DomObject>(
cx: *mut JSContext,
p: &T,
mut rval: MutableHandleObject,
) {
pub fn wrap_call_this_object<T: DomObject>(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<GlobalScope>,
/// 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());

View file

@ -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::<JSObject>());
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::<JSObject>());
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::<JSObject>());
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::<JSObject>());
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::<JSObject>());
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::<dom::types::%s>(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::<GlobalScope>(), Error::Type("new.target is null".to_owned()));
throw_dom_exception(cx, global.upcast::<GlobalScope>(), Error::Type("new.target is null".to_owned()));
return false;
}
if args.callee() == new_target.get() {
throw_dom_exception(*cx, global.upcast::<GlobalScope>(),
throw_dom_exception(cx, global.upcast::<GlobalScope>(),
Error::Type("new.target must not be the active function object".to_owned()));
return false;
}
@ -5601,7 +5602,7 @@ let result: Result<DomRoot<%s>, Error> = html_constructor(&global, &args);
let result = match result {
Ok(result) => result,
Err(e) => {
throw_dom_exception(*cx, global.upcast::<GlobalScope>(), e);
throw_dom_exception(cx, global.upcast::<GlobalScope>(), 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<ConversionResult<${actualType}>, ()> {\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::<JSObject>());\n"
"rooted!(in(*s.get_context()) let mut thisObjJS = ptr::null_mut::<JSObject>());\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::<JSObject>());\n"
"rooted!(in(*s.get_context()) let thisObjJS = ptr::null_mut::<JSObject>());\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'

View file

@ -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
));
}
}
}

View file

@ -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<T> = Result<T, Error>;
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);

View file

@ -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<T: Clone + Copy> Guard<T> {
/// 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<T> {
pub fn expose(&self, cx: JSContext, obj: HandleObject, global: HandleObject) -> Option<T> {
if self.condition.is_satisfied(cx, obj, global) {
Some(self.value)
} else {
@ -45,7 +40,7 @@ impl<T: Clone + Copy> Guard<T> {
/// 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),

View file

@ -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
})
);

View file

@ -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::<JSObject>());
rooted!(in(*cx) let mut unscopable_obj = ptr::null_mut::<JSObject>());
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::<JSObject>());
rooted!(in(*cx) let mut constructor = ptr::null_mut::<JSObject>());
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.
/// <http://heycam.github.io/webidl/#es-interface-hasinstance>
unsafe fn has_instance(
cx: *mut JSContext,
fn has_instance(
cx: SafeJSContext,
interface_object: HandleObject,
value: HandleValue,
) -> Result<bool, ()> {
@ -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(

View file

@ -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<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
pub fn new(
iterable: &T,
type_: IteratorType,
wrap: unsafe fn(SafeJSContext, &GlobalScope, Box<IterableIterator<T>>) -> DomRoot<Self>,
wrap: unsafe fn(JSContext, &GlobalScope, Box<IterableIterator<T>>) -> DomRoot<Self>,
) -> DomRoot<Self> {
let iterator = Box::new(IterableIterator {
reflector: Reflector::new(),
@ -76,12 +76,12 @@ impl<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
/// Return the next value from the iterable object.
#[allow(non_snake_case)]
pub fn Next(&self, cx: SafeJSContext) -> Fallible<NonNull<JSObject>> {
pub fn Next(&self, cx: JSContext) -> Fallible<NonNull<JSObject>> {
let index = self.index.get();
rooted!(in(*cx) let mut value = UndefinedValue());
rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
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<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
.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<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
.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<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
.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<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
}
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(())

View file

@ -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,

View file

@ -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<BluetoothPermissionDescriptor, Error> {
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<Promise>,
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<Promise>,
descriptor: &BluetoothPermissionDescriptor,
status: &BluetoothPermissionResult,

View file

@ -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);
}

View file

@ -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 {
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define>
/// Step 10.4
#[allow(unsafe_code)]
unsafe fn get_callback(
cx: *mut JSContext,
fn get_callback(
cx: JSContext,
prototype: HandleObject,
name: &[u8],
) -> Fallible<Option<Rc<Function>>> {
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 {
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-get>
#[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<CustomElementDefinition>, 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;

View file

@ -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<Option<FileReaderResult>>,
cx: *mut JSContext,
cx: JSContext,
_: ReadMetaData,
bytes: &[u8],
) {
unsafe {
rooted!(in(cx) let mut array_buffer = ptr::null_mut::<JSObject>());
rooted!(in(*cx) let mut array_buffer = ptr::null_mut::<JSObject>());
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<StringOrObject> {
fn GetResult(&self, _: JSContext) -> Option<StringOrObject> {
self.result.borrow().as_ref().map(|r| match *r {
FileReaderResult::String(ref string) => StringOrObject::String(string.clone()),
FileReaderResult::ArrayBuffer(ref arr_buffer) => {

View file

@ -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

View file

@ -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<USVString>,
@ -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::<GlobalScope>();
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<JSVal> {
fn GetState(&self, _cx: JSContext) -> Fallible<JSVal> {
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<USVString>,
) -> 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<USVString>,
) -> ErrorResult {
self.push_or_replace_state(*cx, data, title, url, PushOrReplace::Replace)
self.push_or_replace_state(cx, data, title, url, PushOrReplace::Replace)
}
}

View file

@ -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<DomRoot<WebGLRenderingContext>> {
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<DomRoot<WebGL2RenderingContext>> {
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<GLContextAttributes> {
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<GLContextAttributes> {
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<RenderingContext> {
@ -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<DOMString>,
_quality: HandleValue,
) -> Fallible<USVString> {

View file

@ -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<Self::Descriptor, Error>;
fn permission_query(
cx: *mut JSContext,
cx: JSContext,
promise: &Rc<Promise>,
descriptor: &Self::Descriptor,
status: &Self::Status,
);
fn permission_request(
cx: *mut JSContext,
cx: JSContext,
promise: &Rc<Promise>,
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<Promise>>,
) -> Rc<Promise> {
@ -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<Promise> {
self.manipulate(Operation::Query, *cx, permissionDesc, None)
fn Query(&self, cx: JSContext, permissionDesc: *mut JSObject) -> Rc<Promise> {
self.manipulate(Operation::Query, cx, permissionDesc, None)
}
// https://w3c.github.io/permissions/#dom-permissions-request
fn Request(&self, cx: SafeJSContext, permissionDesc: *mut JSObject) -> Rc<Promise> {
self.manipulate(Operation::Request, *cx, permissionDesc, None)
fn Request(&self, cx: JSContext, permissionDesc: *mut JSObject) -> Rc<Promise> {
self.manipulate(Operation::Request, cx, permissionDesc, None)
}
// https://w3c.github.io/permissions/#dom-permissions-revoke
fn Revoke(&self, cx: SafeJSContext, permissionDesc: *mut JSObject) -> Rc<Promise> {
self.manipulate(Operation::Revoke, *cx, permissionDesc, None)
fn Revoke(&self, cx: JSContext, permissionDesc: *mut JSObject) -> Rc<Promise> {
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<PermissionDescriptor, Error> {
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<Promise>,
_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<Promise>,
descriptor: &PermissionDescriptor,
status: &PermissionStatus,

View file

@ -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<Promise>.
trait PromiseHelper {
#[allow(unsafe_code)]
unsafe fn initialize(&self, cx: *mut JSContext);
fn initialize(&self, cx: SafeJSContext);
}
impl PromiseHelper for Rc<Promise> {
#[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<Promise> {
let cx = global.get_cx();
rooted!(in(*cx) let mut obj = ptr::null_mut::<JSObject>());
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<Promise> {
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<Promise> {
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<Promise> {
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<Rc<Promise>> {
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<Rc<Promise>> {
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);
}
}
}

View file

@ -941,29 +941,21 @@ impl TestBindingMethods for TestBinding {
}
#[allow(unrooted_must_root)]
#[allow(unsafe_code)]
fn ReturnResolvedPromise(&self, cx: SafeJSContext, v: HandleValue) -> Fallible<Rc<Promise>> {
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<Rc<Promise>> {
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
}
}

View file

@ -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
}

View file

@ -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<NonNull<JSObject>> {
fn arraybuffer_response(&self, cx: JSContext) -> Option<NonNull<JSObject>> {
// 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::<JSObject>());
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::<JSObject>());
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();
}
}

View file

@ -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) };
}
/// <https://html.spec.whatwg.org/multipage/#perform-a-microtask-checkpoint>
/// Perform a microtask checkpoint, executing all queued microtasks until the queue is empty.
#[allow(unsafe_code)]
pub unsafe fn checkpoint<F>(
pub fn checkpoint<F>(
&self,
cx: *mut JSContext,
cx: JSContext,
target_provider: F,
globalscopes: Vec<DomRoot<GlobalScope>>,
) 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 {

View file

@ -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)
})

View file

@ -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,
)
}
}

View file

@ -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)
},
}