Auto merge of #8954 - nox:protochain, r=Ms2ger

Fix prototypes of interface objects (fixes #2665)

Callback interface objects' (i.e. NodeFilter's) prototype is now Object instead of
Function and non-callback interface objects' their proper ancestor, starting with
the Function prototype.

The function do_create_interface_objects is removed in favour of 4 functions:
create_callback_interface_object, create_interface_prototype_object,
create_noncallback_interface_object and create_named_constructors.

While this increases the amount of codegen'd code, this greatly improves the
readability of the code involved in this part of DOM, instead of having one function
doing 4 different things. We can always find a more adequate abstraction later.

NativeProperties and everything related to the interface objects have been removed
from the utils module.

Fixes #2665.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8954)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-01-12 22:00:47 +05:30
commit e977a6e69a
15 changed files with 517 additions and 728 deletions

View file

@ -276,34 +276,6 @@ class CGThing():
raise NotImplementedError # Override me!
class CGNativePropertyHooks(CGThing):
"""
Generate a NativePropertyHooks for a given descriptor
"""
def __init__(self, descriptor, properties):
CGThing.__init__(self)
self.descriptor = descriptor
self.properties = properties
def define(self):
parent = self.descriptor.interface.parent
if parent:
parentHooks = ("Some(&::dom::bindings::codegen::Bindings::%sBinding::sNativePropertyHooks)"
% parent.identifier.name)
else:
parentHooks = "None"
substitutions = {
"parentHooks": parentHooks
}
return string.Template(
"pub static sNativePropertyHooks: NativePropertyHooks = NativePropertyHooks {\n"
" native_properties: &sNativeProperties,\n"
" proto_hooks: ${parentHooks},\n"
"};\n").substitute(substitutions)
class CGMethodCall(CGThing):
"""
A class to generate selection of a method signature from a set of
@ -1750,17 +1722,16 @@ def DOMClassTypeId(desc):
def DOMClass(descriptor):
protoList = ['PrototypeList::ID::' + proto for proto in descriptor.prototypeChain]
# Pad out the list to the right length with ID::Count so we
# guarantee that all the lists are the same length. id::Count
# Pad out the list to the right length with ID::Last so we
# guarantee that all the lists are the same length. ID::Last
# is never the ID of any prototype, so it's safe to use as
# padding.
protoList.extend(['PrototypeList::ID::Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
protoList.extend(['PrototypeList::ID::Last'] * (descriptor.config.maxProtoChainLength - len(protoList)))
prototypeChainString = ', '.join(protoList)
heapSizeOf = 'heap_size_of_raw_self_and_children::<%s>' % descriptor.interface.identifier.name
return """\
DOMClass {
interface_chain: [ %s ],
native_hooks: &sNativePropertyHooks,
type_id: %s,
heap_size_of: %s as unsafe fn(_) -> _,
}""" % (prototypeChainString, DOMClassTypeId(descriptor), heapSizeOf)
@ -1839,6 +1810,7 @@ static Class: DOMJSClass = DOMJSClass {
getElements: None,
enumerate: None,
thisObject: %s,
funToString: None,
},
},
dom_class: %s
@ -1882,40 +1854,32 @@ static PrototypeClass: JSClass = JSClass {
hasInstance: None,
construct: None,
trace: None,
reserved: [0 as *mut libc::c_void; 25]
reserved: [0 as *mut libc::c_void; 26]
};
""" % {'name': name, 'slotCount': slotCount}
class CGInterfaceObjectJSClass(CGThing):
def __init__(self, descriptor):
assert descriptor.interface.hasInterfaceObject() and not descriptor.interface.isCallback()
CGThing.__init__(self)
self.descriptor = descriptor
def define(self):
if True:
return ""
ctorname = "0 as *const u8" if not self.descriptor.interface.ctor() else CONSTRUCT_HOOK_NAME
hasinstance = HASINSTANCE_HOOK_NAME
if self.descriptor.interface.ctor():
constructor = CONSTRUCT_HOOK_NAME
else:
constructor = "throwing_constructor"
args = {
"constructor": constructor,
"hasInstance": HASINSTANCE_HOOK_NAME,
"name": self.descriptor.interface.identifier.name,
}
return """\
const InterfaceObjectClass: JSClass = {
%s, 0,
JS_PropertyStub,
JS_PropertyStub,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
0 as *const u8,
0 as *const u8,
%s,
%s,
%s,
0 as *const u8,
JSCLASS_NO_INTERNAL_MEMBERS
};
""" % (str_to_const_array("Function"), ctorname, hasinstance, ctorname)
static InterfaceObjectClass: NonCallbackInterfaceObjectClass =
NonCallbackInterfaceObjectClass::new(%(constructor)s, %(hasInstance)s,
fun_to_string);
""" % args
class CGList(CGThing):
@ -2312,8 +2276,8 @@ class CGIDLInterface(CGThing):
name = self.descriptor.name
if (interface.getUserData("hasConcreteDescendant", False) or
interface.getUserData("hasProxyDescendant", False)):
depth = len(self.descriptor.prototypeChain)
check = "class.interface_chain[%s] == PrototypeList::ID::%s" % (depth - 1, name)
depth = self.descriptor.prototypeDepth
check = "class.interface_chain[%s] == PrototypeList::ID::%s" % (depth, name)
elif self.descriptor.proxy:
check = "class as *const _ == &Class as *const _"
else:
@ -2384,30 +2348,6 @@ class PropertyArrays():
return define
class CGNativeProperties(CGThing):
def __init__(self, descriptor, properties):
CGThing.__init__(self)
self.properties = properties
def define(self):
def getField(array):
propertyArray = getattr(self.properties, array)
if propertyArray.length() > 0:
value = "Some(%s)" % propertyArray.variableName()
else:
value = "None"
return CGGeneric(string.Template('${name}: ${value},').substitute({
'name': array,
'value': value,
}))
nativeProps = CGList([getField(array) for array in self.properties.arrayNames()], '\n')
return CGWrapper(CGIndenter(nativeProps),
pre="static sNativeProperties: NativeProperties = NativeProperties {\n",
post="\n};\n").define()
class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
"""
Generate the CreateInterfaceObjects method for an interface descriptor.
@ -2415,62 +2355,113 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
properties should be a PropertyArrays instance.
"""
def __init__(self, descriptor, properties):
args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'),
Argument('HandleObject', 'receiver'),
Argument('MutableHandleObject', 'rval')]
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
args = [Argument('*mut JSContext', 'cx')]
if not descriptor.interface.isCallback():
args += [Argument('HandleObject', 'global'),
Argument('*mut ProtoOrIfaceArray', 'cache')]
args.append(Argument('HandleObject', 'receiver'))
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args,
unsafe=True)
self.properties = properties
def definition_body(self):
name = self.descriptor.interface.identifier.name
if self.descriptor.interface.isCallback():
assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants()
return CGGeneric("""\
create_callback_interface_object(cx, receiver, sConstants, %s);""" % str_to_const_array(name))
protoChain = self.descriptor.prototypeChain
if len(protoChain) == 1:
self.unsafe = True
getParentProto = "parent_proto.ptr = JS_GetObjectPrototype(cx, global)"
getPrototypeProto = "prototype_proto.ptr = JS_GetObjectPrototype(cx, global)"
else:
parentProtoName = self.descriptor.prototypeChain[-2]
getParentProto = ("%s::GetProtoObject(cx, global, receiver, parent_proto.handle_mut())" %
toBindingNamespace(parentProtoName))
getPrototypeProto = ("%s::GetProtoObject(cx, global, receiver, prototype_proto.handle_mut())" %
toBindingNamespace(self.descriptor.prototypeChain[-2]))
getParentProto = ("let mut parent_proto = RootedObject::new(cx, ptr::null_mut());\n"
"%s;\n"
"assert!(!parent_proto.ptr.is_null());\n") % getParentProto
code = [CGGeneric("""\
let mut prototype_proto = RootedObject::new(cx, ptr::null_mut());
%s;
assert!(!prototype_proto.ptr.is_null());""" % getPrototypeProto)]
if self.descriptor.interface.isCallback():
protoClass = "None"
else:
protoClass = "Some(&PrototypeClass)"
properties = {"id": name}
for arrayName in self.properties.arrayNames():
array = getattr(self.properties, arrayName)
if arrayName == "consts":
if array.length():
properties[arrayName] = array.variableName()
else:
properties[arrayName] = "&[]"
elif array.length():
properties[arrayName] = "Some(%s)" % array.variableName()
else:
properties[arrayName] = "None"
code.append(CGGeneric("""
let mut prototype = RootedObject::new(cx, ptr::null_mut());
create_interface_prototype_object(cx,
prototype_proto.handle(),
&PrototypeClass,
%(methods)s,
%(attrs)s,
%(consts)s,
prototype.handle_mut());
assert!(!prototype.ptr.is_null());
(*cache)[PrototypeList::ID::%(id)s as usize] = prototype.ptr;
if <*mut JSObject>::needs_post_barrier(prototype.ptr) {
<*mut JSObject>::post_barrier((*cache).as_mut_ptr().offset(PrototypeList::ID::%(id)s as isize));
}""" % properties))
if self.descriptor.interface.hasInterfaceObject():
properties["name"] = str_to_const_array(name)
if self.descriptor.interface.ctor():
constructHook = CONSTRUCT_HOOK_NAME
constructArgs = methodLength(self.descriptor.interface.ctor())
properties["constructor"] = CONSTRUCT_HOOK_NAME
properties["length"] = methodLength(self.descriptor.interface.ctor())
else:
constructHook = "throwing_constructor"
constructArgs = 0
properties["constructor"] = "throwing_constructor"
properties["length"] = 0
if self.descriptor.interface.parent:
parentName = toBindingNamespace(self.descriptor.getParentName())
code.append(CGGeneric("""
let mut interface_proto = RootedObject::new(cx, ptr::null_mut());
%s::GetConstructorObject(cx, global, receiver, interface_proto.handle_mut());""" % parentName))
else:
code.append(CGGeneric("""
let interface_proto = RootedObject::new(cx, JS_GetFunctionPrototype(cx, global));"""))
code.append(CGGeneric("""\
assert!(!interface_proto.ptr.is_null());
constructor = 'Some((%s as NonNullJSNative, "%s", %d))' % (
constructHook, self.descriptor.interface.identifier.name,
constructArgs)
else:
constructor = 'None'
let mut interface = RootedObject::new(cx, ptr::null_mut());
create_noncallback_interface_object(cx,
receiver,
interface_proto.handle(),
&InterfaceObjectClass,
%(static_methods)s,
%(static_attrs)s,
%(consts)s,
prototype.handle(),
%(name)s,
%(length)s,
interface.handle_mut());
assert!(!interface.ptr.is_null());""" % properties))
if self.descriptor.hasDescendants():
code.append(CGGeneric("""\
(*cache)[PrototypeList::Constructor::%(id)s as usize] = interface.ptr;
if <*mut JSObject>::needs_post_barrier(prototype.ptr) {
<*mut JSObject>::post_barrier((*cache).as_mut_ptr().offset(PrototypeList::Constructor::%(id)s as isize));
}""" % properties))
call = """\
do_create_interface_objects(cx, receiver, parent_proto.handle(),
%s, %s,
&named_constructors,
&sNativeProperties, rval);""" % (protoClass, constructor)
createArray = """\
let named_constructors: [(NonNullJSNative, &'static str, u32); %d] = [
""" % len(self.descriptor.interface.namedConstructors)
for ctor in self.descriptor.interface.namedConstructors:
constructHook = CONSTRUCT_HOOK_NAME + "_" + ctor.identifier.name
constructArgs = methodLength(ctor)
constructor = '(%s as NonNullJSNative, "%s", %d)' % (
constructHook, ctor.identifier.name, constructArgs)
createArray += constructor
createArray += ","
createArray += "];"
constructors = self.descriptor.interface.namedConstructors
if constructors:
decl = "let named_constructors: [(NonNullJSNative, &'static [u8], u32); %d]" % len(constructors)
specs = []
for constructor in constructors:
hook = CONSTRUCT_HOOK_NAME + "_" + constructor.identifier.name
name = str_to_const_array(constructor.identifier.name)
length = methodLength(constructor)
specs.append(CGGeneric("(%s as NonNullJSNative, %s, %d)" % (hook, name, length)))
values = CGIndenter(CGList(specs, "\n"), 4)
code.append(CGWrapper(values, pre="%s = [\n" % decl, post="\n];"))
code.append(CGGeneric("create_named_constructors(cx, receiver, &named_constructors, prototype.handle());"))
if self.descriptor.hasUnforgeableMembers:
# We want to use the same JSClass and prototype as the object we'll
@ -2486,41 +2477,22 @@ let named_constructors: [(NonNullJSNative, &'static str, u32); %d] = [
# the prototype.
if self.descriptor.proxy or self.descriptor.isGlobal():
holderClass = "ptr::null()"
holderProto = "ptr::null_mut()"
holderProto = "HandleObject::null()"
else:
holderClass = "&Class.base as *const js::jsapi::Class as *const JSClass"
holderProto = "rval.get()"
# JS_NewObjectWithoutMetadata() is unsafe.
self.unsafe = True
createUnforgeableHolder = CGGeneric("""
holderProto = "prototype.handle()"
code.append(CGGeneric("""
let mut unforgeable_holder = RootedObject::new(cx, ptr::null_mut());
{
let holder_class = %(holderClass)s;
let holder_proto = RootedObject::new(cx, %(holderProto)s);
unforgeable_holder.handle_mut().set(
JS_NewObjectWithoutMetadata(cx, holder_class, holder_proto.handle()));
assert!(!unforgeable_holder.ptr.is_null());
}""" % {'holderClass': holderClass, 'holderProto': holderProto})
defineUnforgeables = InitUnforgeablePropertiesOnHolder(self.descriptor,
self.properties)
createUnforgeableHolder = CGList(
[createUnforgeableHolder, defineUnforgeables], "\n")
unforgeable_holder.handle_mut().set(
JS_NewObjectWithoutMetadata(cx, %(holderClass)s, %(holderProto)s));
assert!(!unforgeable_holder.ptr.is_null());
""" % {'holderClass': holderClass, 'holderProto': holderProto}))
code.append(InitUnforgeablePropertiesOnHolder(self.descriptor, self.properties))
code.append(CGGeneric("""\
JS_SetReservedSlot(prototype.ptr, DOM_PROTO_UNFORGEABLE_HOLDER_SLOT,
ObjectValue(&*unforgeable_holder.ptr))"""))
installUnforgeableHolder = CGGeneric("""\
JS_SetReservedSlot(rval.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT,
ObjectValue(&*unforgeable_holder.ptr))""")
unforgeableHolderSetup = CGList(
[createUnforgeableHolder, installUnforgeableHolder], "\n")
else:
unforgeableHolderSetup = None
return CGList([
CGGeneric(getParentProto),
CGGeneric(createArray),
CGGeneric(call % self.properties.variableNames()),
unforgeableHolderSetup,
], "\n")
return CGList(code, "\n")
class CGGetPerInterfaceObject(CGAbstractMethod):
@ -2534,7 +2506,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
Argument('MutableHandleObject', 'rval')]
CGAbstractMethod.__init__(self, descriptor, name,
'void', args, pub=pub, unsafe=True)
self.id = idPrefix + "ID::" + self.descriptor.name
self.id = idPrefix + "::" + self.descriptor.name
def definition_body(self):
return CGGeneric("""
@ -2549,18 +2521,15 @@ assert!(((*JS_GetClass(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0);
/* Check to see whether the interface objects are already installed */
let proto_or_iface_array = get_proto_or_iface_array(global.get());
rval.set((*proto_or_iface_array)[%s as usize]);
rval.set((*proto_or_iface_array)[%(id)s as usize]);
if !rval.get().is_null() {
return;
}
CreateInterfaceObjects(cx, global, receiver, rval);
CreateInterfaceObjects(cx, global, proto_or_iface_array, receiver);
rval.set((*proto_or_iface_array)[%(id)s as usize]);
assert!(!rval.get().is_null());
(*proto_or_iface_array)[%s as usize] = rval.get();
if <*mut JSObject>::needs_post_barrier(rval.get()) {
<*mut JSObject>::post_barrier((*proto_or_iface_array).as_mut_ptr().offset(%s as isize))
}
""" % (self.id, self.id, self.id))
""" % {"id": self.id})
class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
@ -2569,7 +2538,7 @@ class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
"""
def __init__(self, descriptor):
CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject",
"PrototypeList::", pub=descriptor.hasDescendants())
"PrototypeList::ID", pub=descriptor.hasDescendants())
def definition_body(self):
return CGList([
@ -2586,7 +2555,8 @@ class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
"""
def __init__(self, descriptor):
CGGetPerInterfaceObject.__init__(self, descriptor, "GetConstructorObject",
"constructors::", pub=descriptor.hasDescendants())
"PrototypeList::Constructor",
pub=descriptor.hasDescendants())
def definition_body(self):
return CGList([
@ -2674,10 +2644,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
def definition_body(self):
if self.descriptor.interface.isCallback():
code = """\
let mut obj = RootedObject::new(cx, ptr::null_mut());
CreateInterfaceObjects(cx, global, global, obj.handle_mut());
"""
code = "CreateInterfaceObjects(cx, global);"
else:
code = """\
let mut proto = RootedObject::new(cx, ptr::null_mut());
@ -4738,6 +4705,44 @@ let args = CallArgs::from_vp(vp, argc);
return CGList([preamble, callGenerator])
class CGClassHasInstanceHook(CGAbstractExternMethod):
def __init__(self, descriptor):
args = [Argument('*mut JSContext', 'cx'),
Argument('HandleObject', 'obj'),
Argument('MutableHandleValue', 'value'),
Argument('*mut bool', 'rval')]
assert descriptor.interface.hasInterfaceObject() and not descriptor.interface.isCallback()
CGAbstractExternMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
'bool', args)
def definition_body(self):
id = "PrototypeList::ID::%s" % self.descriptor.interface.identifier.name
return CGGeneric("""\
match has_instance(cx, obj, value.handle(), %(id)s, %(index)s) {
Ok(result) => {
*rval = result;
true
}
Err(()) => false,
}
""" % {"id": id, "index": self.descriptor.prototypeDepth})
class CGClassFunToStringHook(CGAbstractExternMethod):
"""
A hook to convert functions to strings.
"""
def __init__(self, descriptor):
args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_obj'),
Argument('u32', '_indent')]
CGAbstractExternMethod.__init__(self, descriptor, "fun_to_string", '*mut JSString', args)
def definition_body(self):
name = self.descriptor.interface.identifier.name
string = str_to_const_array("function %s() {\\n [native code]\\n}" % name)
return CGGeneric("JS_NewStringCopyZ(cx, %s as *const _ as *const libc::c_char)" % string)
class CGClassFinalizeHook(CGAbstractClassHook):
"""
A hook for finalize, used to release our native object.
@ -4858,10 +4863,8 @@ class CGDescriptor(CGThing):
cgThings = []
if not descriptor.interface.isCallback():
cgThings.append(CGGetProtoObjectMethod(descriptor))
if descriptor.interface.hasInterfaceObject():
# https://github.com/mozilla/servo/issues/2665
# cgThings.append(CGGetConstructorObjectMethod(descriptor))
pass
if descriptor.interface.hasInterfaceObject() and descriptor.hasDescendants():
cgThings.append(CGGetConstructorObjectMethod(descriptor))
for m in descriptor.interface.members:
if (m.isMethod() and
@ -4905,15 +4908,16 @@ class CGDescriptor(CGThing):
cgThings.append(CGClassConstructHook(descriptor))
for ctor in descriptor.interface.namedConstructors:
cgThings.append(CGClassConstructHook(descriptor, ctor))
cgThings.append(CGInterfaceObjectJSClass(descriptor))
if not descriptor.interface.isCallback():
cgThings.append(CGInterfaceObjectJSClass(descriptor))
cgThings.append(CGClassHasInstanceHook(descriptor))
cgThings.append(CGClassFunToStringHook(descriptor))
if not descriptor.interface.isCallback():
cgThings.append(CGPrototypeJSClass(descriptor))
properties = PropertyArrays(descriptor)
cgThings.append(CGGeneric(str(properties)))
cgThings.append(CGNativeProperties(descriptor, properties))
cgThings.append(CGNativePropertyHooks(descriptor, properties))
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
cgThings.append(CGNamespace.build([descriptor.name + "Constants"],
@ -4973,22 +4977,12 @@ class CGDescriptor(CGThing):
class CGNonNamespacedEnum(CGThing):
def __init__(self, enumName, names, values, comment="", deriving="", repr=""):
def __init__(self, enumName, names, first, comment="", deriving="", repr=""):
# Account for first value
entries = ["%s = %s" % (names[0], first)] + names[1:]
if not values:
values = []
# Account for explicit enum values.
entries = []
for i in range(0, len(names)):
if len(values) > i and values[i] is not None:
entry = "%s = %s" % (names[i], values[i])
else:
entry = names[i]
entries.append(entry)
# Append a Count.
entries.append('Count = ' + str(len(entries)))
# Append a Last.
entries.append('Last = ' + str(first + len(entries)))
# Indent.
entries = [' ' + e for e in entries]
@ -5301,16 +5295,16 @@ class CGBindingRoot(CGThing):
'js::jsapi::{HandleId, HandleObject, HandleValue, HandleValueArray}',
'js::jsapi::{INTERNED_STRING_TO_JSID, IsCallable, JS_CallFunctionValue}',
'js::jsapi::{JS_ComputeThis, JS_CopyPropertiesFrom, JS_ForwardGetPropertyTo}',
'js::jsapi::{JS_GetClass, JS_GetGlobalForObject, JS_GetObjectPrototype}',
'js::jsapi::{JS_GetProperty, JS_GetPropertyById, JS_GetPropertyDescriptorById}',
'js::jsapi::{JS_GetReservedSlot, JS_HasProperty, JS_HasPropertyById}',
'js::jsapi::{JS_InitializePropertiesFromCompatibleNativeObject, JS_InternString}',
'js::jsapi::{JS_IsExceptionPending, JS_NewObject, JS_NewObjectWithGivenProto}',
'js::jsapi::{JS_NewObjectWithoutMetadata, JS_SetProperty, JS_SetPrototype}',
'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSAutoCompartment, JSAutoRequest}',
'js::jsapi::{JSContext, JSClass, JSFreeOp, JSFunctionSpec, JSJitGetterCallArgs}',
'js::jsapi::{JSJitInfo, JSJitMethodCallArgs, JSJitSetterCallArgs, JSNative}',
'js::jsapi::{JSObject, JSNativeWrapper, JSPropertyDescriptor, JSPropertySpec}',
'js::jsapi::{JS_GetClass, JS_GetFunctionPrototype, JS_GetGlobalForObject}',
'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}',
'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot, JS_HasProperty}',
'js::jsapi::{JS_HasPropertyById, JS_InitializePropertiesFromCompatibleNativeObject}',
'js::jsapi::{JS_InternString, JS_IsExceptionPending, JS_NewObject, JS_NewObjectWithGivenProto}',
'js::jsapi::{JS_NewObjectWithoutMetadata, JS_NewStringCopyZ, JS_SetProperty}',
'js::jsapi::{JS_SetPrototype, JS_SetReservedSlot, JS_WrapValue, JSAutoCompartment}',
'js::jsapi::{JSAutoRequest, JSContext, JSClass, JSFreeOp, JSFunctionSpec}',
'js::jsapi::{JSJitGetterCallArgs, JSJitInfo, JSJitMethodCallArgs, JSJitSetterCallArgs}',
'js::jsapi::{JSNative, JSObject, JSNativeWrapper, JSPropertyDescriptor, JSPropertySpec}',
'js::jsapi::{JSString, JSTracer, JSType, JSTypedMethodJitInfo, JSValueType}',
'js::jsapi::{ObjectOpResult, OpType, MutableHandle, MutableHandleObject}',
'js::jsapi::{MutableHandleValue, RootedId, RootedObject, RootedString}',
@ -5326,14 +5320,16 @@ class CGBindingRoot(CGThing):
'js::rust::{GCMethods, define_methods, define_properties}',
'dom::bindings',
'dom::bindings::global::{GlobalRef, global_root_from_object, global_root_from_reflector}',
'dom::bindings::interface::{NonCallbackInterfaceObjectClass, create_callback_interface_object}',
'dom::bindings::interface::{create_interface_prototype_object, create_named_constructors}',
'dom::bindings::interface::{create_noncallback_interface_object, has_instance}',
'dom::bindings::js::{JS, Root, RootedReference}',
'dom::bindings::js::{OptionalRootedReference}',
'dom::bindings::reflector::{Reflectable}',
'dom::bindings::utils::{ConstantSpec, DOMClass, DOMJSClass}',
'dom::bindings::utils::{DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, JSCLASS_DOM_GLOBAL}',
'dom::bindings::utils::{NativeProperties, NativePropertyHooks, NonNullJSNative}',
'dom::bindings::utils::{create_dom_global, do_create_interface_objects, finalize_global}',
'dom::bindings::utils::{find_enum_string_index, generic_getter}',
'dom::bindings::utils::{NonNullJSNative, ProtoOrIfaceArray, create_dom_global}',
'dom::bindings::utils::{finalize_global, find_enum_string_index, generic_getter}',
'dom::bindings::utils::{generic_lenient_getter, generic_lenient_setter}',
'dom::bindings::utils::{generic_method, generic_setter, get_array_index_from_id}',
'dom::bindings::utils::{get_dictionary_property, get_property_on_prototype}',
@ -5985,23 +5981,28 @@ class GlobalGenRoots():
@staticmethod
def PrototypeList(config):
# Prototype ID enum.
protos = [d.name for d in config.getDescriptors(isCallback=False)]
interfaces = config.getDescriptors(isCallback=False)
protos = [d.name for d in interfaces]
constructors = [d.name for d in interfaces if d.hasDescendants()]
proxies = [d.name for d in config.getDescriptors(proxy=True)]
return CGList([
CGGeneric(AUTOGENERATED_WARNING_COMMENT),
CGGeneric("pub const PROTO_OR_IFACE_LENGTH: usize = %d;\n" % (len(protos) + len(constructors))),
CGGeneric("pub const MAX_PROTO_CHAIN_LENGTH: usize = %d;\n\n" % config.maxProtoChainLength),
CGNonNamespacedEnum('ID', protos, [0], deriving="PartialEq, Copy, Clone", repr="u16"),
CGNonNamespacedEnum('ID', protos, 0, deriving="PartialEq, Copy, Clone", repr="u16"),
CGNonNamespacedEnum('Constructor', constructors, len(protos),
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"
" debug_assert!(proto_id < ID::Last as u16);\n"
" INTERFACES[proto_id as usize]\n"
"}\n\n"),
CGNonNamespacedEnum('Proxies', proxies, [0], deriving="PartialEq, Copy, Clone"),
CGNonNamespacedEnum('Proxies', proxies, 0, deriving="PartialEq, Copy, Clone"),
])
@staticmethod

View file

@ -296,6 +296,7 @@ class Descriptor(DescriptorProvider):
while parent:
self.prototypeChain.insert(0, parent.identifier.name)
parent = parent.parent
self.prototypeDepth = len(self.prototypeChain) - 1
config.maxProtoChainLength = max(config.maxProtoChainLength,
len(self.prototypeChain))

View file

@ -0,0 +1,284 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Machinery to initialise interface prototype objects and interface objects.
use dom::bindings::codegen::PrototypeList;
use dom::bindings::conversions::get_dom_class;
use dom::bindings::utils::{ConstantSpec, NonNullJSNative, define_constants};
use js::glue::UncheckedUnwrapObject;
use js::jsapi::{Class, ClassExtension, ClassSpec, HandleObject, HandleValue, JSClass};
use js::jsapi::{JSContext, JSFunctionSpec, JSPropertySpec, JSString, JS_DefineProperty1};
use js::jsapi::{JS_DefineProperty2, JS_DefineProperty4, JS_GetFunctionObject};
use js::jsapi::{JS_GetPrototype, JS_InternString, JS_LinkConstructorAndPrototype};
use js::jsapi::{JS_NewFunction, JS_NewObject, JS_NewObjectWithUniqueType};
use js::jsapi::{MutableHandleObject, MutableHandleValue, ObjectOps, RootedObject};
use js::jsapi::{RootedString, Value};
use js::rust::{define_methods, define_properties};
use js::{JSFUN_CONSTRUCTOR, JSPROP_PERMANENT, JSPROP_READONLY};
use libc;
use std::ptr;
/// A constructor class hook.
pub type ConstructorClassHook =
unsafe extern "C" fn(cx: *mut JSContext, argc: u32, vp: *mut Value) -> bool;
/// A has_instance class hook.
pub type HasInstanceClassHook =
unsafe extern "C" fn(cx: *mut JSContext,
obj: HandleObject,
vp: MutableHandleValue,
bp: *mut bool)
-> bool;
/// A fun_to_string class hook.
pub type FunToStringHook =
unsafe extern "C" fn(cx: *mut JSContext,
obj: HandleObject,
indent: u32)
-> *mut JSString;
/// The class of a non-callback interface object.
#[derive(Copy, Clone)]
pub struct NonCallbackInterfaceObjectClass {
/// The SpiderMonkey Class structure.
pub class: Class,
}
unsafe impl Sync for NonCallbackInterfaceObjectClass {}
impl NonCallbackInterfaceObjectClass {
/// Create a new `NonCallbackInterfaceObjectClass` structure.
pub const fn new(
constructor: ConstructorClassHook,
has_instance: HasInstanceClassHook,
fun_to_string: FunToStringHook)
-> 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,
convert: None,
finalize: None,
call: Some(constructor),
hasInstance: Some(has_instance),
construct: Some(constructor),
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 {
outerObject: None,
innerObject: None,
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,
thisObject: None,
funToString: Some(fun_to_string),
}
},
}
}
}
/// Create and define the interface object of a callback interface.
pub unsafe fn create_callback_interface_object(
cx: *mut JSContext,
receiver: HandleObject,
constants: &'static [ConstantSpec],
name: &'static [u8]) {
assert!(!constants.is_empty());
let interface_object = RootedObject::new(cx, JS_NewObject(cx, ptr::null()));
assert!(!interface_object.ptr.is_null());
define_constants(cx, interface_object.handle(), constants);
define_name(cx, interface_object.handle(), name);
define_on_global_object(cx, receiver, name, interface_object.handle());
}
/// Create the interface prototype object of a non-callback interface.
pub unsafe fn create_interface_prototype_object(
cx: *mut JSContext,
proto: HandleObject,
class: &'static JSClass,
regular_methods: Option<&'static [JSFunctionSpec]>,
regular_properties: Option<&'static [JSPropertySpec]>,
constants: &'static [ConstantSpec],
rval: MutableHandleObject) {
create_object(cx, proto, class, regular_methods, regular_properties, constants, rval);
}
/// Create and define the interface object of a non-callback interface.
pub unsafe fn create_noncallback_interface_object(
cx: *mut JSContext,
receiver: HandleObject,
proto: HandleObject,
class: &'static NonCallbackInterfaceObjectClass,
static_methods: Option<&'static [JSFunctionSpec]>,
static_properties: Option<&'static [JSPropertySpec]>,
constants: &'static [ConstantSpec],
interface_prototype_object: HandleObject,
name: &'static [u8],
length: u32,
rval: MutableHandleObject) {
create_object(cx,
proto,
&*(class as *const _ as *const JSClass),
static_methods,
static_properties,
constants,
rval);
assert!(JS_LinkConstructorAndPrototype(cx, rval.handle(), interface_prototype_object));
define_name(cx, rval.handle(), name);
define_length(cx, rval.handle(), length);
define_on_global_object(cx, receiver, name, rval.handle());
}
/// Create and define the named constructors of a non-callback interface.
pub unsafe fn create_named_constructors(
cx: *mut JSContext,
receiver: HandleObject,
named_constructors: &[(NonNullJSNative, &'static [u8], u32)],
interface_prototype_object: HandleObject) {
let mut constructor = RootedObject::new(cx, ptr::null_mut());
for &(native, name, arity) in named_constructors {
assert!(*name.last().unwrap() == b'\0');
let fun = JS_NewFunction(cx,
Some(native),
arity,
JSFUN_CONSTRUCTOR,
name.as_ptr() as *const libc::c_char);
assert!(!fun.is_null());
constructor.ptr = JS_GetFunctionObject(fun);
assert!(!constructor.ptr.is_null());
assert!(JS_DefineProperty1(cx,
constructor.handle(),
b"prototype\0".as_ptr() as *const libc::c_char,
interface_prototype_object,
JSPROP_PERMANENT | JSPROP_READONLY,
None,
None));
define_on_global_object(cx, receiver, name, constructor.handle());
}
}
/// Return whether a value is an instance of a given prototype.
/// http://heycam.github.io/webidl/#es-interface-hasinstance
pub unsafe fn has_instance(
cx: *mut JSContext,
prototype: HandleObject,
value: HandleValue,
id: PrototypeList::ID,
index: usize)
-> Result<bool, ()> {
if !value.is_object() {
// Step 1.
return Ok(false);
}
let mut value = RootedObject::new(cx, value.to_object());
// Steps 2-3 only concern callback interface objects.
if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject(value.ptr, /* stopAtOuter = */ 0)) {
if dom_class.interface_chain[index] == id {
// Step 4.
return Ok(true);
}
}
while JS_GetPrototype(cx, value.handle(), value.handle_mut()) {
if value.ptr.is_null() {
// Step 5.2.
return Ok(false);
} else if value.ptr as *const _ == prototype.ptr {
// Step 5.3.
return Ok(true);
}
}
// JS_GetPrototype threw an exception.
Err(())
}
unsafe fn create_object(
cx: *mut JSContext,
proto: HandleObject,
class: &'static JSClass,
methods: Option<&'static [JSFunctionSpec]>,
properties: Option<&'static [JSPropertySpec]>,
constants: &'static [ConstantSpec],
rval: MutableHandleObject) {
rval.set(JS_NewObjectWithUniqueType(cx, class, proto));
assert!(!rval.ptr.is_null());
if let Some(methods) = methods {
define_methods(cx, rval.handle(), methods).unwrap();
}
if let Some(properties) = properties {
define_properties(cx, rval.handle(), properties).unwrap();
}
define_constants(cx, rval.handle(), constants);
}
unsafe fn define_name(cx: *mut JSContext, obj: HandleObject, name: &'static [u8]) {
assert!(*name.last().unwrap() == b'\0');
let name =
RootedString::new(cx, JS_InternString(cx, name.as_ptr() as *const libc::c_char));
assert!(!name.ptr.is_null());
assert!(JS_DefineProperty2(cx,
obj,
b"name\0".as_ptr() as *const libc::c_char,
name.handle(),
JSPROP_READONLY,
None, None));
}
unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: u32) {
assert!(JS_DefineProperty4(cx,
obj,
b"length\0".as_ptr() as *const libc::c_char,
length,
JSPROP_READONLY,
None, None));
}
unsafe fn define_on_global_object(
cx: *mut JSContext,
receiver: HandleObject,
name: &'static [u8],
obj: HandleObject) {
assert!(*name.last().unwrap() == b'\0');
assert!(JS_DefineProperty1(cx,
receiver,
name.as_ptr() as *const libc::c_char,
obj,
0,
None, None));
}

View file

@ -138,6 +138,7 @@ pub mod conversions;
pub mod error;
pub mod global;
pub mod inheritance;
pub mod interface;
pub mod js;
pub mod num;
pub mod proxyhandler;

View file

@ -5,7 +5,7 @@
//! Various utilities to glue JavaScript and the DOM implementation together.
use dom::bindings::codegen::PrototypeList;
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
use dom::bindings::codegen::PrototypeList::{MAX_PROTO_CHAIN_LENGTH, PROTO_OR_IFACE_LENGTH};
use dom::bindings::conversions::{DOM_OBJECT_SLOT, is_dom_class};
use dom::bindings::conversions::{private_from_proto_check, root_from_handleobject};
use dom::bindings::error::throw_invalid_this;
@ -19,32 +19,19 @@ use js::glue::{CallJitGetterOp, CallJitMethodOp, CallJitSetterOp, IsWrapper};
use js::glue::{GetCrossCompartmentWrapper, WrapperNew};
use js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT};
use js::glue::{RUST_JSID_TO_INT, UnwrapObject};
use js::jsapi::JSAutoCompartment;
use js::jsapi::JS_DeletePropertyById1;
use js::jsapi::JS_GetFunctionObject;
use js::jsapi::JS_IsExceptionPending;
use js::jsapi::JS_NewObjectWithUniqueType;
use js::jsapi::JS_ObjectToOuterObject;
use js::jsapi::{CallArgs, GetGlobalForObjectCrossCompartment, JSJitInfo};
use js::jsapi::{CompartmentOptions, OnNewGlobalHookOption};
use js::jsapi::{DOMCallbacks, JSWrapObjectCallbacks};
use js::jsapi::{HandleId, HandleObject, HandleValue, MutableHandleValue};
use js::jsapi::{Heap, MutableHandleObject, ObjectOpResult, RootedObject, RootedValue};
use js::jsapi::{JSClass, JSContext, JSObject, JSTracer};
use js::jsapi::{JSFunctionSpec, JSPropertySpec};
use js::jsapi::{JSTraceOp, JS_AlreadyHasOwnProperty, JS_NewFunction};
use js::jsapi::{JSVersion, JS_FireOnNewGlobalObject};
use js::jsapi::{JS_DefineProperty, JS_DefineProperty1, JS_ForwardGetPropertyTo};
use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype};
use js::jsapi::{JS_GetProperty, JS_HasProperty, JS_SetProperty};
use js::jsapi::{JS_GetPrototype, JS_HasPropertyById};
use js::jsapi::{JS_GetReservedSlot, JS_SetReservedSlot};
use js::jsapi::{JS_InitStandardClasses, JS_NewGlobalObject};
use js::jsapi::{CallArgs, CompartmentOptions, DOMCallbacks, GetGlobalForObjectCrossCompartment};
use js::jsapi::{HandleId, HandleObject, HandleValue, Heap, JSAutoCompartment, JSClass, JSContext};
use js::jsapi::{JSJitInfo, JSObject, JSTraceOp, JSTracer, JSVersion, JSWrapObjectCallbacks};
use js::jsapi::{JS_DefineProperty, JS_DeletePropertyById1, JS_FireOnNewGlobalObject};
use js::jsapi::{JS_ForwardGetPropertyTo, JS_GetClass, JS_GetProperty, JS_GetPrototype};
use js::jsapi::{JS_GetReservedSlot, JS_HasProperty, JS_HasPropertyById, JS_InitStandardClasses};
use js::jsapi::{JS_IsExceptionPending, JS_NewGlobalObject, JS_ObjectToOuterObject, JS_SetProperty};
use js::jsapi::{JS_SetReservedSlot, MutableHandleValue, ObjectOpResult, OnNewGlobalHookOption};
use js::jsapi::{RootedObject, RootedValue};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue};
use js::jsval::{PrivateValue, UInt32Value, UndefinedValue};
use js::rust::{GCMethods, ToString, define_methods, define_properties};
use js::{JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE, JS_CALLEE};
use js::{JSPROP_PERMANENT, JSPROP_READONLY};
use js::rust::{GCMethods, ToString};
use js::{JS_CALLEE, JSPROP_ENUMERATE, JSPROP_PERMANENT, JSPROP_READONLY};
use libc::{self, c_uint};
use std::default::Default;
use std::ffi::CString;
@ -129,15 +116,6 @@ impl ConstantSpec {
}
}
/// Helper structure for cross-origin wrappers for DOM binding objects.
pub struct NativePropertyHooks {
/// The property arrays for this interface.
pub native_properties: &'static NativeProperties,
/// The NativePropertyHooks instance for the parent interface, if any.
pub proto_hooks: Option<&'static NativePropertyHooks>,
}
/// The struct that holds inheritance information for DOM object reflectors.
#[derive(Copy, Clone)]
pub struct DOMClass {
@ -148,9 +126,6 @@ pub struct DOMClass {
/// The type ID of that interface.
pub type_id: TopTypeId,
/// The NativePropertyHooks for the interface associated with this class.
pub native_hooks: &'static NativePropertyHooks,
/// The HeapSizeOf function wrapper for that interface.
pub heap_size_of: unsafe fn(*const libc::c_void) -> usize,
}
@ -180,153 +155,13 @@ pub fn get_proto_or_iface_array(global: *mut JSObject) -> *mut ProtoOrIfaceArray
}
}
/// Contains references to lists of methods, attributes, and constants for a
/// given interface.
pub struct NativeProperties {
/// Instance methods for the interface.
pub methods: Option<&'static [JSFunctionSpec]>,
/// Unforgeable instance methods for the interface.
pub unforgeable_methods: Option<&'static [JSFunctionSpec]>,
/// Instance attributes for the interface.
pub attrs: Option<&'static [JSPropertySpec]>,
/// Unforgeable instance attributes for the interface.
pub unforgeable_attrs: Option<&'static [JSPropertySpec]>,
/// Constants for the interface.
pub consts: Option<&'static [ConstantSpec]>,
/// Static methods for the interface.
pub static_methods: Option<&'static [JSFunctionSpec]>,
/// Static attributes for the interface.
pub static_attrs: Option<&'static [JSPropertySpec]>,
}
unsafe impl Sync for NativeProperties {}
/// A JSNative that cannot be null.
pub type NonNullJSNative =
unsafe extern "C" fn (arg1: *mut JSContext, arg2: c_uint, arg3: *mut JSVal) -> bool;
/// Creates the *interface prototype object* (if a `proto_class` is given)
/// and the *interface object* (if a `constructor` is given).
/// Fails on JSAPI failure.
pub fn do_create_interface_objects(cx: *mut JSContext,
receiver: HandleObject,
proto_proto: HandleObject,
proto_class: Option<&'static JSClass>,
constructor: Option<(NonNullJSNative, &'static str, u32)>,
named_constructors: &[(NonNullJSNative, &'static str, u32)],
members: &'static NativeProperties,
rval: MutableHandleObject) {
assert!(rval.get().is_null());
if let Some(proto_class) = proto_class {
create_interface_prototype_object(cx, proto_proto, proto_class, members, rval);
}
if let Some((native, name, nargs)) = constructor {
let s = CString::new(name).unwrap();
create_interface_object(cx,
receiver,
native,
nargs,
rval.handle(),
members,
s.as_ptr())
}
for ctor in named_constructors {
let (cnative, cname, cnargs) = *ctor;
let cs = CString::new(cname).unwrap();
let constructor = RootedObject::new(cx,
create_constructor(cx, cnative, cnargs, cs.as_ptr()));
assert!(!constructor.ptr.is_null());
unsafe {
assert!(JS_DefineProperty1(cx,
constructor.handle(),
b"prototype\0".as_ptr() as *const libc::c_char,
rval.handle(),
JSPROP_PERMANENT | JSPROP_READONLY,
None,
None));
}
define_constructor(cx, receiver, cs.as_ptr(), constructor.handle());
}
}
fn create_constructor(cx: *mut JSContext,
constructor_native: NonNullJSNative,
ctor_nargs: u32,
name: *const libc::c_char)
-> *mut JSObject {
unsafe {
let fun = JS_NewFunction(cx,
Some(constructor_native),
ctor_nargs,
JSFUN_CONSTRUCTOR,
name);
assert!(!fun.is_null());
let constructor = JS_GetFunctionObject(fun);
assert!(!constructor.is_null());
constructor
}
}
fn define_constructor(cx: *mut JSContext,
receiver: HandleObject,
name: *const libc::c_char,
constructor: HandleObject) {
unsafe {
let mut already_defined = false;
assert!(JS_AlreadyHasOwnProperty(cx, receiver, name, &mut already_defined));
if !already_defined {
assert!(JS_DefineProperty1(cx, receiver, name, constructor, 0, None, None));
}
}
}
/// Creates the *interface object*.
/// Fails on JSAPI failure.
fn create_interface_object(cx: *mut JSContext,
receiver: HandleObject,
constructor_native: NonNullJSNative,
ctor_nargs: u32,
proto: HandleObject,
members: &'static NativeProperties,
name: *const libc::c_char) {
unsafe {
let constructor = RootedObject::new(cx,
create_constructor(cx,
constructor_native,
ctor_nargs,
name));
assert!(!constructor.ptr.is_null());
if let Some(static_methods) = members.static_methods {
define_methods(cx, constructor.handle(), static_methods).unwrap();
}
if let Some(static_properties) = members.static_attrs {
define_properties(cx, constructor.handle(), static_properties).unwrap();
}
if let Some(constants) = members.consts {
define_constants(cx, constructor.handle(), constants);
}
if !proto.get().is_null() {
assert!(JS_LinkConstructorAndPrototype(cx, constructor.handle(), proto));
}
define_constructor(cx, receiver, name, constructor.handle());
}
}
/// Defines constants on `obj`.
/// Fails on JSAPI failure.
fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &'static [ConstantSpec]) {
pub fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &'static [ConstantSpec]) {
for spec in constants {
let value = RootedValue::new(cx, spec.get_value());
unsafe {
@ -341,31 +176,6 @@ fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &'static [
}
}
/// Creates the *interface prototype object*.
/// Fails on JSAPI failure.
fn create_interface_prototype_object(cx: *mut JSContext,
parent_proto: HandleObject,
proto_class: &'static JSClass,
members: &'static NativeProperties,
rval: MutableHandleObject) {
unsafe {
rval.set(JS_NewObjectWithUniqueType(cx, proto_class, parent_proto));
assert!(!rval.get().is_null());
if let Some(methods) = members.methods {
define_methods(cx, rval.handle(), methods).unwrap();
}
if let Some(properties) = members.attrs {
define_properties(cx, rval.handle(), properties).unwrap();
}
if let Some(constants) = members.consts {
define_constants(cx, rval.handle(), constants);
}
}
}
/// A throwing constructor, for those interfaces that have neither
/// `NoInterfaceObject` nor `Constructor`.
pub unsafe extern "C" fn throwing_constructor(cx: *mut JSContext,
@ -376,8 +186,8 @@ pub unsafe extern "C" fn throwing_constructor(cx: *mut JSContext,
false
}
/// An array of *mut JSObject of size PrototypeList::ID::Count
pub type ProtoOrIfaceArray = [*mut JSObject; PrototypeList::ID::Count as usize];
/// An array of *mut JSObject of size PROTO_OR_IFACE_LENGTH.
pub type ProtoOrIfaceArray = [*mut JSObject; PROTO_OR_IFACE_LENGTH];
/// Gets the property `id` on `proxy`'s prototype. If it exists, `*found` is
/// set to true and `*vp` to the value, otherwise `*found` is set to false.
@ -574,7 +384,7 @@ pub fn create_dom_global(cx: *mut JSContext,
// avoid getting trace hooks called on a partially initialized object.
JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT, PrivateValue(private));
let proto_array: Box<ProtoOrIfaceArray> =
box [0 as *mut JSObject; PrototypeList::ID::Count as usize];
box [0 as *mut JSObject; PROTO_OR_IFACE_LENGTH];
JS_SetReservedSlot(obj.ptr,
DOM_PROTOTYPE_SLOT,
PrivateValue(Box::into_raw(proto_array) as *const libc::c_void));
@ -590,7 +400,7 @@ pub fn create_dom_global(cx: *mut JSContext,
pub unsafe fn finalize_global(obj: *mut JSObject) {
let protolist = get_proto_or_iface_array(obj);
let list = (*protolist).as_mut_ptr();
for idx in 0..(PrototypeList::ID::Count as isize) {
for idx in 0..PROTO_OR_IFACE_LENGTH as isize {
let entry = list.offset(idx);
let value = *entry;
if <*mut JSObject>::needs_post_barrier(value) {