diff options
author | Ms2ger <Ms2ger@gmail.com> | 2016-07-04 16:24:09 +0200 |
---|---|---|
committer | Ms2ger <Ms2ger@gmail.com> | 2016-07-28 13:05:56 +0200 |
commit | 89efccc4267706eec8d1cd32043bb25d7f37f9b2 (patch) | |
tree | d64ac6286bf487cb16e22639e658bc4eaaa35816 /components/script/dom | |
parent | a0c502261dc2bd710e31dcbbbd2d81d2a2c53724 (diff) | |
download | servo-89efccc4267706eec8d1cd32043bb25d7f37f9b2.tar.gz servo-89efccc4267706eec8d1cd32043bb25d7f37f9b2.zip |
Update SpiderMonkey to m-c bcf4ff0c3eef.
This currently breaks Servo on Android, because there are a number of
interdependent changes that cannot easily land serially in a way that
keeps it working throughout. We expect to fix this in the near future.
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 84 | ||||
-rw-r--r-- | components/script/dom/bindings/error.rs | 109 | ||||
-rw-r--r-- | components/script/dom/bindings/interface.rs | 92 | ||||
-rw-r--r-- | components/script/dom/bindings/proxyhandler.rs | 21 | ||||
-rw-r--r-- | components/script/dom/browsingcontext.rs | 25 |
5 files changed, 220 insertions, 111 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 8360dfc322a..2e0dc2415dd 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1872,56 +1872,31 @@ class CGDOMJSClass(CGThing): elif self.descriptor.weakReferenceable: args["slots"] = "2" return """\ +static CLASS_OPS: js::jsapi::ClassOps = js::jsapi::ClassOps { + addProperty: None, + delProperty: None, + getProperty: None, + setProperty: None, + enumerate: %(enumerateHook)s, + resolve: %(resolveHook)s, + mayResolve: None, + finalize: Some(%(finalizeHook)s), + call: None, + hasInstance: None, + construct: None, + trace: Some(%(traceHook)s), +}; + static Class: DOMJSClass = DOMJSClass { base: js::jsapi::Class { name: %(name)s as *const u8 as *const libc::c_char, flags: JSCLASS_IS_DOMJSCLASS | %(flags)s | (((%(slots)s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT) /* JSCLASS_HAS_RESERVED_SLOTS(%(slots)s) */, - addProperty: None, - delProperty: None, - getProperty: None, - setProperty: None, - enumerate: %(enumerateHook)s, - resolve: %(resolveHook)s, - mayResolve: None, - finalize: Some(%(finalizeHook)s), - call: None, - hasInstance: None, - construct: None, - trace: Some(%(traceHook)s), - - spec: js::jsapi::ClassSpec { - createConstructor_: None, - createPrototype_: None, - constructorFunctions_: 0 as *const js::jsapi::JSFunctionSpec, - constructorProperties_: 0 as *const js::jsapi::JSPropertySpec, - prototypeFunctions_: 0 as *const js::jsapi::JSFunctionSpec, - prototypeProperties_: 0 as *const js::jsapi::JSPropertySpec, - finishInit_: None, - flags: 0, - }, - - ext: js::jsapi::ClassExtension { - isWrappedNative: false, - weakmapKeyDelegateOp: None, - objectMovedOp: None, - }, - - ops: js::jsapi::ObjectOps { - lookupProperty: None, - defineProperty: None, - hasProperty: None, - getProperty: None, - setProperty: None, - getOwnPropertyDescriptor: None, - deleteProperty: None, - watch: None, - unwatch: None, - getElements: None, - enumerate: None, - funToString: None, - }, + cOps: &CLASS_OPS, + spec: ptr::null(), + ext: ptr::null(), + oOps: ptr::null(), }, dom_class: %(domClass)s };""" % args @@ -1947,19 +1922,8 @@ static PrototypeClass: JSClass = JSClass { flags: // JSCLASS_HAS_RESERVED_SLOTS(%(slotCount)s) (%(slotCount)s & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT, - addProperty: None, - delProperty: None, - getProperty: None, - setProperty: None, - enumerate: None, - resolve: None, - mayResolve: None, - finalize: None, - call: None, - hasInstance: None, - construct: None, - trace: None, - reserved: [0 as *mut os::raw::c_void; 23] + cOps: 0 as *const _, + reserved: [0 as *mut os::raw::c_void; 3] }; """ % {'name': name, 'slotCount': slotCount} @@ -1983,9 +1947,12 @@ class CGInterfaceObjectJSClass(CGThing): "depth": self.descriptor.prototypeDepth } return """\ +static INTERFACE_OBJECT_OPS: js::jsapi::ClassOps = + NonCallbackInterfaceObjectClass::ops(%(constructorBehavior)s); + static InterfaceObjectClass: NonCallbackInterfaceObjectClass = NonCallbackInterfaceObjectClass::new( - %(constructorBehavior)s, + &INTERFACE_OBJECT_OPS, %(representation)s, PrototypeList::ID::%(id)s, %(depth)s); @@ -2772,6 +2739,7 @@ let traps = ProxyTraps { ownPropertyKeys: Some(own_property_keys), delete_: Some(%(delete)s), enumerate: None, + getPrototypeIfOrdinary: Some(proxyhandler::get_prototype_if_ordinary), preventExtensions: Some(proxyhandler::prevent_extensions), isExtensible: Some(proxyhandler::is_extensible), has: None, diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index d0074335c23..bd63ba84fb1 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -4,15 +4,26 @@ //! Utilities to throw exceptions from Rust bindings. +use dom::bindings::codegen::Bindings::DOMExceptionBinding::DOMExceptionMethods; use dom::bindings::codegen::PrototypeList::proto_id_to_name; -use dom::bindings::conversions::ToJSValConvertible; +use dom::bindings::conversions::root_from_object; +use dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}; use dom::bindings::global::GlobalRef; +use dom::bindings::str::USVString; use dom::domexception::{DOMErrorName, DOMException}; use js::error::{throw_range_error, throw_type_error}; +use js::jsapi::HandleObject; use js::jsapi::JSAutoCompartment; -use js::jsapi::{JSContext, JSObject}; -use js::jsapi::{JS_IsExceptionPending, JS_ReportPendingException, JS_SetPendingException}; +use js::jsapi::JSContext; +use js::jsapi::JSObject; +use js::jsapi::JS_ClearPendingException; +use js::jsapi::JS_ErrorFromException; +use js::jsapi::JS_GetPendingException; +use js::jsapi::JS_IsExceptionPending; +use js::jsapi::JS_SetPendingException; use js::jsval::UndefinedValue; +use libc::c_uint; +use std::slice::from_raw_parts; /// DOM exceptions that can be thrown by a native DOM method. #[derive(Debug, Clone, HeapSizeOf)] @@ -123,11 +134,101 @@ pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef, result: JS_SetPendingException(cx, thrown.handle()); } +struct ErrorInfo { + filename: String, + message: String, + lineno: c_uint, + column: c_uint, +} + +impl ErrorInfo { + unsafe fn from_native_error(cx: *mut JSContext, object: HandleObject) + -> Option<ErrorInfo> { + let report = JS_ErrorFromException(cx, object); + if report.is_null() { + return None; + } + + let filename = { + let filename = (*report).filename as *const u8; + if !filename.is_null() { + let length = (0..).find(|idx| *filename.offset(*idx) == 0).unwrap(); + let filename = from_raw_parts(filename, length as usize); + String::from_utf8_lossy(filename).into_owned() + } else { + "none".to_string() + } + }; + + let lineno = (*report).lineno; + let column = (*report).column; + + let message = { + let message = (*report).ucmessage; + let length = (0..).find(|idx| *message.offset(*idx) == 0).unwrap(); + let message = from_raw_parts(message, length as usize); + String::from_utf16_lossy(message) + }; + + Some(ErrorInfo { + filename: filename, + message: message, + lineno: lineno, + column: column, + }) + } + + fn from_dom_exception(cx: *mut JSContext, object: HandleObject) -> Option<ErrorInfo> { + let exception = match root_from_object::<DOMException>(object.get()) { + Ok(exception) => exception, + Err(_) => return None, + }; + + Some(ErrorInfo { + filename: "".to_string(), + message: exception.Stringifier().into(), + lineno: 0, + column: 0, + }) + } +} + /// Report a pending exception, thereby clearing it. pub unsafe fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) { if JS_IsExceptionPending(cx) { let _ac = JSAutoCompartment::new(cx, obj); - JS_ReportPendingException(cx); + rooted!(in(cx) let mut value = UndefinedValue()); + if !JS_GetPendingException(cx, value.handle_mut()) { + JS_ClearPendingException(cx); + error!("Uncaught exception: JS_GetPendingException failed"); + return; + } + + JS_ClearPendingException(cx); + if !value.is_object() { + match USVString::from_jsval(cx, value.handle(), ()) { + Ok(USVString(string)) => error!("Uncaught exception: {}", string), + Err(_) => error!("Uncaught exception: failed to stringify primitive"), + } + return; + } + + rooted!(in(cx) let object = value.to_object()); + let error_info = ErrorInfo::from_native_error(cx, object.handle()) + .or_else(|| ErrorInfo::from_dom_exception(cx, object.handle())); + let error_info = match error_info { + Some(error_info) => error_info, + None => { + error!("Uncaught exception: failed to extract information"); + return; + } + }; + + error!("Error at {}:{}:{} {}", + error_info.filename, + error_info.lineno, + error_info.column, + error_info.message); } } diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 4e2c630a453..3b2b5dbde36 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -11,7 +11,7 @@ use dom::bindings::guard::Guard; use dom::bindings::utils::get_proto_or_iface_array; use js::error::throw_type_error; use js::glue::{RUST_SYMBOL_TO_JSID, UncheckedUnwrapObject}; -use js::jsapi::{Class, ClassExtension, ClassSpec, GetGlobalForObjectCrossCompartment}; +use js::jsapi::{Class, ClassOps, GetGlobalForObjectCrossCompartment}; use js::jsapi::{GetWellKnownSymbol, HandleObject, HandleValue, JSClass, JSContext}; use js::jsapi::{JSFunctionSpec, JSNative, JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE}; use js::jsapi::{JSPROP_PERMANENT, JSPROP_READONLY, JSPROP_RESOLVING, JSPropertySpec}; @@ -101,6 +101,21 @@ unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext, ret } +const OBJECT_OPS: ObjectOps = ObjectOps { + lookupProperty: None, + defineProperty: None, + hasProperty: None, + getProperty: None, + setProperty: None, + getOwnPropertyDescriptor: None, + deleteProperty: None, + watch: None, + unwatch: None, + getElements: None, + enumerate: None, + funToString: Some(fun_to_string_hook), +}; + /// The class of a non-callback interface object. #[derive(Copy, Clone)] pub struct NonCallbackInterfaceObjectClass { @@ -117,58 +132,39 @@ pub struct NonCallbackInterfaceObjectClass { unsafe impl Sync for NonCallbackInterfaceObjectClass {} impl NonCallbackInterfaceObjectClass { + /// Create `ClassOps` for a `NonCallbackInterfaceObjectClass`. + pub const fn ops(constructor_behavior: InterfaceConstructorBehavior) + -> ClassOps { + ClassOps { + addProperty: None, + delProperty: None, + getProperty: None, + setProperty: None, + enumerate: None, + resolve: None, + mayResolve: None, + finalize: None, + call: constructor_behavior.call, + construct: constructor_behavior.construct, + hasInstance: Some(has_instance_hook), + trace: None, + } + } + /// Create a new `NonCallbackInterfaceObjectClass` structure. - pub const fn new( - constructor_behavior: InterfaceConstructorBehavior, - string_rep: &'static [u8], - proto_id: PrototypeList::ID, - proto_depth: u16) - -> NonCallbackInterfaceObjectClass { + pub const fn new(ops: &'static ClassOps, + string_rep: &'static [u8], + proto_id: PrototypeList::ID, + proto_depth: u16) + -> NonCallbackInterfaceObjectClass { NonCallbackInterfaceObjectClass { class: Class { name: b"Function\0" as *const _ as *const libc::c_char, flags: 0, - addProperty: None, - delProperty: None, - getProperty: None, - setProperty: None, - enumerate: None, - resolve: None, - mayResolve: None, - finalize: None, - call: constructor_behavior.call, - construct: constructor_behavior.construct, - hasInstance: Some(has_instance_hook), - trace: None, - spec: ClassSpec { - createConstructor_: None, - createPrototype_: None, - constructorFunctions_: ptr::null(), - constructorProperties_: ptr::null(), - prototypeFunctions_: ptr::null(), - prototypeProperties_: ptr::null(), - finishInit_: None, - flags: 0, - }, - ext: ClassExtension { - isWrappedNative: false, - weakmapKeyDelegateOp: None, - objectMovedOp: None, - }, - ops: ObjectOps { - lookupProperty: None, - defineProperty: None, - hasProperty: None, - getProperty: None, - setProperty: None, - getOwnPropertyDescriptor: None, - deleteProperty: None, - watch: None, - unwatch: None, - getElements: None, - enumerate: None, - funToString: Some(fun_to_string_hook), - } + cOps: ops, + spec: ptr::null(), + ext: ptr::null(), + oOps: &OBJECT_OPS, }, proto_id: proto_id, proto_depth: proto_depth, diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs index 9db30d8835c..c863cc31994 100644 --- a/components/script/dom/bindings/proxyhandler.rs +++ b/components/script/dom/bindings/proxyhandler.rs @@ -12,7 +12,9 @@ use js::glue::GetProxyExtra; use js::glue::InvokeGetOwnPropertyDescriptor; use js::glue::{GetProxyHandler, SetProxyExtra}; use js::jsapi::GetObjectProto; +use js::jsapi::GetStaticPrototype; use js::jsapi::JS_GetPropertyDescriptorById; +use js::jsapi::MutableHandleObject; use js::jsapi::{Handle, HandleId, HandleObject, MutableHandle, ObjectOpResult}; use js::jsapi::{JSContext, JSObject, JSPROP_GETTER, PropertyDescriptor}; use js::jsapi::{JSErrNum, JS_StrictPropertyStub}; @@ -103,6 +105,25 @@ pub unsafe extern "C" fn is_extensible(_cx: *mut JSContext, true } +/// If `proxy` (underneath any functionally-transparent wrapper proxies) has as +/// its `[[GetPrototypeOf]]` trap the ordinary `[[GetPrototypeOf]]` behavior +/// defined for ordinary objects, set `*is_ordinary` to true and store `obj`'s +/// prototype in `proto`. Otherwise set `*isOrdinary` to false. In case of +/// error, both outparams have unspecified value. +/// +/// This implementation always handles the case of the ordinary +/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be +/// necessary for the Location object. +pub unsafe extern "C" fn get_prototype_if_ordinary(_: *mut JSContext, + proxy: HandleObject, + is_ordinary: *mut bool, + proto: MutableHandleObject) + -> bool { + *is_ordinary = true; + proto.set(GetStaticPrototype(proxy.get())); + true +} + /// Get the expando object, or null if there is none. pub fn get_expando_object(obj: HandleObject) -> *mut JSObject { unsafe { diff --git a/components/script/dom/browsingcontext.rs b/components/script/dom/browsingcontext.rs index 4c0914ddf3c..878d376ca66 100644 --- a/components/script/dom/browsingcontext.rs +++ b/components/script/dom/browsingcontext.rs @@ -22,7 +22,7 @@ use js::jsapi::{Handle, HandleId, HandleObject, HandleValue, JSAutoCompartment}; use js::jsapi::{JSContext, JSPROP_READONLY, JSErrNum, JSObject, PropertyDescriptor, JS_DefinePropertyById}; use js::jsapi::{JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo, JS_GetClass, JSTracer, FreeOp}; use js::jsapi::{JS_GetOwnPropertyDescriptorById, JS_HasPropertyById, MutableHandle}; -use js::jsapi::{MutableHandleValue, ObjectOpResult}; +use js::jsapi::{MutableHandleObject, MutableHandleValue, ObjectOpResult}; use js::jsval::{UndefinedValue, PrivateValue}; use msg::constellation_msg::{PipelineId, SubpageId}; use std::cell::Cell; @@ -354,6 +354,28 @@ unsafe extern "C" fn set(cx: *mut JSContext, res) } +#[allow(unsafe_code)] +unsafe extern "C" fn get_prototype_if_ordinary(_: *mut JSContext, + _: HandleObject, + is_ordinary: *mut bool, + _: MutableHandleObject) + -> bool { + // Window's [[GetPrototypeOf]] trap isn't the ordinary definition: + // + // https://html.spec.whatwg.org/multipage/#windowproxy-getprototypeof + // + // We nonetheless can implement it with a static [[Prototype]], because + // wrapper-class handlers (particularly, XOW in FilteringWrapper.cpp) supply + // all non-ordinary behavior. + // + // But from a spec point of view, it's the exact same object in both cases -- + // only the observer's changed. So this getPrototypeIfOrdinary trap on the + // non-wrapper object *must* report non-ordinary, even if static [[Prototype]] + // usually means ordinary. + *is_ordinary = false; + return true; +} + static PROXY_HANDLER: ProxyTraps = ProxyTraps { enter: None, getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor), @@ -361,6 +383,7 @@ static PROXY_HANDLER: ProxyTraps = ProxyTraps { ownPropertyKeys: None, delete_: None, enumerate: None, + getPrototypeIfOrdinary: Some(get_prototype_if_ordinary), preventExtensions: None, isExtensible: None, has: Some(has), |