mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
Refactor prototype initialisation
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.
This commit is contained in:
parent
967948be06
commit
833e0d2fac
4 changed files with 256 additions and 295 deletions
|
@ -2355,30 +2355,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.
|
||||
|
@ -2389,59 +2365,85 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
|||
args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'),
|
||||
Argument('HandleObject', 'receiver'),
|
||||
Argument('MutableHandleObject', 'rval')]
|
||||
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
|
||||
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, throwing_constructor, 0, 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("""
|
||||
create_interface_prototype_object(cx,
|
||||
prototype_proto.handle(),
|
||||
&PrototypeClass,
|
||||
%(methods)s,
|
||||
%(attrs)s,
|
||||
%(consts)s,
|
||||
rval);
|
||||
assert!(!rval.ptr.is_null());""" % 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
|
||||
|
||||
constructor = 'Some((%s as NonNullJSNative, "%s", %d))' % (
|
||||
constructHook, self.descriptor.interface.identifier.name,
|
||||
constructArgs)
|
||||
else:
|
||||
constructor = 'None'
|
||||
code.append(CGGeneric("""\
|
||||
|
||||
call = """\
|
||||
do_create_interface_objects(cx, receiver, parent_proto.handle(),
|
||||
%s, %s,
|
||||
&named_constructors,
|
||||
&sNativeProperties, rval);""" % (protoClass, constructor)
|
||||
create_noncallback_interface_object(cx,
|
||||
receiver,
|
||||
%(constructor)s,
|
||||
%(static_methods)s,
|
||||
%(static_attrs)s,
|
||||
%(consts)s,
|
||||
rval.handle(),
|
||||
%(name)s,
|
||||
%(length)s);""" % properties))
|
||||
|
||||
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, rval.handle());"))
|
||||
|
||||
if self.descriptor.hasUnforgeableMembers:
|
||||
# We want to use the same JSClass and prototype as the object we'll
|
||||
|
@ -2457,41 +2459,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 = "rval.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")
|
||||
|
||||
installUnforgeableHolder = CGGeneric("""\
|
||||
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(rval.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT,
|
||||
ObjectValue(&*unforgeable_holder.ptr))""")
|
||||
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):
|
||||
|
@ -4883,7 +4866,6 @@ class CGDescriptor(CGThing):
|
|||
|
||||
properties = PropertyArrays(descriptor)
|
||||
cgThings.append(CGGeneric(str(properties)))
|
||||
cgThings.append(CGNativeProperties(descriptor, properties))
|
||||
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
|
||||
|
||||
cgThings.append(CGNamespace.build([descriptor.name + "Constants"],
|
||||
|
@ -5271,16 +5253,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::jsapi::{JS_NewObjectWithGivenProto, JS_NewObjectWithoutMetadata, 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}',
|
||||
|
@ -5296,13 +5278,14 @@ 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::{create_callback_interface_object, create_interface_prototype_object}',
|
||||
'dom::bindings::interface::{create_named_constructors, create_noncallback_interface_object}',
|
||||
'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, NonNullJSNative, create_dom_global}',
|
||||
'dom::bindings::utils::{do_create_interface_objects, finalize_global}',
|
||||
'dom::bindings::utils::{NonNullJSNative, create_dom_global, finalize_global}',
|
||||
'dom::bindings::utils::{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}',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue