mirror of
https://github.com/servo/servo.git
synced 2025-06-24 17:14:33 +01:00
Auto merge of #12255 - servo:smup, r=jdm
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. <!-- Reviewable:start --> This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/12255) <!-- Reviewable:end -->
This commit is contained in:
commit
5ae1fcd6fe
7 changed files with 224 additions and 115 deletions
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue