Use safe JSContext when possible in interface.rs

This commit is contained in:
marmeladema 2019-07-27 18:52:12 +01:00
parent 8b070fef52
commit 78034a90d0
6 changed files with 194 additions and 176 deletions

View file

@ -2651,8 +2651,8 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties):
""" """
unforgeables = [] unforgeables = []
defineUnforgeableAttrs = "define_guarded_properties(*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);" defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s, global);"
unforgeableMembers = [ unforgeableMembers = [
(defineUnforgeableAttrs, properties.unforgeable_attrs), (defineUnforgeableAttrs, properties.unforgeable_attrs),
@ -2762,7 +2762,7 @@ class CGWrapGlobalMethod(CGAbstractMethod):
("define_guarded_methods", self.properties.methods), ("define_guarded_methods", self.properties.methods),
("define_guarded_constants", self.properties.consts) ("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] for (function, array) in pairs if array.length() > 0]
values["members"] = "\n".join(members) values["members"] = "\n".join(members)
@ -2772,7 +2772,7 @@ let _rt = RootedTraceable::new(&*raw);
rooted!(in(*cx) let mut obj = ptr::null_mut::<JSObject>()); rooted!(in(*cx) let mut obj = ptr::null_mut::<JSObject>());
create_global_object( create_global_object(
*cx, cx,
&Class.base, &Class.base,
raw as *const libc::c_void, raw as *const libc::c_void,
_trace, _trace,
@ -2911,7 +2911,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
rooted!(in(*cx) let proto = %(proto)s); rooted!(in(*cx) let proto = %(proto)s);
assert!(!proto.is_null()); assert!(!proto.is_null());
rooted!(in(*cx) let mut namespace = ptr::null_mut::<JSObject>()); 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()); %(methods)s, %(name)s, namespace.handle_mut());
assert!(!namespace.is_null()); assert!(!namespace.is_null());
assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
@ -2924,7 +2924,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants() assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants()
return CGGeneric("""\ return CGGeneric("""\
rooted!(in(*cx) let mut interface = ptr::null_mut::<JSObject>()); 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!(!interface.is_null());
assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
(*cache)[PrototypeList::Constructor::%(id)s as usize] = interface.get(); (*cache)[PrototypeList::Constructor::%(id)s as usize] = interface.get();
@ -2976,7 +2976,7 @@ assert!(!prototype_proto.is_null());""" % getPrototypeProto)]
code.append(CGGeneric(""" code.append(CGGeneric("""
rooted!(in(*cx) let mut prototype = ptr::null_mut::<JSObject>()); rooted!(in(*cx) let mut prototype = ptr::null_mut::<JSObject>());
create_interface_prototype_object(*cx, create_interface_prototype_object(cx,
global.into(), global.into(),
prototype_proto.handle().into(), prototype_proto.handle().into(),
&PrototypeClass, &PrototypeClass,
@ -3011,7 +3011,7 @@ assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null());
assert!(!interface_proto.is_null()); assert!(!interface_proto.is_null());
rooted!(in(*cx) let mut interface = ptr::null_mut::<JSObject>()); rooted!(in(*cx) let mut interface = ptr::null_mut::<JSObject>());
create_noncallback_interface_object(*cx, create_noncallback_interface_object(cx,
global.into(), global.into(),
interface_proto.handle(), interface_proto.handle(),
&INTERFACE_OBJECT_CLASS, &INTERFACE_OBJECT_CLASS,
@ -3093,7 +3093,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
specs.append(CGGeneric("(%s as ConstructorClassHook, %s, %d)" % (hook, name, length))) specs.append(CGGeneric("(%s as ConstructorClassHook, %s, %d)" % (hook, name, length)))
values = CGIndenter(CGList(specs, "\n"), 4) values = CGIndenter(CGList(specs, "\n"), 4)
code.append(CGWrapper(values, pre="%s = [\n" % decl, post="\n];")) 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: if self.descriptor.hasUnforgeableMembers:
# We want to use the same JSClass and prototype as the object we'll # We want to use the same JSClass and prototype as the object we'll

View file

@ -4,8 +4,9 @@
//! WebIDL constants. //! WebIDL constants.
use crate::script_runtime::JSContext;
use js::jsapi::JSPROP_READONLY; 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::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, UInt32Value};
use js::rust::wrappers::JS_DefineProperty; use js::rust::wrappers::JS_DefineProperty;
use js::rust::HandleObject; use js::rust::HandleObject;
@ -50,15 +51,17 @@ impl ConstantSpec {
/// Defines constants on `obj`. /// Defines constants on `obj`.
/// Fails on JSAPI failure. /// 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 { for spec in constants {
rooted!(in(cx) let value = spec.get_value()); rooted!(in(*cx) let value = spec.get_value());
assert!(JS_DefineProperty( unsafe {
cx, assert!(JS_DefineProperty(
obj, *cx,
spec.name.as_ptr() as *const libc::c_char, obj,
value.handle(), spec.name.as_ptr() as *const libc::c_char,
(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) as u32 value.handle(),
)); (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) as u32
));
}
} }
} }

View file

@ -6,7 +6,7 @@
use crate::dom::bindings::codegen::InterfaceObjectMap; use crate::dom::bindings::codegen::InterfaceObjectMap;
use crate::dom::bindings::interface::is_exposed_in; use crate::dom::bindings::interface::is_exposed_in;
use js::jsapi::JSContext; use crate::script_runtime::JSContext;
use js::rust::HandleObject; use js::rust::HandleObject;
use servo_config::prefs; use servo_config::prefs;
@ -28,12 +28,7 @@ impl<T: Clone + Copy> Guard<T> {
/// Expose the value if the condition is satisfied. /// Expose the value if the condition is satisfied.
/// ///
/// The passed handle is the object on which the value may be exposed. /// The passed handle is the object on which the value may be exposed.
pub unsafe fn expose( pub fn expose(&self, cx: JSContext, obj: HandleObject, global: HandleObject) -> Option<T> {
&self,
cx: *mut JSContext,
obj: HandleObject,
global: HandleObject,
) -> Option<T> {
if self.condition.is_satisfied(cx, obj, global) { if self.condition.is_satisfied(cx, obj, global) {
Some(self.value) Some(self.value)
} else { } else {
@ -45,7 +40,7 @@ impl<T: Clone + Copy> Guard<T> {
/// A condition to expose things. /// A condition to expose things.
pub enum Condition { pub enum Condition {
/// The condition is satisfied if the function returns true. /// 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. /// The condition is satisfied if the preference is set.
Pref(&'static str), Pref(&'static str),
// The condition is satisfied if the interface is exposed in the global. // The condition is satisfied if the interface is exposed in the global.
@ -55,12 +50,7 @@ pub enum Condition {
} }
impl Condition { impl Condition {
unsafe fn is_satisfied( fn is_satisfied(&self, cx: JSContext, obj: HandleObject, global: HandleObject) -> bool {
&self,
cx: *mut JSContext,
obj: HandleObject,
global: HandleObject,
) -> bool {
match *self { match *self {
Condition::Pref(name) => prefs::pref_map().get(name).as_bool().unwrap_or(false), Condition::Pref(name) => prefs::pref_map().get(name).as_bool().unwrap_or(false),
Condition::Func(f) => f(cx, obj), Condition::Func(f) => f(cx, obj),

View file

@ -12,6 +12,7 @@ use crate::dom::bindings::guard::Guard;
use crate::dom::bindings::utils::{ use crate::dom::bindings::utils::{
get_proto_or_iface_array, ProtoOrIfaceArray, DOM_PROTOTYPE_SLOT, get_proto_or_iface_array, ProtoOrIfaceArray, DOM_PROTOTYPE_SLOT,
}; };
use crate::script_runtime::JSContext as SafeJSContext;
use js::error::throw_type_error; use js::error::throw_type_error;
use js::glue::UncheckedUnwrapObject; use js::glue::UncheckedUnwrapObject;
use js::jsapi::HandleObject as RawHandleObject; 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. /// Create a global object with the given class.
pub unsafe fn create_global_object( pub unsafe fn create_global_object(
cx: *mut JSContext, cx: SafeJSContext,
class: &'static JSClass, class: &'static JSClass,
private: *const libc::c_void, private: *const libc::c_void,
trace: TraceHook, trace: TraceHook,
@ -142,7 +143,7 @@ pub unsafe fn create_global_object(
options.creationOptions_.sharedMemoryAndAtomics_ = true; options.creationOptions_.sharedMemoryAndAtomics_ = true;
rval.set(JS_NewGlobalObject( rval.set(JS_NewGlobalObject(
cx, *cx,
class, class,
ptr::null_mut(), ptr::null_mut(),
OnNewGlobalHookOption::DontFireOnNewGlobalHook, 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); let val = PrivateValue(Box::into_raw(proto_array) as *const libc::c_void);
JS_SetReservedSlot(rval.get(), DOM_PROTOTYPE_SLOT, &val); JS_SetReservedSlot(rval.get(), DOM_PROTOTYPE_SLOT, &val);
let _ac = JSAutoRealm::new(cx, rval.get()); let _ac = JSAutoRealm::new(*cx, rval.get());
JS_FireOnNewGlobalObject(cx, rval.handle()); JS_FireOnNewGlobalObject(*cx, rval.handle());
} }
/// Create and define the interface object of a callback interface. /// Create and define the interface object of a callback interface.
pub unsafe fn create_callback_interface_object( pub fn create_callback_interface_object(
cx: *mut JSContext, cx: SafeJSContext,
global: HandleObject, global: HandleObject,
constants: &[Guard<&[ConstantSpec]>], constants: &[Guard<&[ConstantSpec]>],
name: &[u8], name: &[u8],
mut rval: MutableHandleObject, mut rval: MutableHandleObject,
) { ) {
assert!(!constants.is_empty()); assert!(!constants.is_empty());
rval.set(JS_NewObject(cx, ptr::null())); unsafe {
rval.set(JS_NewObject(*cx, ptr::null()));
}
assert!(!rval.is_null()); assert!(!rval.is_null());
define_guarded_constants(cx, rval.handle(), constants, global); define_guarded_constants(cx, rval.handle(), constants, global);
define_name(cx, rval.handle(), name); 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. /// Create the interface prototype object of a non-callback interface.
pub unsafe fn create_interface_prototype_object( pub fn create_interface_prototype_object(
cx: *mut JSContext, cx: SafeJSContext,
global: HandleObject, global: HandleObject,
proto: HandleObject, proto: HandleObject,
class: &'static JSClass, class: &'static JSClass,
@ -203,27 +206,29 @@ pub unsafe fn create_interface_prototype_object(
); );
if !unscopable_names.is_empty() { 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()); 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); rooted!(in(*cx) let mut unscopable_id: jsid);
assert!(!unscopable_symbol.is_null()); RUST_SYMBOL_TO_JSID(unscopable_symbol, unscopable_id.handle_mut());
rooted!(in(cx) let mut unscopable_id: jsid); assert!(JS_DefinePropertyById5(
RUST_SYMBOL_TO_JSID(unscopable_symbol, unscopable_id.handle_mut()); *cx,
assert!(JS_DefinePropertyById5( rval.handle(),
cx, unscopable_id.handle(),
rval.handle(), unscopable_obj.handle(),
unscopable_id.handle(), JSPROP_READONLY as u32
unscopable_obj.handle(), ))
JSPROP_READONLY as u32 }
))
} }
} }
/// Create and define the interface object of a non-callback interface. /// Create and define the interface object of a non-callback interface.
pub unsafe fn create_noncallback_interface_object( pub fn create_noncallback_interface_object(
cx: *mut JSContext, cx: SafeJSContext,
global: HandleObject, global: HandleObject,
proto: HandleObject, proto: HandleObject,
class: &'static NonCallbackInterfaceObjectClass, class: &'static NonCallbackInterfaceObjectClass,
@ -245,54 +250,58 @@ pub unsafe fn create_noncallback_interface_object(
constants, constants,
rval, rval,
); );
assert!(JS_LinkConstructorAndPrototype( unsafe {
cx, assert!(JS_LinkConstructorAndPrototype(
rval.handle(), *cx,
interface_prototype_object rval.handle(),
)); interface_prototype_object
));
}
define_name(cx, rval.handle(), name); define_name(cx, rval.handle(), name);
define_length(cx, rval.handle(), i32::try_from(length).expect("overflow")); define_length(cx, rval.handle(), i32::try_from(length).expect("overflow"));
define_on_global_object(cx, global, name, rval.handle()); define_on_global_object(cx, global, name, rval.handle());
} }
/// Create and define the named constructors of a non-callback interface. /// Create and define the named constructors of a non-callback interface.
pub unsafe fn create_named_constructors( pub fn create_named_constructors(
cx: *mut JSContext, cx: SafeJSContext,
global: HandleObject, global: HandleObject,
named_constructors: &[(ConstructorClassHook, &[u8], u32)], named_constructors: &[(ConstructorClassHook, &[u8], u32)],
interface_prototype_object: HandleObject, 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 { for &(native, name, arity) in named_constructors {
assert_eq!(*name.last().unwrap(), b'\0'); assert_eq!(*name.last().unwrap(), b'\0');
let fun = JS_NewFunction( unsafe {
cx, let fun = JS_NewFunction(
Some(native), *cx,
arity, Some(native),
JSFUN_CONSTRUCTOR, arity,
name.as_ptr() as *const libc::c_char, JSFUN_CONSTRUCTOR,
); name.as_ptr() as *const libc::c_char,
assert!(!fun.is_null()); );
constructor.set(JS_GetFunctionObject(fun)); assert!(!fun.is_null());
assert!(!constructor.is_null()); constructor.set(JS_GetFunctionObject(fun));
assert!(!constructor.is_null());
assert!(JS_DefineProperty3( assert!(JS_DefineProperty3(
cx, *cx,
constructor.handle(), constructor.handle(),
b"prototype\0".as_ptr() as *const libc::c_char, b"prototype\0".as_ptr() as *const libc::c_char,
interface_prototype_object, interface_prototype_object,
(JSPROP_PERMANENT | JSPROP_READONLY) as u32 (JSPROP_PERMANENT | JSPROP_READONLY) as u32
)); ));
}
define_on_global_object(cx, global, name, constructor.handle()); define_on_global_object(cx, global, name, constructor.handle());
} }
} }
/// Create a new object with a unique type. /// Create a new object with a unique type.
pub unsafe fn create_object( pub fn create_object(
cx: *mut JSContext, cx: SafeJSContext,
global: HandleObject, global: HandleObject,
proto: HandleObject, proto: HandleObject,
class: &'static JSClass, class: &'static JSClass,
@ -301,7 +310,9 @@ pub unsafe fn create_object(
constants: &[Guard<&[ConstantSpec]>], constants: &[Guard<&[ConstantSpec]>],
mut rval: MutableHandleObject, mut rval: MutableHandleObject,
) { ) {
rval.set(JS_NewObjectWithUniqueType(cx, class, proto)); unsafe {
rval.set(JS_NewObjectWithUniqueType(*cx, class, proto));
}
assert!(!rval.is_null()); assert!(!rval.is_null());
define_guarded_methods(cx, rval.handle(), methods, global); define_guarded_methods(cx, rval.handle(), methods, global);
define_guarded_properties(cx, rval.handle(), properties, global); define_guarded_properties(cx, rval.handle(), properties, global);
@ -309,8 +320,8 @@ pub unsafe fn create_object(
} }
/// Conditionally define constants on an object. /// Conditionally define constants on an object.
pub unsafe fn define_guarded_constants( pub fn define_guarded_constants(
cx: *mut JSContext, cx: SafeJSContext,
obj: HandleObject, obj: HandleObject,
constants: &[Guard<&[ConstantSpec]>], constants: &[Guard<&[ConstantSpec]>],
global: HandleObject, global: HandleObject,
@ -323,57 +334,65 @@ pub unsafe fn define_guarded_constants(
} }
/// Conditionally define methods on an object. /// Conditionally define methods on an object.
pub unsafe fn define_guarded_methods( pub fn define_guarded_methods(
cx: *mut JSContext, cx: SafeJSContext,
obj: HandleObject, obj: HandleObject,
methods: &[Guard<&'static [JSFunctionSpec]>], methods: &[Guard<&'static [JSFunctionSpec]>],
global: HandleObject, global: HandleObject,
) { ) {
for guard in methods { for guard in methods {
if let Some(specs) = guard.expose(cx, obj, global) { 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. /// Conditionally define properties on an object.
pub unsafe fn define_guarded_properties( pub fn define_guarded_properties(
cx: *mut JSContext, cx: SafeJSContext,
obj: HandleObject, obj: HandleObject,
properties: &[Guard<&'static [JSPropertySpec]>], properties: &[Guard<&'static [JSPropertySpec]>],
global: HandleObject, global: HandleObject,
) { ) {
for guard in properties { for guard in properties {
if let Some(specs) = guard.expose(cx, obj, global) { 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 /// Returns whether an interface with exposure set given by `globals` should
/// be exposed in the global object `obj`. /// be exposed in the global object `obj`.
pub unsafe fn is_exposed_in(object: HandleObject, globals: Globals) -> bool { pub fn is_exposed_in(object: HandleObject, globals: Globals) -> bool {
let unwrapped = UncheckedUnwrapObject(object.get(), /* stopAtWindowProxy = */ 0); unsafe {
let dom_class = get_dom_class(unwrapped).unwrap(); let unwrapped = UncheckedUnwrapObject(object.get(), /* stopAtWindowProxy = */ 0);
globals.contains(dom_class.global) 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 /// Define a property with a given name on the global object. Should be called
/// through the resolve hook. /// through the resolve hook.
pub unsafe fn define_on_global_object( pub fn define_on_global_object(
cx: *mut JSContext, cx: SafeJSContext,
global: HandleObject, global: HandleObject,
name: &[u8], name: &[u8],
obj: HandleObject, obj: HandleObject,
) { ) {
assert_eq!(*name.last().unwrap(), b'\0'); assert_eq!(*name.last().unwrap(), b'\0');
assert!(JS_DefineProperty3( unsafe {
cx, assert!(JS_DefineProperty3(
global, *cx,
name.as_ptr() as *const libc::c_char, global,
obj, name.as_ptr() as *const libc::c_char,
JSPROP_RESOLVING obj,
)); JSPROP_RESOLVING
));
}
} }
const OBJECT_OPS: ObjectOps = ObjectOps { const OBJECT_OPS: ObjectOps = ObjectOps {
@ -409,6 +428,7 @@ unsafe extern "C" fn has_instance_hook(
value: RawMutableHandleValue, value: RawMutableHandleValue,
rval: *mut bool, rval: *mut bool,
) -> bool { ) -> bool {
let cx = SafeJSContext::from_ptr(cx);
let obj_raw = HandleObject::from_raw(obj); let obj_raw = HandleObject::from_raw(obj);
let val_raw = HandleValue::from_raw(value.handle()); let val_raw = HandleValue::from_raw(value.handle());
match has_instance(cx, obj_raw, val_raw) { 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. /// Return whether a value is an instance of a given prototype.
/// <http://heycam.github.io/webidl/#es-interface-hasinstance> /// <http://heycam.github.io/webidl/#es-interface-hasinstance>
unsafe fn has_instance( fn has_instance(
cx: *mut JSContext, cx: SafeJSContext,
interface_object: HandleObject, interface_object: HandleObject,
value: HandleValue, value: HandleValue,
) -> Result<bool, ()> { ) -> Result<bool, ()> {
@ -432,86 +452,91 @@ unsafe fn has_instance(
return Ok(false); return Ok(false);
} }
rooted!(in(cx) let mut value_out = value.to_object()); 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 = value.to_object());
let js_class = get_object_class(interface_object.get()); unsafe {
let object_class = &*(js_class as *const NonCallbackInterfaceObjectClass); 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( if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject(
value.get(), value.get(),
/* stopAtWindowProxy = */ 0, /* stopAtWindowProxy = */ 0,
)) { )) {
if dom_class.interface_chain[object_class.proto_depth as usize] == object_class.proto_id { if dom_class.interface_chain[object_class.proto_depth as usize] == object_class.proto_id
// Step 4. {
return Ok(true); // Step 4.
return Ok(true);
}
} }
}
// Step 2. // Step 2.
let global = GetNonCCWObjectGlobal(interface_object.get()); let global = GetNonCCWObjectGlobal(interface_object.get());
assert!(!global.is_null()); assert!(!global.is_null());
let proto_or_iface_array = get_proto_or_iface_array(global); 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]); rooted!(in(*cx) let prototype = (*proto_or_iface_array)[object_class.proto_id as usize]);
assert!(!prototype.is_null()); assert!(!prototype.is_null());
// Step 3 only concern legacy callback interface objects (i.e. NodeFilter). // Step 3 only concern legacy callback interface objects (i.e. NodeFilter).
while JS_GetPrototype(cx, value.handle(), value_out.handle_mut()) { while JS_GetPrototype(*cx, value.handle(), value_out.handle_mut()) {
*value = *value_out; *value = *value_out;
if value.is_null() { if value.is_null() {
// Step 5.2. // Step 5.2.
return Ok(false); return Ok(false);
} else if value.get() as *const _ == prototype.get() { } else if value.get() as *const _ == prototype.get() {
// Step 5.3. // Step 5.3.
return Ok(true); return Ok(true);
}
} }
} }
// JS_GetPrototype threw an exception. // JS_GetPrototype threw an exception.
Err(()) Err(())
} }
unsafe fn create_unscopable_object( fn create_unscopable_object(cx: SafeJSContext, names: &[&[u8]], mut rval: MutableHandleObject) {
cx: *mut JSContext,
names: &[&[u8]],
mut rval: MutableHandleObject,
) {
assert!(!names.is_empty()); assert!(!names.is_empty());
assert!(rval.is_null()); assert!(rval.is_null());
rval.set(JS_NewPlainObject(cx)); unsafe {
assert!(!rval.is_null()); rval.set(JS_NewPlainObject(*cx));
for &name in names { assert!(!rval.is_null());
assert_eq!(*name.last().unwrap(), b'\0'); for &name in names {
assert!(JS_DefineProperty( assert_eq!(*name.last().unwrap(), b'\0');
cx, assert!(JS_DefineProperty(
rval.handle(), *cx,
name.as_ptr() as *const libc::c_char, rval.handle(),
HandleValue::from_raw(TrueHandleValue), name.as_ptr() as *const libc::c_char,
JSPROP_READONLY as u32, 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]) { fn define_length(cx: SafeJSContext, obj: HandleObject, length: i32) {
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!(JS_DefineProperty5(
assert!(!name.is_null()); *cx,
assert!(JS_DefineProperty4( obj,
cx, b"length\0".as_ptr() as *const libc::c_char,
obj, length,
b"name\0".as_ptr() as *const libc::c_char, JSPROP_READONLY as u32
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
));
} }
unsafe extern "C" fn invalid_constructor( unsafe extern "C" fn invalid_constructor(

View file

@ -6,7 +6,8 @@
use crate::dom::bindings::guard::Guard; use crate::dom::bindings::guard::Guard;
use crate::dom::bindings::interface::{create_object, define_on_global_object}; 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}; use js::rust::{HandleObject, MutableHandleObject};
/// The class of a namespace object. /// The class of a namespace object.
@ -28,8 +29,8 @@ impl NamespaceObjectClass {
} }
/// Create a new namespace object. /// Create a new namespace object.
pub unsafe fn create_namespace_object( pub fn create_namespace_object(
cx: *mut JSContext, cx: JSContext,
global: HandleObject, global: HandleObject,
proto: HandleObject, proto: HandleObject,
class: &'static NamespaceObjectClass, class: &'static NamespaceObjectClass,

View file

@ -1090,12 +1090,11 @@ impl TestBinding {
pub fn FuncControlledStaticMethodEnabled(_: &GlobalScope) {} pub fn FuncControlledStaticMethodEnabled(_: &GlobalScope) {}
} }
#[allow(unsafe_code)]
impl TestBinding { impl TestBinding {
pub unsafe fn condition_satisfied(_: *mut JSContext, _: HandleObject) -> bool { pub fn condition_satisfied(_: SafeJSContext, _: HandleObject) -> bool {
true true
} }
pub unsafe fn condition_unsatisfied(_: *mut JSContext, _: HandleObject) -> bool { pub fn condition_unsatisfied(_: SafeJSContext, _: HandleObject) -> bool {
false false
} }
} }