diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2019-06-26 18:51:14 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-26 18:51:14 -0400 |
commit | 57205318c5f76fead08e6410512bad86c6d04739 (patch) | |
tree | aec57e35501e04290e25f2b006dcbc1547d33315 /components/script | |
parent | d170f43b53c840b5f6a1f657968092c096a171e9 (diff) | |
parent | 63714c90fb5bbad86f28fc188120b2ecfd3337ab (diff) | |
download | servo-57205318c5f76fead08e6410512bad86c6d04739.tar.gz servo-57205318c5f76fead08e6410512bad86c6d04739.zip |
Auto merge of #23587 - jdm:smup67, r=asajeffrey
Upgrade to SpiderMonkey 67
<!-- 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/23587)
<!-- Reviewable:end -->
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/audiobuffer.rs | 4 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 23 | ||||
-rw-r--r-- | components/script/dom/bindings/conversions.rs | 74 | ||||
-rw-r--r-- | components/script/dom/bindings/error.rs | 6 | ||||
-rw-r--r-- | components/script/dom/bindings/htmlconstructor.rs | 4 | ||||
-rw-r--r-- | components/script/dom/bindings/proxyhandler.rs | 34 | ||||
-rw-r--r-- | components/script/dom/bindings/structuredclone.rs | 4 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 4 | ||||
-rw-r--r-- | components/script/dom/bindings/utils.rs | 17 | ||||
-rw-r--r-- | components/script/dom/customelementregistry.rs | 4 | ||||
-rw-r--r-- | components/script/dom/globalscope.rs | 53 | ||||
-rw-r--r-- | components/script/dom/promise.rs | 2 | ||||
-rw-r--r-- | components/script/dom/windowproxy.rs | 10 | ||||
-rw-r--r-- | components/script/dom/workerglobalscope.rs | 2 | ||||
-rw-r--r-- | components/script/microtask.rs | 24 | ||||
-rw-r--r-- | components/script/script_runtime.rs | 84 | ||||
-rw-r--r-- | components/script/script_thread.rs | 32 |
17 files changed, 250 insertions, 131 deletions
diff --git a/components/script/dom/audiobuffer.rs b/components/script/dom/audiobuffer.rs index f36e28ad089..be31e56b3e9 100644 --- a/components/script/dom/audiobuffer.rs +++ b/components/script/dom/audiobuffer.rs @@ -15,7 +15,7 @@ use crate::dom::window::Window; use dom_struct::dom_struct; use js::jsapi::JS_GetArrayBufferViewBuffer; use js::jsapi::{Heap, JSAutoRealm, JSContext, JSObject}; -use js::rust::wrappers::JS_DetachArrayBuffer; +use js::rust::wrappers::DetachArrayBuffer; use js::rust::CustomAutoRooterGuard; use js::typedarray::{CreateWith, Float32Array}; use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer; @@ -180,7 +180,7 @@ impl AudioBuffer { JS_GetArrayBufferViewBuffer(cx, channel.handle(), &mut is_shared)); // This buffer is always created unshared debug_assert!(!is_shared); - let _ = JS_DetachArrayBuffer(cx, view_buffer.handle()); + let _ = DetachArrayBuffer(cx, view_buffer.handle()); data } else { return None; diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index d365537e464..dcbdea765d4 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -466,7 +466,7 @@ class CGMethodCall(CGThing): # Check for vanilla JS objects # XXXbz Do we need to worry about security wrappers? - pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object())" % + pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object(), cx)" % (distinguishingArg, distinguishingArg), lambda s: (s[1][distinguishingIndex].type.isCallback() or s[1][distinguishingIndex].type.isCallbackInterface() or @@ -798,7 +798,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, { // Scope for our JSAutoRealm. rooted!(in(cx) let globalObj = CurrentGlobalOrNull(cx)); - let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get()); + let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get(), cx); rooted!(in(cx) let mut valueToResolve = $${val}.get()); if !JS_WrapValue(cx, valueToResolve.handle_mut()) { @@ -866,7 +866,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, templateBody = fill( """ - match ${function}($${val}) { + match ${function}($${val}, cx) { Ok(val) => val, Err(()) => { $*{failureCode} @@ -2158,8 +2158,8 @@ class CGDOMJSClass(CGThing): static CLASS_OPS: js::jsapi::JSClassOps = js::jsapi::JSClassOps { addProperty: None, delProperty: None, - enumerate: %(enumerateHook)s, - newEnumerate: None, + enumerate: None, + newEnumerate: %(enumerateHook)s, resolve: %(resolveHook)s, mayResolve: None, finalize: Some(%(finalizeHook)s), @@ -3223,7 +3223,6 @@ let traps = ProxyTraps { set: None, call: None, construct: None, - getPropertyDescriptor: Some(get_property_descriptor), hasOwn: Some(hasOwn), getOwnEnumerablePropertyKeys: Some(%(getOwnEnumerablePropertyKeys)s), nativeCall: None, @@ -4980,10 +4979,6 @@ class CGProxyUnwrap(CGAbstractMethod): def definition_body(self): return CGGeneric("""\ -/*if (xpc::WrapperFactory::IsXrayWrapper(obj)) { - obj = js::UnwrapObject(obj); -}*/ -//MOZ_ASSERT(IsProxy(obj)); let mut slot = UndefinedValue(); GetProxyReservedSlot(obj.get(), 0, &mut slot); let box_ = slot.to_private() as *const %s; @@ -5430,7 +5425,7 @@ class CGAbstractClassHook(CGAbstractExternMethod): def definition_body_prologue(self): return CGGeneric(""" -let this = native_from_object::<%s>(obj).unwrap(); +let this = native_from_object_static::<%s>(obj).unwrap(); """ % self.descriptor.concreteType) def definition_body(self): @@ -5530,7 +5525,7 @@ let global = DomRoot::downcast::<dom::types::%s>(global).unwrap(); // The new_target might be a cross-compartment wrapper. Get the underlying object // so we can do the spec's object-identity checks. -rooted!(in(cx) let new_target = UnwrapObject(args.new_target().to_object(), 1)); +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())); return false; @@ -5877,7 +5872,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::glue::RUST_JSID_IS_STRING', 'js::glue::RUST_SYMBOL_TO_JSID', 'js::glue::int_to_jsid', - 'js::glue::UnwrapObject', + 'js::glue::UnwrapObjectDynamic', 'js::panic::maybe_resume_unwind', 'js::panic::wrap_panic', 'js::rust::GCMethods', @@ -5959,6 +5954,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::conversions::is_array_like', 'crate::dom::bindings::conversions::native_from_handlevalue', 'crate::dom::bindings::conversions::native_from_object', + 'crate::dom::bindings::conversions::native_from_object_static', 'crate::dom::bindings::conversions::private_from_object', 'crate::dom::bindings::conversions::root_from_handleobject', 'crate::dom::bindings::conversions::root_from_handlevalue', @@ -5979,7 +5975,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::proxyhandler::ensure_expando_object', 'crate::dom::bindings::proxyhandler::fill_property_descriptor', 'crate::dom::bindings::proxyhandler::get_expando_object', - 'crate::dom::bindings::proxyhandler::get_property_descriptor', 'crate::dom::bindings::mozmap::MozMap', 'std::ptr::NonNull', 'crate::dom::bindings::num::Finite', diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs index 0776d39fdcb..161354479b6 100644 --- a/components/script/dom/bindings/conversions.rs +++ b/components/script/dom/bindings/conversions.rs @@ -46,7 +46,7 @@ pub use js::conversions::{ConversionResult, FromJSValConvertible, ToJSValConvert use js::error::throw_type_error; use js::glue::GetProxyReservedSlot; use js::glue::JS_GetReservedSlot; -use js::glue::{IsWrapper, UnwrapObject}; +use js::glue::{IsWrapper, UnwrapObjectDynamic}; use js::glue::{RUST_JSID_IS_INT, RUST_JSID_TO_INT}; use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING}; use js::jsapi::{Heap, JSContext, JSObject, JSString}; @@ -113,11 +113,11 @@ impl<T: DomObject + IDLInterface> FromJSValConvertible for DomRoot<T> { type Config = (); unsafe fn from_jsval( - _cx: *mut JSContext, + cx: *mut JSContext, value: HandleValue, _config: Self::Config, ) -> Result<ConversionResult<DomRoot<T>>, ()> { - Ok(match root_from_handlevalue(value) { + Ok(match root_from_handlevalue(value, cx) { Ok(result) => ConversionResult::Success(result), Err(()) => ConversionResult::Failure("value is not an object".into()), }) @@ -411,6 +411,7 @@ pub unsafe fn get_dom_class(obj: *mut JSObject) -> Result<&'static DOMClass, ()> #[inline] pub unsafe fn private_from_proto_check<F>( mut obj: *mut JSObject, + cx: *mut JSContext, proto_check: F, ) -> Result<*const libc::c_void, ()> where @@ -419,7 +420,7 @@ where let dom_class = get_dom_class(obj).or_else(|_| { if IsWrapper(obj) { trace!("found wrapper"); - obj = UnwrapObject(obj, /* stopAtWindowProxy = */ 0); + obj = UnwrapObjectDynamic(obj, cx, /* stopAtWindowProxy = */ 0); if obj.is_null() { trace!("unwrapping security wrapper failed"); Err(()) @@ -443,12 +444,57 @@ where } } +/// Get a `*const libc::c_void` for the given DOM object, unless it is a DOM +/// wrapper, and checking if the object is of the correct type. +/// +/// Returns Err(()) if `obj` is a wrapper or if the object is not an object +/// for a DOM object of the given type (as defined by the proto_id and proto_depth). +#[inline] +pub unsafe fn private_from_proto_check_static<F>( + obj: *mut JSObject, + proto_check: F, +) -> Result<*const libc::c_void, ()> +where + F: Fn(&'static DOMClass) -> bool, +{ + let dom_class = get_dom_class(obj).map_err(|_| ())?; + if proto_check(dom_class) { + trace!("good prototype"); + Ok(private_from_object(obj)) + } else { + trace!("bad prototype"); + Err(()) + } +} + /// Get a `*const T` for a DOM object accessible from a `JSObject`. -pub fn native_from_object<T>(obj: *mut JSObject) -> Result<*const T, ()> +pub fn native_from_object<T>(obj: *mut JSObject, cx: *mut JSContext) -> Result<*const T, ()> +where + T: DomObject + IDLInterface, +{ + unsafe { private_from_proto_check(obj, cx, T::derives).map(|ptr| ptr as *const T) } +} + +/// Get a `*const T` for a DOM object accessible from a `JSObject`, where the DOM object +/// is guaranteed not to be a wrapper. +pub fn native_from_object_static<T>(obj: *mut JSObject) -> Result<*const T, ()> +where + T: DomObject + IDLInterface, +{ + unsafe { private_from_proto_check_static(obj, T::derives).map(|ptr| ptr as *const T) } +} + +/// Get a `DomRoot<T>` for the given DOM object, unwrapping any wrapper +/// around it first, and checking if the object is of the correct type. +/// +/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is +/// not a reflector for a DOM object of the given type (as defined by the +/// proto_id and proto_depth). +pub fn root_from_object<T>(obj: *mut JSObject, cx: *mut JSContext) -> Result<DomRoot<T>, ()> where T: DomObject + IDLInterface, { - unsafe { private_from_proto_check(obj, T::derives).map(|ptr| ptr as *const T) } + native_from_object(obj, cx).map(|ptr| unsafe { DomRoot::from_ref(&*ptr) }) } /// Get a `DomRoot<T>` for the given DOM object, unwrapping any wrapper @@ -457,43 +503,43 @@ where /// Returns Err(()) if `obj` is an opaque security wrapper or if the object is /// not a reflector for a DOM object of the given type (as defined by the /// proto_id and proto_depth). -pub fn root_from_object<T>(obj: *mut JSObject) -> Result<DomRoot<T>, ()> +pub fn root_from_object_static<T>(obj: *mut JSObject) -> Result<DomRoot<T>, ()> where T: DomObject + IDLInterface, { - native_from_object(obj).map(|ptr| unsafe { DomRoot::from_ref(&*ptr) }) + native_from_object_static(obj).map(|ptr| unsafe { DomRoot::from_ref(&*ptr) }) } /// Get a `*const T` for a DOM object accessible from a `HandleValue`. /// Caller is responsible for throwing a JS exception if needed in case of error. -pub fn native_from_handlevalue<T>(v: HandleValue) -> Result<*const T, ()> +pub fn native_from_handlevalue<T>(v: HandleValue, cx: *mut JSContext) -> Result<*const T, ()> where T: DomObject + IDLInterface, { if !v.get().is_object() { return Err(()); } - native_from_object(v.get().to_object()) + native_from_object(v.get().to_object(), cx) } /// Get a `DomRoot<T>` for a DOM object accessible from a `HandleValue`. /// Caller is responsible for throwing a JS exception if needed in case of error. -pub fn root_from_handlevalue<T>(v: HandleValue) -> Result<DomRoot<T>, ()> +pub fn root_from_handlevalue<T>(v: HandleValue, cx: *mut JSContext) -> Result<DomRoot<T>, ()> where T: DomObject + IDLInterface, { if !v.get().is_object() { return Err(()); } - root_from_object(v.get().to_object()) + root_from_object(v.get().to_object(), cx) } /// Get a `DomRoot<T>` for a DOM object accessible from a `HandleObject`. -pub fn root_from_handleobject<T>(obj: HandleObject) -> Result<DomRoot<T>, ()> +pub fn root_from_handleobject<T>(obj: HandleObject, cx: *mut JSContext) -> Result<DomRoot<T>, ()> where T: DomObject + IDLInterface, { - root_from_object(obj.get()) + root_from_object(obj.get(), cx) } impl<T: DomObject> ToJSValConvertible for DomRoot<T> { diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index fdce3f01065..da460ad94b6 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -207,8 +207,8 @@ impl ErrorInfo { }) } - fn from_dom_exception(object: HandleObject) -> Option<ErrorInfo> { - let exception = match root_from_object::<DOMException>(object.get()) { + fn from_dom_exception(object: HandleObject, cx: *mut JSContext) -> Option<ErrorInfo> { + let exception = match root_from_object::<DOMException>(object.get(), cx) { Ok(exception) => exception, Err(_) => return None, }; @@ -242,7 +242,7 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool) let error_info = if value.is_object() { rooted!(in(cx) let object = value.to_object()); ErrorInfo::from_native_error(cx, object.handle()) - .or_else(|| ErrorInfo::from_dom_exception(object.handle())) + .or_else(|| ErrorInfo::from_dom_exception(object.handle(), cx)) .unwrap_or_else(|| ErrorInfo { message: format!("uncaught exception: unknown (can't convert to string)"), filename: String::new(), diff --git a/components/script/dom/bindings/htmlconstructor.rs b/components/script/dom/bindings/htmlconstructor.rs index d984c687c16..7e122ef6e29 100644 --- a/components/script/dom/bindings/htmlconstructor.rs +++ b/components/script/dom/bindings/htmlconstructor.rs @@ -79,7 +79,7 @@ use crate::dom::window::Window; use crate::script_thread::ScriptThread; use html5ever::interface::QualName; use html5ever::LocalName; -use js::glue::UnwrapObject; +use js::glue::UnwrapObjectStatic; use js::jsapi::{CallArgs, CurrentGlobalOrNull}; use js::jsapi::{JSAutoRealm, JSContext, JSObject}; use js::rust::HandleObject; @@ -109,7 +109,7 @@ where }, }; - rooted!(in(window.get_cx()) let callee = UnwrapObject(call_args.callee(), 1)); + rooted!(in(window.get_cx()) let callee = UnwrapObjectStatic(call_args.callee())); if callee.is_null() { return Err(Error::Security); } diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs index 112bec1b60e..a4b5f418cd2 100644 --- a/components/script/dom/bindings/proxyhandler.rs +++ b/components/script/dom/bindings/proxyhandler.rs @@ -8,17 +8,13 @@ use crate::dom::bindings::conversions::is_dom_proxy; use crate::dom::bindings::utils::delete_property_by_id; -use js::glue::InvokeGetOwnPropertyDescriptor; -use js::glue::{GetProxyHandler, GetProxyHandlerFamily}; +use js::glue::GetProxyHandlerFamily; use js::glue::{GetProxyPrivate, SetProxyPrivate}; -use js::jsapi::GetObjectProto; use js::jsapi::GetStaticPrototype; use js::jsapi::Handle as RawHandle; use js::jsapi::HandleId as RawHandleId; use js::jsapi::HandleObject as RawHandleObject; use js::jsapi::JS_DefinePropertyById; -use js::jsapi::JS_GetPropertyDescriptorById; -use js::jsapi::MutableHandle as RawMutableHandle; use js::jsapi::MutableHandleObject as RawMutableHandleObject; use js::jsapi::ObjectOpResult; use js::jsapi::{DOMProxyShadowsResult, JSContext, JSObject, PropertyDescriptor}; @@ -62,34 +58,6 @@ pub unsafe fn init() { SetDOMProxyInformation(GetProxyHandlerFamily(), Some(shadow_check_callback)); } -/// Invoke the [[GetOwnProperty]] trap (`getOwnPropertyDescriptor`) on `proxy`, -/// with argument `id` and return the result, if it is not `undefined`. -/// Otherwise, walk along the prototype chain to find a property with that -/// name. -pub unsafe extern "C" fn get_property_descriptor( - cx: *mut JSContext, - proxy: RawHandleObject, - id: RawHandleId, - desc: RawMutableHandle<PropertyDescriptor>, -) -> bool { - let handler = GetProxyHandler(proxy.get()); - if !InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, desc) { - return false; - } - if !desc.obj.is_null() { - return true; - } - - rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>()); - if !GetObjectProto(cx, proxy, proto.handle_mut().into()) { - // FIXME(#11868) Should assign to desc.obj, desc.get() is a copy. - desc.get().obj = ptr::null_mut(); - return true; - } - - JS_GetPropertyDescriptorById(cx, proto.handle().into(), id, desc) -} - /// Defines an expando on the given `proxy`. pub unsafe extern "C" fn define_property( cx: *mut JSContext, diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs index c411dece76b..f6f63abbaf7 100644 --- a/components/script/dom/bindings/structuredclone.rs +++ b/components/script/dom/bindings/structuredclone.rs @@ -176,12 +176,12 @@ unsafe extern "C" fn read_callback( } unsafe extern "C" fn write_callback( - _cx: *mut JSContext, + cx: *mut JSContext, w: *mut JSStructuredCloneWriter, obj: RawHandleObject, _closure: *mut raw::c_void, ) -> bool { - if let Ok(blob) = root_from_handleobject::<Blob>(Handle::from_raw(obj)) { + if let Ok(blob) = root_from_handleobject::<Blob>(Handle::from_raw(obj), cx) { return write_blob(blob, w).is_ok(); } return false; diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 023917c172c..b690687d034 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -68,7 +68,7 @@ use hyper::StatusCode; use indexmap::IndexMap; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use js::glue::{CallObjectTracer, CallValueTracer}; -use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind}; +use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, JobQueue, TraceKind}; use js::jsval::JSVal; use js::rust::{GCMethods, Handle, Runtime}; use js::typedarray::TypedArray; @@ -162,6 +162,8 @@ unsafe_no_jsmanaged_fields!(Duration); unsafe_no_jsmanaged_fields!(TexDataType, TexFormat); +unsafe_no_jsmanaged_fields!(*mut JobQueue); + /// Trace a `JSVal`. pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>) { unsafe { diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 621a95c6ef9..54ff2a35eab 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -15,12 +15,12 @@ use crate::dom::bindings::trace::trace_object; use crate::dom::windowproxy; use js::glue::{CallJitGetterOp, CallJitMethodOp, CallJitSetterOp, IsWrapper}; use js::glue::{GetCrossCompartmentWrapper, JS_GetReservedSlot, WrapperNew}; -use js::glue::{UnwrapObject, RUST_JSID_TO_INT, RUST_JSID_TO_STRING}; +use js::glue::{UnwrapObjectDynamic, RUST_JSID_TO_INT, RUST_JSID_TO_STRING}; use js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT, RUST_JSID_IS_STRING}; use js::jsapi::HandleId as RawHandleId; use js::jsapi::HandleObject as RawHandleObject; use js::jsapi::MutableHandleObject as RawMutableHandleObject; -use js::jsapi::{CallArgs, DOMCallbacks, GetNonCCWObjectGlobal}; +use js::jsapi::{AutoIdVector, CallArgs, DOMCallbacks, GetNonCCWObjectGlobal}; use js::jsapi::{Heap, JSAutoRealm, JSContext}; use js::jsapi::{JSJitInfo, JSObject, JSTracer, JSWrapObjectCallbacks}; use js::jsapi::{JS_EnumerateStandardClasses, JS_GetLatin1StringCharsAndLength}; @@ -210,7 +210,7 @@ pub unsafe fn find_enum_value<'a, T>( /// Returns wether `obj` is a platform object /// <https://heycam.github.io/webidl/#dfn-platform-object> -pub fn is_platform_object(obj: *mut JSObject) -> bool { +pub fn is_platform_object(obj: *mut JSObject, cx: *mut JSContext) -> bool { unsafe { // Fast-path the common case let mut clasp = get_object_class(obj); @@ -219,7 +219,7 @@ pub fn is_platform_object(obj: *mut JSObject) -> bool { } // Now for simplicity check for security wrappers before anything else if IsWrapper(obj) { - let unwrapped_obj = UnwrapObject(obj, /* stopAtWindowProxy = */ 0); + let unwrapped_obj = UnwrapObjectDynamic(obj, cx, /* stopAtWindowProxy = */ 0); if unwrapped_obj.is_null() { return false; } @@ -342,7 +342,12 @@ pub unsafe fn trace_global(tracer: *mut JSTracer, obj: *mut JSObject) { } /// Enumerate lazy properties of a global object. -pub unsafe extern "C" fn enumerate_global(cx: *mut JSContext, obj: RawHandleObject) -> bool { +pub unsafe extern "C" fn enumerate_global( + cx: *mut JSContext, + obj: RawHandleObject, + _props: *mut AutoIdVector, + _enumerable_only: bool, +) -> bool { assert!(JS_IsGlobalObject(obj.get())); if !JS_EnumerateStandardClasses(cx, obj) { return false; @@ -463,7 +468,7 @@ unsafe fn generic_call( let depth = (*info).depth; let proto_check = |class: &'static DOMClass| class.interface_chain[depth as usize] as u16 == proto_id; - let this = match private_from_proto_check(obj.get(), proto_check) { + let this = match private_from_proto_check(obj.get(), cx, proto_check) { Ok(val) => val, Err(()) => { if is_lenient { diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs index 2613f722d41..913397cf780 100644 --- a/components/script/dom/customelementregistry.rs +++ b/components/script/dom/customelementregistry.rs @@ -35,7 +35,7 @@ use crate::script_thread::ScriptThread; use dom_struct::dom_struct; use html5ever::{LocalName, Namespace, Prefix}; use js::conversions::ToJSValConvertible; -use js::glue::UnwrapObject; +use js::glue::UnwrapObjectStatic; use js::jsapi::{HandleValueArray, Heap, IsCallable, IsConstructor}; use js::jsapi::{JSAutoRealm, JSContext, JSObject}; use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue}; @@ -259,7 +259,7 @@ impl CustomElementRegistryMethods for CustomElementRegistry { // Step 1 // We must unwrap the constructor as all wrappers are constructable if they are callable. - rooted!(in(cx) let unwrapped_constructor = unsafe { UnwrapObject(constructor.get(), 1) }); + rooted!(in(cx) let unwrapped_constructor = unsafe { UnwrapObjectStatic(constructor.get()) }); if unwrapped_constructor.is_null() { // We do not have permission to access the unwrapped constructor. diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 1330021035a..7bd0e28be6a 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -6,7 +6,7 @@ use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSourceBinding::EventSourceMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods; -use crate::dom::bindings::conversions::root_from_object; +use crate::dom::bindings::conversions::{root_from_object, root_from_object_static}; use crate::dom::bindings::error::{report_pending_exception, ErrorInfo}; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::DomObject; @@ -41,7 +41,7 @@ use crate::timers::{OneshotTimers, TimerCallback}; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; -use js::glue::{IsWrapper, UnwrapObject}; +use js::glue::{IsWrapper, UnwrapObjectDynamic}; use js::jsapi::JSObject; use js::jsapi::{CurrentGlobalOrNull, GetNonCCWObjectGlobal}; use js::jsapi::{HandleObject, Heap}; @@ -233,22 +233,25 @@ impl GlobalScope { pub unsafe fn from_object(obj: *mut JSObject) -> DomRoot<Self> { assert!(!obj.is_null()); let global = GetNonCCWObjectGlobal(obj); - global_scope_from_global(global) + global_scope_from_global_static(global) } /// Returns the global scope for the given JSContext #[allow(unsafe_code)] pub unsafe fn from_context(cx: *mut JSContext) -> DomRoot<Self> { let global = CurrentGlobalOrNull(cx); - global_scope_from_global(global) + global_scope_from_global(global, cx) } /// Returns the global object of the realm that the given JS object /// was created in, after unwrapping any wrappers. #[allow(unsafe_code)] - pub unsafe fn from_object_maybe_wrapped(mut obj: *mut JSObject) -> DomRoot<Self> { + pub unsafe fn from_object_maybe_wrapped( + mut obj: *mut JSObject, + cx: *mut JSContext, + ) -> DomRoot<Self> { if IsWrapper(obj) { - obj = UnwrapObject(obj, /* stopAtWindowProxy = */ 0); + obj = UnwrapObjectDynamic(obj, cx, /* stopAtWindowProxy = */ 0); assert!(!obj.is_null()); } GlobalScope::from_object(obj) @@ -663,16 +666,23 @@ impl GlobalScope { } /// Perform a microtask checkpoint. + #[allow(unsafe_code)] pub fn perform_a_microtask_checkpoint(&self) { - self.microtask_queue.checkpoint( - |_| Some(DomRoot::from_ref(self)), - vec![DomRoot::from_ref(self)], - ); + unsafe { + 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) { - self.microtask_queue.enqueue(job); + unsafe { + self.microtask_queue.enqueue(job, self.get_cx()); + } } /// Create a new sender/receiver pair that can be used to implement an on-demand @@ -749,7 +759,7 @@ impl GlobalScope { if global.is_null() { None } else { - Some(global_scope_from_global(global)) + Some(global_scope_from_global(global, cx)) } } } @@ -797,12 +807,27 @@ fn timestamp_in_ms(time: Timespec) -> u64 { /// Returns the Rust global scope from a JS global object. #[allow(unsafe_code)] -unsafe fn global_scope_from_global(global: *mut JSObject) -> DomRoot<GlobalScope> { +unsafe fn global_scope_from_global( + global: *mut JSObject, + cx: *mut JSContext, +) -> DomRoot<GlobalScope> { + assert!(!global.is_null()); + let clasp = get_object_class(global); + assert_ne!( + ((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)), + 0 + ); + root_from_object(global, cx).unwrap() +} + +/// Returns the Rust global scope from a JS global object. +#[allow(unsafe_code)] +unsafe fn global_scope_from_global_static(global: *mut JSObject) -> DomRoot<GlobalScope> { assert!(!global.is_null()); let clasp = get_object_class(global); assert_ne!( ((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)), 0 ); - root_from_object(global).unwrap() + root_from_object_static(global).unwrap() } diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs index 152828b8110..9fcb728ae0f 100644 --- a/components/script/dom/promise.rs +++ b/components/script/dom/promise.rs @@ -286,7 +286,7 @@ unsafe extern "C" fn native_handler_callback( rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER)); assert!(v.get().is_object()); - let handler = root_from_object::<PromiseNativeHandler>(v.to_object()) + let handler = root_from_object::<PromiseNativeHandler>(v.to_object(), cx) .expect("unexpected value for native handler in promise native handler callback"); rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER_TASK)); diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index 7b53656e918..69a73a1547e 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -6,7 +6,7 @@ use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::conversions::{root_from_handleobject, ToJSValConvertible}; use crate::dom::bindings::error::{throw_dom_exception, Error}; use crate::dom::bindings::inheritance::Castable; -use crate::dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor}; +use crate::dom::bindings::proxyhandler::fill_property_descriptor; use crate::dom::bindings::reflector::{DomObject, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; @@ -712,7 +712,7 @@ unsafe fn GetSubframeWindowProxy( let mut slot = UndefinedValue(); GetProxyPrivate(*proxy, &mut slot); rooted!(in(cx) let target = slot.to_object()); - if let Ok(win) = root_from_handleobject::<Window>(target.handle()) { + if let Ok(win) = root_from_handleobject::<Window>(target.handle(), cx) { let browsing_context_id = win.window_proxy().browsing_context_id(); let (result_sender, result_receiver) = ipc::channel().unwrap(); @@ -730,7 +730,9 @@ unsafe fn GetSubframeWindowProxy( .and_then(|maybe_bcid| maybe_bcid) .and_then(ScriptThread::find_window_proxy) .map(|proxy| (proxy, (JSPROP_ENUMERATE | JSPROP_READONLY) as u32)); - } else if let Ok(win) = root_from_handleobject::<DissimilarOriginWindow>(target.handle()) { + } else if let Ok(win) = + root_from_handleobject::<DissimilarOriginWindow>(target.handle(), cx) + { let browsing_context_id = win.window_proxy().browsing_context_id(); let (result_sender, result_receiver) = ipc::channel().unwrap(); @@ -912,7 +914,6 @@ static PROXY_HANDLER: ProxyTraps = ProxyTraps { set: Some(set), call: None, construct: None, - getPropertyDescriptor: Some(get_property_descriptor), hasOwn: None, getOwnEnumerablePropertyKeys: None, nativeCall: None, @@ -1049,7 +1050,6 @@ static XORIGIN_PROXY_HANDLER: ProxyTraps = ProxyTraps { set: Some(set_xorigin), call: None, construct: None, - getPropertyDescriptor: Some(getOwnPropertyDescriptor_xorigin), hasOwn: Some(has_xorigin), getOwnEnumerablePropertyKeys: None, nativeCall: None, diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 572bebff905..87722f2358e 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -131,7 +131,7 @@ impl WorkerGlobalScope { init.resource_threads, timer_event_chan, MutableOrigin::new(init.origin), - Default::default(), + runtime.microtask_queue.clone(), ), worker_id: init.worker_id, worker_name, diff --git a/components/script/microtask.rs b/components/script/microtask.rs index a523c1c83dc..db420e20eaa 100644 --- a/components/script/microtask.rs +++ b/components/script/microtask.rs @@ -16,6 +16,7 @@ use crate::dom::htmlmediaelement::MediaElementMicrotask; use crate::dom::mutationobserver::MutationObserver; use crate::script_runtime::notify_about_rejected_promises; use crate::script_thread::ScriptThread; +use js::jsapi::{JSContext, JobQueueIsEmpty, JobQueueMayNotBeEmpty}; use msg::constellation_msg::PipelineId; use std::cell::Cell; use std::mem; @@ -54,14 +55,21 @@ pub struct EnqueuedPromiseCallback { impl MicrotaskQueue { /// Add a new microtask to this queue. It will be invoked as part of the next /// microtask checkpoint. - pub fn enqueue(&self, job: Microtask) { + #[allow(unsafe_code)] + pub unsafe fn enqueue(&self, job: Microtask, cx: *mut JSContext) { self.microtask_queue.borrow_mut().push(job); + 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. - pub fn checkpoint<F>(&self, target_provider: F, globalscopes: Vec<DomRoot<GlobalScope>>) - where + #[allow(unsafe_code)] + pub unsafe fn checkpoint<F>( + &self, + cx: *mut JSContext, + target_provider: F, + globalscopes: Vec<DomRoot<GlobalScope>>, + ) where F: Fn(PipelineId) -> Option<DomRoot<GlobalScope>>, { if self.performing_a_microtask_checkpoint.get() { @@ -76,7 +84,11 @@ impl MicrotaskQueue { rooted_vec!(let mut pending_queue); mem::swap(&mut *pending_queue, &mut *self.microtask_queue.borrow_mut()); - for job in pending_queue.iter() { + for (idx, job) in pending_queue.iter().enumerate() { + if idx == pending_queue.len() - 1 && self.microtask_queue.borrow().is_empty() { + JobQueueIsEmpty(cx); + } + match *job { Microtask::Promise(ref job) => { if let Some(target) = target_provider(job.pipeline) { @@ -109,4 +121,8 @@ impl MicrotaskQueue { // Step 5 self.performing_a_microtask_checkpoint.set(false); } + + pub fn empty(&self) -> bool { + self.microtask_queue.borrow().is_empty() + } } diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index ce64f363594..b5119949193 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -21,15 +21,14 @@ use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; use crate::dom::promiserejectionevent::PromiseRejectionEvent; -use crate::microtask::{EnqueuedPromiseCallback, Microtask}; +use crate::microtask::{EnqueuedPromiseCallback, Microtask, MicrotaskQueue}; use crate::script_thread::trace_thread; use crate::task::TaskBox; use crate::task_source::{TaskSource, TaskSourceName}; -use js::glue::CollectServoSizes; -use js::glue::SetBuildId; +use js::glue::{CollectServoSizes, CreateJobQueue, DeleteJobQueue, JobQueueTraps, SetBuildId}; use js::jsapi::ContextOptionsRef; use js::jsapi::{BuildIdCharVector, DisableIncrementalGC, GCDescription, GCProgress}; -use js::jsapi::{HandleObject, Heap}; +use js::jsapi::{HandleObject, Heap, JobQueue}; use js::jsapi::{JSContext, JSTracer, SetDOMCallbacks, SetGCSliceCallback}; use js::jsapi::{JSGCInvocationKind, JSGCStatus, JS_AddExtraGCRootsTracer, JS_SetGCCallback}; use js::jsapi::{JSGCMode, JSGCParamKey, JS_SetGCParameter, JS_SetGlobalJitCompilerOption}; @@ -37,9 +36,7 @@ use js::jsapi::{ JSJitCompilerOption, JS_SetOffthreadIonCompilationEnabled, JS_SetParallelParsingEnabled, }; use js::jsapi::{JSObject, PromiseRejectionHandlingState, SetPreserveWrapperCallback}; -use js::jsapi::{ - SetEnqueuePromiseJobCallback, SetProcessBuildIdOp, SetPromiseRejectionTrackerCallback, -}; +use js::jsapi::{SetJobQueue, SetProcessBuildIdOp, SetPromiseRejectionTrackerCallback}; use js::panic::wrap_panic; use js::rust::wrappers::{GetPromiseIsHandled, GetPromiseResult}; use js::rust::Handle; @@ -60,10 +57,17 @@ use std::os; use std::os::raw::c_void; use std::panic::AssertUnwindSafe; use std::ptr; +use std::rc::Rc; use std::sync::Arc; use style::thread_state::{self, ThreadState}; use time::{now, Tm}; +static JOB_QUEUE_TRAPS: JobQueueTraps = JobQueueTraps { + getIncumbentGlobal: Some(get_incumbent_global), + enqueuePromiseJob: Some(enqueue_promise_job), + empty: Some(empty), +}; + /// Common messages used to control the event loops in both the script and the worker pub enum CommonScriptMsg { /// Requests that the script thread measure its memory usage. The results are sent back via the @@ -134,25 +138,52 @@ pub trait ScriptPort { fn recv(&self) -> Result<CommonScriptMsg, ()>; } +#[allow(unsafe_code)] +unsafe extern "C" fn get_incumbent_global(_: *const c_void, _: *mut JSContext) -> *mut JSObject { + wrap_panic( + AssertUnwindSafe(|| { + GlobalScope::incumbent() + .map(|g| g.reflector().get_jsobject().get()) + .unwrap_or(ptr::null_mut()) + }), + ptr::null_mut(), + ) +} + +#[allow(unsafe_code)] +unsafe extern "C" fn empty(extra: *const c_void) -> bool { + wrap_panic( + AssertUnwindSafe(|| { + let microtask_queue = &*(extra as *const MicrotaskQueue); + microtask_queue.empty() + }), + false, + ) +} + /// SM callback for promise job resolution. Adds a promise callback to the current /// global's microtask queue. #[allow(unsafe_code)] -unsafe extern "C" fn enqueue_job( +unsafe extern "C" fn enqueue_promise_job( + extra: *const c_void, cx: *mut JSContext, _promise: HandleObject, job: HandleObject, _allocation_site: HandleObject, incumbent_global: HandleObject, - _data: *mut c_void, ) -> bool { wrap_panic( AssertUnwindSafe(|| { + let microtask_queue = &*(extra as *const MicrotaskQueue); let global = GlobalScope::from_object(incumbent_global.get()); let pipeline = global.pipeline_id(); - global.enqueue_microtask(Microtask::Promise(EnqueuedPromiseCallback { - callback: PromiseJobCallback::new(cx, job.get()), - pipeline: pipeline, - })); + microtask_queue.enqueue( + Microtask::Promise(EnqueuedPromiseCallback { + callback: PromiseJobCallback::new(cx, job.get()), + pipeline, + }), + cx, + ); true }), false, @@ -309,10 +340,18 @@ pub fn notify_about_rejected_promises(global: &GlobalScope) { } #[derive(JSTraceable)] -pub struct Runtime(RustRuntime); +pub struct Runtime { + rt: RustRuntime, + pub microtask_queue: Rc<MicrotaskQueue>, + job_queue: *mut JobQueue, +} impl Drop for Runtime { + #[allow(unsafe_code)] fn drop(&mut self) { + unsafe { + DeleteJobQueue(self.job_queue); + } THREAD_ACTIVE.with(|t| { LiveDOMReferences::destruct(); t.set(false); @@ -323,7 +362,7 @@ impl Drop for Runtime { impl Deref for Runtime { type Target = RustRuntime; fn deref(&self) -> &RustRuntime { - &self.0 + &self.rt } } @@ -370,7 +409,12 @@ unsafe fn new_rt_and_cx_with_parent(parent: Option<ParentRuntime>) -> Runtime { // Pre barriers aren't working correctly at the moment DisableIncrementalGC(cx); - SetEnqueuePromiseJobCallback(cx, Some(enqueue_job), ptr::null_mut()); + let microtask_queue = Rc::new(MicrotaskQueue::default()); + let job_queue = CreateJobQueue( + &JOB_QUEUE_TRAPS, + &*microtask_queue as *const _ as *const c_void, + ); + SetJobQueue(cx, job_queue); SetPromiseRejectionTrackerCallback(cx, Some(promise_rejection_tracker), ptr::null_mut()); set_gc_zeal_options(cx); @@ -407,7 +451,7 @@ unsafe fn new_rt_and_cx_with_parent(parent: Option<ParentRuntime>) -> Runtime { ); JS_SetGlobalJitCompilerOption( cx, - JSJitCompilerOption::JSJITCOMPILER_ION_WARMUP_TRIGGER, + JSJitCompilerOption::JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER, if pref!(js.ion.unsafe_eager_compilation.enabled) { 0 } else { @@ -511,7 +555,11 @@ unsafe fn new_rt_and_cx_with_parent(parent: Option<ParentRuntime>) -> Runtime { JS_SetGCParameter(cx, JSGCParamKey::JSGC_MAX_EMPTY_CHUNK_COUNT, val as u32); } - Runtime(runtime) + Runtime { + rt: runtime, + microtask_queue, + job_queue, + } } fn in_range<T: PartialOrd + Copy>(val: T, min: T, max: T) -> Option<T> { diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index b81ff6d5fc7..a0c8ad3ab43 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -845,11 +845,16 @@ 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() { - let script_thread = unsafe { &*script_thread }; - script_thread.microtask_queue.enqueue(task); + unsafe { + let script_thread = &*script_thread; + script_thread + .microtask_queue + .enqueue(task, script_thread.get_cx()); + } } }); } @@ -1123,6 +1128,8 @@ impl ScriptThread { devtools_port: devtools_port, devtools_sender: ipc_devtools_sender, + microtask_queue: runtime.microtask_queue.clone(), + js_runtime: Rc::new(runtime), topmost_mouse_over_target: MutNullableDom::new(Default::default()), closed_pipelines: DomRefCell::new(HashSet::new()), @@ -1133,8 +1140,6 @@ impl ScriptThread { content_process_shutdown_chan: state.content_process_shutdown_chan, - microtask_queue: Default::default(), - mutation_observer_microtask_queued: Default::default(), mutation_observers: Default::default(), @@ -3544,13 +3549,17 @@ impl ScriptThread { } } + #[allow(unsafe_code)] pub fn enqueue_microtask(job: Microtask) { - SCRIPT_THREAD_ROOT.with(|root| { - let script_thread = unsafe { &*root.get().unwrap() }; - script_thread.microtask_queue.enqueue(job); + SCRIPT_THREAD_ROOT.with(|root| unsafe { + let script_thread = &*root.get().unwrap(); + script_thread + .microtask_queue + .enqueue(job, script_thread.get_cx()); }); } + #[allow(unsafe_code)] fn perform_a_microtask_checkpoint(&self) { let globals = self .documents @@ -3559,8 +3568,13 @@ impl ScriptThread { .map(|(_id, document)| document.global()) .collect(); - self.microtask_queue - .checkpoint(|id| self.documents.borrow().find_global(id), globals) + unsafe { + self.microtask_queue.checkpoint( + self.get_cx(), + |id| self.documents.borrow().find_global(id), + globals, + ) + } } } |