diff options
author | yvt <i@yvt.jp> | 2021-07-10 17:24:27 +0900 |
---|---|---|
committer | yvt <i@yvt.jp> | 2021-07-10 17:55:42 +0900 |
commit | 01a7de50ab1843d85295f9dccad7f4c099e7208c (patch) | |
tree | ee53fb6e8889deb7b880ee969e6c662e6128d210 /components/script/dom/bindings/interface.rs | |
parent | ff8d2cdbbfc7a9dc7f38b7dd47cb350fde39388f (diff) | |
parent | 94b613fbdaa2b98f2179fc0bbda13c64e6fa0d38 (diff) | |
download | servo-01a7de50ab1843d85295f9dccad7f4c099e7208c.tar.gz servo-01a7de50ab1843d85295f9dccad7f4c099e7208c.zip |
Merge remote-tracking branch 'upstream/master' into feat-cow-infra
`tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html`
was reverted to the upstream version.
Diffstat (limited to 'components/script/dom/bindings/interface.rs')
-rw-r--r-- | components/script/dom/bindings/interface.rs | 637 |
1 files changed, 347 insertions, 290 deletions
diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 3138c00cb89..e982a001fb0 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -1,42 +1,52 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ //! Machinery to initialise interface prototype objects and interface objects. -use dom::bindings::codegen::InterfaceObjectMap::Globals; -use dom::bindings::codegen::PrototypeList; -use dom::bindings::constant::{ConstantSpec, define_constants}; -use dom::bindings::conversions::{DOM_OBJECT_SLOT, get_dom_class}; -use dom::bindings::guard::Guard; -use dom::bindings::utils::{DOM_PROTOTYPE_SLOT, ProtoOrIfaceArray, get_proto_or_iface_array}; +use crate::dom::bindings::codegen::InterfaceObjectMap::Globals; +use crate::dom::bindings::codegen::PrototypeList; +use crate::dom::bindings::constant::{define_constants, ConstantSpec}; +use crate::dom::bindings::conversions::{get_dom_class, DOM_OBJECT_SLOT}; +use crate::dom::bindings::guard::Guard; +use crate::dom::bindings::utils::{ProtoOrIfaceArray, DOM_PROTOTYPE_SLOT}; +use crate::script_runtime::JSContext as SafeJSContext; use dom::window::Window; use js::error::throw_type_error; -use js::glue::{CreateRustJSPrincipal, RUST_SYMBOL_TO_JSID, UncheckedUnwrapObject}; -use js::jsapi::{Class, ClassOps, CompartmentOptions, GetGlobalForObjectCrossCompartment}; -use js::jsapi::{GetWellKnownSymbol, HandleObject, HandleValue, JSAutoCompartment}; -use js::jsapi::{JSClass, JSContext, JSFUN_CONSTRUCTOR, JSFunctionSpec, JSObject}; -use js::jsapi::{JSPROP_PERMANENT, JSPROP_READONLY, JSPROP_RESOLVING}; -use js::jsapi::{JSPropertySpec, JSString, JSTracer, JSVersion, JS_AtomizeAndPinString}; -use js::jsapi::{JS_DefineProperty, JS_DefineProperty1, JS_DefineProperty2}; -use js::jsapi::{JS_DefineProperty4, JS_DefinePropertyById3, JS_FireOnNewGlobalObject}; -use js::jsapi::{JS_GetFunctionObject, JS_GetPrototype}; -use js::jsapi::{JS_LinkConstructorAndPrototype, JS_NewFunction, JS_NewGlobalObject}; -use js::jsapi::{JS_NewObject, JS_NewObjectWithUniqueType, JS_NewPlainObject}; -use js::jsapi::{JS_NewStringCopyN, JS_SetReservedSlot, MutableHandleObject}; -use js::jsapi::{MutableHandleValue, ObjectOps, OnNewGlobalHookOption, SymbolCode}; +use js::glue::UncheckedUnwrapObject; +use js::jsapi::GetWellKnownSymbol; +use js::jsapi::HandleObject as RawHandleObject; +use js::jsapi::{jsid, JSClass, JSClassOps}; +use js::jsapi::{ + Compartment, CompartmentSpecifier, IsSharableCompartment, IsSystemCompartment, + JS_IterateCompartments, JS::CompartmentIterResult, +}; +use js::jsapi::{JSAutoRealm, JSContext, JSFunctionSpec, JSObject, JSFUN_CONSTRUCTOR}; +use js::jsapi::{JSPropertySpec, JSString, JSTracer, JS_AtomizeAndPinString}; +use js::jsapi::{JS_GetFunctionObject, JS_NewFunction, JS_NewGlobalObject}; +use js::jsapi::{JS_NewObject, JS_NewPlainObject}; +use js::jsapi::{JS_NewStringCopyN, JS_SetReservedSlot}; +use js::jsapi::{ObjectOps, OnNewGlobalHookOption, SymbolCode}; use js::jsapi::{TrueHandleValue, Value}; +use js::jsapi::{JSPROP_PERMANENT, JSPROP_READONLY, JSPROP_RESOLVING}; use js::jsval::{JSVal, PrivateValue}; +use js::rust::wrappers::JS_FireOnNewGlobalObject; +use js::rust::wrappers::RUST_SYMBOL_TO_JSID; +use js::rust::wrappers::{JS_DefineProperty, JS_DefineProperty5}; +use js::rust::wrappers::{JS_DefineProperty3, JS_DefineProperty4, JS_DefinePropertyById5}; +use js::rust::wrappers::{JS_LinkConstructorAndPrototype, JS_NewObjectWithGivenProto}; use js::rust::{define_methods, define_properties, get_object_class}; +use js::rust::{HandleObject, HandleValue, MutableHandleObject, RealmOptions}; use libc; use servo_url::MutableOrigin; +use std::convert::TryFrom; use std::ptr; /// The class of a non-callback interface object. -#[derive(Copy, Clone)] +#[derive(Clone, Copy)] pub struct NonCallbackInterfaceObjectClass { - /// The SpiderMonkey Class structure. - pub class: Class, + /// The SpiderMonkey class structure. + pub class: JSClass, /// The prototype id of that interface, used in the hasInstance hook. pub proto_id: PrototypeList::ID, /// The prototype depth of that interface, used in the hasInstance hook. @@ -49,18 +59,19 @@ unsafe impl Sync for NonCallbackInterfaceObjectClass {} impl NonCallbackInterfaceObjectClass { /// Create a new `NonCallbackInterfaceObjectClass` structure. - pub const fn new(constructor_behavior: &'static InterfaceConstructorBehavior, - string_rep: &'static [u8], - proto_id: PrototypeList::ID, - proto_depth: u16) - -> NonCallbackInterfaceObjectClass { + pub const fn new( + constructor_behavior: &'static InterfaceConstructorBehavior, + string_rep: &'static [u8], + proto_id: PrototypeList::ID, + proto_depth: u16, + ) -> NonCallbackInterfaceObjectClass { NonCallbackInterfaceObjectClass { - class: Class { + class: JSClass { name: b"Function\0" as *const _ as *const libc::c_char, flags: 0, cOps: &constructor_behavior.0, - spec: ptr::null(), - ext: ptr::null(), + spec: 0 as *const _, + ext: 0 as *const _, oOps: &OBJECT_OPS, }, proto_id: proto_id, @@ -71,9 +82,7 @@ impl NonCallbackInterfaceObjectClass { /// cast own reference to `JSClass` reference pub fn as_jsclass(&self) -> &JSClass { - unsafe { - &*(self as *const _ as *const JSClass) - } + unsafe { &*(self as *const _ as *const JSClass) } } } @@ -82,263 +91,363 @@ pub type ConstructorClassHook = unsafe extern "C" fn(cx: *mut JSContext, argc: u32, vp: *mut Value) -> bool; /// The constructor behavior of a non-callback interface object. -pub struct InterfaceConstructorBehavior(ClassOps); +pub struct InterfaceConstructorBehavior(JSClassOps); impl InterfaceConstructorBehavior { /// An interface constructor that unconditionally throws a type error. pub const fn throw() -> Self { - InterfaceConstructorBehavior(ClassOps { + InterfaceConstructorBehavior(JSClassOps { addProperty: None, delProperty: None, - getProperty: None, - setProperty: None, enumerate: None, + newEnumerate: None, resolve: None, mayResolve: None, finalize: None, call: Some(invalid_constructor), construct: Some(invalid_constructor), - hasInstance: Some(has_instance_hook), + hasInstance: None, // heycam/webidl#356 trace: None, }) } /// An interface constructor that calls a native Rust function. pub const fn call(hook: ConstructorClassHook) -> Self { - InterfaceConstructorBehavior(ClassOps { + InterfaceConstructorBehavior(JSClassOps { addProperty: None, delProperty: None, - getProperty: None, - setProperty: None, enumerate: None, + newEnumerate: None, resolve: None, mayResolve: None, finalize: None, call: Some(non_new_constructor), construct: Some(hook), - hasInstance: Some(has_instance_hook), + hasInstance: None, // heycam/webidl#356 trace: None, }) } } /// A trace hook. -pub type TraceHook = - unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject); +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, - class: &'static JSClass, - private: *const libc::c_void, - trace: TraceHook, - rval: MutableHandleObject, - origin: &MutableOrigin) { + cx: SafeJSContext, + class: &'static JSClass, + private: *const libc::c_void, + trace: TraceHook, + mut rval: MutableHandleObject, + origin: &MutableOrigin, +) { assert!(rval.is_null()); - let mut options = CompartmentOptions::default(); - options.behaviors_.version_ = JSVersion::JSVERSION_ECMA_5; + let mut options = RealmOptions::default(); options.creationOptions_.traceGlobal_ = Some(trace); - options.creationOptions_.sharedMemoryAndAtomics_ = true; + options.creationOptions_.sharedMemoryAndAtomics_ = false; + options.creationOptions_.streams_ = true; + select_compartment(cx, &mut options); let origin = Box::new(origin.clone()); - let mut principal = CreateRustJSPrincipal(Box::into_raw(origin) as *const ::libc::c_void, - None, - None); - - rval.set(JS_NewGlobalObject(cx, - class, - principal, - OnNewGlobalHookOption::DontFireOnNewGlobalHook, - &options)); + let mut principal = + CreateRustJSPrincipal(Box::into_raw(origin) as *const ::libc::c_void, None, None); + + rval.set(JS_NewGlobalObject( + *cx, + class, + principal, + OnNewGlobalHookOption::DontFireOnNewGlobalHook, + &*options, + )); assert!(!rval.is_null()); // Initialize the reserved slots before doing anything that can GC, to // avoid getting trace hooks called on a partially initialized object. - JS_SetReservedSlot(rval.get(), DOM_OBJECT_SLOT, PrivateValue(private)); + let private_val = PrivateValue(private); + JS_SetReservedSlot(rval.get(), DOM_OBJECT_SLOT, &private_val); let proto_array: Box<ProtoOrIfaceArray> = - box [0 as *mut JSObject; PrototypeList::PROTO_OR_IFACE_LENGTH]; - JS_SetReservedSlot(rval.get(), - DOM_PROTOTYPE_SLOT, - PrivateValue(Box::into_raw(proto_array) as *const libc::c_void)); + Box::new([0 as *mut JSObject; PrototypeList::PROTO_OR_IFACE_LENGTH]); + let val = PrivateValue(Box::into_raw(proto_array) as *const libc::c_void); + JS_SetReservedSlot(rval.get(), DOM_PROTOTYPE_SLOT, &val); - let _ac = JSAutoCompartment::new(cx, rval.get()); - JS_FireOnNewGlobalObject(cx, rval.handle()); + let _ac = JSAutoRealm::new(*cx, rval.get()); + JS_FireOnNewGlobalObject(*cx, rval.handle()); +} + +/// Choose the compartment to create a new global object in. +fn select_compartment(cx: SafeJSContext, options: &mut RealmOptions) { + type Data = *mut Compartment; + unsafe extern "C" fn callback( + _cx: *mut JSContext, + data: *mut libc::c_void, + compartment: *mut Compartment, + ) -> CompartmentIterResult { + let data = data as *mut Data; + + if !IsSharableCompartment(compartment) || IsSystemCompartment(compartment) { + return CompartmentIterResult::KeepGoing; + } + + // Choose any sharable, non-system compartment in this context to allow + // same-agent documents to share JS and DOM objects. + *data = compartment; + CompartmentIterResult::Stop + } + + let mut compartment: Data = ptr::null_mut(); + unsafe { + JS_IterateCompartments( + *cx, + (&mut compartment) as *mut Data as *mut libc::c_void, + Some(callback), + ); + } + + if compartment.is_null() { + options.creationOptions_.compSpec_ = CompartmentSpecifier::NewCompartmentAndZone; + } else { + options.creationOptions_.compSpec_ = CompartmentSpecifier::ExistingCompartment; + options.creationOptions_.__bindgen_anon_1.comp_ = compartment; + } } /// Create and define the interface object of a callback interface. -pub unsafe fn create_callback_interface_object( - cx: *mut JSContext, - global: HandleObject, - constants: &[Guard<&[ConstantSpec]>], - name: &[u8], - rval: MutableHandleObject) { +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())); - assert!(!rval.ptr.is_null()); - define_guarded_constants(cx, rval.handle(), constants); + 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); define_on_global_object(cx, global, name, rval.handle()); } /// Create the interface prototype object of a non-callback interface. -pub unsafe fn create_interface_prototype_object( - cx: *mut JSContext, - proto: HandleObject, - class: &'static JSClass, - regular_methods: &[Guard<&'static [JSFunctionSpec]>], - regular_properties: &[Guard<&'static [JSPropertySpec]>], - constants: &[Guard<&[ConstantSpec]>], - unscopable_names: &[&[u8]], - rval: MutableHandleObject) { - create_object(cx, proto, class, regular_methods, regular_properties, constants, rval); +pub fn create_interface_prototype_object( + cx: SafeJSContext, + global: HandleObject, + proto: HandleObject, + class: &'static JSClass, + regular_methods: &[Guard<&'static [JSFunctionSpec]>], + regular_properties: &[Guard<&'static [JSPropertySpec]>], + constants: &[Guard<&[ConstantSpec]>], + unscopable_names: &[&[u8]], + rval: MutableHandleObject, +) { + create_object( + cx, + global, + proto, + class, + regular_methods, + regular_properties, + constants, + rval, + ); if !unscopable_names.is_empty() { - rooted!(in(cx) let mut unscopable_obj = ptr::null_mut()); + rooted!(in(*cx) let mut unscopable_obj = ptr::null_mut::<JSObject>()); create_unscopable_object(cx, unscopable_names, unscopable_obj.handle_mut()); - - let unscopable_symbol = GetWellKnownSymbol(cx, SymbolCode::unscopables); - assert!(!unscopable_symbol.is_null()); - - rooted!(in(cx) let unscopable_id = RUST_SYMBOL_TO_JSID(unscopable_symbol)); - assert!(JS_DefinePropertyById3( - cx, rval.handle(), unscopable_id.handle(), unscopable_obj.handle(), - JSPROP_READONLY, None, None)) + unsafe { + 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()); + + 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, - global: HandleObject, - proto: HandleObject, - class: &'static NonCallbackInterfaceObjectClass, - static_methods: &[Guard<&'static [JSFunctionSpec]>], - static_properties: &[Guard<&'static [JSPropertySpec]>], - constants: &[Guard<&[ConstantSpec]>], - interface_prototype_object: HandleObject, - name: &[u8], - length: u32, - rval: MutableHandleObject) { - create_object(cx, - proto, - class.as_jsclass(), - static_methods, - static_properties, - constants, - rval); - assert!(JS_LinkConstructorAndPrototype(cx, rval.handle(), interface_prototype_object)); +pub fn create_noncallback_interface_object( + cx: SafeJSContext, + global: HandleObject, + proto: HandleObject, + class: &'static NonCallbackInterfaceObjectClass, + static_methods: &[Guard<&'static [JSFunctionSpec]>], + static_properties: &[Guard<&'static [JSPropertySpec]>], + constants: &[Guard<&[ConstantSpec]>], + interface_prototype_object: HandleObject, + name: &[u8], + length: u32, + legacy_window_alias_names: &[&[u8]], + rval: MutableHandleObject, +) { + create_object( + cx, + global, + proto, + class.as_jsclass(), + static_methods, + static_properties, + constants, + rval, + ); + unsafe { + assert!(JS_LinkConstructorAndPrototype( + *cx, + rval.handle(), + interface_prototype_object + )); + } define_name(cx, rval.handle(), name); - define_length(cx, rval.handle(), length); + define_length(cx, rval.handle(), i32::try_from(length).expect("overflow")); define_on_global_object(cx, global, name, rval.handle()); + + if is_exposed_in(global, Globals::WINDOW) { + for legacy_window_alias in legacy_window_alias_names { + define_on_global_object(cx, global, legacy_window_alias, rval.handle()); + } + } } /// Create and define the named constructors of a non-callback interface. -pub unsafe fn create_named_constructors( - cx: *mut JSContext, - global: HandleObject, - named_constructors: &[(ConstructorClassHook, &[u8], u32)], - interface_prototype_object: HandleObject) { - rooted!(in(cx) let mut constructor = ptr::null_mut()); +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>()); for &(native, name, arity) in named_constructors { - assert!(*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()); - - assert!(JS_DefineProperty1(cx, - constructor.handle(), - b"prototype\0".as_ptr() as *const libc::c_char, - interface_prototype_object, - JSPROP_PERMANENT | JSPROP_READONLY, - None, - None)); + assert_eq!(*name.last().unwrap(), b'\0'); + + 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 + )); + } 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, - proto: HandleObject, - class: &'static JSClass, - methods: &[Guard<&'static [JSFunctionSpec]>], - properties: &[Guard<&'static [JSPropertySpec]>], - constants: &[Guard<&[ConstantSpec]>], - rval: MutableHandleObject) { - rval.set(JS_NewObjectWithUniqueType(cx, class, proto)); - assert!(!rval.ptr.is_null()); - define_guarded_methods(cx, rval.handle(), methods); - define_guarded_properties(cx, rval.handle(), properties); - define_guarded_constants(cx, rval.handle(), constants); +pub fn create_object( + cx: SafeJSContext, + global: HandleObject, + proto: HandleObject, + class: &'static JSClass, + methods: &[Guard<&'static [JSFunctionSpec]>], + properties: &[Guard<&'static [JSPropertySpec]>], + constants: &[Guard<&[ConstantSpec]>], + mut rval: MutableHandleObject, +) { + unsafe { + rval.set(JS_NewObjectWithGivenProto(*cx, class, proto)); + } + assert!(!rval.is_null()); + define_guarded_methods(cx, rval.handle(), methods, global); + define_guarded_properties(cx, rval.handle(), properties, global); + define_guarded_constants(cx, rval.handle(), constants, global); } /// Conditionally define constants on an object. -pub unsafe fn define_guarded_constants( - cx: *mut JSContext, - obj: HandleObject, - constants: &[Guard<&[ConstantSpec]>]) { +pub fn define_guarded_constants( + cx: SafeJSContext, + obj: HandleObject, + constants: &[Guard<&[ConstantSpec]>], + global: HandleObject, +) { for guard in constants { - if let Some(specs) = guard.expose(cx, obj) { + if let Some(specs) = guard.expose(cx, obj, global) { define_constants(cx, obj, specs); } } } /// Conditionally define methods on an object. -pub unsafe fn define_guarded_methods( - cx: *mut JSContext, - obj: HandleObject, - methods: &[Guard<&'static [JSFunctionSpec]>]) { +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) { - define_methods(cx, obj, specs).unwrap(); + if let Some(specs) = guard.expose(cx, obj, global) { + unsafe { + define_methods(*cx, obj, specs).unwrap(); + } } } } /// Conditionally define properties on an object. -pub unsafe fn define_guarded_properties( - cx: *mut JSContext, - obj: HandleObject, - properties: &[Guard<&'static [JSPropertySpec]>]) { +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) { - define_properties(cx, obj, specs).unwrap(); + if let Some(specs) = guard.expose(cx, obj, global) { + 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, - global: HandleObject, - name: &[u8], - obj: HandleObject) { - assert!(*name.last().unwrap() == b'\0'); - assert!(JS_DefineProperty1(cx, - global, - name.as_ptr() as *const libc::c_char, - obj, - JSPROP_RESOLVING, - None, None)); +pub fn define_on_global_object( + cx: SafeJSContext, + global: HandleObject, + name: &[u8], + obj: HandleObject, +) { + assert_eq!(*name.last().unwrap(), b'\0'); + unsafe { + assert!(JS_DefineProperty3( + *cx, + global, + name.as_ptr() as *const libc::c_char, + obj, + JSPROP_RESOLVING + )); + } } const OBJECT_OPS: ObjectOps = ObjectOps { @@ -349,17 +458,15 @@ const OBJECT_OPS: ObjectOps = ObjectOps { setProperty: None, getOwnPropertyDescriptor: None, deleteProperty: None, - watch: None, - unwatch: None, getElements: None, - enumerate: None, funToString: Some(fun_to_string_hook), }; -unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext, - obj: HandleObject, - _indent: u32) - -> *mut JSString { +unsafe extern "C" fn fun_to_string_hook( + cx: *mut JSContext, + obj: RawHandleObject, + _is_to_source: bool, +) -> *mut JSString { let js_class = get_object_class(obj.get()); assert!(!js_class.is_null()); let repr = (*(js_class as *const NonCallbackInterfaceObjectClass)).representation; @@ -369,116 +476,66 @@ unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext, ret } -/// Hook for instanceof on interface objects. -unsafe extern "C" fn has_instance_hook(cx: *mut JSContext, - obj: HandleObject, - value: MutableHandleValue, - rval: *mut bool) -> bool { - match has_instance(cx, obj, value.handle()) { - Ok(result) => { - *rval = result; - true +fn create_unscopable_object(cx: SafeJSContext, names: &[&[u8]], mut rval: MutableHandleObject) { + assert!(!names.is_empty()); + assert!(rval.is_null()); + 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, + )); } - Err(()) => false, } } -/// 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, - interface_object: HandleObject, - value: HandleValue) - -> Result<bool, ()> { - if !value.is_object() { - // Step 1. - return Ok(false); +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 + )); } - 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); - - 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 = GetGlobalForObjectCrossCompartment(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.handle_mut()) { - 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]], - rval: MutableHandleObject) { - assert!(!names.is_empty()); - assert!(rval.is_null()); - rval.set(JS_NewPlainObject(cx)); - assert!(!rval.ptr.is_null()); - for &name in names { - assert!(*name.last().unwrap() == b'\0'); - assert!(JS_DefineProperty( - cx, rval.handle(), name.as_ptr() as *const libc::c_char, TrueHandleValue, - JSPROP_READONLY, None, None)); +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 fn define_name(cx: *mut JSContext, obj: HandleObject, name: &[u8]) { - assert!(*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_DefineProperty2(cx, - obj, - b"name\0".as_ptr() as *const libc::c_char, - name.handle(), - JSPROP_READONLY, - None, None)); -} - -unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: u32) { - assert!(JS_DefineProperty4(cx, - obj, - b"length\0".as_ptr() as *const libc::c_char, - length, - JSPROP_READONLY, - None, None)); -} - unsafe extern "C" fn invalid_constructor( - cx: *mut JSContext, - _argc: libc::c_uint, - _vp: *mut JSVal) - -> bool { + cx: *mut JSContext, + _argc: libc::c_uint, + _vp: *mut JSVal, +) -> bool { throw_type_error(cx, "Illegal constructor."); false } unsafe extern "C" fn non_new_constructor( - cx: *mut JSContext, - _argc: libc::c_uint, - _vp: *mut JSVal) - -> bool { + cx: *mut JSContext, + _argc: libc::c_uint, + _vp: *mut JSVal, +) -> bool { throw_type_error(cx, "This constructor needs to be called with `new`."); false } |