Implement [Unforgeable]

This is mostly stolen from Gecko. As there, we define the unforgeable members
on an object stored in the slots of the prototype object. They are then copied
onto instance objects when they are instantiated. It should be noted that
proxy objects see their unforgeable memebers defined on their expando object.

Unforgeable attributes aren't properly inherited in codegen (in a similar
fashion as getters and setters as filed in #5875) and require to be redefined
in derived interfaces. Fortunately, there are currently no such interfaces.

No unforgeable members can be included into the TestBinding interfaces for good
measure because they are not compatible with setters.

Given the unforgeable holder object has the same prototype as actual instances
of the interface, the finalize hook needs to check its slot pointer for nullity
before dropping it.

The new failing test isn't related to Unforgeable attributes, but to the fact
that all Document instances currently have a Location, even if their window
isn't in a browsing context.
This commit is contained in:
Anthony Ramine 2015-10-12 14:50:07 +02:00
parent 29c42a9f78
commit 60976406cc
11 changed files with 267 additions and 125 deletions

View file

@ -21,7 +21,12 @@ from WebIDL import (
IDLUndefinedValue,
)
from Configuration import getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback
from Configuration import (
MemberIsUnforgeable,
getTypesFromCallback,
getTypesFromDescriptor,
getTypesFromDictionary,
)
AUTOGENERATED_WARNING_COMMENT = \
"/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
@ -1380,7 +1385,8 @@ class MethodDefiner(PropertyDefiner):
"""
A class for defining methods on a prototype object.
"""
def __init__(self, descriptor, name, static):
def __init__(self, descriptor, name, static, unforgeable):
assert not (static and unforgeable)
PropertyDefiner.__init__(self, descriptor, name)
# FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
@ -1391,36 +1397,40 @@ class MethodDefiner(PropertyDefiner):
if not descriptor.interface.isCallback() or static:
methods = [m for m in descriptor.interface.members if
m.isMethod() and m.isStatic() == static and
not m.isIdentifierLess()]
not m.isIdentifierLess() and
MemberIsUnforgeable(m, descriptor) == unforgeable]
else:
methods = []
self.regular = [{"name": m.identifier.name,
"methodInfo": not m.isStatic(),
"length": methodLength(m),
"flags": "JSPROP_ENUMERATE"} for m in methods]
"length": methodLength(m)} for m in methods]
# FIXME Check for an existing iterator on the interface first.
if any(m.isGetter() and m.isIndexed() for m in methods):
self.regular.append({"name": '@@iterator',
"methodInfo": False,
"selfHostedName": "ArrayValues",
"length": 0,
"flags": "JSPROP_ENUMERATE"})
"length": 0})
if not static:
isUnforgeableInterface = bool(descriptor.interface.getExtendedAttribute("Unforgeable"))
if not static and unforgeable == isUnforgeableInterface:
stringifier = descriptor.operations['Stringifier']
if stringifier:
self.regular.append({
"name": "toString",
"nativeName": stringifier.identifier.name,
"length": 0,
"flags": "JSPROP_ENUMERATE"
})
self.unforgeable = unforgeable
def generateArray(self, array, name):
if len(array) == 0:
return ""
flags = "JSPROP_ENUMERATE"
if self.unforgeable:
flags += " | JSPROP_PERMANENT | JSPROP_READONLY"
def specData(m):
# TODO: Use something like JS_FNSPEC
# https://github.com/servo/servo/issues/6391
@ -1444,16 +1454,16 @@ class MethodDefiner(PropertyDefiner):
accessor = 'Some(%s)' % m.get("nativeName", m["name"])
if m["name"].startswith("@@"):
return ('(SymbolCode::%s as i32 + 1)'
% m["name"][2:], accessor, jitinfo, m["length"], m["flags"], selfHostedName)
return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], m["flags"], selfHostedName)
% m["name"][2:], accessor, jitinfo, m["length"], flags, selfHostedName)
return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], flags, selfHostedName)
return self.generatePrefableArray(
array, name,
' JSFunctionSpec {\n'
' name: %s as *const u8 as *const libc::c_char,\n'
' call: JSNativeWrapper {op: %s, info: %s},\n'
' call: JSNativeWrapper { op: %s, info: %s },\n'
' nargs: %s,\n'
' flags: %s as u16,\n'
' flags: (%s) as u16,\n'
' selfHostedName: %s\n'
' }',
' JSFunctionSpec {\n'
@ -1468,23 +1478,27 @@ class MethodDefiner(PropertyDefiner):
class AttrDefiner(PropertyDefiner):
def __init__(self, descriptor, name, static):
def __init__(self, descriptor, name, static, unforgeable):
assert not (static and unforgeable)
PropertyDefiner.__init__(self, descriptor, name)
self.name = name
self.descriptor = descriptor
self.regular = [
m
for m in descriptor.interface.members
if m.isAttr() and m.isStatic() == static
for m in descriptor.interface.members if
m.isAttr() and m.isStatic() == static and
MemberIsUnforgeable(m, descriptor) == unforgeable
]
self.static = static
self.unforgeable = unforgeable
def generateArray(self, array, name):
if len(array) == 0:
return ""
def flags(attr):
return "JSPROP_SHARED | JSPROP_ENUMERATE"
flags = "JSPROP_ENUMERATE | JSPROP_SHARED"
if self.unforgeable:
flags += " | JSPROP_READONLY | JSPROP_PERMANENT"
def getter(attr):
if self.static:
@ -1520,7 +1534,7 @@ class AttrDefiner(PropertyDefiner):
"native": accessor})
def specData(attr):
return (str_to_const_array(attr.identifier.name), flags(attr), getter(attr),
return (str_to_const_array(attr.identifier.name), flags, getter(attr),
setter(attr))
return self.generatePrefableArray(
@ -1844,10 +1858,16 @@ class CGPrototypeJSClass(CGThing):
self.descriptor = descriptor
def define(self):
name = str_to_const_array(self.descriptor.interface.identifier.name + "Prototype")
slotCount = 0
if self.descriptor.hasUnforgeableMembers:
slotCount += 1
return """\
static PrototypeClass: JSClass = JSClass {
name: %s as *const u8 as *const libc::c_char,
flags: 0,
name: %(name)s as *const u8 as *const libc::c_char,
flags:
// JSCLASS_HAS_RESERVED_SLOTS(%(slotCount)s)
(%(slotCount)s & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT,
addProperty: None,
delProperty: None,
getProperty: None,
@ -1862,7 +1882,7 @@ static PrototypeClass: JSClass = JSClass {
trace: None,
reserved: [0 as *mut libc::c_void; 25]
};
""" % str_to_const_array(self.descriptor.interface.identifier.name + "Prototype")
""" % {'name': name, 'slotCount': slotCount}
class CGInterfaceObjectJSClass(CGThing):
@ -2181,6 +2201,68 @@ JS_SetReservedSlot(obj.ptr, DOM_WEAK_SLOT, PrivateValue(ptr::null()));"""
return create
def InitUnforgeablePropertiesOnHolder(descriptor, properties):
"""
Define the unforgeable properties on the unforgeable holder for
the interface represented by descriptor.
properties is a PropertyArrays instance.
"""
unforgeables = []
defineUnforgeableAttrs = "define_properties(cx, unforgeable_holder.handle(), %s).unwrap();"
defineUnforgeableMethods = "define_methods(cx, unforgeable_holder.handle(), %s).unwrap();"
unforgeableMembers = [
(defineUnforgeableAttrs, properties.unforgeable_attrs),
(defineUnforgeableMethods, properties.unforgeable_methods),
]
for template, array in unforgeableMembers:
if array.length() > 0:
unforgeables.append(CGGeneric(template % array.variableName()))
return CGList(unforgeables, "\n")
def CopyUnforgeablePropertiesToInstance(descriptor):
"""
Copy the unforgeable properties from the unforgeable holder for
this interface to the instance object we have.
"""
if not descriptor.hasUnforgeableMembers:
return ""
copyCode = ""
# For proxies, we want to define on the expando object, not directly on the
# reflector, so we can make sure we don't get confused by named getters.
if descriptor.proxy:
copyCode += """\
let mut expando = RootedObject::new(cx, ptr::null_mut());
{
let _ac = JSAutoCompartment::new(cx, scope.get());
expando.handle_mut().set(ensure_expando_object(cx, obj.handle()));
}
"""
obj = "expando"
else:
obj = "obj"
# We can't do the fast copy for globals, because we can't allocate the
# unforgeable holder for those with the right JSClass. Luckily, there
# aren't too many globals being created.
if descriptor.isGlobal():
copyFunc = "JS_CopyPropertiesFrom"
else:
copyFunc = "JS_InitializePropertiesFromCompatibleNativeObject"
copyCode += """\
let mut unforgeable_holder = RootedObject::new(cx, ptr::null_mut());
unforgeable_holder.handle_mut().set(
JS_GetReservedSlot(proto.ptr, DOM_PROTO_UNFORGEABLE_HOLDER_SLOT).to_object());
assert!(%(copyFunc)s(cx, %(obj)s.handle(), unforgeable_holder.handle()));
""" % {'copyFunc': copyFunc, 'obj': obj}
return copyCode
class CGWrapMethod(CGAbstractMethod):
"""
Class that generates the FooBinding::Wrap function for non-callback
@ -2199,7 +2281,9 @@ class CGWrapMethod(CGAbstractMethod):
pub=True, unsafe=True)
def definition_body(self):
unforgeable = CopyUnforgeablePropertiesToInstance(self.descriptor)
if not self.descriptor.isGlobal():
create = CreateBindingJSObject(self.descriptor, "scope")
return CGGeneric("""\
let _ar = JSAutoRequest::new(cx);
let scope = scope.reflector().get_jsobject();
@ -2213,28 +2297,31 @@ let mut proto = RootedObject::new(cx, ptr::null_mut());
}
assert!(!proto.ptr.is_null());
%s
%(createObject)s
%(copyUnforgeable)s
(*raw).init_reflector(obj.ptr);
Root::from_ref(&*raw)""" % CreateBindingJSObject(self.descriptor, "scope"))
Root::from_ref(&*raw)""" % {'copyUnforgeable': unforgeable, 'createObject': create})
else:
create = CreateBindingJSObject(self.descriptor)
return CGGeneric("""\
let _ar = JSAutoRequest::new(cx);
%s
%(createObject)s
let _ac = JSAutoCompartment::new(cx, obj.ptr);
let mut proto = RootedObject::new(cx, ptr::null_mut());
GetProtoObject(cx, obj.handle(), obj.handle(), proto.handle_mut());
JS_SetPrototype(cx, obj.handle(), proto.handle());
%(copyUnforgeable)s
(*raw).init_reflector(obj.ptr);
let ret = Root::from_ref(&*raw);
RegisterBindings::Register(cx, obj.handle());
ret""" % CreateBindingJSObject(self.descriptor))
ret""" % {'copyUnforgeable': unforgeable, 'createObject': create})
class CGIDLInterface(CGThing):
@ -2279,17 +2366,29 @@ class CGAbstractExternMethod(CGAbstractMethod):
class PropertyArrays():
def __init__(self, descriptor):
self.static_methods = MethodDefiner(descriptor, "StaticMethods",
static=True)
static=True, unforgeable=False)
self.static_attrs = AttrDefiner(descriptor, "StaticAttributes",
static=True)
self.methods = MethodDefiner(descriptor, "Methods", static=False)
self.attrs = AttrDefiner(descriptor, "Attributes", static=False)
static=True, unforgeable=False)
self.methods = MethodDefiner(descriptor, "Methods", static=False, unforgeable=False)
self.unforgeable_methods = MethodDefiner(descriptor, "UnforgeableMethods",
static=False, unforgeable=True)
self.attrs = AttrDefiner(descriptor, "Attributes", static=False, unforgeable=False)
self.unforgeable_attrs = AttrDefiner(descriptor, "UnforgeableAttributes",
static=False, unforgeable=True)
self.consts = ConstDefiner(descriptor, "Constants")
pass
@staticmethod
def arrayNames():
return ["static_methods", "static_attrs", "methods", "attrs", "consts"]
return [
"static_methods",
"static_attrs",
"methods",
"unforgeable_methods",
"attrs",
"unforgeable_attrs",
"consts",
]
def variableNames(self):
names = {}
@ -2392,10 +2491,54 @@ let named_constructors: [(NonNullJSNative, &'static str, u32); %d] = [
createArray += ","
createArray += "];"
if self.descriptor.hasUnforgeableMembers:
# We want to use the same JSClass and prototype as the object we'll
# end up defining the unforgeable properties on in the end, so that
# we can use JS_InitializePropertiesFromCompatibleNativeObject to do
# a fast copy. In the case of proxies that's null, because the
# expando object is a vanilla object, but in the case of other DOM
# objects it's whatever our class is.
#
# Also, for a global we can't use the global's class; just use
# nullpr and when we do the copy off the holder we'll take a slower
# path. This also means that we don't need to worry about matching
# the prototype.
if self.descriptor.proxy or self.descriptor.isGlobal():
holderClass = "ptr::null()"
holderProto = "ptr::null_mut()"
else:
holderClass = "&Class.base as *const js::jsapi::Class as *const JSClass"
holderProto = "rval.get()"
# JS_NewObjectWithoutMetadata() is unsafe.
self.unsafe = True
createUnforgeableHolder = 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("""\
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())
CGGeneric(call % self.properties.variableNames()),
unforgeableHolderSetup,
], "\n")
@ -4269,6 +4412,9 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
namedSetter = self.descriptor.operations['NamedSetter']
if namedSetter:
if self.descriptor.hasUnforgeableMembers:
raise TypeError("Can't handle a named setter on an interface that has "
"unforgeables. Figure out how that should work!")
set += ("if RUST_JSID_IS_STRING(id) {\n" +
CGIndenter(CGProxyNamedSetter(self.descriptor)).define() +
" (*opresult).code_ = 0; /* SpecialCodes::OkCode */\n" +
@ -4308,6 +4454,9 @@ class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
def getBody(self):
set = ""
if self.descriptor.operations['NamedDeleter']:
if self.descriptor.hasUnforgeableMembers:
raise TypeError("Can't handle a deleter on an interface that has "
"unforgeables. Figure out how that should work!")
set += CGProxyNamedDeleter(self.descriptor).define()
set += "return proxyhandler::delete(%s);" % ", ".join(a.name for a in self.args)
return set
@ -4422,7 +4571,7 @@ return true;"""
class CGDOMJSProxyHandler_get(CGAbstractExternMethod):
def __init__(self, descriptor):
args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
Argument('HandleObject', '_receiver'), Argument('HandleId', 'id'),
Argument('HandleObject', 'receiver'), Argument('HandleId', 'id'),
Argument('MutableHandleValue', 'vp')]
CGAbstractExternMethod.__init__(self, descriptor, "get", "bool", args)
self.descriptor = descriptor
@ -4437,7 +4586,7 @@ if !expando.ptr.is_null() {
}
if hasProp {
return JS_GetPropertyById(cx, expando.handle(), id, vp);
return JS_ForwardGetPropertyTo(cx, expando.handle(), id, receiver, vp);
}
}"""
@ -4554,7 +4703,10 @@ if !weak_box_ptr.is_null() {
}
""" % descriptor.concreteType
release += """\
let _ = Box::from_raw(this as *mut %s);
if !this.is_null() {
// The pointer can be null if the object is the unforgeable holder of that interface.
let _ = Box::from_raw(this as *mut %s);
}
debug!("%s finalize: {:p}", this);\
""" % (descriptor.concreteType, descriptor.concreteType)
return release
@ -5177,30 +5329,31 @@ class CGBindingRoot(CGThing):
# Add imports
curr = CGImports(curr, descriptors + callbackDescriptors, mainCallbacks, [
'js',
'js::JS_CALLEE',
'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS, JSCLASS_IMPLEMENTS_BARRIERS}',
'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}',
'js::{JSCLASS_RESERVED_SLOTS_MASK}',
'js::{JSPROP_ENUMERATE, JSPROP_SHARED}',
'js::{JSITER_OWNONLY, JSITER_HIDDEN, JSITER_SYMBOLS}',
'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IMPLEMENTS_BARRIERS}',
'js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_MASK}',
'js::{JSCLASS_RESERVED_SLOTS_SHIFT, JSITER_HIDDEN, JSITER_OWNONLY}',
'js::{JSITER_SYMBOLS, JSPROP_ENUMERATE, JSPROP_PERMANENT, JSPROP_READONLY}',
'js::{JSPROP_SHARED, JS_CALLEE}',
'js::error::throw_type_error',
'js::jsapi::{JS_CallFunctionValue, JS_GetClass, JS_GetGlobalForObject}',
'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}',
'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot}',
'js::jsapi::{JS_HasProperty, JS_HasPropertyById, JS_IsExceptionPending}',
'js::jsapi::{JS_NewObjectWithGivenProto, JS_NewObject, IsCallable, JS_SetProperty, JS_SetPrototype}',
'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSContext}',
'js::jsapi::{JSClass, FreeOp, JSFreeOp, JSFunctionSpec, jsid}',
'js::jsapi::{MutableHandleValue, MutableHandleObject, HandleObject, HandleValue, RootedObject}',
'js::jsapi::{RootedValue, JSNativeWrapper, JSNative, JSObject, JSPropertyDescriptor}',
'js::jsapi::{RootedId, JS_InternString, RootedString, INTERNED_STRING_TO_JSID}',
'js::jsapi::{JSPropertySpec}',
'js::jsapi::{JSString, JSTracer, JSJitInfo, JSTypedMethodJitInfo, OpType, AliasSet, ArgType}',
'js::jsapi::{MutableHandle, Handle, HandleId, JSType, JSValueType}',
'js::jsapi::{SymbolCode, ObjectOpResult, HandleValueArray}',
'js::jsapi::{JSJitGetterCallArgs, JSJitSetterCallArgs, JSJitMethodCallArgs, CallArgs}',
'js::jsapi::{JSAutoCompartment, JSAutoRequest, JS_ComputeThis}',
'js::jsapi::{GetGlobalForObjectCrossCompartment, AutoIdVector, GetPropertyKeys}',
'js::jsapi::{AliasSet, ArgType, AutoIdVector, CallArgs, FreeOp}',
'js::jsapi::{GetGlobalForObjectCrossCompartment , GetPropertyKeys, Handle}',
'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::{JSString, JSTracer, JSType, JSTypedMethodJitInfo, JSValueType}',
'js::jsapi::{ObjectOpResult, OpType, MutableHandle, MutableHandleObject}',
'js::jsapi::{MutableHandleValue, RootedId, RootedObject, RootedString}',
'js::jsapi::{RootedValue, SymbolCode, jsid}',
'js::jsval::JSVal',
'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}',
'js::jsval::{NullValue, UndefinedValue}',
@ -5209,30 +5362,24 @@ class CGBindingRoot(CGThing):
'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}',
'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING, int_to_jsid}',
'js::glue::AppendToAutoIdVector',
'js::rust::GCMethods',
'js::rust::{GCMethods, define_methods, define_properties}',
'dom::bindings',
'dom::bindings::global::{GlobalRef, global_root_from_object, global_root_from_reflector}',
'dom::bindings::js::{JS, Root, RootedReference}',
'dom::bindings::js::{OptionalRootedReference}',
'dom::bindings::reflector::{Reflectable}',
'dom::bindings::utils::{create_dom_global, do_create_interface_objects}',
'dom::bindings::utils::ConstantSpec',
'dom::bindings::utils::{DOMClass}',
'dom::bindings::utils::{DOMJSClass, JSCLASS_DOM_GLOBAL}',
'dom::bindings::utils::{find_enum_string_index, get_array_index_from_id}',
'dom::bindings::utils::{get_property_on_prototype, get_proto_or_iface_array}',
'dom::bindings::utils::{finalize_global, trace_global}',
'dom::bindings::utils::has_property_on_prototype',
'dom::bindings::utils::is_platform_object',
'dom::bindings::utils::throwing_constructor',
'dom::bindings::utils::get_dictionary_property',
'dom::bindings::utils::set_dictionary_property',
'dom::bindings::utils::{NativeProperties, NativePropertyHooks}',
'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::{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}',
'dom::bindings::utils::{get_proto_or_iface_array, has_property_on_prototype}',
'dom::bindings::utils::{is_platform_object, set_dictionary_property}',
'dom::bindings::utils::{throwing_constructor, trace_global}',
'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}',
@ -5248,8 +5395,8 @@ class CGBindingRoot(CGThing):
'dom::bindings::error::Error::JSFailed',
'dom::bindings::error::throw_dom_exception',
'dom::bindings::proxyhandler',
'dom::bindings::proxyhandler::{fill_property_descriptor, get_expando_object}',
'dom::bindings::proxyhandler::{get_property_descriptor}',
'dom::bindings::proxyhandler::{ensure_expando_object, fill_property_descriptor}',
'dom::bindings::proxyhandler::{get_expando_object, get_property_descriptor}',
'dom::bindings::num::Finite',
'dom::bindings::str::ByteString',
'dom::bindings::str::USVString',