Overhaul the config file format and configuration system in general. Config is now more fully separated from codegen, and centered around the notion of |descriptor|s. I apologize in advance to anyone who has to rebase on this... :-(
authorBobby Holley <bobbyholley@gmail.com>
Tue, 31 Jan 2012 18:58:21 +0100
changeset 85187 688faf7ebf54fcf7434b1946d973687e2d71c44c
parent 85186 db71857e3ce83e02224f4d55e27fe9ac94071ceb
child 85188 988157b08a4bb2ed92a78624aa15f8a344c845c8
push id82
push userbobbyholley@gmail.com
push dateTue, 31 Jan 2012 18:00:24 +0000
milestone12.0a1
Overhaul the config file format and configuration system in general. Config is now more fully separated from codegen, and centered around the notion of |descriptor|s. I apologize in advance to anyone who has to rebase on this... :-(
dom/bindings/BindingGen.py
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/bindings/Configuration.py
dom/bindings/GlobalGen.py
dom/bindings/Makefile.in
--- a/dom/bindings/BindingGen.py
+++ b/dom/bindings/BindingGen.py
@@ -1,16 +1,17 @@
 # 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/.
 
 import os
 import cPickle
 import WebIDL
-from Codegen import *
+from Configuration import *
+from Codegen import CGRoot
 
 def generate_binding_header(config, outputprefix):
     """
     |config| Is the configuration object.
     |outputprefix| is a prefix to use for the header guards and filename.
     """
 
     filename = outputprefix + ".h"
@@ -26,19 +27,22 @@ def generate_binding_header(config, outp
 
 """ % (outputprefix, outputprefix)
 
     epilogue = """
 
 #endif // mozilla_dom_bindings_%s_h__
 """ % (outputprefix)
 
+    # Generate the tree.
+    root = CGRoot(config)
+
     # Write recursively.
     f.write(prologue)
-    f.write(config.cgRoot.declare())
+    f.write(root.declare())
     f.write(epilogue)
     f.close()
 
 def generate_binding_cpp(config, outputprefix):
     """
     |config| Is the configuration object.
     |outputprefix| is a prefix to use for the header guards and filename.
     """
@@ -49,37 +53,37 @@ def generate_binding_cpp(config, outputp
 
     parentIncludeTemplate = """#include "%sBinding.h"
 """
 
     implIncludeTemplate = """#include "%s"
 """
 
     includes = ""
-    domClasses = config.dom_classes.values()
-    domClasses.sort()
-    for domClass in domClasses:
-        parentInterface = domClass.interface.parent
+    for descriptor in config.getConcreteDescriptors():
+        parentInterface = descriptor.interface.parent
         if parentInterface:
             parentFileName = os.path.split(parentInterface.filename())[1].replace(".webidl", "");
             includes += parentIncludeTemplate % parentFileName
-        for implementation in domClass.implementations:
-            includes += implIncludeTemplate % implementation.declarationFile
+        includes += implIncludeTemplate % descriptor.headerFile
 
     prologue = autogenerated_comment + """
 %s
 #include "%s.h"
 
 """ % (includes, outputprefix)
 
     epilogue = """"""
 
+    # Generate the tree.
+    root = CGRoot(config)
+
     # Write recursively.
     f.write(prologue)
-    f.write(config.cgRoot.define())
+    f.write(root.define())
     f.write(epilogue)
     f.close()
 
 def main():
 
     # Parse arguments.
     from optparse import OptionParser
     usagestring = "usage: %prog [header|cpp] configFile outputPrefix webIDLFile"
@@ -96,20 +100,17 @@ def main():
 
     # Load the parsing results
     f = open('ParserResults.pkl', 'rb')
     parserData = cPickle.load(f)
     f.close()
 
     # Filter the parsing results to this file.
     filteredData = dict()
-    for r in parserData:
-        if r.filename() == webIDLFile:
-            filteredData[r.identifier.name] = r
-
+    filteredData = filter(lambda x: x.filename() == webIDLFile, parserData)
     assert(len(filteredData) > 0)
 
     # Mix in the configuration data.
     config = Configuration(configFile, filteredData)
 
     # Generate the prototype classes.
     if buildTarget == "header":
         generate_binding_header(config, outputPrefix);
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1,70 +1,87 @@
-dom_classes = [
-    {
-        'name': 'XMLHttpRequest',
-        'implementations': [
-            {
-                'nativeClass' : 'nsXMLHttpRequest'
-            },
-            {
-                'nativeClass' : 'mozilla::dom::workers::xhr::XMLHttpRequestPrivate',
-                'workers': True
-            }
-        ]
-    },
-    {
-        'name': 'EventTarget',
-        'implementations': [
-            {
-                'nativeClass': 'nsDOMEventTargetHelper'
-            },
-            {
-	    # NO SUCH CLASS YET
-#                'nativeClass': 'mozilla::dom::workers::EventTargetPrivate',
-                'nativeClass': 'nsDOMEventTargetHelper',
-                'workers': True
-            }
-        ]
-    },
-    {
-        'name': 'Event',
-        'implementations': [
-            {
-                'nativeClass': 'nsDOMEvent'
-            },
-            {
-	    # NO SUCH CLASS YET
-#                'nativeClass': 'mozilla::dom::workers::Event',
-                'nativeClass': 'nsDOMEvent',
-                'workers': True
-            }
-        ]
-    },
-    {
-        'name': 'EventListener',
-        'implementations': [
-            {
-                'nativeClass': 'nsIDOMEventListener'
-            },
-            {
-	    # NO SUCH CLASS YET
-#                'nativeClass': 'mozilla::dom::workers::EventListener',
-                'nativeClass': 'nsIDOMEventListener',
-                'workers': True
-            }
-        ]
-    },
-    {
-        'name': 'XMLHttpRequestEventTarget',
-        'implementations': [
-            {
-                'nativeClass': 'nsXMLHttpRequest'
-            },
-            {
-	    # NO SUCH CLASS YET
-#                'nativeClass': 'XMLHttpRequestEventTargetPrivate',
-                'nativeClass': 'nsXMLHttpRequest',
-                'workers': True
-            }
-        ]
-    },
-]
+# DOM Bindings Configuration.
+#
+# The WebIDL interfaces are defined in dom/webidl. For each such interface, there
+# is a corresponding entry in the configuration table below. The configuration
+# table maps each interface name to a |descriptor| or list of |descriptor|s.
+#
+# A |descriptor| has a mandatory boolean member 'concrete' which indicates
+# whether the object unwraps to a known concrete type (arguments of the
+# |implements| variety, for example, are non-concrete).
+#
+# Valid fields for all descriptors:
+#   * concrete - Indicates whether this is a concrete descriptor (required)
+#   * workers - Indicates whether the descriptor is intended to be used for
+#               worker threads (defaults to false)
+#   * headerFile - The file in which the nativeClass or nativeInterface is
+#                  declared (defaults to an educated guess).
+#
+# Valid fields for concrete descriptors:
+#   * nativeClass - The concrete class that instances of this interface will
+#                   unwrap to (required)
+#
+# Valid fields for non-concrete descriptors:
+#   * nativeInterface - The native type that instances of this interface will
+#                       unwrap to.
+
+DOMInterfaces = {
+
+'XMLHttpRequest': [
+{
+    'concrete': True,
+    'nativeClass': 'mozilla::dom::workers::xhr::XMLHttpRequestPrivate',
+},
+{
+    'concrete': True,
+    'nativeClass' : 'mozilla::dom::workers::xhr::XMLHttpRequestPrivate',
+    'workers': True
+}],
+
+'EventTarget': [
+{
+    'concrete': True,
+    'nativeClass': 'nsDOMEventTargetHelper'
+},
+{
+    'concrete': True,
+    # XXX Doesn't exist yet: 'nativeClass': 'mozilla::dom::workers::EventTargetPrivate',
+    'nativeClass': 'nsDOMEventTargetHelper',
+    'workers': True
+}],
+
+'Event': [
+{
+    'concrete': True,
+    'nativeClass': 'nsDOMEvent'
+},
+{
+    'concrete': True,
+    # XXX Doesn't exist yet: 'nativeClass': 'mozilla::dom::workers::Event',
+    'nativeClass': 'nsDOMEvent',
+    'workers': True
+}],
+
+'EventListener': [
+{
+    'concrete': True,
+    'nativeClass': 'nsIDOMEventListener'
+},
+{
+    'concrete': True,
+    # XXX Doesn't exist yet: 'nativeClass': 'mozilla::dom::workers::EventListener',
+    'nativeClass': 'nsIDOMEventListener',
+    'workers': True
+}],
+
+'XMLHttpRequestEventTarget': [
+{
+    'concrete': True,
+    'nativeClass': 'nsXMLHttpRequest'
+},
+{
+    'concrete': True,
+    # XXX Doesn't exist yet: 'nativeClass': 'XMLHttpRequestEventTargetPrivate',
+   'nativeClass': 'nsXMLHttpRequest',
+   'workers': True
+}]
+
+}
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1,58 +1,49 @@
 # 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/.
 
 # Common codegen classes.
 
 import re
 
-autogenerated_comment = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n"
-
 class CGThing():
     """
     Abstract base case for things that spit out code.
     """
     def __init__(self):
         pass # Nothing for now
     def declare(self):
         """Produce code for a header file."""
         assert(False)  # Override me!
     def define(self):
         """Produce code for a cpp file."""
         assert(False) # Override me!
 
-class CGImplThing(CGThing):
-    """
-    CGThing with a reference to a DOMClassImplementation.
-    """
-    def __init__(self, implementation):
+class CGDOMJSClass(CGThing):
+    def __init__(self, descriptor):
         CGThing.__init__(self)
-        self.implementation = implementation
-
-class CGDOMJSClass(CGImplThing):
-    def __init__(self, implementation):
-        CGImplThing.__init__(self, implementation)
+        self.descriptor = descriptor
     def declare(self):
         return "  extern DOMJSClass Class;\n"
     def define(self):
         prototypeChainString = ', '.join(['id::' + proto \
-                                          for proto in self.implementation.prototypeChain])
+                                          for proto in self.descriptor.prototypeChain])
         return """DOMJSClass Class = {
   { "%s",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1),
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
   },
   { %s }, -1, %s
 };
-""" % (self.implementation.domClass.name, prototypeChainString,
-       str(self.implementation.nativeIsISupports).lower())
+""" % (self.descriptor.interface.identifier.name, prototypeChainString,
+       str(self.descriptor.nativeIsISupports).lower())
 
 class CGList(CGThing):
     def __init__(self, children):
         CGThing.__init__(self)
         self.children = children
     def append(self, child):
         self.children.append(child)
     def prepend(self, child):
@@ -96,19 +87,20 @@ class CGNamespace(CGWrapper):
 
 class Argument():
     def __init__(self, argType, name):
         self.argType = argType
         self.name = name
     def __str__(self):
         return self.argType + ' ' + self.name
 
-class CGAbstractMethod(CGImplThing):
-    def __init__(self, implementation, name, returnType, args, inline=False, static=False):
-        CGImplThing.__init__(self, implementation)
+class CGAbstractMethod(CGThing):
+    def __init__(self, descriptor, name, returnType, args, inline=False, static=False):
+        CGThing.__init__(self)
+        self.descriptor = descriptor
         self.name = name
         self.returnType = returnType
         self.args = args
         self.inline = inline
         self.static = static
     def _argstring(self):
         return ', '.join([str(a) for a in self.args])
     def _decorators(self):
@@ -137,28 +129,28 @@ class CGAbstractMethod(CGImplThing):
     def definition_body(self):
         assert(False) # Override me!
 
 class CGAbstractStaticMethod(CGAbstractMethod):
     """
     Abstract base class for codegen of implementation-only (no
     declaration) static methods.
     """
-    def __init__(self, implementation, name, returnType, args):
-        CGAbstractMethod.__init__(self, implementation, name, returnType, args,
+    def __init__(self, descriptor, name, returnType, args):
+        CGAbstractMethod.__init__(self, descriptor, name, returnType, args,
                                   inline=False, static=True)
     def declare(self):
         # We only have implementation
         return ""
 
 class MethodDefiner:
-    def __init__(self, implementation):
-        self.implementation = implementation
+    def __init__(self, descriptor):
+        self.descriptor = descriptor
     def __str__(self):
-        methods = [m for m in self.implementation.domClass.interface.members if m.isMethod()]
+        methods = [m for m in self.descriptor.interface.members if m.isMethod()]
         if len(methods) == 0:
             return ""
 
         # The length of a method is the maximum of the lengths of the
         # argument lists of all its overloads.
         def methodLength(method):
             signatures = method.signatures()
             return max([len(s[1]) for s in signatures])
@@ -172,20 +164,20 @@ class MethodDefiner:
         return ("  static JSFunctionSpec methods[] = {\n" +
                 ',\n'.join(funcdecls) + "\n" +
                 "  };\n" +
                 "  if (!JS_DefineFunctions(aCx, ourProto, methods)) {\n" +
                 "    return NULL;\n" +
                 "  }\n")
 
 class AttrDefiner:
-    def __init__(self, implementation):
-        self.implementation = implementation
+    def __init__(self, descriptor):
+        self.descriptor = descriptor
     def __str__(self):
-        attrs = [m for m in self.implementation.domClass.interface.members if m.isAttr()]
+        attrs = [m for m in self.descriptor.interface.members if m.isAttr()]
         if len(attrs) == 0:
             return ""
 
         def flags(attr):
             flags = "JSPROP_NATIVE_ACCESSORS | JSPROP_SHARED | JSPROP_ENUMERATE"
             if attr.readonly:
                 return "JSPROP_READONLY | " + flags
             return flags
@@ -206,29 +198,29 @@ class AttrDefiner:
         return ("  static JSPropertySpec props[] = {\n" +
                 ',\n'.join(attrdecls) + "\n" +
                 "  };\n" +
                 "  if (!JS_DefineProperties(aCx, ourProto, props)) {\n" +
                 "    return NULL;\n" +
                 "  }\n")
 
 class CGCreateProtoObjectMethod(CGAbstractMethod):
-    def __init__(self, implementation):
+    def __init__(self, descriptor):
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
-        CGAbstractMethod.__init__(self, implementation, 'CreateProtoObject', 'JSObject*', args)
+        CGAbstractMethod.__init__(self, descriptor, 'CreateProtoObject', 'JSObject*', args)
     def definition_body(self):
-        protoChain = self.implementation.prototypeChain
+        protoChain = self.descriptor.prototypeChain
         if len(protoChain) == 1:
             getParentProto = "GetCanonicalObjectProto(aCx, aGlobal)"
         else:
-            parentProtoName = self.implementation.prototypeChain[-2]
+            parentProtoName = self.descriptor.prototypeChain[-2]
             getParentProto = "%s::GetProtoObject(aCx, aGlobal)" % (parentProtoName)
 
-        defineMethods = MethodDefiner(self.implementation)
-        defineAttributes = AttrDefiner(self.implementation);
+        defineMethods = MethodDefiner(self.descriptor)
+        defineAttributes = AttrDefiner(self.descriptor);
 
         return """
   JSObject* parentProto = %s;
   if (!parentProto) {
     return NULL;
   }
 
   JSObject* ourProto = JS_NewObject(aCx, NULL, parentProto, aGlobal);
@@ -237,19 +229,19 @@ class CGCreateProtoObjectMethod(CGAbstra
   }
 
 %s
 %s
 
   return ourProto;""" % (getParentProto, defineMethods, defineAttributes)
 
 class CGGetProtoObjectMethod(CGAbstractMethod):
-    def __init__(self, implementation):
+    def __init__(self, descriptor):
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
-        CGAbstractMethod.__init__(self, implementation, 'GetProtoObject',
+        CGAbstractMethod.__init__(self, descriptor, 'GetProtoObject',
                                   'JSObject*', args, inline=True)
     def definition_body(self):
         return """
   /* Get the prototype object for this class.  This will create the prototype
      as needed. */
 
   /* Make sure our global is sane.  Hopefully we can remove this sometime */
   if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) {
@@ -258,33 +250,33 @@ class CGGetProtoObjectMethod(CGAbstractM
   /* Check to see whether the prototype is already installed */
   JSObject **protoArray = GetProtoArray(aGlobal);
   JSObject *ourProto = protoArray[id::%s];
   if (!ourProto) {
     ourProto = protoArray[id::%s] = CreateProtoObject(aCx, aGlobal);
   }
 
   /* ourProto might _still_ be null, but that's OK */
-  return ourProto;""" % (self.implementation.name, self.implementation.name)
+  return ourProto;""" % (self.descriptor.name, self.descriptor.name)
 
 class CGAbstractBindingMethod(CGAbstractStaticMethod):
-    def __init__(self, implementation, name, returnType, args):
-        CGAbstractStaticMethod.__init__(self, implementation, name,
+    def __init__(self, descriptor, name, returnType, args):
+        CGAbstractStaticMethod.__init__(self, descriptor, name,
                                         returnType, args)
     def definition_body(self):
         return (self.unwrap_this() + self.unwrap_args() +
                 self.generate_call() + self.wrap_return_value())
 
     def unwrap_this(self):
         return """
   %s *self;
   if (!UnwrapThis(cx, obj, %s, %s, &self))
     return false;
-""" % (self.implementation.nativeClass, "id::" + self.implementation.name,
-       "depth::" + self.implementation.name)
+""" % (self.descriptor.nativeClass, "id::" + self.descriptor.name,
+       "depth::" + self.descriptor.name)
 
     def unwrap_args(self):
         # NEED TO ADD SOME IMPL HERE
         return """// XXXbz ARGUMENT UNWRAPPING CODE HERE.  Maybe this should be in subclasses of CGAbstractBindingMethod!
 """
 
     def generate_call(self):
         # NEED TO ADD SOME IMPL HERE
@@ -293,119 +285,73 @@ class CGAbstractBindingMethod(CGAbstract
 
     def wrap_return_value(self):
         # NEED TO ADD SOME IMPL HERE
         return """// XXXbz RETURN VALUE WRAPPING, IF ANY, HERE
   return false;"""
 
 
 class CGNativeMethod(CGAbstractBindingMethod):
-    def __init__(self, implementation, method):
+    def __init__(self, descriptor, method):
         self.method = method
         args = [Argument('JSContext*', 'cx'), Argument('uintN', 'argc'),
                 Argument('JS::Value*', 'vp')]
-        CGAbstractBindingMethod.__init__(self, implementation,
+        CGAbstractBindingMethod.__init__(self, descriptor,
                                          method.identifier.name,
                                          'JSBool', args)
     def unwrap_this(self):
          return """
   JSObject *obj = JS_THIS_OBJECT(cx, vp);
   if (!obj)
     return false;""" + CGAbstractBindingMethod.unwrap_this(self)
 
 class CGNativeGetter(CGAbstractBindingMethod):
-    def __init__(self, implementation, attr):
+    def __init__(self, descriptor, attr):
         self.attr = attr
         args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'obj'),
                 Argument('jsid', 'id'), Argument('JS::Value*', 'vp')]
-        CGAbstractBindingMethod.__init__(self, implementation,
+        CGAbstractBindingMethod.__init__(self, descriptor,
                                          'get_'+attr.identifier.name,
                                          'JSBool', args)
 
 class CGNativeSetter(CGAbstractBindingMethod):
-    def __init__(self, implementation, attr):
+    def __init__(self, descriptor, attr):
         self.attr = attr
         args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'obj'),
                 Argument('jsid', 'id'), Argument('JSBool', 'strict'),
                 Argument('JS::Value*', 'vp')]
-        CGAbstractBindingMethod.__init__(self, implementation,
+        CGAbstractBindingMethod.__init__(self, descriptor,
                                          'set_'+attr.identifier.name,
                                          'JSBool', args)
 
-class DOMClassImplementation(CGThing):
-    def __init__(self, domClass, implConf):
+class CGDescriptor(CGThing):
+    def __init__(self, descriptor):
         CGThing.__init__(self)
-        self.domClass = domClass
-        self.nativeClass = implConf['nativeClass']
-        if "declarationFile" in implConf:
-            self.declarationFile = implConf["declarationFile"]
-        else:
-            # Just use the native class, minus the namespaces
-            self.declarationFile = self.nativeClass.split("::")[-1] + ".h"
-        self.workers = implConf.get('workers', False)
-        def make_name(name):
-            return name + "_workers" if self.workers else name
-        self.name = make_name(domClass.name)
-        self.nativeIsISupports = not self.workers
-
-        # Build the prototype chain.
-        self.prototypeChain = []
-        parent = domClass.interface
-        while parent:
-            self.prototypeChain.insert(0, make_name(parent.identifier.name))
-            parent = parent.parent
 
         # XXXbholley - Not everything should actually have a jsclass.
-        cgThings = [CGNativeMethod(self, m) for m in
-                    domClass.interface.members if m.isMethod()]
-        cgThings.extend([CGNativeGetter(self, a) for a in
-                         domClass.interface.members if a.isAttr()])
-        cgThings.extend([CGNativeSetter(self, a) for a in
-                         domClass.interface.members if
+        cgThings = [CGNativeMethod(descriptor, m) for m in
+                    descriptor.interface.members if m.isMethod()]
+        cgThings.extend([CGNativeGetter(descriptor, a) for a in
+                         descriptor.interface.members if a.isAttr()])
+        cgThings.extend([CGNativeSetter(descriptor, a) for a in
+                         descriptor.interface.members if
                          a.isAttr() and not a.readonly])
-        cgThings.extend([CGDOMJSClass(self),
-                         CGCreateProtoObjectMethod(self),
-                         CGGetProtoObjectMethod(self)])
+        cgThings.extend([CGDOMJSClass(descriptor),
+                         CGCreateProtoObjectMethod(descriptor),
+                         CGGetProtoObjectMethod(descriptor)])
 
         allCGThings = CGList(cgThings)
         allCGThings = CGWrapper(allCGThings, post="\n")
-        self.cgRoot = CGWrapper(CGNamespace(self.name, allCGThings), post="\n")
+        self.cgRoot = CGWrapper(CGNamespace(descriptor.name, allCGThings), post="\n")
     def declare(self):
         return self.cgRoot.declare()
     def define(self):
         return self.cgRoot.define()
 
-
-class DOMClass(CGThing):
-    def __init__(self, classConf, interface):
-        CGThing.__init__(self)
-        self.name = classConf['name']
-        self.interface = interface
-        self.implementations = [DOMClassImplementation(self, implConf)
-                                for implConf in classConf['implementations']]
-        self.cgRoot = CGList(self.implementations)
+class CGRoot(CGThing):
+    def __init__(self, config):
+        descriptors = CGList([CGDescriptor(x) for x in config.getConcreteDescriptors()])
+        self.root = CGNamespace.build(['mozilla', 'dom', 'bindings', 'prototypes'],
+                                      CGWrapper(descriptors, pre="\n"))
     def declare(self):
-        return self.cgRoot.declare()
+        return self.root.declare()
     def define(self):
-        return self.cgRoot.define()
-
-class Configuration:
-    def __init__(self, filename, parseData):
-        self.configFile = {}
-        execfile(filename, self.configFile)
-
-        # We need dom_classes.
-        if 'dom_classes' not in self.configFile:
-            raise UserError(filename + ": `dom_classes` was not defined.")
-
-        # Build data structures for classes where we have parse data. We've
-        # already filtered the parse data so that this does what we want.
-        self.dom_classes = dict()
-        for classConf in self.configFile['dom_classes']:
-            name = classConf['name']
-            if name not in parseData:
-                continue
-            self.dom_classes[name] = DOMClass(classConf, parseData[name])
-
-        classCollection = [cls for cls in self.dom_classes.values()]
-        classCollection.sort();
-        self.cgRoot = CGNamespace.build(['mozilla', 'dom', 'bindings', 'prototypes'],
-                                        CGWrapper(CGList(classCollection), pre="\n"))
+        return self.root.define()
new file mode 100644
--- /dev/null
+++ b/dom/bindings/Configuration.py
@@ -0,0 +1,76 @@
+# 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/.
+
+autogenerated_comment = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n"
+
+class Configuration:
+    """
+    Represents global configuration state based on IDL parse data and
+    the configuration file.
+    """
+    def __init__(self, filename, parseData):
+
+        # Read the configuration file.
+        glbl = {}
+        execfile(filename, glbl)
+        config = glbl['DOMInterfaces']
+
+        # Build descriptors for all the interfaces we have in the parse data.
+        # This allows callers to specify a subset of interfaces by filtering
+        # |parseData|.
+        self.descriptors = []
+        self.interfaces = {}
+        for iface in parseData:
+            if not iface.isInterface(): continue
+            self.interfaces[iface.identifier.name] = iface
+            if iface.identifier.name not in config: continue
+            entry = config[iface.identifier.name]
+            if not isinstance(entry, list):
+                assert isinstance(entry, dict)
+                entry = [entry]
+            self.descriptors.extend([Descriptor(iface, x) for x in entry])
+
+        # 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 getAllDescriptors(self):
+        return self.descriptors
+    def getConcreteDescriptors(self):
+        return filter(lambda x: x.concrete, self.descriptors)
+    def getDesciptorsForInterface(self, iface):
+        return filter(lambda x: x.interface is iface, self.descriptors)
+
+class Descriptor:
+    """
+    Represents a single descriptor for an interface. See Bindings.conf.
+    """
+    def __init__(self, interface, desc):
+        self.interface = interface
+
+        # Read the desc, and fill in the relevant defaults.
+        self.concrete = desc['concrete']
+        self.workers = desc.get('workers', False)
+        self.nativeIsISupports = not self.workers
+        if self.concrete:
+            self.nativeClass = desc['nativeClass']
+        else:
+            self.nativeInterface = desc.get('nativeInterface', 'XXXFillMeInbz!')
+
+        headerDefault = self.nativeClass if self.concrete else self.nativeInterface
+        headerDefault = headerDefault.split("::")[-1] + ".h"
+        self.headerFile = desc.get('headerFile', headerDefault)
+
+        def make_name(name):
+            return name + "_workers" if self.workers else name
+        self.name = make_name(interface.identifier.name)
+
+        # Build the prototype chain.
+        self.prototypeChain = []
+        parent = interface
+        while parent:
+            self.prototypeChain.insert(0, make_name(parent.identifier.name))
+            parent = parent.parent
+
--- a/dom/bindings/GlobalGen.py
+++ b/dom/bindings/GlobalGen.py
@@ -4,17 +4,17 @@
 
 # We do one global pass over all the WebIDL to generate our prototype enum
 # and generate information for subsequent phases.
 
 import os
 import cStringIO
 import WebIDL
 import cPickle
-from Codegen import Configuration, DOMClass, DOMClassImplementation, autogenerated_comment
+from Configuration import *
 
 def generate_prototype_list(config, filename):
 
     # Read a copy of the old file, so that we don't touch it if it hasn't changed.
     oldFileContents = ""
     try:
         oldFile = open(filename, 'r')
         oldFileContents = ''.join(oldFile.readlines())
@@ -60,43 +60,38 @@ typedef depth::Depth Depth;
 } // namespace prototypes
 } // namespace bindings
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_bindings_PrototypeList_h
 """
 
-    protoList = []
-
-    domClasses = config.dom_classes.values()
-    # Sort the class list so that it doesn't change from run to run
-    domClasses.sort()
-    for domClass in domClasses:
-        for implementation in domClass.implementations:
-            protoList.append(implementation.name)
+    # Make a list of the protos.
+    protoList = [x.name for x in config.getConcreteDescriptors()]
 
     # Append the enum count.
     protoList.append('Count')
 
     # Add appropriate indentation before the prototype strings.
     protoList = ["  " + p for p in protoList]
 
     # Start the enum at 0
     protoList[0] = protoList[0] + " = 0"
 
+    # XXXbholley - This calculation should go in IDLInterface.inheritanceDepth()
+    # or something.
     indexList = []
-    for domClass in domClasses:
-        for implementation in domClass.implementations:
-            index = 0
-            interface = domClass.interface
-            while interface.parent:
-                interface = interface.parent
-                index = index + 1
-            indexList.append(implementation.name + " = " + str(index));
+    for descriptor in config.getConcreteDescriptors():
+        index = 0
+        interface = descriptor.interface
+        while interface.parent:
+            interface = interface.parent
+            index = index + 1
+        indexList.append(descriptor.name + " = " + str(index));
     indexList.append('IndexCount');
     indexList = ["  " + i for i in indexList]
 
     newFileContents = (prologue + ',\n'.join(protoList) + middle +
                        ',\n'.join(indexList) + epilogue)
 
     if newFileContents == oldFileContents:
         print "Prototype list hasn't changed - not touching %s" % (filename)
@@ -134,18 +129,16 @@ def main():
         parser.parse(''.join(lines), fullPath)
     parserResults = parser.finish()
 
     # Write the parser results out to a pickle.
     resultsFile = open('ParserResults.pkl', 'wb')
     cPickle.dump(parserResults, resultsFile, -1)
     resultsFile.close()
 
-    configData = dict()
-    for r in parserResults:
-        configData[r.identifier.name] = r
-    config = Configuration(configFile, configData)
+    # Load the configuration.
+    config = Configuration(configFile, parserResults)
 
     # Generate the prototype list header.
     generate_prototype_list(config, "PrototypeList.h")
 
 if __name__ == '__main__':
     main()
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -41,16 +41,17 @@ LOCAL_INCLUDES += \
   -I$(topsrcdir)/dom/base \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 bindinggen_dependencies := \
   BindingGen.py \
   Bindings.conf \
+  Configuration.py \
   Codegen.py \
   ParserResults.pkl \
   $(NULL)
 
 $(binding_header_files): %Binding.h: $(bindinggen_dependencies) \
                                      $(webidl_base)/%.webidl \
                                      $(NULL)
 	$(PYTHON) $(topsrcdir)/config/pythonpath.py \
@@ -66,16 +67,17 @@ bindinggen_dependencies := \
     $(srcdir)/BindingGen.py cpp $(srcdir)/Bindings.conf $*Binding \
     $(webidl_base)/$*.webidl
 
 PrototypeList.h: ParserResults.pkl
 
 globalgen_dependencies := \
   GlobalGen.py \
   Bindings.conf \
+  Configuration.py \
   Codegen.py \
   $(NULL)
 
 ParserResults.pkl: $(globalgen_dependencies) \
                    $(addprefix $(webidl_base)/, $(webidl_files))
 	$(PYTHON_PATH) -I$(topsrcdir)/other-licenses/ply -I$(srcdir)/parser \
     $(srcdir)/GlobalGen.py $(srcdir)/Bindings.conf $(webidl_base) \
     $(webidl_files)