aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <metajack+bors@gmail.com>2015-06-24 03:54:56 -0600
committerbors-servo <metajack+bors@gmail.com>2015-06-24 03:54:56 -0600
commit6247a96761279979412fb49fa4fbca2fd9a82e1b (patch)
tree6503e916806f73b0434073a7e2a22f32993f3e1f
parent469b9550f6feec56d87ea5c772cb76453c13036a (diff)
parenta90983553b78e3450cc91d810eb3d053398169d0 (diff)
downloadservo-6247a96761279979412fb49fa4fbca2fd9a82e1b.tar.gz
servo-6247a96761279979412fb49fa4fbca2fd9a82e1b.zip
Auto merge of #6223 - nox:merge-generic-functions, r=Ms2ger
Merge generic funs to share them across all bindings (fixes #2684) <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6223) <!-- Reviewable:end -->
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py157
-rw-r--r--components/script/dom/bindings/conversions.rs107
-rw-r--r--components/script/dom/bindings/error.rs10
-rw-r--r--components/script/dom/bindings/utils.rs108
-rw-r--r--tests/wpt/metadata/html/dom/interfaces.html.ini3
5 files changed, 185 insertions, 200 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index f9e929c68da..832dd564736 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -1441,7 +1441,7 @@ class MethodDefiner(PropertyDefiner):
if m.get("methodInfo", True):
identifier = m.get("nativeName", m["name"])
jitinfo = "&%s_methodinfo" % identifier
- accessor = "Some(genericMethod)"
+ accessor = "Some(generic_method)"
else:
jitinfo = "0 as *const JSJitInfo"
accessor = 'Some(%s)' % m.get("nativeName", m["name"])
@@ -1481,9 +1481,9 @@ class AttrDefiner(PropertyDefiner):
jitinfo = "0 as *const JSJitInfo"
else:
if attr.hasLenientThis():
- accessor = "genericLenientGetter"
+ accessor = "generic_lenient_getter"
else:
- accessor = "genericGetter"
+ accessor = "generic_getter"
jitinfo = "&%s_getterinfo" % attr.identifier.name
return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
@@ -1499,9 +1499,9 @@ class AttrDefiner(PropertyDefiner):
jitinfo = "0 as *const JSJitInfo"
else:
if attr.hasLenientThis():
- accessor = "genericLenientSetter"
+ accessor = "generic_lenient_setter"
else:
- accessor = "genericSetter"
+ accessor = "generic_setter"
jitinfo = "&%s_setterinfo" % attr.identifier.name
return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
@@ -2696,52 +2696,6 @@ class CGSetterCall(CGPerSignatureCall):
# We just get our stuff from our last arg no matter what
return ""
-class CGAbstractBindingMethod(CGAbstractExternMethod):
- """
- Common class to generate the JSNatives for all our methods, getters, and
- setters. This will generate the function declaration and unwrap the
- |this| object. Subclasses are expected to override the generate_code
- function to do the rest of the work. This function should return a
- CGThing which is already properly indented.
- """
- def __init__(self, descriptor, name, args, unwrapFailureCode=None):
- CGAbstractExternMethod.__init__(self, descriptor, name, "u8", args)
-
- if unwrapFailureCode is None:
- self.unwrapFailureCode = (
- 'throw_type_error(cx, "\\"this\\" object does not '
- 'implement interface %s.");\n'
- 'return 0;' % descriptor.interface.identifier.name)
- else:
- self.unwrapFailureCode = unwrapFailureCode
-
- def definition_body(self):
- # Our descriptor might claim that we're not castable, simply because
- # we're someone's consequential interface. But for this-unwrapping, we
- # know that we're the real deal. So fake a descriptor here for
- # consumption by FailureFatalCastableObjectUnwrapper.
- unwrapThis = str(CastableObjectUnwrapper(
- FakeCastableDescriptor(self.descriptor),
- "obj.handle()", self.unwrapFailureCode, "object"))
- unwrapThis = CGGeneric(
- "let args = CallArgs::from_vp(vp, argc);\n"
- "let thisobj = args.thisv();\n"
- "if !thisobj.get().is_null_or_undefined() && !thisobj.get().is_object() {\n"
- " return JSFalse;\n"
- "}\n"
- "let obj = if thisobj.get().is_object() {\n"
- " RootedObject::new(cx, thisobj.get().to_object())\n"
- "} else {\n"
- " RootedObject::new(cx, GetGlobalForObjectCrossCompartment(JS_CALLEE(cx, vp).to_object_or_null()))\n"
- "};\n"
- "\n"
- "let this: Root<%s> = %s;\n" % (self.descriptor.concreteType, unwrapThis))
- return CGList([ unwrapThis, self.generate_code() ], "\n")
-
- def generate_code(self):
- assert(False) # Override me
-
-
class CGAbstractStaticBindingMethod(CGAbstractMethod):
"""
Common class to generate the JSNatives for all our static methods, getters
@@ -2767,21 +2721,6 @@ let global = global_object_for_js_object(JS_CALLEE(cx, vp).to_object());
def generate_code(self):
assert False # Override me
-
-class CGGenericMethod(CGAbstractBindingMethod):
- """
- A class for generating the C++ code for an IDL method..
- """
- def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', 'argc'),
- Argument('*mut JSVal', 'vp')]
- CGAbstractBindingMethod.__init__(self, descriptor, 'genericMethod', args)
-
- def generate_code(self):
- return CGGeneric(
- "let _info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
- "return CallJitMethodOp(_info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp);")
-
class CGSpecializedMethod(CGAbstractExternMethod):
"""
A class for generating the C++ code for a specialized method that the JIT
@@ -2825,30 +2764,6 @@ class CGStaticMethod(CGAbstractStaticBindingMethod):
call = CGMethodCall(["global.r()"], nativeName, True, self.descriptor, self.method)
return CGList([setupArgs, call])
-class CGGenericGetter(CGAbstractBindingMethod):
- """
- A class for generating the C++ code for an IDL attribute getter.
- """
- def __init__(self, descriptor, lenientThis=False):
- args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', 'argc'),
- Argument('*mut JSVal', 'vp')]
- if lenientThis:
- name = "genericLenientGetter"
- unwrapFailureCode = (
- "assert!(JS_IsExceptionPending(cx) == 0);\n"
- "*vp = UndefinedValue();\n"
- "return 1;")
- else:
- name = "genericGetter"
- unwrapFailureCode = None
- CGAbstractBindingMethod.__init__(self, descriptor, name, args,
- unwrapFailureCode)
-
- def generate_code(self):
- return CGGeneric(
- "let info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
- "return CallJitGetterOp(info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp);")
-
class CGSpecializedGetter(CGAbstractExternMethod):
"""
A class for generating the code for a specialized attribute getter
@@ -2900,34 +2815,6 @@ class CGStaticGetter(CGAbstractStaticBindingMethod):
self.attr)
return CGList([setupArgs, call])
-
-class CGGenericSetter(CGAbstractBindingMethod):
- """
- A class for generating the Rust code for an IDL attribute setter.
- """
- def __init__(self, descriptor, lenientThis=False):
- args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', 'argc'),
- Argument('*mut JSVal', 'vp')]
- if lenientThis:
- name = "genericLenientSetter"
- unwrapFailureCode = (
- "assert!(JS_IsExceptionPending(cx) == 0);\n"
- "return 1;")
- else:
- name = "genericSetter"
- unwrapFailureCode = None
- CGAbstractBindingMethod.__init__(self, descriptor, name, args,
- unwrapFailureCode)
-
- def generate_code(self):
- return CGGeneric(
- "let info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
- "if CallJitSetterOp(info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp) == 0 {\n"
- " return 0;\n"
- "}\n"
- "*vp = UndefinedValue();\n"
- "return 1;")
-
class CGSpecializedSetter(CGAbstractExternMethod):
"""
A class for generating the code for a specialized attribute setter
@@ -4641,8 +4528,6 @@ class CGDescriptor(CGThing):
# cgThings.append(CGGetConstructorObjectMethod(descriptor))
pass
- (hasMethod, hasGetter, hasLenientGetter,
- hasSetter, hasLenientSetter) = False, False, False, False, False
for m in descriptor.interface.members:
if (m.isMethod() and
(not m.isIdentifierLess() or m == descriptor.operations["Stringifier"])):
@@ -4652,7 +4537,6 @@ class CGDescriptor(CGThing):
elif not descriptor.interface.isCallback():
cgThings.append(CGSpecializedMethod(descriptor, m))
cgThings.append(CGMemberJITInfo(descriptor, m))
- hasMethod = True
elif m.isAttr():
if m.stringifier:
raise TypeError("Stringifier attributes not supported yet. "
@@ -4664,10 +4548,6 @@ class CGDescriptor(CGThing):
cgThings.append(CGStaticGetter(descriptor, m))
elif not descriptor.interface.isCallback():
cgThings.append(CGSpecializedGetter(descriptor, m))
- if m.hasLenientThis():
- hasLenientGetter = True
- else:
- hasGetter = True
if not m.readonly:
if m.isStatic():
@@ -4675,27 +4555,12 @@ class CGDescriptor(CGThing):
cgThings.append(CGStaticSetter(descriptor, m))
elif not descriptor.interface.isCallback():
cgThings.append(CGSpecializedSetter(descriptor, m))
- if m.hasLenientThis():
- hasLenientSetter = True
- else:
- hasSetter = True
elif m.getExtendedAttribute("PutForwards"):
cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
- hasSetter = True
if (not m.isStatic() and
not descriptor.interface.isCallback()):
cgThings.append(CGMemberJITInfo(descriptor, m))
- if hasMethod:
- cgThings.append(CGGenericMethod(descriptor))
- if hasGetter:
- cgThings.append(CGGenericGetter(descriptor))
- if hasLenientGetter:
- cgThings.append(CGGenericGetter(descriptor, lenientThis=True))
- if hasSetter:
- cgThings.append(CGGenericSetter(descriptor))
- if hasLenientSetter:
- cgThings.append(CGGenericSetter(descriptor, lenientThis=True))
if descriptor.concrete:
cgThings.append(CGClassFinalizeHook(descriptor))
@@ -5128,6 +4993,9 @@ class CGBindingRoot(CGThing):
'dom::bindings::utils::{NativeProperties, NativePropertyHooks}',
'dom::bindings::utils::ConstantVal::{IntVal, UintVal}',
'dom::bindings::utils::NonNullJSNative',
+ 'dom::bindings::utils::{generic_getter, generic_lenient_getter}',
+ 'dom::bindings::utils::{generic_lenient_setter, generic_method}',
+ 'dom::bindings::utils::generic_setter',
'dom::bindings::trace::{JSTraceable, RootedTraceable}',
'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}',
'dom::bindings::callback::{CallSetup,ExceptionHandling}',
@@ -5756,6 +5624,15 @@ class GlobalGenRoots():
CGGeneric(AUTOGENERATED_WARNING_COMMENT),
CGGeneric("pub const MAX_PROTO_CHAIN_LENGTH: usize = %d;\n\n" % config.maxProtoChainLength),
CGNonNamespacedEnum('ID', protos, [0], deriving="PartialEq, Copy, Clone", repr="u16"),
+ CGWrapper(CGIndenter(CGList([CGGeneric('"' + name + '"') for name in protos],
+ ",\n"),
+ indentLevel=4),
+ pre="static INTERFACES: [&'static str; %d] = [\n" % len(protos),
+ post="\n];\n\n"),
+ CGGeneric("pub fn proto_id_to_name(proto_id: u16) -> &'static str {\n"
+ " debug_assert!(proto_id < ID::Count as u16);\n"
+ " INTERFACES[proto_id as usize]\n"
+ "}\n\n"),
CGNonNamespacedEnum('Proxies', proxies, [0], deriving="PartialEq, Copy, Clone"),
])
diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs
index 317744907c7..1f29eeb687d 100644
--- a/components/script/dom/bindings/conversions.rs
+++ b/components/script/dom/bindings/conversions.rs
@@ -41,17 +41,16 @@ use dom::bindings::utils::{Reflectable, Reflector, DOMClass};
use util::str::DOMString;
use js;
-use js::glue::{RUST_JSID_TO_STRING, RUST_JSID_IS_STRING};
-use js::glue::RUST_JS_NumberValue;
+use js::glue::{GetProxyPrivate, IsWrapper, RUST_JS_NumberValue};
+use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING, UnwrapObject};
use js::rust::{ToUint64, ToInt64};
use js::rust::{ToUint32, ToInt32};
use js::rust::{ToUint16, ToNumber, ToBoolean, ToString};
-use js::jsapi::{JSContext, JSObject, JSString};
-use js::jsapi::{JS_StringHasLatin1Chars, JS_GetLatin1StringCharsAndLength, JS_GetTwoByteStringCharsAndLength};
-use js::jsapi::{JS_NewUCStringCopyN, JS_NewStringCopyN};
-use js::jsapi::{JS_WrapValue};
-use js::jsapi::{JSClass, JS_GetClass};
-use js::jsapi::{HandleId, HandleValue, HandleObject, MutableHandleValue};
+use js::jsapi::{HandleId, HandleObject, HandleValue, JS_GetClass};
+use js::jsapi::{JS_GetLatin1StringCharsAndLength, JS_GetReservedSlot};
+use js::jsapi::{JS_GetTwoByteStringCharsAndLength, JS_NewStringCopyN};
+use js::jsapi::{JS_NewUCStringCopyN, JS_StringHasLatin1Chars, JS_WrapValue};
+use js::jsapi::{JSClass, JSContext, JSObject, JSString, MutableHandleValue};
use js::jsval::JSVal;
use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value};
use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue};
@@ -504,25 +503,27 @@ pub fn is_dom_proxy(obj: *mut JSObject) -> bool {
// globals and non-globals.
pub const DOM_OBJECT_SLOT: u32 = 0;
-/// Get the DOM object from the given reflector.
-pub unsafe fn native_from_reflector<T>(obj: *mut JSObject) -> *const T {
- use js::jsapi::JS_GetReservedSlot;
- use js::glue::GetProxyPrivate;
-
+/// Get the private pointer of a DOM object from a given reflector.
+unsafe fn private_from_reflector(obj: *mut JSObject) -> *const libc::c_void {
let clasp = JS_GetClass(obj);
let value = if is_dom_class(clasp) {
JS_GetReservedSlot(obj, DOM_OBJECT_SLOT)
} else {
- assert!(is_dom_proxy(obj));
+ debug_assert!(is_dom_proxy(obj));
GetProxyPrivate(obj)
};
if value.is_undefined() {
ptr::null()
} else {
- value.to_private() as *const T
+ value.to_private()
}
}
+/// Get the DOM object from the given reflector.
+pub unsafe fn native_from_reflector<T>(obj: *mut JSObject) -> *const T {
+ private_from_reflector(obj) as *const T
+}
+
/// Get the `DOMClass` from `obj`, or `Err(())` if `obj` is not a DOM object.
unsafe fn get_dom_class(obj: *mut JSObject) -> Result<DOMClass, ()> {
use dom::bindings::utils::DOMJSClass;
@@ -543,47 +544,57 @@ unsafe fn get_dom_class(obj: *mut JSObject) -> Result<DOMClass, ()> {
return Err(());
}
-/// Get an `Unrooted<T>` for the given DOM object, unwrapping any wrapper
-/// around it first, and checking if the object is of the correct type.
+/// Get a `*const libc::c_void` 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
+/// not an object for a DOM object of the given type (as defined by the
/// proto_id and proto_depth).
-pub fn native_from_reflector_jsmanaged<T>(mut obj: *mut JSObject) -> Result<Root<T>, ()>
- where T: Reflectable + IDLInterface
-{
- use js::glue::{IsWrapper, UnwrapObject};
-
- unsafe {
- let dom_class = try!(get_dom_class(obj).or_else(|_| {
- if IsWrapper(obj) == 1 {
- debug!("found wrapper");
- obj = UnwrapObject(obj, /* stopAtOuter = */ 0);
- if obj.is_null() {
- debug!("unwrapping security wrapper failed");
- Err(())
- } else {
- assert!(IsWrapper(obj) == 0);
- debug!("unwrapped successfully");
- get_dom_class(obj)
- }
- } else {
- debug!("not a dom wrapper");
+pub unsafe fn private_from_proto_chain(mut obj: *mut JSObject,
+ proto_id: u16, proto_depth: u16)
+ -> Result<*const libc::c_void, ()> {
+ let dom_class = try!(get_dom_class(obj).or_else(|_| {
+ if IsWrapper(obj) == 1 {
+ debug!("found wrapper");
+ obj = UnwrapObject(obj, /* stopAtOuter = */ 0);
+ if obj.is_null() {
+ debug!("unwrapping security wrapper failed");
Err(())
+ } else {
+ assert!(IsWrapper(obj) == 0);
+ debug!("unwrapped successfully");
+ get_dom_class(obj)
}
- }));
-
- let proto_id = <T as IDLInterface>::get_prototype_id();
- let proto_depth = <T as IDLInterface>::get_prototype_depth();
- if dom_class.interface_chain[proto_depth] == proto_id {
- debug!("good prototype");
- let native = native_from_reflector(obj);
- assert!(!native.is_null());
- Ok(Root::new(NonZero::new(native)))
} else {
- debug!("bad prototype");
+ debug!("not a dom wrapper");
Err(())
}
+ }));
+
+ if dom_class.interface_chain[proto_depth as usize] as u16 == proto_id {
+ debug!("good prototype");
+ Ok(private_from_reflector(obj))
+ } else {
+ debug!("bad prototype");
+ Err(())
+ }
+}
+
+/// Get a `Root<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 native_from_reflector_jsmanaged<T>(obj: *mut JSObject) -> Result<Root<T>, ()>
+ where T: Reflectable + IDLInterface
+{
+ let proto_id = <T as IDLInterface>::get_prototype_id() as u16;
+ let proto_depth = <T as IDLInterface>::get_prototype_depth() as u16;
+ unsafe {
+ private_from_proto_chain(obj, proto_id, proto_depth).map(|obj| {
+ Root::new(NonZero::new(obj as *const T))
+ })
}
}
diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs
index 683e5e19feb..9c0567067db 100644
--- a/components/script/dom/bindings/error.rs
+++ b/components/script/dom/bindings/error.rs
@@ -4,6 +4,7 @@
//! Utilities to throw exceptions from Rust bindings.
+use dom::bindings::codegen::PrototypeList::proto_id_to_name;
use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::global::GlobalRef;
use dom::domexception::{DOMException, DOMErrorName};
@@ -149,6 +150,15 @@ pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) {
throw_type_error(cx, &error);
}
+/// Throw an exception to signal that a `JSObject` can not be converted to a
+/// given DOM type.
+pub fn throw_invalid_this(cx: *mut JSContext, proto_id: u16) {
+ debug_assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
+ let error = format!("\"this\" object does not implement interface {}.",
+ proto_id_to_name(proto_id));
+ throw_type_error(cx, &error);
+}
+
/// Format string used to throw javascript errors.
static ERROR_FORMAT_STRING_STRING: [libc::c_char; 4] = [
'{' as libc::c_char,
diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs
index 43f920a4f02..c57de127dfc 100644
--- a/components/script/dom/bindings/utils.rs
+++ b/components/script/dom/bindings/utils.rs
@@ -6,8 +6,11 @@
use dom::bindings::codegen::PrototypeList;
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
-use dom::bindings::conversions::{native_from_handleobject, is_dom_class, jsstring_to_str};
-use dom::bindings::error::{Error, ErrorResult, Fallible, throw_type_error};
+use dom::bindings::conversions::{is_dom_class, jsstring_to_str};
+use dom::bindings::conversions::native_from_handleobject;
+use dom::bindings::conversions::private_from_proto_chain;
+use dom::bindings::error::{Error, ErrorResult, Fallible, throw_invalid_this};
+use dom::bindings::error::throw_type_error;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use dom::bindings::trace::trace_object;
@@ -24,8 +27,11 @@ use std::ptr;
use std::cmp::PartialEq;
use std::default::Default;
use std::cell::UnsafeCell;
-use js::glue::UnwrapObject;
-use js::glue::{IsWrapper, RUST_JSID_IS_INT, RUST_JSID_TO_INT};
+use js::glue::{CallJitMethodOp, CallJitGetterOp, CallJitSetterOp, IsWrapper};
+use js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT};
+use js::glue::{RUST_JSID_TO_INT, UnwrapObject};
+use js::jsapi::{CallArgs, GetGlobalForObjectCrossCompartment, JSJitInfo};
+use js::jsapi::JS_IsExceptionPending;
use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewFunction, JSTraceOp};
use js::jsapi::{JS_DefineProperties, JS_ForwardGetPropertyTo};
use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype};
@@ -47,13 +53,12 @@ use js::jsapi::{ObjectOpResult, RootedObject, RootedValue, Heap, MutableHandleOb
use js::jsapi::PropertyDefinitionBehavior;
use js::jsapi::JSAutoCompartment;
use js::jsapi::{DOMCallbacks, JSWrapObjectCallbacks};
-use js::jsval::JSVal;
-use js::jsval::{PrivateValue, NullValue};
-use js::jsval::{Int32Value, UInt32Value, DoubleValue, BooleanValue};
+use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue};
+use js::jsval::{PrivateValue, UInt32Value, UndefinedValue};
use js::rust::{GCMethods, ToString};
use js::glue::{WrapperNew, GetCrossCompartmentWrapper};
-use js::{JSPROP_ENUMERATE, JSPROP_READONLY, JSPROP_PERMANENT};
-use js::JSFUN_CONSTRUCTOR;
+use js::{JS_ARGV, JS_CALLEE, JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE};
+use js::{JSPROP_PERMANENT, JSPROP_READONLY};
use js;
use string_cache::{Atom, Namespace};
@@ -670,6 +675,91 @@ pub unsafe fn delete_property_by_id(cx: *mut JSContext, object: HandleObject,
JS_DeletePropertyById1(cx, object, id, bp)
}
+unsafe fn generic_call(cx: *mut JSContext, argc: libc::c_uint, vp: *mut JSVal,
+ is_lenient: bool,
+ call: unsafe extern fn(*const JSJitInfo, *mut JSContext,
+ HandleObject, *mut libc::c_void, u32,
+ *mut JSVal)
+ -> u8)
+ -> u8 {
+ let args = CallArgs::from_vp(vp, argc);
+ let thisobj = args.thisv();
+ if !thisobj.get().is_null_or_undefined() && !thisobj.get().is_object() {
+ return 0;
+ }
+ let obj = if thisobj.get().is_object() {
+ thisobj.get().to_object()
+ } else {
+ GetGlobalForObjectCrossCompartment(JS_CALLEE(cx, vp).to_object_or_null())
+ };
+ let obj = RootedObject::new(cx, obj);
+ let info = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));
+ let proto_id = (*info).protoID;
+ let depth = (*info).depth;
+ let this = match private_from_proto_chain(obj.ptr, proto_id, depth) {
+ Ok(val) => val,
+ Err(()) => {
+ if is_lenient {
+ debug_assert!(JS_IsExceptionPending(cx) == 0);
+ *vp = UndefinedValue();
+ return 1;
+ } else {
+ throw_invalid_this(cx, proto_id);
+ return 0;
+ }
+ }
+ };
+ call(info, cx, obj.handle(), this as *mut libc::c_void, argc, vp)
+}
+
+/// Generic method of IDL interface.
+pub unsafe extern fn generic_method(cx: *mut JSContext,
+ argc: libc::c_uint, vp: *mut JSVal)
+ -> u8 {
+ generic_call(cx, argc, vp, false, CallJitMethodOp)
+}
+
+/// Generic getter of IDL interface.
+pub unsafe extern fn generic_getter(cx: *mut JSContext,
+ argc: libc::c_uint, vp: *mut JSVal)
+ -> u8 {
+ generic_call(cx, argc, vp, false, CallJitGetterOp)
+}
+
+/// Generic lenient getter of IDL interface.
+pub unsafe extern fn generic_lenient_getter(cx: *mut JSContext,
+ argc: libc::c_uint,
+ vp: *mut JSVal)
+ -> u8 {
+ generic_call(cx, argc, vp, true, CallJitGetterOp)
+}
+
+unsafe extern fn call_setter(info: *const JSJitInfo, cx: *mut JSContext,
+ handle: HandleObject, this: *mut libc::c_void,
+ argc: u32, vp: *mut JSVal)
+ -> u8 {
+ if CallJitSetterOp(info, cx, handle, this, argc, vp) == 0 {
+ return 0;
+ }
+ *vp = UndefinedValue();
+ 1
+}
+
+/// Generic setter of IDL interface.
+pub unsafe extern fn generic_setter(cx: *mut JSContext,
+ argc: libc::c_uint, vp: *mut JSVal)
+ -> u8 {
+ generic_call(cx, argc, vp, false, call_setter)
+}
+
+/// Generic lenient setter of IDL interface.
+pub unsafe extern fn generic_lenient_setter(cx: *mut JSContext,
+ argc: libc::c_uint,
+ vp: *mut JSVal)
+ -> u8 {
+ generic_call(cx, argc, vp, true, call_setter)
+}
+
/// Validate a qualified name. See https://dom.spec.whatwg.org/#validate for details.
pub fn validate_qualified_name(qualified_name: &str) -> ErrorResult {
match xml_name_type(qualified_name) {
diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini
index b1228b4171f..02a810d184b 100644
--- a/tests/wpt/metadata/html/dom/interfaces.html.ini
+++ b/tests/wpt/metadata/html/dom/interfaces.html.ini
@@ -57,9 +57,6 @@
[Document interface: attribute commands]
expected: FAIL
- [Document interface: attribute onreadystatechange]
- expected: FAIL
-
[Document interface: attribute fgColor]
expected: FAIL