Add traits classes, clean up codegen a little.
authorBen Turner <bent.mozilla@gmail.com>
Mon, 20 Feb 2012 00:46:40 -0800
changeset 87318 5dff147e65338c9343d379e86aeff70495c844c8
parent 87317 65f21dd411d1c21ba9a0a01f03153e53b0a76858
child 87319 8d6b7cd7baeece56b10a2085ae26e282579fba22
push id130
push userbturner@mozilla.com
push dateMon, 20 Feb 2012 08:46:47 +0000
milestone13.0a1
Add traits classes, clean up codegen a little.
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/bindings/Configuration.py
dom/bindings/DOMJSClass.h
dom/bindings/Utils.h
dom/bindings/parser/WebIDL.py
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -31,79 +31,44 @@
 #                       unwrap to.
 
 DOMInterfaces = {
 
 'XMLHttpRequest': [
 {
     'concrete': True,
     'nativeClass': 'nsXMLHttpRequest',
-},
-{
-    'concrete': True,
-    'nativeClass' : 'mozilla::dom::workers::xhr::XMLHttpRequestPrivate',
-    'workers': True
 }],
 
 'XMLHttpRequestUpload': [
 {
      'concrete': True,
      'nativeClass': 'nsXMLHttpRequestUpload',
      'headerFile': 'nsXMLHttpRequest.h'
-},
-{
-     'concrete': True,
-   # XXX Doesn't exist yet: 'nativeClass': 'mozilla::dom::workers::xhr:XMLHttpRequestUpload',
-     'nativeClass': 'nsXMLHttpRequestUpload',
-     'headerFile': 'nsXMLHttpRequest.h',
-     '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': [
 {
     # XXXbz should this really be true?
     '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
+    'nativeClass': 'nsXHREventTarget',
+    'headerFile': 'nsXMLHttpRequest.h'
 }]
 
 }
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4,18 +4,20 @@
 
 # Common codegen classes.
 
 import os
 import string
 
 from WebIDL import *
 
-FINALIZE_HOOK_NAME = 'Finalize'
-TRACE_HOOK_NAME = 'Trace'
+AUTOGENERATED_WARNING_COMMENT = \
+    "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
+FINALIZE_HOOK_NAME = '_Finalize'
+TRACE_HOOK_NAME = '_Trace'
 
 def replaceFileIfChanged(filename, newContents):
     """
     Read a copy of the old file, so that we don't touch it if it hasn't changed.
     Returns True if the file was updated, false otherwise.
     """
     oldFileContents = ""
     try:
@@ -188,43 +190,49 @@ class CGIndenter(CGThing):
             return re.sub(self.pattern, self.indent, defn)
         else:
             return ""
 
 class CGWrapper(CGThing):
     """
     Generic CGThing that wraps other CGThings with pre and post text.
     """
-    def __init__(self, child, pre="", post="",
-                 declarePre=None, declarePost=None,
-                 definePre=None, definePost=None):
+    def __init__(self, child, pre="", post="", declarePre=None,
+                 declarePost=None, definePre=None, definePost=None,
+                 declareOnly=False):
         CGThing.__init__(self)
         self.child = child
         self.declarePre = declarePre or pre
         self.declarePost = declarePost or post
         self.definePre = definePre or pre
         self.definePost = definePost or post
+        self.declareOnly = declareOnly
     def declare(self):
         return self.declarePre + self.child.declare() + self.declarePost
     def define(self):
+        if self.declareOnly:
+            return ''
         return self.definePre + self.child.define() + self.definePost
 
 class CGNamespace(CGWrapper):
-    def __init__(self, namespace, child):
+    def __init__(self, namespace, child, declareOnly=False):
         pre = "namespace %s {\n" % namespace
         post="} // namespace %s\n" % namespace
-        CGWrapper.__init__(self, child, pre=pre, post=post)
+        CGWrapper.__init__(self, child, pre=pre, post=post,
+                           declareOnly=declareOnly)
     @staticmethod
-    def build(namespaces, child):
+    def build(namespaces, child, declareOnly=False):
         """
         Static helper method to build multiple wrapped namespaces.
         """
         if not namespaces:
             return child
-        return CGNamespace(namespaces[0], CGNamespace.build(namespaces[1:], child))
+        return CGNamespace(namespaces[0], CGNamespace.build(namespaces[1:],
+                                                            child),
+                           declareOnly=declareOnly)
 
 class CGIncludeGuard(CGWrapper):
     """
     Generates include guards for a header.
     """
     def __init__(self, prefix, child):
         """|prefix| is the filename without the extension."""
         define = 'mozilla_dom_bindings_%s_h__' % prefix
@@ -237,52 +245,59 @@ class CGHeaders(CGWrapper):
     Generates the appropriate include statements.
     """
     def __init__(self, descriptors, declareIncludes, child):
         """
         Builds a set of include to cover |descriptors|.
 
         Also includes the files in |declareIncludes| in the header file.
         """
+        def getInterfaceFilename(interface):
+            basename = os.path.basename(interface.filename())
+            return 'mozilla/dom/bindings/' + \
+                   basename.replace('.webidl', 'Binding.h')
+
         # Determine the filenames for which we need headers.
         interfaceDeps = [d.interface for d in descriptors]
         interfaceDeps.extend([d.parent for d in interfaceDeps if d.parent])
-        filenames = set([os.path.basename(d.filename()) for d in interfaceDeps])
-        bindingIncludes = ['mozilla/dom/bindings/' + f.replace('.webidl', 'Binding.h')
-                           for f in filenames]
+        bindingIncludes = [getInterfaceFilename(d) for d in interfaceDeps]
 
         # Grab all the implementation declaration files we need.
         implementationIncludes = [f for f in set([d.headerFile for d in descriptors])]
 
         # Now find all the things we'll need as arguments because we
         # need to wrap or unwrap them.
+        bindingHeaders = []
         typeHeaders = []
         for d in descriptors:
             members = [m for m in d.interface.members]
             signatures = [s for m in members if m.isMethod() for s in m.signatures()]
             types = [s[0] for s in signatures]
             types.extend([t.type for s in signatures for t in s[1]])
 
             attrs = [a for a in members if a.isAttr()]
             types.extend([a.type for a in attrs])
 
             typeDescriptors = [d.getDescriptor(t.inner.identifier.name)
                                for t in types
                                if t.isInterface() and not t.isArrayBuffer()]
-            typeHeaders.extend(desc.headerFile for desc in typeDescriptors)
-            
+            for typeDesc in typeDescriptors:
+                typeHeaders.append(typeDesc.headerFile)
+                bindingHeaders.append(getInterfaceFilename(typeDesc.interface))
+
         implementationIncludes.extend([f for f in set(typeHeaders)])
 
         # Let the machinery do its thing.
         def _includeString(includes):
             return ''.join(['#include "%s"\n' % i for i in includes]) + '\n'
         CGWrapper.__init__(self, child,
                            declarePre=_includeString(declareIncludes),
-                           definePre=_includeString(implementationIncludes)
-                                     + _includeString(bindingIncludes))
+                           definePre=_includeString(bindingIncludes) +
+                                     _includeString(bindingHeaders) +
+                                     _includeString(implementationIncludes))
 
 class Argument():
     def __init__(self, argType, name):
         self.argType = argType
         self.name = name
     def __str__(self):
         return self.argType + ' ' + self.name
 
@@ -528,26 +543,24 @@ class ConcreteObjectUnwrapper():
     based on the passed-in descriptor and storing it in a variable
     called by the name in the "target" argument.
 
     codeOnFailure is the code to run if unwrapping fails.
     """
     def __init__(self, descriptor, source, target, codeOnFailure):
         self.substitution = { "type" : descriptor.nativeClass,
                               "protoID" : "id::" + descriptor.name,
-                              "protoIDIndex" : "depth::" + descriptor.name,
                               "source" : source,
                               "target" : target,
                               "codeOnFailure" : codeOnFailure }
 
     def __str__(self):
         return string.Template("""
   {
-    nsresult rv = UnwrapObject(cx, ${source}, ${protoID},
-                               ${protoIDIndex}, &${target});
+    nsresult rv = UnwrapObject<${protoID}>(cx, ${source}, &${target});
     if (NS_FAILED(rv)) {
       ${codeOnFailure}
     }
   }""").substitute(self.substitution)
 
 class FailureFatalConcreteObjectUnwrapper(ConcreteObjectUnwrapper):
     """
     As ConcreteObjectUnwrapper, but defaulting to throwing if unwrapping fails
@@ -631,16 +644,19 @@ def getArgumentConversionTemplate(type, 
         return (
             "  JSObject *${name};\n"
             "  if (${argVal}.isObject() && JS_ObjectIsCallable(cx, &${argVal}.toObject())) {\n"
             "    ${name} = &${argVal}.toObject();\n"
             "  } else {\n"
             "    ${name} = NULL;\n"
             "  }\n")
 
+    if type.isAny():
+        return "  JS::Value ${name} = ${argVal};\n"
+
     if not type.isPrimitive():
         raise TypeError("Need conversion for argument type '%s'" % type)
 
     tag = type.tag()
     replacements = dict()
     if type.nullable():
         replacements["declareArg"] = (
             "  Nullable<${typeName}> ${name};\n"
@@ -784,31 +800,34 @@ def getWrapTemplateForTypeImpl(type, res
         wrappingCode = ("""
   if (!%s) {
     ${jsvalRef} = JSVAL_NULL;
     return true;
   }""" % result) if type.nullable() else ""
         if descriptor.concrete:
             # All our concrete objects inherit from wrapper cache for now
             wrappingCode += """
-  JSObject* result_obj = %s->GetWrapper();
-  if (result_obj &&
-      js::GetObjectCompartment(result_obj) == js::GetObjectCompartment(obj)) {
-    ${jsvalRef} = JS::ObjectValue(*result_obj);
+  if (WrapNewBindingObject(cx, obj, %s, ${jsvalPtr})) {
     return true;
   }
-  // XXXbz figure out the actual security wrapper story here
-  bool triedToWrap;
-  result_obj = %s->WrapObject(cx, obj, &triedToWrap);
-  if (!result_obj) {
+  if (JS_IsExceptionPending(cx)) {
     return false;
+  }""" % result
+            if not descriptor.workers:
+                # Try old-style wrapping for non-worker bindings
+                wrappingCode += """
+  if (WrapOtherObject(cx, obj, %s, ${jsvalPtr})) {
+    return true;
   }
-  ${jsvalRef} = JS::ObjectValue(*result_obj);
-  return true;
-""" % (result, result);
+  if (JS_IsExceptionPending(cx)) {
+    return false;
+  }""" % result
+            wrappingCode += """
+  return ThrowMethodFailedWithDetails(cx, NS_ERROR_XPC_BAD_CONVERT_JS,
+                                      "${interfaceName}", "${methodName}");"""
         else:
             raise TypeError("Don't know how to wrap non-concrete types yet")
         return wrappingCode
 
     if type.isString():
         if type.nullable():
             return """
   return xpc::StringToJsval(cx, %s, ${jsvalPtr});""" % result
@@ -1017,25 +1036,29 @@ class PerSignatureCall(CGThing):
         assert(False) # Override me
     def getErrorReport(self):
         assert(False) # Override me
 
     def isFallible(self):
         return not 'infallible' in self.extendedAttributes
 
     def wrap_return_value(self):
-        resultTemplateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp'}
+        resultTemplateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp',
+                                'interfaceName': \
+                                    self.descriptor.interface.identifier.name,
+                                'methodName': self.idlNode.identifier.name }
         return string.Template(
             getWrapTemplateForType(self.returnType, self.descriptor,
                                    self.resultAlreadyAddRefed)
             ).substitute(resultTemplateValues)
 
     def getErrorReport(self):
         return 'return ThrowMethodFailedWithDetails(cx, rv, "%s", "%s");'\
-               % (self.descriptor.name, self.idlNode.identifier.name)
+               % (self.descriptor.interface.identifier.name,
+                  self.idlNode.identifier.name)
 
     def define(self):
         return (self.cgRoot.define() + self.wrap_return_value())
 
 class PerSignatureMethodCall(PerSignatureCall):
     def __init__(self, returnType, arguments, nativeMethodName, descriptor,
                  method, extendedAttributes):
         PerSignatureCall.__init__(self, returnType, arguments, nativeMethodName,
@@ -1213,16 +1236,344 @@ class CGEnum(CGThing):
 
 """ % (",\n    ".join(map(getEnumValueName, self.enum.values())),
        ",\n    ".join(['"' + val + '"' for val in self.enum.values()]))
 
     def define(self):
         # We only go in the header
         return "";
 
+class ClassItem:
+    """ Use with CGClass """
+    def __init__(self, name, visibility):
+        self.name = name
+        self.visibility = visibility
+    def declare(self, cgClass):
+        assert False
+    def define(self, cgClass):
+        assert False
+
+class ClassBase(ClassItem):
+    def __init__(self, name, visibility='public'):
+        ClassItem.__init__(self, name, visibility)
+    def declare(self, cgClass):
+        return '%s %s' % (self.visibility, self.name)
+    def define(self, cgClass):
+        # Only in the header
+        return ''
+
+class ClassMethod(ClassItem):
+    def __init__(self, name, returnType, args, inline=False, static=False,
+                 virtual=False, const=False, bodyInHeader=False,
+                 templateArgs=None, visibility='public', body=None):
+        self.returnType = returnType
+        self.args = args
+        self.inline = inline or bodyInHeader
+        self.static = static
+        self.virtual = virtual
+        self.const = const
+        self.bodyInHeader = bodyInHeader
+        self.templateArgs = templateArgs
+        self.body = body
+        ClassItem.__init__(self, name, visibility)
+
+    def getDecorators(self, declaring):
+        decorators = []
+        if self.inline:
+            decorators.append('inline')
+        if declaring:
+            if self.static:
+                decorators.append('static')
+            if self.virtual:
+                decorators.append('virtual')
+        if decorators:
+            return ' '.join(decorators) + ' '
+        return ''
+
+    def getBody(self):
+        # Override me or pass a string to constructor
+        assert self.body is not None
+        return self.body
+
+    def declare(self, cgClass):
+        templateClause = 'template <%s>\n' % ', '.join(self.templateArgs) \
+                         if self.bodyInHeader and self.templateArgs else ''
+        args = ', '.join([str(a) for a in self.args])
+        if self.bodyInHeader:
+            body = '  ' + self.getBody();
+            body = body.replace('\n', '\n  ').rstrip(' ')
+            body = '\n{\n' + body + '\n}'
+        else:
+           body = ';'
+
+        return string.Template("""${templateClause}${decorators}${returnType}
+${name}(${args})${const}${body}
+""").substitute({ 'templateClause': templateClause,
+                  'decorators': self.getDecorators(True),
+                  'returnType': self.returnType,
+                  'name': self.name,
+                  'const': ' const' if self.const else '',
+                  'args': args,
+                  'body': body })
+
+    def define(self, cgClass):
+        if self.bodyInHeader:
+            return ''
+
+        templateArgs = cgClass.templateArgs
+        if templateArgs:
+            if cgClass.templateSpecialization:
+                templateArgs = \
+                    templateArgs[len(cgClass.templateSpecialization):]
+
+        if templateArgs:
+            templateClause = \
+                'template <%s>\n' % ', '.join([str(a) for a in templateArgs])
+        else:
+            templateClause = ''
+
+        args = ', '.join([str(a) for a in self.args])
+
+        body = '  ' + self.getBody()
+        body = body.replace('\n', '\n  ').rstrip(' ')
+
+        return string.Template("""${templateClause}${decorators}${returnType}
+${className}::${name}(${args})${const}
+{
+${body}
+}\n
+""").substitute({ 'templateClause': templateClause,
+                  'decorators': self.getDecorators(False),
+                  'returnType': self.returnType,
+                  'className': cgClass.getNameString(),
+                  'name': self.name,
+                  'args': args,
+                  'const': ' const' if self.const else '',
+                  'body': body })
+
+class ClassMember(ClassItem):
+    def __init__(self, name, type, visibility="private", static=False,
+                 body=None):
+        self.type = type;
+        self.static = static
+        self.body = body
+        ClassItem.__init__(self, name, visibility)
+
+    def getBody(self):
+        assert self.body is not None
+        return self.body
+
+    def declare(self, cgClass):
+        return '%s%s %s;\n' % ('static ' if self.static else '', self.type,
+                               self.name)
+
+    def define(self, cgClass):
+        if not self.static:
+            return ''
+        return '%s %s::%s = %s;\n' % (self.type, cgClass.getNameString(),
+                                      self.name, self.getBody())
+
+class ClassTypedef(ClassItem):
+    def __init__(self, name, type, visibility="public"):
+        self.type = type
+        ClassItem.__init__(self, name, visibility)
+
+    def declare(self, cgClass):
+        return 'typedef %s %s;\n' % (self.type, self.name)
+
+    def define(self, cgClass):
+        # Only goes in the header
+        return ''
+
+class ClassEnum(ClassItem):
+    def __init__(self, name, entries, values=None, visibility="public"):
+        self.entries = entries
+        self.values = values
+        ClassItem.__init__(self, name, visibility)
+
+    def declare(self, cgClass):
+        entries = []
+        for i in range(0, len(self.entries)):
+            if i >= len(self.values):
+                entry = '%s' % self.entries[i]
+            else:
+                entry = '%s = %s' % (self.entries[i], self.values[i])
+            entries.append(entry)
+        name = '' if not self.name else ' ' + self.name
+        return 'enum%s\n{\n  %s\n};\n' % (name, ',\n  '.join(entries))
+
+    def define(self, cgClass):
+        # Only goes in the header
+        return ''
+
+class CGClass(CGThing):
+    def __init__(self, name, bases=[], members=[], methods=[], typedefs = [],
+                 enums=[], templateArgs=[], templateSpecialization=[],
+                 isStruct=False, indent=''):
+        CGThing.__init__(self)
+        self.name = name
+        self.bases = bases
+        self.members = members
+        self.methods = methods
+        self.typedefs = typedefs
+        self.enums = enums
+        self.templateArgs = templateArgs
+        self.templateSpecialization = templateSpecialization
+        self.isStruct = isStruct
+        self.indent = indent
+        self.defaultVisibility ='public' if isStruct else 'private'
+
+    def getNameString(self):
+        className = self.name
+        if self.templateSpecialization:
+            className = className + \
+                '<%s>' % ', '.join([str(a) for a
+                                    in self.templateSpecialization])
+        return className
+
+    def declare(self):
+        result = ''
+        if self.templateArgs:
+            templateArgs = [str(a) for a in self.templateArgs]
+            templateArgs = templateArgs[len(self.templateSpecialization):]
+            result = result + self.indent + 'template <%s>\n' \
+                     % ','.join([str(a) for a in templateArgs])
+
+        type = 'struct' if self.isStruct else 'class'
+
+        if self.templateSpecialization:
+            specialization = \
+                '<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
+        else:
+            specialization = ''
+
+        result = result + '%s%s %s%s' \
+                 % (self.indent, type, self.name, specialization)
+
+        if self.bases:
+            result = result + ' : %s' % ', '.join([d.declare(self) for d in self.bases])
+
+        result = result + '\n%s{\n' % self.indent
+
+        def declareMembers(cgClass, memberList, defaultVisibility, itemCount,
+                           separator=''):
+            members = { 'private': [], 'protected': [], 'public': [] }
+
+            for member in memberList:
+                members[member.visibility].append(member)
+
+
+            if defaultVisibility == 'public':
+                order = [ 'public', 'protected', 'private' ]
+            else:
+                order = [ 'private', 'protected', 'public' ]
+
+            result = ''
+
+            lastVisibility = defaultVisibility
+            for visibility in order:
+                list = members[visibility]
+                if list:
+                    if visibility != lastVisibility:
+                        if itemCount:
+                            result = result + '\n'
+                        result = result + visibility + ':\n'
+                        itemCount = 0
+                    for member in list:
+                        if itemCount == 0:
+                            result = result + '  '
+                        else:
+                            result = result + separator + '  '
+                        declaration = member.declare(cgClass)
+                        declaration = declaration.replace('\n', '\n  ')
+                        declaration = declaration.rstrip(' ')
+                        result = result + declaration
+                        itemCount = itemCount + 1
+                    lastVisibility = visibility
+            return (result, lastVisibility, itemCount)
+
+        order = [(self.enums, ''), (self.typedefs, ''), (self.members, ''),
+                 (self.methods, '\n')]
+
+        lastVisibility = self.defaultVisibility
+        itemCount = 0
+        for (memberList, separator) in order:
+            (memberString, lastVisibility, itemCount) = \
+                declareMembers(self, memberList, lastVisibility, itemCount,
+                               separator)
+            if self.indent:
+                memberString = self.indent + memberString
+                memberString = memberString.replace('\n', '\n' + self.indent)
+                memberString = memberString.rstrip(' ')
+            result = result + memberString
+
+        result = result + self.indent + '};\n\n'
+        return result
+
+    def define(self):
+        def defineMembers(cgClass, memberList, itemCount, separator=''):
+            result = ''
+            for member in memberList:
+                if itemCount != 0:
+                    result = result + separator
+                result = result + member.define(cgClass)
+                itemCount = itemCount + 1
+            return (result, itemCount)
+
+        order = [(self.members, '\n'), (self.methods, '\n')]
+
+        result = ''
+        itemCount = 0
+        for (memberList, separator) in order:
+            (memberString, itemCount) = defineMembers(self, memberList,
+                                                      itemCount, separator)
+            result = result + memberString
+        return result
+
+class CGPrototypeTraitsClass(CGClass):
+    def __init__(self, descriptor, indent=''):
+        templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
+        templateSpecialization = ['prototypes::id::' + descriptor.name]
+        enums = [ClassEnum('', ['Depth'],
+                           [descriptor.interface.inheritanceDepth()])]
+        typedefs = [ClassTypedef('NativeClass', descriptor.nativeClass)]
+        CGClass.__init__(self, 'PrototypeTraits', indent=indent,
+                         templateArgs=templateArgs,
+                         templateSpecialization=templateSpecialization,
+                         enums=enums, typedefs=typedefs, isStruct=True)
+
+class CGPrototypeIDMapClass(CGClass):
+    def __init__(self, descriptor, indent=''):
+        templateArgs = [Argument('class', 'ConcreteClass')]
+        templateSpecialization = [descriptor.nativeClass]
+        enums = [ClassEnum('', ['PrototypeID'],
+                           ['prototypes::id::' + descriptor.name])]
+        CGClass.__init__(self, 'PrototypeIDMap', indent=indent,
+                         templateArgs=templateArgs,
+                         templateSpecialization=templateSpecialization,
+                         enums=enums, isStruct=True)
+
+class CGClassForwardDeclare(CGThing):
+    def __init__(self, name, isStruct=False):
+        CGThing.__init__(self)
+        self.name = name
+        self.isStruct = isStruct
+    def declare(self):
+        type = 'struct' if self.isStruct else 'class'
+        return '%s %s;\n' % (type, self.name)
+    def define(self):
+        # Header only
+        return ''
+
+def stripTrailingWhitespace(text):
+    lines = text.splitlines()
+    for i in range(len(lines)):
+        lines[i] = lines[i].rstrip()
+    return '\n'.join(lines)
+
 class CGDescriptor(CGThing):
     def __init__(self, descriptor):
         CGThing.__init__(self)
 
         # XXXbholley - Not everything should actually have a jsclass.
         cgThings = [CGNativeMethod(descriptor, m) for m in
                     descriptor.interface.members if m.isMethod()]
         cgThings.extend([CGNativeGetter(descriptor, a) for a in
@@ -1234,46 +1585,51 @@ class CGDescriptor(CGThing):
         # Always have a finalize hook, regardless of whether the class wants a
         # custom hook.
         cgThings.append(CGClassFinalizeHook(descriptor))
 
         # Only generate a trace hook if the class wants a custom hook.
         if (descriptor.customTrace):
             cgThings.append(CGClassTraceHook(descriptor))
 
-        # XXXbz this should check for [NoInterfaceObject]
-        if True:
+        if descriptor.interface.hasInterfaceObject:
             cgThings.append(CGConstructorJSClass(descriptor))
+
         cgThings.extend([CGDOMJSClass(descriptor),
                          CGPrototypeJSClass(descriptor),
                          CGCreateProtoObjectMethod(descriptor),
                          CGIndenter(CGGetProtoObjectMethod(descriptor))])
 
-        allCGThings = CGList(cgThings)
-        allCGThings = CGWrapper(allCGThings, post="\n")
-        self.cgRoot = CGWrapper(CGNamespace(descriptor.name, allCGThings), post="\n")
+        cgThings = CGList(cgThings)
+        cgThings = CGWrapper(cgThings, post='\n')
+        self.cgRoot = CGWrapper(CGNamespace(descriptor.name, cgThings),
+                                post='\n')
+
     def declare(self):
         return self.cgRoot.declare()
     def define(self):
         return self.cgRoot.define()
 
 class CGNamespacedEnum(CGThing):
     def __init__(self, namespace, enumName, names, values, comment=""):
 
         if not values:
-            values = [None for i in range(0, len(names))]
+            values = []
 
         # Account for explicit enum values.
         entries = []
         for i in range(0, len(names)):
-            entry = names[i] if values[i] is None else "%s = %s" % (names[i], values[i])
+            if len(values) > i and values[i] is not None:
+                entry = "%s = %s" % (names[i], values[i])
+            else:
+                entry = names[i]
             entries.append(entry)
 
         # Append a Count.
-        entries.append('Count')
+        entries.append('_' + enumName + '_Count')
 
         # Indent.
         entries = ['  ' + e for e in entries]
 
         # Buildthe enum body.
         enumstr = comment + 'enum %s\n{\n%s\n};\n' % (enumName, ',\n'.join(entries))
         curr = CGGeneric(declare=enumstr)
 
@@ -1296,45 +1652,76 @@ class CGNamespacedEnum(CGThing):
         assert False # Only for headers.
 
 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.getConcreteDescriptors(webIDLFile)
+
+        forwardDeclares = []
+
+        for x in descriptors:
+            nativeClass = x.nativeClass
+            components = x.nativeClass.split('::')
+            declare = CGClassForwardDeclare(components[-1])
+            if len(components) > 1:
+                declare = CGNamespace.build(components[:-1],
+                                            CGWrapper(declare, declarePre='\n',
+                                                      declarePost='\n'),
+                                            declareOnly=True)
+            forwardDeclares.append(CGWrapper(declare, declarePost='\n'))
+
+        forwardDeclares = CGList(forwardDeclares)
+
+        traitsClasses = [CGPrototypeTraitsClass(d) for d in descriptors]
+
+        # We must have a 1:1 mapping here, skip for prototypes that have more
+        # than one concrete class implementation.
+        traitsClasses.extend([CGPrototypeIDMapClass(d) for d in descriptors
+                              if d.uniqueImplementation])
+
+        # Wrap all of that in our namespaces.
+        traitsClasses = CGNamespace.build(['mozilla', 'dom', 'bindings'],
+                                     CGWrapper(CGList(traitsClasses), pre='\n'))
+        traitsClasses = CGWrapper(traitsClasses, post='\n')
 
         # Do codegen for all the descriptors and enums.
         cgthings = [CGWrapper(CGNamespace.build([e.identifier.name],
                                                 CGEnum(e)),
                               post="\n") for e in config.getEnums(webIDLFile)]
         cgthings.extend([CGDescriptor(x) for x
                          in config.getConcreteDescriptors(webIDLFile)])
         curr = CGList(cgthings)
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom', 'bindings', 'prototypes'],
                                  CGWrapper(curr, pre="\n"))
 
+        curr = CGList([forwardDeclares, traitsClasses, curr])
+
         # Add header includes.
-        curr = CGHeaders(config.getConcreteDescriptors(webIDLFile), ['DOMJSClass.h', 'Utils.h'], curr)
+        curr = CGHeaders(config.getConcreteDescriptors(webIDLFile),
+                         ['DOMJSClass.h', 'Utils.h'], curr)
 
         # Add include guards.
         curr = CGIncludeGuard(prefix, curr)
 
         # Add the auto-generated comment.
-        curr = CGWrapper(curr, pre="/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n")
+        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 
         # Store the final result.
         self.root = curr
 
     def declare(self):
-        return self.root.declare()
+        return stripTrailingWhitespace(self.root.declare())
     def define(self):
-        return self.root.define()
+        return stripTrailingWhitespace(self.root.define())
 
 
 class CGGlobalRoot():
     """
     Root codegen class for global code generation. Instantiate the class, and call
 
     It's possible that we may at some point wish to generate more than just
     PrototypeList.h. As such, this class eschews the define/declare
@@ -1345,31 +1732,36 @@ class CGGlobalRoot():
     def __init__(self, config, prefix):
         self.config = config
         self.prefix = prefix
 
     def prototypeList_h(self):
 
         # Prototype ID enum.
         protos = [d.name for d in self.config.getConcreteDescriptors()]
-        idThing = CGNamespacedEnum('id', 'ID', protos, None)
-
-        # Depth enum.
-        depths = [d.interface.inheritanceDepth() for d in self.config.getConcreteDescriptors()]
-        depthComment = '/* The depths at which we expect the above IDs in inheritance chains;\n' + \
-                       '   0 means there is no superclass */\n'
-        depthThing = CGNamespacedEnum('depth', 'Depth', protos, depths, depthComment)
-
-        # Combine.
-        curr = CGList([idThing, depthThing])
+        idEnum = CGNamespacedEnum('id', 'ID', protos, [0])
 
         # Wrap all of that in our namespaces.
-        curr = CGNamespace.build(['mozilla', 'dom', 'bindings', 'prototypes'],
-                                 CGWrapper(curr, pre="\n"))
+        idEnum = CGNamespace.build(['mozilla', 'dom', 'bindings', 'prototypes'],
+                                   CGWrapper(idEnum, pre='\n'))
+        idEnum = CGWrapper(idEnum, post='\n')
+
+        traitsDecl = CGGeneric(declare="""
+template <prototypes::ID PrototypeID>
+struct PrototypeTraits;
+
+template <class ConcreteClass>
+struct PrototypeIDMap;
+""")
+
+        traitsDecl = CGNamespace.build(['mozilla', 'dom', 'bindings'],
+                                        CGWrapper(traitsDecl, post='\n'))
+
+        curr = CGList([idEnum, traitsDecl])
 
         # Add include guards.
         curr = CGIncludeGuard(self.prefix, curr)
 
         # Add the auto-generated comment.
-        curr = CGWrapper(curr, pre="/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n")
+        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 
         # Do header generation on the reuslt.
-        return curr.declare()
+        return stripTrailingWhitespace(curr.declare())
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -26,16 +26,24 @@ class Configuration:
             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(self, iface, x) for x in entry])
 
+        # Mark the descriptors for which only a single nativeClass implements
+        # 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()]
 
         # 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, webIDLFile=None):
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -24,17 +24,17 @@ struct DOMJSClass
 {
   // It would be nice to just inherit from JSClass, but that precludes pure
   // compile-time initialization of the form |DOMJSClass = {...};|, since C++
   // only allows brace initialization for aggregate/POD types.
   JSClass mBase;
 
   // A list of interfaces that this object implements, in order of decreasing
   // derivedness.
-  const prototypes::ID mInterfaceChain[prototypes::id::Count];
+  const prototypes::ID mInterfaceChain[prototypes::id::_ID_Count];
 
   // We cache the VTable index of GetWrapperCache for objects that support it.
   //
   // -1 indicates that GetWrapperCache is not implemented on the underlying object.
   const int16_t mGetWrapperCacheVTableOffset;
 
   // We store the DOM object in reserved slot DOM_OBJECT_SLOT.
   // Sometimes it's an nsISupports and sometimes it's not; this class tells
--- a/dom/bindings/Utils.h
+++ b/dom/bindings/Utils.h
@@ -32,181 +32,34 @@ Throw(JSContext* cx, nsresult rv)
 inline bool
 ThrowMethodFailedWithDetails(JSContext* cx, nsresult rv,
                              const char* /* ifaceName */,
                              const char* /* memberName */)
 {
   return Throw(cx, rv);
 }
 
-// "Hide" some stuff in detail...
-namespace detail {
-
-// Little helper for testing nsISupports inheritance.
-// Types we need to determine inheritance relationships.
-typedef char TrueType;
-
-struct FalseType
-{
-  // Guarantee non-equal size by making more than one.
-  TrueType foo[2];
-};
-
-// Unspecialized If struct always returns false.
-template<bool Condition>
-struct If
-{
-  enum
-  {
-    Result = false
-  };
-};
-
-// This specialized If struct always returns true.
-template<>
-struct If<true>
-{
-  enum
-  {
-    Result = true
-  };
-};
-
-// Class to determine inheritance. IsBaseOf<Base, Derived>::Result will be
-// true or false depending on whether Derived is actually derived from Base.
-template<class Base, class Derived>
-class IsBaseOf
-{
-  // None of these methods are implemented and they're never called. The
-  // compiler can deduce the proper return type based on the argument passed
-  // to these functions, and we use this trick to determine inheritance.
-  static TrueType& Inherits(Base*);
-  static FalseType& Inherits(...);
-
-  // This function doesn't exist either, but its return type is needed for the
-  // compiler to select the proper overload above (and therefore its proper
-  // return type).
-  static Derived* Create();
-
-public:
-  enum
-  {
-    Result = If<sizeof(Inherits(Create())) == sizeof(TrueType)>::Result
-  };
-};
-
-template<class T>
-class InheritsISupports
-{
-
-public:
-  enum
-  {
-    Result = IsBaseOf<nsISupports, T>::Result
-  };
-};
-
-template<class T>
-MOZ_ALWAYS_INLINE bool
-CommonWrap(JSContext *cx, JSObject *scope, T *value, jsval *vp)
-{
-  JSObject *obj = value->GetWrapper();
-  if (obj) {
-    *vp = OBJECT_TO_JSVAL(obj);
-    return true;
-  }
-
-  bool enabled;
-  obj = value->WrapObject(cx, scope, &enabled);
-  if (enabled) {
-    *vp = OBJECT_TO_JSVAL(obj);
-    return obj != NULL;
-  }
-
-  return false;
-}
-
-// Unspecialized WrapHelper is for when T does not inherit nsISupports. In such
-// a case we do not attempt to call WrapOtherObject (see below) because it
-// expects T to inherit nsISupports (T will never inherit nsISupports on
-// Workers, for instance). Implements an operator(), so calling is as simple as
-// making a stack instance and calling like a function:
-//
-//   WrapHelper<MyClass, true> helper;
-//   bool result = helper(cx, scope, value, vp);
-//
-// The compiler should optimize the stack variable out entirely.
-template<class T, bool InheritsISupports>
-struct WrapHelper
-{
-  MOZ_ALWAYS_INLINE bool
-  operator() (JSContext *cx, JSObject *scope, T *value, jsval *vp)
-  {
-    if (CommonWrap(cx, scope, value, vp)) {
-      return true;
-    }
-
-    if (!JS_IsExceptionPending(cx)) {
-      JS_ReportError(cx, "Can't wrap object!");
-    }
-
-    return false;
-  }
-};
-
-// Specialized WrapHelper is for when T inherits nsISupports. In such a case we
-// may attempt to call WrapOtherObject (see below) if the object is not a
-// new-style binding. WrapOtherObject expects that T inherits nsISupports.
-template<class T>
-struct WrapHelper<T, true>
-{
-  MOZ_ALWAYS_INLINE bool
-  operator() (JSContext *cx, JSObject *scope, T *value, jsval *vp)
-  {
-    if (CommonWrap(cx, scope, value, vp)) {
-      return true;
-    }
-
-    if (JS_IsExceptionPending(cx)) {
-      return false;
-    }
-
-    return WrapOtherObject(cx, scope, value, vp);
-  }
-};
-
-} // namespace detail
-
 inline bool
 IsDOMClass(JSClass *clasp)
 {
   return clasp->flags & JSCLASS_IS_DOMJSCLASS;
 }
 
-template<class T>
+template <class T>
 inline T*
 UnwrapDOMObject(JSObject *obj)
 {
   MOZ_ASSERT(IsDOMClass(js::GetObjectJSClass(obj)));
   return static_cast<T*>(js::GetReservedSlot(obj,
                                              DOM_OBJECT_SLOT).toPrivate());
 }
 
-/*
- * - protoID is the ID of the prototype that corresponds to type T
- * - protoIDIndex is the index at which we expect to find protoID in the DOM
- *                class's mInterfaceChain.
- */
-template<class T>
+template <prototypes::ID PrototypeID, class T>
 inline nsresult
-UnwrapObject(JSContext *cx,
-             JSObject *obj,
-             prototypes::ID protoID,
-             prototypes::Depth protoIDIndex,
-             T **value)
+UnwrapObject(JSContext *cx, JSObject *obj, T **value)
 {
   /* First check to see whether we have a DOM object */
   JSClass *clasp = js::GetObjectJSClass(obj);
   if (!IsDOMClass(clasp)) {
     /* Maybe we have a security wrapper or outer window? */
     if (!js::IsWrapper(obj)) {
       /* Not a DOM object, not a wrapper, just bail */
       return NS_ERROR_XPC_BAD_CONVERT_JS;
@@ -225,39 +78,48 @@ UnwrapObject(JSContext *cx,
   }
 
   MOZ_ASSERT(IsDOMClass(clasp));
 
   /* This object is a DOM object.  Double-check that it is safely
      castable to T by checking whether it claims to inherit from the
      class identified by protoID. */
   DOMJSClass *domClass = DOMJSClass::FromJSClass(clasp);
-  if (domClass->mInterfaceChain[protoIDIndex] == protoID) {
+  if (domClass->mInterfaceChain[PrototypeTraits<PrototypeID>::Depth] ==
+      PrototypeID) {
     *value = UnwrapDOMObject<T>(obj);
     return NS_OK;
   }
 
   /* It's the wrong sort of DOM object */
   return NS_ERROR_XPC_BAD_CONVERT_JS;
 }
 
+template <class T>
+inline nsresult
+UnwrapObject(JSContext *cx, JSObject *obj, T **value)
+{
+  return UnwrapObject<static_cast<prototypes::ID>(
+           PrototypeIDMap<T>::PrototypeID)>(cx, obj, value);
+}
+
 inline JSObject **
 GetProtoArray(JSObject *global)
 {
   MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL);
   return static_cast<JSObject**>(
     js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).toPrivate());
 }
 
 inline void
 AllocateProtoCache(JSObject *obj)
 {
   MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
   // Important: The () at the end ensure zero-initialization
-  JSObject** protoArray = new JSObject*[prototypes::id::Count]();
+  JSObject** protoArray = new JSObject*[prototypes::id::_ID_Count]();
   js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT, JS::PrivateValue(protoArray));
 }
 
 inline void
 DestroyProtoCache(JSObject *obj)
 {
   JSObject **protoArray = GetProtoArray(obj);
   delete [] protoArray;
@@ -283,54 +145,71 @@ JSObject*
 CreateProtoObject(JSContext *cx, JSObject *parentProto,
                   JSClass *protoClass,
                   JSClass *constructorClass,
                   JSFunctionSpec *methods,
                   JSPropertySpec *properties,
                   JSObject *global,
                   const char* name);
 
-template<class T>
+template <class T>
 inline bool
 WrapNewBindingObject(JSContext *cx, JSObject *scope, T *value, jsval *vp)
 {
-  // XXX Would love to use auto and a templated getter here :(
-  detail::WrapHelper<T, detail::InheritsISupports<T>::Result> helper;
-  return helper(cx, scope, value, vp);
+  JSObject *obj = value->GetWrapper();
+  if (obj && js::GetObjectCompartment(obj) == js::GetObjectCompartment(scope)) {
+    *vp = JS::ObjectValue(*obj);
+    return true;
+  }
+
+  // XXXbz figure out the actual security wrapper story here
+  bool triedToWrap;
+  obj = value->WrapObject(cx, scope, &triedToWrap);
+  if (triedToWrap && obj) {
+    *vp = JS::ObjectValue(*obj);
+    return true;
+  }
+
+  return false;
 }
 
 // Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
-template<template <class> class SmartPtr, class T>
+template <template <class> class SmartPtr, class T>
 inline bool
 WrapNewBindingObject(JSContext *cx, JSObject *scope, const SmartPtr<T>& value,
                      jsval *vp)
 {
   return WrapNewBindingObject(cx, scope, value.get(), vp);
 }
 
-template<class T>
+template <class T>
 inline bool
 WrapOtherObject(JSContext *cx, JSObject *scope, T *value, jsval *vp)
 {
   XPCLazyCallContext lccx(JS_CALLER, cx, scope);
 
-  xpcObjectHelper helper(value);
+  nsCOMPtr<nsISupports> canonical;
+  if (NS_FAILED(CallQueryInterface(value, getter_AddRefs(canonical)))) {
+    return false;
+  }
+
+  xpcObjectHelper helper(canonical);
   nsresult rv;
   if (!XPCConvert::NativeInterface2JSObject(lccx, vp, NULL, helper, NULL, NULL,
                                             true, OBJ_IS_NOT_GLOBAL, &rv)) {
     if (!JS_IsExceptionPending(cx))
       Throw(cx, rv);
     return false;
   }
 
   return true;
 }
 
 // Support for nullable types
-template<typename T>
+template <typename T>
 struct Nullable
 {
 private:
   T mValue;
   bool mIsNull;
 
 public:
   Nullable() :
@@ -356,17 +235,17 @@ public:
   }
 
   bool IsNull() {
     return mIsNull;
   }
 };
 
 // Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
-template<template <class> class SmartPtr, class T>
+template <template <class> class SmartPtr, class T>
 inline bool
 WrapOtherObject(JSContext *cx, JSObject *scope, const SmartPtr<T>& value,
                 jsval *vp)
 {
   return WrapOtherObject(cx, scope, value.get(), vp);
 }
 
 inline int
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -458,17 +458,17 @@ class IDLInterface(IDLObjectWithScope):
         depth = 0
         parent = self.parent
         while parent:
             depth = depth + 1
             parent = parent.parent
         return depth
 
     def hasInterfaceObject(self):
-        return False
+        return True
 
 class IDLEnum(IDLObjectWithIdentifier):
     def __init__(self, location, parentScope, name, values):
         assert isinstance(parentScope, IDLScope)
         assert isinstance(name, IDLUnresolvedIdentifier)
 
         if len(values) != len(set(values)):
             raise WebIDLError("Enum %s has multiple identical strings" % name.name, location)
@@ -900,16 +900,19 @@ class IDLBuiltinType(IDLType):
         # but we handle them as builtins because SpiderMonkey implements
         # ArrayBuffers.
         return self.type == IDLBuiltinType.Types.ArrayBuffer
 
     def isFloat(self):
         return self.type == IDLBuiltinType.Types.float or \
                self.type == IDLBuiltinType.Types.double
 
+    def isAny(self):
+        return self.type == IDLBuiltinType.Types.any
+
     def tag(self):
         return IDLBuiltinType.TagLookup[self.type]
 
 BuiltinTypes = {
       IDLBuiltinType.Types.byte:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Byte",
                          IDLBuiltinType.Types.byte),
       IDLBuiltinType.Types.octet: