Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix prototypes of interface objects (fixes #2665) #8954

Merged
merged 8 commits into from Jan 12, 2016

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.
  • Loading branch information
nox committed Jan 12, 2016
commit 833e0d2fac7724967e15cff61c95610f18c6b958
@@ -2355,30 +2355,6 @@ def __str__(self):
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 @@ 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)
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))

getParentProto = ("let mut parent_proto = RootedObject::new(cx, ptr::null_mut());\n"
"%s;\n"
"assert!(!parent_proto.ptr.is_null());\n") % getParentProto

if self.descriptor.interface.isCallback():
protoClass = "None"
else:
protoClass = "Some(&PrototypeClass)"
getPrototypeProto = ("%s::GetProtoObject(cx, global, receiver, prototype_proto.handle_mut())" %
toBindingNamespace(self.descriptor.prototypeChain[-2]))

code = [CGGeneric("""\
let mut prototype_proto = RootedObject::new(cx, ptr::null_mut());
%s;
assert!(!prototype_proto.ptr.is_null());""" % getPrototypeProto)]

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

constructor = 'Some((%s as NonNullJSNative, "%s", %d))' % (
constructHook, self.descriptor.interface.identifier.name,
constructArgs)
else:
constructor = 'None'

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 += "];"
properties["constructor"] = "throwing_constructor"
properties["length"] = 0

code.append(CGGeneric("""\
create_noncallback_interface_object(cx,
receiver,
%(constructor)s,
%(static_methods)s,
%(static_attrs)s,
%(consts)s,
rval.handle(),
%(name)s,
%(length)s);""" % properties))

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 @@ def definition_body(self):
# 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))""")

unforgeableHolderSetup = CGList(
[createUnforgeableHolder, installUnforgeableHolder], "\n")
else:
unforgeableHolderSetup = None
ObjectValue(&*unforgeable_holder.ptr))"""))

return CGList([
CGGeneric(getParentProto),
CGGeneric(createArray),
CGGeneric(call % self.properties.variableNames()),
unforgeableHolderSetup,
], "\n")
return CGList(code, "\n")


class CGGetPerInterfaceObject(CGAbstractMethod):
@@ -4883,7 +4866,6 @@ def __init__(self, descriptor):

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 @@ def __init__(self, config, prefix, webIDLFile):
'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 @@ def __init__(self, config, prefix, webIDLFile):
'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}',
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.