Bug 830099. Flag WebIDL dictionaries and callbacks with some information indicating whether we need main-thread and worker codegen for them and then use that information to skip unneccessary codegen. r=peterv
☠☠ backed out by 2f6fa70c289a ☠ ☠
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 28 Jan 2013 23:30:17 -0500
changeset 130017 32786d29daf8b2e83549fc316bdc36662e2cd96a
parent 130016 19b9f064d8eb910c9d7a613bb01812dd0e4ad904
child 130018 2f6fa70c289a04c1c2653b7c090879ca441c61fb
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs830099
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 830099. Flag WebIDL dictionaries and callbacks with some information indicating whether we need main-thread and worker codegen for them and then use that information to skip unneccessary codegen. r=peterv
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/bindings/Configuration.py
dom/bindings/parser/WebIDL.py
dom/webidl/DummyBinding.webidl
dom/webidl/WebIDL.mk
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -243,16 +243,27 @@ DOMInterfaces = {
 
 'DOMTokenList': {
     'nativeType': 'nsDOMTokenList',
     'binaryNames': {
         '__stringifier': 'Stringify'
     }
 },
 
+'DummyInterface': {
+    'skipGen': True,
+    'register': False,
+},
+
+'DummyInterfaceWorkers': {
+    'skipGen': True,
+    'register': False,
+    'workers': True
+},
+
 'DynamicsCompressorNode': {
     'resultNotAddRefed': [ 'threshold', 'knee', 'ratio',
                            'reduction', 'attack', 'release' ],
     'binaryNames': {
         'release': 'getRelease'
     },
     'wrapperCache': False
 },
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5,17 +5,17 @@
 # Common codegen classes.
 
 import operator
 import os
 import re
 import string
 
 from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType
-from Configuration import NoSuchDescriptorError
+from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback
 
 AUTOGENERATED_WARNING_COMMENT = \
     "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
 ADDPROPERTY_HOOK_NAME = '_addProperty'
 FINALIZE_HOOK_NAME = '_finalize'
 TRACE_HOOK_NAME = '_trace'
 CONSTRUCT_HOOK_NAME = '_constructor'
 HASINSTANCE_HOOK_NAME = '_hasInstance'
@@ -384,55 +384,16 @@ class CGIncludeGuard(CGWrapper):
     """
     def __init__(self, prefix, child):
         """|prefix| is the filename without the extension."""
         define = 'mozilla_dom_%s_h__' % prefix
         CGWrapper.__init__(self, child,
                            declarePre='#ifndef %s\n#define %s\n\n' % (define, define),
                            declarePost='\n#endif // %s\n' % define)
 
-def getTypesFromDescriptor(descriptor):
-    """
-    Get all argument and return types for all members of the descriptor
-    """
-    members = [m for m in descriptor.interface.members]
-    if descriptor.interface.ctor():
-        members.append(descriptor.interface.ctor())
-    signatures = [s for m in members if m.isMethod() for s in m.signatures()]
-    types = []
-    for s in signatures:
-        assert len(s) == 2
-        (returnType, arguments) = s
-        types.append(returnType)
-        types.extend(a.type for a in arguments)
-
-    types.extend(a.type for a in members if a.isAttr())
-    return types
-
-def getTypesFromDictionary(dictionary):
-    """
-    Get all member types for this dictionary
-    """
-    types = []
-    curDict = dictionary
-    while curDict:
-        types.extend([m.type for m in curDict.members])
-        curDict = curDict.parent
-    return types
-
-def getTypesFromCallback(callback):
-    """
-    Get the types this callback depends on: its return type and the
-    types of its arguments.
-    """
-    sig = callback.signatures()[0]
-    types = [sig[0]] # Return type
-    types.extend(arg.type for arg in sig[1]) # Arguments
-    return types
-
 def getRelevantProviders(descriptor, dictionary, config):
     assert not descriptor or not dictionary
     if descriptor is not None:
         return [descriptor]
     if dictionary is not None:
         # Do both the non-worker and worker versions
         return [
             config.getDescriptorProvider(False),
@@ -6518,44 +6479,26 @@ class CGNamespacedEnum(CGThing):
         assert False # Only for headers.
 
 class CGDictionary(CGThing):
     def __init__(self, dictionary, descriptorProvider):
         self.dictionary = dictionary
         self.descriptorProvider = descriptorProvider
         self.workers = descriptorProvider.workers
         self.needToInitIds = not self.workers and len(dictionary.members) > 0
-        if all(CGDictionary(d, descriptorProvider).generatable for
-               d in CGDictionary.getDictionaryDependencies(dictionary)):
-            self.generatable = True
-        else:
-            self.generatable = False
-            # Nothing else to do here
-            return
-        # Getting a conversion template for interface types can fail
-        # if we don't have a relevant descriptor when self.workers is True.
-        # If that happens, just mark ourselves as not being
-        # generatable and move on.
-        try:
-            self.memberInfo = [
-                (member,
-                 getJSToNativeConversionTemplate(member.type,
-                                                 descriptorProvider,
-                                                 isMember="Dictionary",
-                                                 isOptional=(not member.defaultValue),
-                                                 defaultValue=member.defaultValue))
-                for member in dictionary.members ]
-        except NoSuchDescriptorError, err:
-            if not self.workers:
-                raise err
-            self.generatable = False
+        self.memberInfo = [
+            (member,
+             getJSToNativeConversionTemplate(member.type,
+                                             descriptorProvider,
+                                             isMember="Dictionary",
+                                             isOptional=(not member.defaultValue),
+                                             defaultValue=member.defaultValue))
+            for member in dictionary.members ]
 
     def declare(self):
-        if not self.generatable:
-            return ""
         d = self.dictionary
         if d.parent:
             inheritance = ": public %s " % self.makeClassName(d.parent)
         elif not self.workers:
             inheritance = ": public MainThreadDictionaryBase "
         else:
             inheritance = ""
         memberDecls = ["  %s %s;" %
@@ -6594,18 +6537,16 @@ class CGDictionary(CGThing):
                 "  ${selfName}Initializer() {\n"
                 "    // Safe to pass a null context if we pass a null value\n"
                 "    Init(nullptr, nullptr, JS::NullValue());\n"
                 "  }\n"
                 "};").substitute( { "selfName": self.makeClassName(d),
                                     "inheritance": inheritance }))
 
     def define(self):
-        if not self.generatable:
-            return ""
         d = self.dictionary
         if d.parent:
             initParent = ("// Per spec, we init the parent's members first\n"
                           "if (!%s::Init(cx, scopeObj, val)) {\n"
                           "  return false;\n"
                           "}\n" % self.makeClassName(d.parent))
             toObjectParent = ("// Per spec, we define the parent's members first\n"
                               "if (!%s::ToObject(cx, parentObject, vp)) {\n"
@@ -6879,40 +6820,49 @@ class CGBindingRoot(CGThing):
     """
     Root codegen class for binding generation. Instantiate the class, and call
     declare or define to generate header or cpp code (respectively).
     """
     def __init__(self, config, prefix, webIDLFile):
         descriptors = config.getDescriptors(webIDLFile=webIDLFile,
                                             hasInterfaceOrInterfacePrototypeObject=True,
                                             skipGen=False)
-        dictionaries = config.getDictionaries(webIDLFile)
-        callbacks = config.getCallbacks(webIDLFile)
+        mainDictionaries = config.getDictionaries(webIDLFile=webIDLFile,
+                                                  workers=False)
+        workerDictionaries = config.getDictionaries(webIDLFile=webIDLFile,
+                                                    workers=True)
+        mainCallbacks = config.getCallbacks(webIDLFile=webIDLFile,
+                                            workers=False)
+        workerCallbacks = config.getCallbacks(webIDLFile=webIDLFile,
+                                              workers=True)
         callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile,
                                                     isCallback=True)
 
         forwardDeclares = [CGClassForwardDeclare('XPCWrappedNativeScope')]
 
         descriptorsForForwardDeclaration = list(descriptors)
         ifaces = []
         workerIfaces = []
-        for dictionary in dictionaries:
-            dictionaryIfaces = [ type.unroll().inner
-                                 for type in getTypesFromDictionary(dictionary)
-                                 if type.unroll().isGeckoInterface() ]
-            ifaces.extend(dictionaryIfaces)
-            workerIfaces.extend(dictionaryIfaces)
-
-        for callback in callbacks:
-            callbackIfaces = [ t.unroll().inner
-                               for t in getTypesFromCallback(callback)
-                               if t.unroll().isGeckoInterface() ]
-            workerIfaces.extend(callbackIfaces)
-            if not callback.isWorkerOnly():
-                ifaces.extend(callbackIfaces)
+        def getInterfacesFromDictionary(d):
+            return [ type.unroll().inner
+                     for type in getTypesFromDictionary(d)
+                     if type.unroll().isGeckoInterface() ]
+        for dictionary in mainDictionaries:
+            ifaces.extend(getInterfacesFromDictionary(dictionary))
+        for dictionary in workerDictionaries:
+            workerIfaces.extend(getInterfacesFromDictionary(dictionary))
+
+        def getInterfacesFromCallback(c):
+            return [ t.unroll().inner
+                     for t in getTypesFromCallback(c)
+                     if t.unroll().isGeckoInterface() ]
+        for callback in mainCallbacks:
+            ifaces.extend(getInterfacesFromCallback(callback))
+        for callback in workerCallbacks:
+            workerIfaces.extend(getInterfacesFromCallback(callback))
 
         for callbackDescriptor in callbackDescriptors:
             callbackDescriptorIfaces = [
                 t.unroll().inner
                 for t in getTypesFromDescriptor(callbackDescriptor)
                 if t.unroll().isGeckoInterface() ]
             workerIfaces.extend(callbackDescriptorIfaces)
             ifaces.extend(callbackDescriptorIfaces)
@@ -6943,30 +6893,30 @@ class CGBindingRoot(CGThing):
                                             declareOnly=True)
             return CGWrapper(declare, declarePost='\n')
 
         for x in descriptorsForForwardDeclaration:
             forwardDeclares.append(declareNativeType(x.nativeType))
 
         # Now add the forward declarations we need for our union types
         # and callback functions.
-        for callback in callbacks:
+        for callback in mainCallbacks + workerCallbacks:
             forwardDeclares.extend(
                 declareNativeType("mozilla::dom::" + str(t.unroll()))
                 for t in getTypesFromCallback(callback)
                 if t.unroll().isUnion() or t.unroll().isCallback())
 
         for callbackDescriptor in callbackDescriptors:
             forwardDeclares.extend(
                 declareNativeType("mozilla::dom::" + str(t.unroll()))
                 for t in getTypesFromDescriptor(callbackDescriptor)
                 if t.unroll().isUnion() or t.unroll().isCallback())
 
         # Forward declarations for callback functions used in dictionaries.
-        for dictionary in dictionaries:
+        for dictionary in mainDictionaries + workerDictionaries:
             forwardDeclares.extend(
                 declareNativeType("mozilla::dom::" + str(t.unroll()))
                 for t in getTypesFromDictionary(dictionary)
                 if t.unroll().isCallback())
 
         forwardDeclares = CGList(forwardDeclares)
 
         descriptorsWithPrototype = filter(lambda d: d.interface.hasInterfacePrototypeObject(),
@@ -7002,40 +6952,41 @@ class CGBindingRoot(CGThing):
         # here, because we have to generate these in order from least derived
         # to most derived so that class inheritance works out.  We also have to
         # generate members before the dictionary that contains them.
         #
         # XXXbz this will fail if we have two webidl files A and B such that A
         # declares a dictionary which inherits from a dictionary in B and B
         # declares a dictionary (possibly a different one!) that inherits from a
         # dictionary in A.  The good news is that I expect this to never happen.
-        reSortedDictionaries = []
-        dictionaries = set(dictionaries)
-        while len(dictionaries) != 0:
-            # Find the dictionaries that don't depend on anything else anymore
-            # and move them over.
-            toMove = [d for d in dictionaries if
-                      len(CGDictionary.getDictionaryDependencies(d) &
-                          dictionaries) == 0]
-            if len(toMove) == 0:
-                raise TypeError("Loop in dictionary dependency graph")
-            dictionaries = dictionaries - set(toMove)
-            reSortedDictionaries.extend(toMove)
-
-        dictionaries = reSortedDictionaries
+        def sortDictionaries(dictionaries):
+            reSortedDictionaries = []
+            dictionaries = set(dictionaries)
+            while len(dictionaries) != 0:
+                # Find the dictionaries that don't depend on anything else
+                # anymore and move them over.
+                toMove = [d for d in dictionaries if
+                          len(CGDictionary.getDictionaryDependencies(d) &
+                              dictionaries) == 0]
+                if len(toMove) == 0:
+                    raise TypeError("Loop in dictionary dependency graph")
+                dictionaries = dictionaries - set(toMove)
+                reSortedDictionaries.extend(toMove)
+            return reSortedDictionaries
+
         cgthings.extend([CGDictionary(d, config.getDescriptorProvider(True))
-                         for d in dictionaries])
+                         for d in sortDictionaries(workerDictionaries)])
         cgthings.extend([CGDictionary(d, config.getDescriptorProvider(False))
-                         for d in dictionaries])
+                         for d in sortDictionaries(mainDictionaries)])
 
         # Do codegen for all the callbacks.  Only do non-worker codegen for now,
         # since we don't have a sane setup yet for invoking callbacks in workers
         # and managing their lifetimes.
         cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider(False))
-                        for c in callbacks)
+                        for c in mainCallbacks)
 
         # Do codegen for all the descriptors
         cgthings.extend([CGDescriptor(x) for x in descriptors])
 
         # Do codegen for all the callback interfaces
         cgthings.extend([CGCallbackInterface(x) for x in callbackDescriptors])
 
         # And make sure we have the right number of newlines at the end
@@ -7048,18 +6999,18 @@ class CGBindingRoot(CGThing):
         curr = CGList([forwardDeclares,
                        CGWrapper(CGGeneric("using namespace mozilla::dom;"),
                                  defineOnly=True),
                        traitsClasses, curr],
                       "\n")
 
         # Add header includes.
         curr = CGHeaders(descriptors,
-                         dictionaries,
-                         callbacks,
+                         mainDictionaries + workerDictionaries,
+                         mainCallbacks + workerCallbacks,
                          callbackDescriptors,
                          ['mozilla/dom/BindingDeclarations.h',
                           'mozilla/ErrorResult.h',
                           'mozilla/dom/DOMJSClass.h',
                           'mozilla/dom/DOMJSProxyHandler.h'],
                          ['mozilla/dom/BindingUtils.h',
                           'mozilla/dom/NonRefcountedDOMObject.h',
                           'mozilla/dom/Nullable.h',
@@ -7664,48 +7615,32 @@ class CGExampleRoot(CGThing):
 
 class CGCallback(CGClass):
     def __init__(self, idlObject, descriptorProvider, baseName, methods,
                  getters=[], setters=[]):
         self.baseName = baseName
         name = idlObject.identifier.name
         if descriptorProvider.workers:
             name += "Workers"
-        try:
-            # For our public methods that needThisHandling we want most of the
-            # same args and the same return type as what CallbackMember
-            # generates.  So we want to take advantage of all its
-            # CGNativeMember infrastructure, but that infrastructure can't deal
-            # with templates and most especially template arguments.  So just
-            # cheat and have CallbackMember compute all those things for us.
-            realMethods = []
-            for method in methods:
-                if not method.needThisHandling:
-                    realMethods.append(method)
-                else:
-                    realMethods.extend(self.getMethodImpls(method))
-            CGClass.__init__(self, name,
-                             bases=[ClassBase(baseName)],
-                             constructors=self.getConstructors(),
-                             methods=realMethods+getters+setters)
-            self.generatable = True
-        except NoSuchDescriptorError, err:
-            if not descriptorProvider.workers:
-                raise err
-            self.generatable = False
-
-    def define(self):
-        if not self.generatable:
-            return ""
-        return CGClass.define(self)
-
-    def declare(self):
-        if not self.generatable:
-            return ""
-        return CGClass.declare(self)
+        # For our public methods that needThisHandling we want most of the
+        # same args and the same return type as what CallbackMember
+        # generates.  So we want to take advantage of all its
+        # CGNativeMember infrastructure, but that infrastructure can't deal
+        # with templates and most especially template arguments.  So just
+        # cheat and have CallbackMember compute all those things for us.
+        realMethods = []
+        for method in methods:
+            if not method.needThisHandling:
+                realMethods.append(method)
+            else:
+                realMethods.extend(self.getMethodImpls(method))
+        CGClass.__init__(self, name,
+                         bases=[ClassBase(baseName)],
+                         constructors=self.getConstructors(),
+                         methods=realMethods+getters+setters)
 
     def getConstructors(self):
         return [ClassConstructor(
             [Argument("JSContext*", "cx"),
              Argument("JSObject*", "aOwner"),
              Argument("JSObject*", "aCallback"),
              Argument("bool*", "aInited")],
             bodyInHeader=True,
@@ -7763,19 +7698,16 @@ class CGCallback(CGClass):
                             body=bodyWithThis),
                 ClassMethod(method.name, method.returnType, argsWithoutThis,
                             bodyInHeader=True,
                             body=bodyWithoutThis),
                 method]
 
 class CGCallbackFunction(CGCallback):
     def __init__(self, callback, descriptorProvider):
-        if callback.isWorkerOnly() and not descriptorProvider.workers:
-            self.generatable = False
-            return
         CGCallback.__init__(self, callback, descriptorProvider,
                             "CallbackFunction",
                             methods=[CallCallback(callback, descriptorProvider)])
 
     def getConstructors(self):
         return CGCallback.getConstructors(self) + [
             ClassConstructor(
             [Argument("CallbackFunction*", "aOther")],
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -57,20 +57,43 @@ class Configuration:
         # an interface.
         for descriptor in self.descriptors:
             intefaceName = descriptor.interface.identifier.name
             otherDescriptors = [d for d in self.descriptors
                                 if d.interface.identifier.name == intefaceName]
             descriptor.uniqueImplementation = len(otherDescriptors) == 1
 
         self.enums = [e for e in parseData if e.isEnum()]
+
+        # Figure out what our main-thread and worker dictionaries and callbacks
+        # are.
+        mainTypes = set()
+        for descriptor in self.getDescriptors(workers=False, isExternal=False):
+            mainTypes |= set(getFlatTypes(getTypesFromDescriptor(descriptor)))
+        (mainCallbacks, mainDictionaries) = findCallbacksAndDictionaries(mainTypes)
+
+        workerTypes = set();
+        for descriptor in self.getDescriptors(workers=True, isExternal=False):
+            workerTypes |= set(getFlatTypes(getTypesFromDescriptor(descriptor)))
+        (workerCallbacks, workerDictionaries) = findCallbacksAndDictionaries(workerTypes)
+
         self.dictionaries = [d for d in parseData if d.isDictionary()]
         self.callbacks = [c for c in parseData if
                           c.isCallback() and not c.isInterface()]
 
+        def flagWorkerOrMainThread(items, main, worker):
+            for item in items:
+                if item in main:
+                    item.setUserData("mainThread", True)
+                if item in worker:
+                    item.setUserData("workers", True)
+        flagWorkerOrMainThread(self.dictionaries, mainDictionaries,
+                               workerDictionaries);
+        flagWorkerOrMainThread(self.callbacks, mainCallbacks, workerCallbacks)
+
         # Keep the descriptor list sorted for determinism.
         self.descriptors.sort(lambda x,y: cmp(x.name, y.name))
 
     def getInterface(self, ifname):
         return self.interfaces[ifname]
     def getDescriptors(self, **filters):
         """Gets the descriptors that match the given filters."""
         curr = self.descriptors
@@ -90,24 +113,36 @@ class Configuration:
             elif key == 'isExternal':
                 getter = lambda x: x.interface.isExternal()
             else:
                 getter = lambda x: getattr(x, key)
             curr = filter(lambda x: getter(x) == val, curr)
         return curr
     def getEnums(self, webIDLFile):
         return filter(lambda e: e.filename() == webIDLFile, self.enums)
-    def getDictionaries(self, webIDLFile=None):
-        if not webIDLFile:
-            return self.dictionaries
-        return filter(lambda d: d.filename() == webIDLFile, self.dictionaries)
-    def getCallbacks(self, webIDLFile=None):
-        if not webIDLFile:
-            return self.callbacks
-        return filter(lambda d: d.filename() == webIDLFile, self.callbacks)
+
+    @staticmethod
+    def _filterForFileAndWorkers(items, filters):
+        """Gets the items that match the given filters."""
+        for key, val in filters.iteritems():
+            if key == 'webIDLFile':
+                items = filter(lambda x: x.filename() == val, items)
+            elif key == 'workers':
+                if val:
+                    items = filter(lambda x: x.getUserData("workers", False), items)
+                else:
+                    items = filter(lambda x: x.getUserData("mainThread", False), items)
+            else:
+                assert(0) # Unknown key
+        return items
+    def getDictionaries(self, **filters):
+        return self._filterForFileAndWorkers(self.dictionaries, filters)
+    def getCallbacks(self, **filters):
+        return self._filterForFileAndWorkers(self.callbacks, filters)
+
     def getDescriptor(self, interfaceName, workers):
         """
         Gets the appropriate descriptor for the given interface name
         and the given workers boolean.
         """
         iface = self.getInterface(interfaceName)
         descriptors = self.getDescriptors(interface=iface)
 
@@ -402,8 +437,87 @@ class Descriptor(DescriptorProvider):
         return self.operations['IndexedGetter'] is not None
 
     def supportsNamedProperties(self):
         return self.operations['NamedGetter'] is not None
 
     def needsConstructHookHolder(self):
         assert self.interface.hasInterfaceObject()
         return not self.hasInstanceInterface and not self.interface.isCallback()
+
+# Some utility methods
+def getTypesFromDescriptor(descriptor):
+    """
+    Get all argument and return types for all members of the descriptor
+    """
+    members = [m for m in descriptor.interface.members]
+    if descriptor.interface.ctor():
+        members.append(descriptor.interface.ctor())
+    signatures = [s for m in members if m.isMethod() for s in m.signatures()]
+    types = []
+    for s in signatures:
+        assert len(s) == 2
+        (returnType, arguments) = s
+        types.append(returnType)
+        types.extend(a.type for a in arguments)
+
+    types.extend(a.type for a in members if a.isAttr())
+    return types
+
+def getFlatTypes(types):
+    retval = set()
+    for type in types:
+        type = type.unroll()
+        if type.isUnion():
+            retval |= set(type.flatMemberTypes)
+        else:
+            retval.add(type)
+    return retval
+
+def getTypesFromDictionary(dictionary):
+    """
+    Get all member types for this dictionary
+    """
+    types = []
+    curDict = dictionary
+    while curDict:
+        types.extend([m.type for m in curDict.members])
+        curDict = curDict.parent
+    return types
+
+def getTypesFromCallback(callback):
+    """
+    Get the types this callback depends on: its return type and the
+    types of its arguments.
+    """
+    sig = callback.signatures()[0]
+    types = [sig[0]] # Return type
+    types.extend(arg.type for arg in sig[1]) # Arguments
+    return types
+
+def findCallbacksAndDictionaries(inputTypes):
+    """
+    Ensure that all callbacks and dictionaries reachable from types end up in
+    the returned callbacks and dictionaries sets.
+
+    Note that we assume that our initial invocation already includes all types
+    reachable via descriptors in "types", so we only have to deal with things
+    that are themeselves reachable via callbacks and dictionaries.
+    """
+    def doFindCallbacksAndDictionaries(types, callbacks, dictionaries):
+        unhandledTypes = set()
+        for type in types:
+            if type.isCallback() and type not in callbacks:
+                unhandledTypes |= getFlatTypes(getTypesFromCallback(type))
+                callbacks.add(type)
+            elif type.isDictionary() and type.inner not in dictionaries:
+                d = type.inner
+                unhandledTypes |= getFlatTypes(getTypesFromDictionary(d))
+                while d:
+                    dictionaries.add(d)
+                    d = d.parent
+        if len(unhandledTypes) != 0:
+            doFindCallbacksAndDictionaries(unhandledTypes, callbacks, dictionaries)
+
+    retCallbacks = set()
+    retDictionaries = set()
+    doFindCallbacksAndDictionaries(inputTypes, retCallbacks, retDictionaries)
+    return (retCallbacks, retDictionaries)
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -2341,17 +2341,16 @@ class IDLCallbackType(IDLType, IDLObject
 
         IDLObjectWithScope.__init__(self, location, parentScope, identifier)
 
         for (returnType, arguments) in self.signatures():
             for argument in arguments:
                 argument.resolve(self)
 
         self._treatNonCallableAsNull = False
-        self._workerOnly = False
 
     def isCallback(self):
         return True
 
     def signatures(self):
         return [(self._returnType, self._arguments)]
 
     def tag(self):
@@ -2382,26 +2381,21 @@ class IDLCallbackType(IDLType, IDLObject
 
     def isDistinguishableFrom(self, other):
         if other.isUnion():
             # Just forward to the union; it'll deal
             return other.isDistinguishableFrom(self)
         return (other.isPrimitive() or other.isString() or other.isEnum() or
                 other.isNonCallbackInterface() or other.isDate())
 
-    def isWorkerOnly(self):
-        return self._workerOnly
-
     def addExtendedAttributes(self, attrs):
         unhandledAttrs = []
         for attr in attrs:
             if attr.identifier() == "TreatNonCallableAsNull":
                 self._treatNonCallableAsNull = True
-            elif attr.identifier() == "WorkerOnly":
-                self._workerOnly = True
             else:
                 unhandledAttrs.append(attr)
         if len(unhandledAttrs) != 0:
             IDLType.addExtendedAttributes(self, unhandledAttrs)
 
 class IDLMethodOverload:
     """
     A class that represents a single overload of a WebIDL method.  This is not
new file mode 100644
--- /dev/null
+++ b/dom/webidl/DummyBinding.webidl
@@ -0,0 +1,17 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+// Dummy bindings that we need to force generation of things that
+// aren't actually referenced anywhere in IDL yet but are used in C++.
+
+interface DummyInterface {
+  readonly attribute OnErrorEventHandlerNonNull onErrorEventHandler;
+  FilePropertyBag fileBag();
+};
+
+interface DummyInterfaceWorkers {
+  BlobPropertyBag blobBag();
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -35,16 +35,17 @@ webidl_files = \
   DocumentFragment.webidl \
   DocumentType.webidl \
   DOMImplementation.webidl \
   DOMParser.webidl \
   DOMSettableTokenList.webidl \
   DOMStringMap.webidl \
   DOMTokenList.webidl \
   DOMTransaction.webidl \
+  DummyBinding.webidl \
   DynamicsCompressorNode.webidl \
   Element.webidl \
   EventHandler.webidl \
   EventListener.webidl \
   EventSource.webidl \
   EventTarget.webidl \
   File.webidl \
   FileHandle.webidl \