1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bindings/Configuration.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,603 @@ 1.4 +# This Source Code Form is subject to the terms of the Mozilla Public 1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 +# You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + 1.8 +from WebIDL import IDLInterface, IDLExternalInterface 1.9 +import os 1.10 + 1.11 +autogenerated_comment = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n" 1.12 + 1.13 +class Configuration: 1.14 + """ 1.15 + Represents global configuration state based on IDL parse data and 1.16 + the configuration file. 1.17 + """ 1.18 + def __init__(self, filename, parseData): 1.19 + 1.20 + # Read the configuration file. 1.21 + glbl = {} 1.22 + execfile(filename, glbl) 1.23 + config = glbl['DOMInterfaces'] 1.24 + 1.25 + # Build descriptors for all the interfaces we have in the parse data. 1.26 + # This allows callers to specify a subset of interfaces by filtering 1.27 + # |parseData|. 1.28 + self.descriptors = [] 1.29 + self.interfaces = {} 1.30 + self.maxProtoChainLength = 0; 1.31 + for thing in parseData: 1.32 + # Some toplevel things are sadly types, and those have an 1.33 + # isInterface that doesn't mean the same thing as IDLObject's 1.34 + # isInterface()... 1.35 + if (not isinstance(thing, IDLInterface) and 1.36 + not isinstance(thing, IDLExternalInterface)): 1.37 + continue 1.38 + iface = thing 1.39 + self.interfaces[iface.identifier.name] = iface 1.40 + if iface.identifier.name not in config: 1.41 + # Completely skip consequential interfaces with no descriptor 1.42 + # if they have no interface object because chances are we 1.43 + # don't need to do anything interesting with them. 1.44 + if iface.isConsequential() and not iface.hasInterfaceObject(): 1.45 + continue 1.46 + entry = {} 1.47 + else: 1.48 + entry = config[iface.identifier.name] 1.49 + if not isinstance(entry, list): 1.50 + assert isinstance(entry, dict) 1.51 + entry = [entry] 1.52 + elif len(entry) == 1: 1.53 + if entry[0].get("workers", False): 1.54 + # List with only a workers descriptor means we should 1.55 + # infer a mainthread descriptor. If you want only 1.56 + # workers bindings, don't use a list here. 1.57 + entry.append({}) 1.58 + else: 1.59 + raise TypeError("Don't use a single-element list for " 1.60 + "non-worker-only interface " + iface.identifier.name + 1.61 + " in Bindings.conf") 1.62 + elif len(entry) == 2: 1.63 + if entry[0].get("workers", False) == entry[1].get("workers", False): 1.64 + raise TypeError("The two entries for interface " + iface.identifier.name + 1.65 + " in Bindings.conf should not have the same value for 'workers'") 1.66 + else: 1.67 + raise TypeError("Interface " + iface.identifier.name + 1.68 + " should have no more than two entries in Bindings.conf") 1.69 + self.descriptors.extend([Descriptor(self, iface, x) for x in entry]) 1.70 + 1.71 + # Keep the descriptor list sorted for determinism. 1.72 + self.descriptors.sort(lambda x,y: cmp(x.name, y.name)) 1.73 + 1.74 + self.descriptorsByName = {} 1.75 + for d in self.descriptors: 1.76 + self.descriptorsByName.setdefault(d.interface.identifier.name, 1.77 + []).append(d) 1.78 + 1.79 + self.descriptorsByFile = {} 1.80 + for d in self.descriptors: 1.81 + self.descriptorsByFile.setdefault(d.interface.filename(), 1.82 + []).append(d) 1.83 + 1.84 + self.enums = [e for e in parseData if e.isEnum()] 1.85 + 1.86 + # Figure out what our main-thread and worker dictionaries and callbacks 1.87 + # are. 1.88 + mainTypes = set() 1.89 + for descriptor in ([self.getDescriptor("DummyInterface", workers=False)] + 1.90 + self.getDescriptors(workers=False, isExternal=False, skipGen=False)): 1.91 + mainTypes |= set(getFlatTypes(getTypesFromDescriptor(descriptor))) 1.92 + (mainCallbacks, mainDictionaries) = findCallbacksAndDictionaries(mainTypes) 1.93 + 1.94 + workerTypes = set(); 1.95 + for descriptor in ([self.getDescriptor("DummyInterfaceWorkers", workers=True)] + 1.96 + self.getDescriptors(workers=True, isExternal=False, skipGen=False)): 1.97 + workerTypes |= set(getFlatTypes(getTypesFromDescriptor(descriptor))) 1.98 + (workerCallbacks, workerDictionaries) = findCallbacksAndDictionaries(workerTypes) 1.99 + 1.100 + self.dictionaries = [d for d in parseData if d.isDictionary()] 1.101 + self.callbacks = [c for c in parseData if 1.102 + c.isCallback() and not c.isInterface()] 1.103 + 1.104 + def flagWorkerOrMainThread(items, main, worker): 1.105 + for item in items: 1.106 + if item in main: 1.107 + item.setUserData("mainThread", True) 1.108 + if item in worker: 1.109 + item.setUserData("workers", True) 1.110 + flagWorkerOrMainThread(self.callbacks, mainCallbacks, workerCallbacks) 1.111 + 1.112 + def getInterface(self, ifname): 1.113 + return self.interfaces[ifname] 1.114 + def getDescriptors(self, **filters): 1.115 + """Gets the descriptors that match the given filters.""" 1.116 + curr = self.descriptors 1.117 + # Collect up our filters, because we may have a webIDLFile filter that 1.118 + # we always want to apply first. 1.119 + tofilter = [] 1.120 + for key, val in filters.iteritems(): 1.121 + if key == 'webIDLFile': 1.122 + # Special-case this part to make it fast, since most of our 1.123 + # getDescriptors calls are conditioned on a webIDLFile. We may 1.124 + # not have this key, in which case we have no descriptors 1.125 + # either. 1.126 + curr = self.descriptorsByFile.get(val, []) 1.127 + continue 1.128 + elif key == 'hasInterfaceObject': 1.129 + getter = lambda x: (not x.interface.isExternal() and 1.130 + x.interface.hasInterfaceObject()) 1.131 + elif key == 'hasInterfacePrototypeObject': 1.132 + getter = lambda x: (not x.interface.isExternal() and 1.133 + x.interface.hasInterfacePrototypeObject()) 1.134 + elif key == 'hasInterfaceOrInterfacePrototypeObject': 1.135 + getter = lambda x: x.hasInterfaceOrInterfacePrototypeObject() 1.136 + elif key == 'isCallback': 1.137 + getter = lambda x: x.interface.isCallback() 1.138 + elif key == 'isExternal': 1.139 + getter = lambda x: x.interface.isExternal() 1.140 + elif key == 'isJSImplemented': 1.141 + getter = lambda x: x.interface.isJSImplemented() 1.142 + elif key == 'isNavigatorProperty': 1.143 + getter = lambda x: x.interface.getNavigatorProperty() != None 1.144 + else: 1.145 + # Have to watch out: just closing over "key" is not enough, 1.146 + # since we're about to mutate its value 1.147 + getter = (lambda attrName: lambda x: getattr(x, attrName))(key) 1.148 + tofilter.append((getter, val)) 1.149 + for f in tofilter: 1.150 + curr = filter(lambda x: f[0](x) == f[1], curr) 1.151 + return curr 1.152 + def getEnums(self, webIDLFile): 1.153 + return filter(lambda e: e.filename() == webIDLFile, self.enums) 1.154 + 1.155 + @staticmethod 1.156 + def _filterForFileAndWorkers(items, filters): 1.157 + """Gets the items that match the given filters.""" 1.158 + for key, val in filters.iteritems(): 1.159 + if key == 'webIDLFile': 1.160 + items = filter(lambda x: x.filename() == val, items) 1.161 + elif key == 'workers': 1.162 + if val: 1.163 + items = filter(lambda x: x.getUserData("workers", False), items) 1.164 + else: 1.165 + items = filter(lambda x: x.getUserData("mainThread", False), items) 1.166 + else: 1.167 + assert(0) # Unknown key 1.168 + return items 1.169 + def getDictionaries(self, **filters): 1.170 + return self._filterForFileAndWorkers(self.dictionaries, filters) 1.171 + def getCallbacks(self, **filters): 1.172 + return self._filterForFileAndWorkers(self.callbacks, filters) 1.173 + 1.174 + def getDescriptor(self, interfaceName, workers): 1.175 + """ 1.176 + Gets the appropriate descriptor for the given interface name 1.177 + and the given workers boolean. 1.178 + """ 1.179 + for d in self.descriptorsByName[interfaceName]: 1.180 + if d.workers == workers: 1.181 + return d 1.182 + 1.183 + if workers: 1.184 + for d in self.descriptorsByName[interfaceName]: 1.185 + return d 1.186 + 1.187 + raise NoSuchDescriptorError("For " + interfaceName + " found no matches"); 1.188 + def getDescriptorProvider(self, workers): 1.189 + """ 1.190 + Gets a descriptor provider that can provide descriptors as needed, 1.191 + for the given workers boolean 1.192 + """ 1.193 + return DescriptorProvider(self, workers) 1.194 + 1.195 +class NoSuchDescriptorError(TypeError): 1.196 + def __init__(self, str): 1.197 + TypeError.__init__(self, str) 1.198 + 1.199 +class DescriptorProvider: 1.200 + """ 1.201 + A way of getting descriptors for interface names 1.202 + """ 1.203 + def __init__(self, config, workers): 1.204 + self.config = config 1.205 + self.workers = workers 1.206 + 1.207 + def getDescriptor(self, interfaceName): 1.208 + """ 1.209 + Gets the appropriate descriptor for the given interface name given the 1.210 + context of the current descriptor. This selects the appropriate 1.211 + implementation for cases like workers. 1.212 + """ 1.213 + return self.config.getDescriptor(interfaceName, self.workers) 1.214 + 1.215 +class Descriptor(DescriptorProvider): 1.216 + """ 1.217 + Represents a single descriptor for an interface. See Bindings.conf. 1.218 + """ 1.219 + def __init__(self, config, interface, desc): 1.220 + DescriptorProvider.__init__(self, config, desc.get('workers', False)) 1.221 + self.interface = interface 1.222 + 1.223 + # Read the desc, and fill in the relevant defaults. 1.224 + ifaceName = self.interface.identifier.name 1.225 + if self.interface.isExternal(): 1.226 + if self.workers: 1.227 + nativeTypeDefault = "JSObject" 1.228 + else: 1.229 + nativeTypeDefault = "nsIDOM" + ifaceName 1.230 + elif self.interface.isCallback(): 1.231 + nativeTypeDefault = "mozilla::dom::" + ifaceName 1.232 + else: 1.233 + if self.workers: 1.234 + nativeTypeDefault = "mozilla::dom::workers::" + ifaceName 1.235 + else: 1.236 + nativeTypeDefault = "mozilla::dom::" + ifaceName 1.237 + 1.238 + self.nativeType = desc.get('nativeType', nativeTypeDefault) 1.239 + # Now create a version of nativeType that doesn't have extra 1.240 + # mozilla::dom:: at the beginning. 1.241 + prettyNativeType = self.nativeType.split("::") 1.242 + if prettyNativeType[0] == "mozilla": 1.243 + prettyNativeType.pop(0) 1.244 + if prettyNativeType[0] == "dom": 1.245 + prettyNativeType.pop(0) 1.246 + self.prettyNativeType = "::".join(prettyNativeType) 1.247 + 1.248 + self.jsImplParent = desc.get('jsImplParent', self.nativeType) 1.249 + 1.250 + # Do something sane for JSObject 1.251 + if self.nativeType == "JSObject": 1.252 + headerDefault = "js/TypeDecls.h" 1.253 + elif self.interface.isCallback() or self.interface.isJSImplemented(): 1.254 + # A copy of CGHeaders.getDeclarationFilename; we can't 1.255 + # import it here, sadly. 1.256 + # Use our local version of the header, not the exported one, so that 1.257 + # test bindings, which don't export, will work correctly. 1.258 + basename = os.path.basename(self.interface.filename()) 1.259 + headerDefault = basename.replace('.webidl', 'Binding.h') 1.260 + else: 1.261 + if self.workers: 1.262 + headerDefault = "mozilla/dom/workers/bindings/%s.h" % ifaceName 1.263 + elif not self.interface.isExternal() and self.interface.getExtendedAttribute("HeaderFile"): 1.264 + headerDefault = self.interface.getExtendedAttribute("HeaderFile")[0] 1.265 + else: 1.266 + headerDefault = self.nativeType 1.267 + headerDefault = headerDefault.replace("::", "/") + ".h" 1.268 + self.headerFile = desc.get('headerFile', headerDefault) 1.269 + self.headerIsDefault = self.headerFile == headerDefault 1.270 + if self.jsImplParent == self.nativeType: 1.271 + self.jsImplParentHeader = self.headerFile 1.272 + else: 1.273 + self.jsImplParentHeader = self.jsImplParent.replace("::", "/") + ".h" 1.274 + 1.275 + self.skipGen = desc.get('skipGen', False) 1.276 + 1.277 + self.notflattened = desc.get('notflattened', False) 1.278 + self.register = desc.get('register', True) 1.279 + 1.280 + self.hasXPConnectImpls = desc.get('hasXPConnectImpls', False) 1.281 + 1.282 + # If we're concrete, we need to crawl our ancestor interfaces and mark 1.283 + # them as having a concrete descendant. 1.284 + self.concrete = (not self.interface.isExternal() and 1.285 + not self.interface.isCallback() and 1.286 + desc.get('concrete', True)) 1.287 + operations = { 1.288 + 'IndexedGetter': None, 1.289 + 'IndexedSetter': None, 1.290 + 'IndexedCreator': None, 1.291 + 'IndexedDeleter': None, 1.292 + 'NamedGetter': None, 1.293 + 'NamedSetter': None, 1.294 + 'NamedCreator': None, 1.295 + 'NamedDeleter': None, 1.296 + 'Stringifier': None, 1.297 + 'LegacyCaller': None, 1.298 + 'Jsonifier': None 1.299 + } 1.300 + if self.concrete: 1.301 + self.proxy = False 1.302 + iface = self.interface 1.303 + def addOperation(operation, m): 1.304 + if not operations[operation]: 1.305 + operations[operation] = m 1.306 + # Since stringifiers go on the prototype, we only need to worry 1.307 + # about our own stringifier, not those of our ancestor interfaces. 1.308 + for m in iface.members: 1.309 + if m.isMethod() and m.isStringifier(): 1.310 + addOperation('Stringifier', m) 1.311 + if m.isMethod() and m.isJsonifier(): 1.312 + addOperation('Jsonifier', m) 1.313 + # Don't worry about inheriting legacycallers either: in 1.314 + # practice these are on most-derived prototypes. 1.315 + if m.isMethod() and m.isLegacycaller(): 1.316 + if not m.isIdentifierLess(): 1.317 + raise TypeError("We don't support legacycaller with " 1.318 + "identifier.\n%s" % m.location); 1.319 + if len(m.signatures()) != 1: 1.320 + raise TypeError("We don't support overloaded " 1.321 + "legacycaller.\n%s" % m.location) 1.322 + addOperation('LegacyCaller', m) 1.323 + while iface: 1.324 + for m in iface.members: 1.325 + if not m.isMethod(): 1.326 + continue 1.327 + 1.328 + def addIndexedOrNamedOperation(operation, m): 1.329 + self.proxy = True 1.330 + if m.isIndexed(): 1.331 + operation = 'Indexed' + operation 1.332 + else: 1.333 + assert m.isNamed() 1.334 + operation = 'Named' + operation 1.335 + addOperation(operation, m) 1.336 + 1.337 + if m.isGetter(): 1.338 + addIndexedOrNamedOperation('Getter', m) 1.339 + if m.isSetter(): 1.340 + addIndexedOrNamedOperation('Setter', m) 1.341 + if m.isCreator(): 1.342 + addIndexedOrNamedOperation('Creator', m) 1.343 + if m.isDeleter(): 1.344 + addIndexedOrNamedOperation('Deleter', m) 1.345 + if m.isLegacycaller() and iface != self.interface: 1.346 + raise TypeError("We don't support legacycaller on " 1.347 + "non-leaf interface %s.\n%s" % 1.348 + (iface, iface.location)) 1.349 + 1.350 + iface.setUserData('hasConcreteDescendant', True) 1.351 + iface = iface.parent 1.352 + 1.353 + if self.proxy: 1.354 + if (not operations['IndexedGetter'] and 1.355 + (operations['IndexedSetter'] or 1.356 + operations['IndexedDeleter'] or 1.357 + operations['IndexedCreator'])): 1.358 + raise SyntaxError("%s supports indexed properties but does " 1.359 + "not have an indexed getter.\n%s" % 1.360 + (self.interface, self.interface.location)) 1.361 + if (not operations['NamedGetter'] and 1.362 + (operations['NamedSetter'] or 1.363 + operations['NamedDeleter'] or 1.364 + operations['NamedCreator'])): 1.365 + raise SyntaxError("%s supports named properties but does " 1.366 + "not have a named getter.\n%s" % 1.367 + (self.interface, self.interface.location)) 1.368 + iface = self.interface 1.369 + while iface: 1.370 + iface.setUserData('hasProxyDescendant', True) 1.371 + iface = iface.parent 1.372 + self.operations = operations 1.373 + 1.374 + self.nativeOwnership = desc.get('nativeOwnership', 'refcounted') 1.375 + if not self.nativeOwnership in ('owned', 'refcounted'): 1.376 + raise TypeError("Descriptor for %s has unrecognized value (%s) " 1.377 + "for nativeOwnership" % 1.378 + (self.interface.identifier.name, self.nativeOwnership)) 1.379 + if desc.get('wantsQI', None) != None: 1.380 + self._wantsQI = desc.get('wantsQI', None) 1.381 + self.wrapperCache = (not self.interface.isCallback() and 1.382 + (self.nativeOwnership != 'owned' and 1.383 + desc.get('wrapperCache', True))) 1.384 + 1.385 + def make_name(name): 1.386 + return name + "_workers" if self.workers else name 1.387 + self.name = make_name(interface.identifier.name) 1.388 + 1.389 + # self.extendedAttributes is a dict of dicts, keyed on 1.390 + # all/getterOnly/setterOnly and then on member name. Values are an 1.391 + # array of extended attributes. 1.392 + self.extendedAttributes = { 'all': {}, 'getterOnly': {}, 'setterOnly': {} } 1.393 + 1.394 + def addExtendedAttribute(attribute, config): 1.395 + def add(key, members, attribute): 1.396 + for member in members: 1.397 + self.extendedAttributes[key].setdefault(member, []).append(attribute) 1.398 + 1.399 + if isinstance(config, dict): 1.400 + for key in ['all', 'getterOnly', 'setterOnly']: 1.401 + add(key, config.get(key, []), attribute) 1.402 + elif isinstance(config, list): 1.403 + add('all', config, attribute) 1.404 + else: 1.405 + assert isinstance(config, str) 1.406 + if config == '*': 1.407 + iface = self.interface 1.408 + while iface: 1.409 + add('all', map(lambda m: m.name, iface.members), attribute) 1.410 + iface = iface.parent 1.411 + else: 1.412 + add('all', [config], attribute) 1.413 + 1.414 + if self.interface.isJSImplemented(): 1.415 + addExtendedAttribute('implicitJSContext', ['constructor']) 1.416 + else: 1.417 + for attribute in ['implicitJSContext', 'resultNotAddRefed']: 1.418 + addExtendedAttribute(attribute, desc.get(attribute, {})) 1.419 + 1.420 + self.binaryNames = desc.get('binaryNames', {}) 1.421 + if '__legacycaller' not in self.binaryNames: 1.422 + self.binaryNames["__legacycaller"] = "LegacyCall" 1.423 + if '__stringifier' not in self.binaryNames: 1.424 + self.binaryNames["__stringifier"] = "Stringify" 1.425 + 1.426 + # Build the prototype chain. 1.427 + self.prototypeChain = [] 1.428 + parent = interface 1.429 + while parent: 1.430 + self.prototypeChain.insert(0, parent.identifier.name) 1.431 + parent = parent.parent 1.432 + config.maxProtoChainLength = max(config.maxProtoChainLength, 1.433 + len(self.prototypeChain)) 1.434 + 1.435 + def hasInterfaceOrInterfacePrototypeObject(self): 1.436 + 1.437 + # Forward-declared interfaces don't need either interface object or 1.438 + # interface prototype object as they're going to use QI (on main thread) 1.439 + # or be passed as a JSObject (on worker threads). 1.440 + if self.interface.isExternal(): 1.441 + return False 1.442 + 1.443 + return self.interface.hasInterfaceObject() or self.interface.hasInterfacePrototypeObject() 1.444 + 1.445 + def getExtendedAttributes(self, member, getter=False, setter=False): 1.446 + def ensureValidThrowsExtendedAttribute(attr): 1.447 + assert(attr is None or attr is True or len(attr) == 1) 1.448 + if (attr is not None and attr is not True and 1.449 + 'Workers' not in attr and 'MainThread' not in attr): 1.450 + raise TypeError("Unknown value for 'Throws': " + attr[0]) 1.451 + 1.452 + def maybeAppendInfallibleToAttrs(attrs, throws): 1.453 + ensureValidThrowsExtendedAttribute(throws) 1.454 + if (throws is None or 1.455 + (throws is not True and 1.456 + ('Workers' not in throws or not self.workers) and 1.457 + ('MainThread' not in throws or self.workers))): 1.458 + attrs.append("infallible") 1.459 + 1.460 + name = member.identifier.name 1.461 + throws = self.interface.isJSImplemented() or member.getExtendedAttribute("Throws") 1.462 + if member.isMethod(): 1.463 + attrs = self.extendedAttributes['all'].get(name, []) 1.464 + maybeAppendInfallibleToAttrs(attrs, throws) 1.465 + return attrs 1.466 + 1.467 + assert member.isAttr() 1.468 + assert bool(getter) != bool(setter) 1.469 + key = 'getterOnly' if getter else 'setterOnly' 1.470 + attrs = self.extendedAttributes['all'].get(name, []) + self.extendedAttributes[key].get(name, []) 1.471 + if throws is None: 1.472 + throwsAttr = "GetterThrows" if getter else "SetterThrows" 1.473 + throws = member.getExtendedAttribute(throwsAttr) 1.474 + maybeAppendInfallibleToAttrs(attrs, throws) 1.475 + return attrs 1.476 + 1.477 + def supportsIndexedProperties(self): 1.478 + return self.operations['IndexedGetter'] is not None 1.479 + 1.480 + def supportsNamedProperties(self): 1.481 + return self.operations['NamedGetter'] is not None 1.482 + 1.483 + def needsConstructHookHolder(self): 1.484 + assert self.interface.hasInterfaceObject() 1.485 + return False 1.486 + 1.487 + def needsHeaderInclude(self): 1.488 + """ 1.489 + An interface doesn't need a header file if it is not concrete, 1.490 + not pref-controlled, has no prototype object, and has no 1.491 + static methods or attributes. 1.492 + """ 1.493 + return (self.interface.isExternal() or self.concrete or 1.494 + self.interface.hasInterfacePrototypeObject() or 1.495 + any((m.isAttr() or m.isMethod()) and m.isStatic() for m 1.496 + in self.interface.members)) 1.497 + 1.498 + def isExposedConditionally(self): 1.499 + return (self.interface.getExtendedAttribute("Pref") or 1.500 + self.interface.getExtendedAttribute("ChromeOnly") or 1.501 + self.interface.getExtendedAttribute("Func") or 1.502 + self.interface.getExtendedAttribute("AvailableIn")) 1.503 + 1.504 + def needsXrayResolveHooks(self): 1.505 + """ 1.506 + Generally, any interface with NeedNewResolve needs Xray 1.507 + resolveOwnProperty and enumerateOwnProperties hooks. But for 1.508 + the special case of plugin-loading elements, we do NOT want 1.509 + those, because we don't want to instantiate plug-ins simply 1.510 + due to chrome touching them and that's all those hooks do on 1.511 + those elements. So we special-case those here. 1.512 + """ 1.513 + return (self.interface.getExtendedAttribute("NeedNewResolve") and 1.514 + self.interface.identifier.name not in ["HTMLObjectElement", 1.515 + "HTMLEmbedElement", 1.516 + "HTMLAppletElement"]) 1.517 + 1.518 + def needsSpecialGenericOps(self): 1.519 + """ 1.520 + Returns true if this descriptor requires generic ops other than 1.521 + GenericBindingMethod/GenericBindingGetter/GenericBindingSetter. 1.522 + 1.523 + In practice we need to do this if our this value might be an XPConnect 1.524 + object or if we need to coerce null/undefined to the global. 1.525 + """ 1.526 + return self.hasXPConnectImpls or self.interface.isOnGlobalProtoChain() 1.527 + 1.528 +# Some utility methods 1.529 +def getTypesFromDescriptor(descriptor): 1.530 + """ 1.531 + Get all argument and return types for all members of the descriptor 1.532 + """ 1.533 + members = [m for m in descriptor.interface.members] 1.534 + if descriptor.interface.ctor(): 1.535 + members.append(descriptor.interface.ctor()) 1.536 + members.extend(descriptor.interface.namedConstructors) 1.537 + signatures = [s for m in members if m.isMethod() for s in m.signatures()] 1.538 + types = [] 1.539 + for s in signatures: 1.540 + assert len(s) == 2 1.541 + (returnType, arguments) = s 1.542 + types.append(returnType) 1.543 + types.extend(a.type for a in arguments) 1.544 + 1.545 + types.extend(a.type for a in members if a.isAttr()) 1.546 + return types 1.547 + 1.548 +def getFlatTypes(types): 1.549 + retval = set() 1.550 + for type in types: 1.551 + type = type.unroll() 1.552 + if type.isUnion(): 1.553 + retval |= set(type.flatMemberTypes) 1.554 + else: 1.555 + retval.add(type) 1.556 + return retval 1.557 + 1.558 +def getTypesFromDictionary(dictionary): 1.559 + """ 1.560 + Get all member types for this dictionary 1.561 + """ 1.562 + types = [] 1.563 + curDict = dictionary 1.564 + while curDict: 1.565 + types.extend([m.type for m in curDict.members]) 1.566 + curDict = curDict.parent 1.567 + return types 1.568 + 1.569 +def getTypesFromCallback(callback): 1.570 + """ 1.571 + Get the types this callback depends on: its return type and the 1.572 + types of its arguments. 1.573 + """ 1.574 + sig = callback.signatures()[0] 1.575 + types = [sig[0]] # Return type 1.576 + types.extend(arg.type for arg in sig[1]) # Arguments 1.577 + return types 1.578 + 1.579 +def findCallbacksAndDictionaries(inputTypes): 1.580 + """ 1.581 + Ensure that all callbacks and dictionaries reachable from types end up in 1.582 + the returned callbacks and dictionaries sets. 1.583 + 1.584 + Note that we assume that our initial invocation already includes all types 1.585 + reachable via descriptors in "types", so we only have to deal with things 1.586 + that are themeselves reachable via callbacks and dictionaries. 1.587 + """ 1.588 + def doFindCallbacksAndDictionaries(types, callbacks, dictionaries): 1.589 + unhandledTypes = set() 1.590 + for type in types: 1.591 + if type.isCallback() and type not in callbacks: 1.592 + unhandledTypes |= getFlatTypes(getTypesFromCallback(type)) 1.593 + callbacks.add(type) 1.594 + elif type.isDictionary() and type.inner not in dictionaries: 1.595 + d = type.inner 1.596 + unhandledTypes |= getFlatTypes(getTypesFromDictionary(d)) 1.597 + while d: 1.598 + dictionaries.add(d) 1.599 + d = d.parent 1.600 + if len(unhandledTypes) != 0: 1.601 + doFindCallbacksAndDictionaries(unhandledTypes, callbacks, dictionaries) 1.602 + 1.603 + retCallbacks = set() 1.604 + retDictionaries = set() 1.605 + doFindCallbacksAndDictionaries(inputTypes, retCallbacks, retDictionaries) 1.606 + return (retCallbacks, retDictionaries)