diff options
Diffstat (limited to 'dom/bindings/Codegen.py')
-rw-r--r-- | dom/bindings/Codegen.py | 345 |
1 files changed, 175 insertions, 170 deletions
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 7a6a28bffc..a6a49f9b2f 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -926,11 +926,51 @@ def InterfaceObjectProtoGetter(descriptor, forXrays=False): return (protoGetter, protoHandleGetter) -class CGInterfaceObjectJSClass(CGThing): - def __init__(self, descriptor, properties): +class CGNamespaceObjectJSClass(CGThing): + def __init__(self, descriptor): + CGThing.__init__(self) + self.descriptor = descriptor + + def declare(self): + # We're purely for internal consumption + return "" + + def define(self): + (protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor, forXrays=True) + + classString = self.descriptor.interface.getExtendedAttribute("ClassString") + if classString is None: + classString = self.descriptor.interface.identifier.name + else: + classString = classString[0] + return fill( + """ + static const DOMIfaceAndProtoJSClass sNamespaceObjectClass = { + { + "${classString}", + JSCLASS_IS_DOMIFACEANDPROTOJSCLASS, + JS_NULL_CLASS_OPS, + JS_NULL_CLASS_SPEC, + JS_NULL_CLASS_EXT, + JS_NULL_OBJECT_OPS + }, + eNamespace, + prototypes::id::_ID_Count, + 0, + ${hooks}, + ${protoGetter} + }; + """, + classString=classString, + hooks=NativePropertyHooks(self.descriptor), + protoGetter=protoGetter, + ) + + +class CGInterfaceObjectInfo(CGThing): + def __init__(self, descriptor): CGThing.__init__(self) self.descriptor = descriptor - self.properties = properties def declare(self): # We're purely for internal consumption @@ -938,104 +978,31 @@ class CGInterfaceObjectJSClass(CGThing): def define(self): if self.descriptor.interface.ctor(): - assert not self.descriptor.interface.isNamespace() ctorname = CONSTRUCT_HOOK_NAME - elif self.descriptor.interface.isNamespace(): - ctorname = "nullptr" else: ctorname = "ThrowingConstructor" wantsIsInstance = self.descriptor.interface.hasInterfacePrototypeObject() prototypeID, depth = PrototypeIDAndDepth(self.descriptor) - slotCount = "DOM_INTERFACE_SLOTS_BASE" - if len(self.descriptor.interface.legacyFactoryFunctions) > 0: - slotCount += " + %i /* slots for the legacy factory functions */" % len( - self.descriptor.interface.legacyFactoryFunctions - ) (protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor, forXrays=True) - if ctorname == "ThrowingConstructor": - ret = "" - classOpsPtr = "&sBoringInterfaceObjectClassClassOps" - elif ctorname == "nullptr": - ret = "" - classOpsPtr = "JS_NULL_CLASS_OPS" - else: - ret = fill( - """ - static const JSClassOps sInterfaceObjectClassOps = { - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* enumerate */ - nullptr, /* newEnumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - ${ctorname}, /* call */ - ${ctorname}, /* construct */ - nullptr, /* trace */ - }; - - """, - ctorname=ctorname, - ) - classOpsPtr = "&sInterfaceObjectClassOps" - - if self.descriptor.interface.isNamespace(): - classString = self.descriptor.interface.getExtendedAttribute("ClassString") - if classString is None: - classString = self.descriptor.interface.identifier.name - else: - classString = classString[0] - funToString = "nullptr" - objectOps = "JS_NULL_OBJECT_OPS" - else: - classString = "Function" - funToString = ( - '"function %s() {\\n [native code]\\n}"' - % self.descriptor.interface.identifier.name - ) - # We need non-default ObjectOps so we can actually make - # use of our funToString. - objectOps = "&sInterfaceObjectClassObjectOps" - - ret = ret + fill( + return fill( """ - static const DOMIfaceJSClass sInterfaceObjectClass = { - { - { - "${classString}", - JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}), - ${classOpsPtr}, - JS_NULL_CLASS_SPEC, - JS_NULL_CLASS_EXT, - ${objectOps} - }, - ${type}, - ${prototypeID}, - ${depth}, - ${hooks}, - ${protoGetter} - }, + static const DOMInterfaceInfo sInterfaceObjectInfo = { + { ${ctorname}, ${hooks} }, + ${protoGetter}, + ${prototypeID}, + ${depth}, ${wantsIsInstance}, - ${funToString} }; """, - classString=classString, - slotCount=slotCount, - classOpsPtr=classOpsPtr, + ctorname=ctorname, hooks=NativePropertyHooks(self.descriptor), - objectOps=objectOps, - type="eNamespace" - if self.descriptor.interface.isNamespace() - else "eInterface", + protoGetter=protoGetter, prototypeID=prototypeID, depth=depth, - protoGetter=protoGetter, wantsIsInstance=toStringBool(wantsIsInstance), - funToString=funToString, ) - return ret class CGList(CGThing): @@ -2323,7 +2290,6 @@ class CGLegacyFactoryFunctions(CGThing): static const LegacyFactoryFunction legacyFactoryFunctions[] = { $*{legacyFactoryFunctions} - { nullptr, { nullptr, nullptr }, 0 } }; """, name=self.descriptor.name, @@ -3538,83 +3504,30 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): self.haveLegacyWindowAliases = haveLegacyWindowAliases def definition_body(self): - (protoGetter, protoHandleGetter) = InterfacePrototypeObjectProtoGetter( - self.descriptor - ) - if protoHandleGetter is None: - parentProtoType = "Rooted" - getParentProto = "aCx, " + protoGetter - else: - parentProtoType = "Handle" - getParentProto = protoHandleGetter - getParentProto = getParentProto + "(aCx)" - - (protoGetter, protoHandleGetter) = InterfaceObjectProtoGetter(self.descriptor) - if protoHandleGetter is None: - getConstructorProto = "aCx, " + protoGetter - constructorProtoType = "Rooted" - else: - getConstructorProto = protoHandleGetter - constructorProtoType = "Handle" - getConstructorProto += "(aCx)" - needInterfaceObject = self.descriptor.interface.hasInterfaceObject() - needInterfacePrototypeObject = ( - self.descriptor.interface.hasInterfacePrototypeObject() - ) - - # if we don't need to create anything, why are we generating this? - assert needInterfaceObject or needInterfacePrototypeObject - - getParentProto = fill( - """ - JS::${type}<JSObject*> parentProto(${getParentProto}); - if (!parentProto) { - return; - } - """, - type=parentProtoType, - getParentProto=getParentProto, - ) - - getConstructorProto = fill( - """ - JS::${type}<JSObject*> constructorProto(${getConstructorProto}); - if (!constructorProto) { - return; - } - """, - type=constructorProtoType, - getConstructorProto=getConstructorProto, - ) - - if self.descriptor.interface.ctor(): - constructArgs = methodLength(self.descriptor.interface.ctor()) - isConstructorChromeOnly = isChromeOnly(self.descriptor.interface.ctor()) - else: - constructArgs = 0 - isConstructorChromeOnly = False - if len(self.descriptor.interface.legacyFactoryFunctions) > 0: - legacyFactoryFunctions = "legacyFactoryFunctions" - else: - legacyFactoryFunctions = "nullptr" + if needInterfaceObject: + (protoGetter, protoHandleGetter) = InterfaceObjectProtoGetter( + self.descriptor + ) + if protoHandleGetter is None: + getConstructorProto = "aCx, " + protoGetter + constructorProtoType = "Rooted" + else: + getConstructorProto = protoHandleGetter + constructorProtoType = "Handle" - if needInterfacePrototypeObject: - protoClass = "&sPrototypeClass" - protoCache = ( - "&aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::%s)" - % self.descriptor.name + getConstructorProto = fill( + """ + JS::${type}<JSObject*> constructorProto(${getConstructorProto}(aCx)); + if (!constructorProto) { + return; + } + """, + type=constructorProtoType, + getConstructorProto=getConstructorProto, ) - parentProto = "parentProto" - getParentProto = CGGeneric(getParentProto) - else: - protoClass = "nullptr" - protoCache = "nullptr" - parentProto = "nullptr" - getParentProto = None - if needInterfaceObject: - interfaceClass = "&sInterfaceObjectClass" + interfaceInfo = "&sInterfaceObjectInfo" interfaceCache = ( "&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)" % self.descriptor.name @@ -3624,12 +3537,11 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): else: # We don't have slots to store the legacy factory functions. assert len(self.descriptor.interface.legacyFactoryFunctions) == 0 - interfaceClass = "nullptr" + interfaceInfo = "nullptr" interfaceCache = "nullptr" getConstructorProto = None constructorProto = "nullptr" - isGlobal = self.descriptor.isGlobal() is not None if self.properties.hasNonChromeOnly(): properties = "sNativeProperties.Upcast()" else: @@ -3648,31 +3560,117 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): name = self.descriptor.interface.getClassName() assert not (needInterfaceObject and " " in name) - call = fill( + if self.descriptor.interface.isNamespace(): + # If we don't need to create anything, why are we generating this? + assert needInterfaceObject + + call = fill( + """ + JS::Heap<JSObject*>* interfaceCache = ${interfaceCache}; + dom::CreateNamespaceObject(aCx, aGlobal, ${constructorProto}, + sNamespaceObjectClass, + interfaceCache, + ${properties}, + ${chromeProperties}, + "${name}", aDefineOnGlobal); + """, + interfaceCache=interfaceCache, + constructorProto=constructorProto, + properties=properties, + chromeProperties=chromeProperties, + name=name, + ) + return CGList( + [ + getConstructorProto, + CGGeneric(call), + ], + "\n", + ).define() + + needInterfacePrototypeObject = ( + self.descriptor.interface.hasInterfacePrototypeObject() + ) + + # If we don't need to create anything, why are we generating this? + assert needInterfaceObject or needInterfacePrototypeObject + + if needInterfacePrototypeObject: + (protoGetter, protoHandleGetter) = InterfacePrototypeObjectProtoGetter( + self.descriptor + ) + if protoHandleGetter is None: + parentProtoType = "Rooted" + getParentProto = "aCx, " + protoGetter + else: + parentProtoType = "Handle" + getParentProto = protoHandleGetter + + getParentProto = fill( + """ + JS::${type}<JSObject*> parentProto(${getParentProto}(aCx)); + if (!parentProto) { + return; + } + """, + type=parentProtoType, + getParentProto=getParentProto, + ) + + protoClass = "&sPrototypeClass" + protoCache = ( + "&aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::%s)" + % self.descriptor.name + ) + parentProto = "parentProto" + getParentProto = CGGeneric(getParentProto) + else: + protoClass = "nullptr" + protoCache = "nullptr" + parentProto = "nullptr" + getParentProto = None + + if self.descriptor.interface.ctor(): + constructArgs = methodLength(self.descriptor.interface.ctor()) + isConstructorChromeOnly = isChromeOnly(self.descriptor.interface.ctor()) + else: + constructArgs = 0 + isConstructorChromeOnly = False + if len(self.descriptor.interface.legacyFactoryFunctions) > 0: + legacyFactoryFunctions = "Span(legacyFactoryFunctions)" + else: + legacyFactoryFunctions = "Span<const LegacyFactoryFunction, 0>{}" + + isGlobal = self.descriptor.isGlobal() is not None + + ensureCaches = fill( """ JS::Heap<JSObject*>* protoCache = ${protoCache}; JS::Heap<JSObject*>* interfaceCache = ${interfaceCache}; + """, + protoCache=protoCache, + interfaceCache=interfaceCache, + ) + call = fill( + """ dom::CreateInterfaceObjects(aCx, aGlobal, ${parentProto}, ${protoClass}, protoCache, - ${constructorProto}, ${interfaceClass}, ${constructArgs}, ${isConstructorChromeOnly}, ${legacyFactoryFunctions}, + ${constructorProto}, ${interfaceInfo}, ${constructArgs}, ${isConstructorChromeOnly}, ${legacyFactoryFunctions}, interfaceCache, ${properties}, ${chromeProperties}, "${name}", aDefineOnGlobal, ${unscopableNames}, ${isGlobal}, - ${legacyWindowAliases}, - ${isNamespace}); + ${legacyWindowAliases}); """, protoClass=protoClass, parentProto=parentProto, - protoCache=protoCache, constructorProto=constructorProto, - interfaceClass=interfaceClass, + interfaceInfo=interfaceInfo, constructArgs=constructArgs, isConstructorChromeOnly=toStringBool(isConstructorChromeOnly), legacyFactoryFunctions=legacyFactoryFunctions, - interfaceCache=interfaceCache, properties=properties, chromeProperties=chromeProperties, name=name, @@ -3681,7 +3679,6 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): legacyWindowAliases="legacyWindowAliases" if self.haveLegacyWindowAliases else "nullptr", - isNamespace=toStringBool(self.descriptor.interface.isNamespace()), ) # If we fail after here, we must clear interface and prototype caches @@ -3896,8 +3893,14 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): ) else: defineProtoVar = None + + # ensureCaches needs to come first as it crashes on failure (like OOM). + # We want to make sure that the caches do exist before we try to return + # to the caller, so it can rely on that (and detect other failures by + # checking for null in the caches). return CGList( [ + CGGeneric(ensureCaches), getParentProto, getConstructorProto, CGGeneric(call), @@ -16955,9 +16958,11 @@ class CGDescriptor(CGThing): # done, set up our NativePropertyHooks. cgThings.append(CGNativePropertyHooks(descriptor, properties)) - if descriptor.interface.hasInterfaceObject(): + if descriptor.interface.isNamespace(): + cgThings.append(CGNamespaceObjectJSClass(descriptor)) + elif descriptor.interface.hasInterfaceObject(): cgThings.append(CGClassConstructor(descriptor, descriptor.interface.ctor())) - cgThings.append(CGInterfaceObjectJSClass(descriptor, properties)) + cgThings.append(CGInterfaceObjectInfo(descriptor)) cgThings.append(CGLegacyFactoryFunctions(descriptor)) cgThings.append(CGLegacyCallHook(descriptor)) |