Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorEd Morley <bmo@edmorley.co.uk>
Sat, 31 Mar 2012 22:41:59 +0100
changeset 90793 bbe5086163c91cdb78a979720e0071077eb7fef8
parent 90723 83dce280d87141d551af64bddd9694eb84de125b (current diff)
parent 90792 a963db912f08dc7adf7b4a8889084c9726c44350 (diff)
child 90794 4a8a5e8ef78bdcf1d781294ae5bef76bfa530f88
push id22382
push userbmo@edmorley.co.uk
push dateSat, 31 Mar 2012 21:44:34 +0000
treeherdermozilla-central@bbe5086163c9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone14.0a1
first release with
nightly linux32
bbe5086163c9 / 14.0a1 / 20120331161857 / files
nightly linux64
bbe5086163c9 / 14.0a1 / 20120331161857 / files
nightly mac
bbe5086163c9 / 14.0a1 / 20120331161857 / files
nightly win32
bbe5086163c9 / 14.0a1 / 20120331161857 / files
nightly win64
bbe5086163c9 / 14.0a1 / 20120331161857 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
content/base/public/nsContentUtils.h
content/base/public/nsIDocument.h
content/base/src/nsContentUtils.cpp
content/base/src/nsGkAtomList.h
content/base/src/nsXMLHttpRequest.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsJSEnvironment.cpp
dom/wifi/libcutils.js
dom/wifi/network_worker.js
dom/workers/ListenerManager.cpp
dom/workers/ListenerManager.h
dom/workers/XMLHttpRequestPrivate.cpp
dom/workers/XMLHttpRequestPrivate.h
js/xpconnect/src/nsXPConnect.cpp
layout/svg/base/src/nsSVGLeafFrame.cpp
mobile/android/base/gfx/GLThread.java
--- a/Makefile.in
+++ b/Makefile.in
@@ -75,16 +75,17 @@ endif
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 tier_base_dirs += \
   other-licenses/android \
   $(NULL)
 endif
 
 ifdef MOZ_MEMORY
 tier_base_dirs += memory/jemalloc
+tier_base_dirs += memory/build
 endif
 tier_base_dirs += \
   mozglue \
   memory/mozalloc \
   $(NULL)
 endif
 
 ifdef COMPILE_ENVIRONMENT
--- a/allmakefiles.sh
+++ b/allmakefiles.sh
@@ -83,16 +83,17 @@ if [ ! "$LIBXUL_SDK" ]; then
   add_makefiles "
     memory/mozalloc/Makefile
     mozglue/Makefile
     mozglue/build/Makefile
   "
   if [ "$MOZ_MEMORY" ]; then
     add_makefiles "
       memory/jemalloc/Makefile
+      memory/build/Makefile
     "
   fi
   if [ "$MOZ_WIDGET_TOOLKIT" = "android" ]; then
     add_makefiles "
       other-licenses/android/Makefile
       other-licenses/skia-npapi/Makefile
       mozglue/android/Makefile
     "
--- a/b2g/installer/removed-files.in
+++ b/b2g/installer/removed-files.in
@@ -1,2 +1,3 @@
 README.txt
 @DLL_PREFIX@mozutils@DLL_SUFFIX@
+jssubloader/
--- a/browser/components/build/Makefile.in
+++ b/browser/components/build/Makefile.in
@@ -19,17 +19,17 @@ USE_STATIC_LIBS = 1
 endif
 
 EXPORTS = nsBrowserCompsCID.h
 
 CPPSRCS = nsModule.cpp \
           $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
-OS_LIBS	+= $(call EXPAND_LIBNAME,ole32 shell32)
+OS_LIBS	+= $(call EXPAND_LIBNAME,ole32 shell32 shlwapi)
 endif
 
 LOCAL_INCLUDES = \
 	-I$(srcdir)/../shell/src \
 	-I$(srcdir)/../feeds/src \
 	-I$(srcdir)/../privatebrowsing/src \
 	-I$(srcdir)/../about \
 	-I$(srcdir)/../dirprovider \
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -72,18 +72,16 @@
 
 #ifdef _WIN32_WINNT
 #undef _WIN32_WINNT
 #endif
 #define _WIN32_WINNT 0x0600
 #define INITGUID
 #include <shlobj.h>
 
-#pragma comment(lib, "shlwapi.lib") // for SHDeleteKeyW
-
 #include <mbstring.h>
 #include <shlwapi.h>
 
 #ifndef MAX_BUF
 #define MAX_BUF 4096
 #endif
 
 #define REG_SUCCEEDED(val) \
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -1470,8 +1470,9 @@ extensions/inspector@mozilla.org/compone
 extensions/inspector@mozilla.org/chrome/icons/default/winInspectorMain.ico
 components/nsPlacesTransactionsService.js
 components/browserplaces.xpt
 components/nsPlacesDBFlush.js
 #ifndef MOZ_MAINTENANCE_SERVICE
 maintenanceservice.exe
 maintenanceservice_installer.exe
 #endif
+jssubloader/
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -89,18 +89,20 @@
 #include "nsAboutProtocolUtils.h"
 #include "nsIClassInfo.h"
 #include "nsIURIFixup.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsIChromeRegistry.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/bindings/Utils.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
 
 nsIIOService    *nsScriptSecurityManager::sIOService = nsnull;
 nsIXPConnect    *nsScriptSecurityManager::sXPConnect = nsnull;
 nsIThreadJSContextStack *nsScriptSecurityManager::sJSContextStack = nsnull;
 nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
 JSRuntime       *nsScriptSecurityManager::sRuntime   = 0;
@@ -2440,19 +2442,27 @@ nsScriptSecurityManager::doGetObjectPrin
                                               aAllowShortCircuit
 #else
                                               true
 #endif
                                               );
             if (result) {
                 break;
             }
-        } else if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
-                                        JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
-            nsISupports *priv = (nsISupports *) js::GetObjectPrivate(aObj);
+        } else {
+            nsISupports *priv;
+            if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
+                                     JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
+                priv = (nsISupports *) js::GetObjectPrivate(aObj);
+            } else if ((jsClass->flags & JSCLASS_IS_DOMJSCLASS) &&
+                       bindings::DOMJSClass::FromJSClass(jsClass)->mDOMObjectIsISupports) {
+                priv = bindings::UnwrapDOMObject<nsISupports>(aObj, jsClass);
+            } else {
+                priv = nsnull;
+            }
 
 #ifdef DEBUG
             if (aAllowShortCircuit) {
                 nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
                     do_QueryInterface(priv);
 
                 NS_ASSERTION(!xpcWrapper ||
                              !strcmp(jsClass->name, "XPCNativeWrapper"),
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1637,17 +1637,20 @@ public:
   // Returns NS_OK for same origin, error (NS_ERROR_DOM_BAD_URI) if not.
   static nsresult CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel);
   static nsIInterfaceRequestor* GetSameOriginChecker();
 
   static nsIThreadJSContextStack* ThreadJSContextStack()
   {
     return sThreadJSContextStack;
   }
-  
+
+  // Trace the safe JS context of the ThreadJSContextStack.
+  static void TraceSafeJSContext(JSTracer* aTrc);
+
 
   /**
    * Get the Origin of the passed in nsIPrincipal or nsIURI. If the passed in
    * nsIURI or the URI of the passed in nsIPrincipal does not have a host, the
    * origin is set to 'null'.
    *
    * The ASCII versions return a ASCII strings that are puny-code encoded,
    * suitable for, for example, header values. The UTF versions return strings
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -178,19 +178,20 @@ public:
       mPartID(0)
   {
     SetInDocument();
   }
 #endif
   
   /**
    * Let the document know that we're starting to load data into it.
-   * @param aCommand The parser command
+   * @param aCommand The parser command. Must not be null.
    *                 XXXbz It's odd to have that here.
-   * @param aChannel The channel the data will come from
+   * @param aChannel The channel the data will come from. The channel must be
+   *                 able to report its Content-Type.
    * @param aLoadGroup The loadgroup this document should use from now on.
    *                   Note that the document might not be the only thing using
    *                   this loadgroup.
    * @param aContainer The container this document is in.  This may be null.
    *                   XXXbz maybe we should make it more explicit (eg make the
    *                   container an nsIWebNavigation or nsIDocShell or
    *                   something)?
    * @param [out] aDocListener the listener to pump data from the channel into.
@@ -199,16 +200,19 @@ public:
    *                           documents.
    * @param aReset whether the document should call Reset() on itself.  If this
    *               is false, the document will NOT set its principal to the
    *               channel's owner, will not clear any event listeners that are
    *               already set on it, etc.
    * @param aSink The content sink to use for the data.  If this is null and
    *              the document needs a content sink, it will create one based
    *              on whatever it knows about the data it's going to load.
+   *              This MUST be null if the underlying document is an HTML
+   *              document. Even in the XML case, please don't add new calls
+   *              with non-null sink.
    *
    * Once this has been called, the document will return false for
    * MayStartLayout() until SetMayStartLayout(true) is called on it.  Making
    * sure this happens is the responsibility of the caller of
    * StartDocumentLoad().
    */  
   virtual nsresult StartDocumentLoad(const char* aCommand,
                                      nsIChannel* aChannel,
--- a/content/base/public/nsIDocumentEncoder.idl
+++ b/content/base/public/nsIDocumentEncoder.idl
@@ -233,16 +233,22 @@ interface nsIDocumentEncoder : nsISuppor
   /**
    * Output for delsp=yes (RFC 3676). This is used with OutputFormatFlowed
    * when converting to text for mail sending.
    * PlainText output only.
    */
   const unsigned long OutputFormatDelSp  = (1 << 20);
  
   /**
+   * Drop <br> elements considered "invisible" by the editor. OutputPreformatted
+   * implies this flag.
+   */
+  const unsigned long OutputDropInvisibleBreak = (1 << 21);
+
+  /**
    * Initialize with a pointer to the document and the mime type.
    * @param aDocument Document to encode.
    * @param aMimeType MimeType to use. May also be set by SetMimeType.
    * @param aFlags Flags to use while encoding. May also be set by SetFlags.
    */
   void init(in nsIDOMDocument aDocument,
             in AString aMimeType,
             in unsigned long aFlags);
--- a/content/base/src/nsCCUncollectableMarker.cpp
+++ b/content/base/src/nsCCUncollectableMarker.cpp
@@ -398,9 +398,12 @@ mozilla::dom::TraceBlackJS(JSTracer* aTr
   }
 
   // Mark globals of active windows black.
   nsGlobalWindow::WindowByIdTable* windowsById =
     nsGlobalWindow::GetWindowsTable();
   if (windowsById) {
     windowsById->Enumerate(TraceActiveWindowGlobal, aTrc);
   }
+
+  // Mark the safe context black
+  nsContentUtils::TraceSafeJSContext(aTrc);
 }
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -1660,16 +1660,33 @@ nsContentUtils::GetContextAndScope(nsIDo
   }
 
   *aCx = cx;
   *aNewScope = newScope;
 
   return NS_OK;
 }
 
+//static
+void
+nsContentUtils::TraceSafeJSContext(JSTracer* aTrc)
+{
+  if (!sThreadJSContextStack) {
+    return;
+  }
+  JSContext* cx = nsnull;
+  sThreadJSContextStack->GetSafeJSContext(&cx);
+  if (!cx) {
+    return;
+  }
+  if (JSObject* global = JS_GetGlobalObject(cx)) {
+    JS_CALL_OBJECT_TRACER(aTrc, global, "safe context");
+  }
+}
+
 nsresult
 nsContentUtils::ReparentContentWrappersInScope(JSContext *cx,
                                                nsIScriptGlobalObject *aOldScope,
                                                nsIScriptGlobalObject *aNewScope)
 {
   JSObject *oldScopeObj = aOldScope->GetGlobalJSObject();
   JSObject *newScopeObj = aNewScope->GetGlobalJSObject();
 
@@ -6573,26 +6590,27 @@ nsContentUtils::GetRootDocument(nsIDocum
 }
 
 // static
 void
 nsContentUtils::ReleaseWrapper(nsISupports* aScriptObjectHolder,
                                nsWrapperCache* aCache)
 {
   if (aCache->PreservingWrapper()) {
+    // PreserveWrapper puts new DOM bindings in the JS holders hash, but they
+    // can also be in the DOM expando hash, so we need to try to remove them
+    // from both here.
     JSObject* obj = aCache->GetWrapperPreserveColor();
-    if (aCache->IsDOMBinding()) {
+    if (aCache->IsDOMBinding() && obj) {
       JSCompartment *compartment = js::GetObjectCompartment(obj);
       xpc::CompartmentPrivate *priv =
         static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
       priv->RemoveDOMExpandoObject(obj);
     }
-    else {
-      DropJSObjects(aScriptObjectHolder);
-    }
+    DropJSObjects(aScriptObjectHolder);
 
     aCache->SetPreservingWrapper(false);
   }
 }
 
 // static
 void
 nsContentUtils::TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback,
--- a/content/base/src/nsCopySupport.cpp
+++ b/content/base/src/nsCopySupport.cpp
@@ -155,35 +155,49 @@ SelectionCopyHelper(nsISelection *aSel, 
     return rv;
 
   nsAutoString buffer, parents, info, textBuffer, plaintextBuffer;
 
   rv = docEncoder->EncodeToString(textBuffer);
   if (NS_FAILED(rv)) 
     return rv;
 
-  nsCOMPtr<nsIFormatConverter> htmlConverter;
-
-  // sometimes we also need the HTML version
+  // If the selection was in a text input, in textarea or in pre, the encoder
+  // already produced plain text. Otherwise,the encoder produced HTML. In that
+  // case, we need to create an additional plain text serialization and an
+  // addition HTML serialization that encodes context.
   if (bIsHTMLCopy) {
 
-    // this string may still contain HTML formatting, so we need to remove that too.
-    htmlConverter = do_CreateInstance(kHTMLConverterCID);
-    NS_ENSURE_TRUE(htmlConverter, NS_ERROR_FAILURE);
+    // First, create the plain text serialization
+    mimeType.AssignLiteral("text/plain");
+
+    flags =
+      nsIDocumentEncoder::OutputSelectionOnly |
+      nsIDocumentEncoder::OutputAbsoluteLinks |
+      nsIDocumentEncoder::SkipInvisibleContent |
+      nsIDocumentEncoder::OutputDropInvisibleBreak |
+      (aFlags & nsIDocumentEncoder::OutputNoScriptContent);
+
+    rv = docEncoder->Init(domDoc, mimeType, flags);
+    if (NS_FAILED(rv))
+      return rv;
 
-    nsCOMPtr<nsISupportsString> plainHTML = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
-    NS_ENSURE_TRUE(plainHTML, NS_ERROR_FAILURE);
-    plainHTML->SetData(textBuffer);
+    rv = docEncoder->SetSelection(aSel);
+    if (NS_FAILED(rv))
+      return rv;
 
-    nsCOMPtr<nsISupportsString> ConvertedData;
-    PRUint32 ConvertedLen;
-    rv = htmlConverter->Convert(kHTMLMime, plainHTML, textBuffer.Length() * 2, kUnicodeMime, getter_AddRefs(ConvertedData), &ConvertedLen);
-    NS_ENSURE_SUCCESS(rv, rv);
+    rv = docEncoder->EncodeToString(plaintextBuffer);
+    if (NS_FAILED(rv))
+      return rv;
 
-    ConvertedData->GetData(plaintextBuffer);
+    // Emulate the collateral damage from bug 564737. Remove the following
+    // line to fix bug 739537.
+    plaintextBuffer.Trim(" ", true, false);
+
+    // Now create the version that shows HTML context
 
     mimeType.AssignLiteral(kHTMLMime);
 
     flags = aFlags;
 
     rv = docEncoder->Init(domDoc, mimeType, flags);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -203,17 +217,20 @@ SelectionCopyHelper(nsISelection *aSel, 
       return rv;
   }
 
   if ((doPutOnClipboard && clipboard) || aTransferable != nsnull) {
     // Create a transferable for putting data on the Clipboard
     nsCOMPtr<nsITransferable> trans = do_CreateInstance(kCTransferableCID);
     if (trans) {
       if (bIsHTMLCopy) {
-        // set up the data converter
+        // Set up a format converter so that clipboard flavor queries work.
+        // This converter isn't really used for conversions.
+        nsCOMPtr<nsIFormatConverter> htmlConverter =
+          do_CreateInstance(kHTMLConverterCID);
         trans->SetConverter(htmlConverter);
 
         if (!buffer.IsEmpty()) {
           // Add the html DataFlavor to the transferable
           rv = AppendString(trans, buffer, kHTMLMime);
           NS_ENSURE_SUCCESS(rv, rv);
         }
 
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -78,16 +78,20 @@
 #include "nsITransferable.h" // for kUnicodeMime
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
 #include "nsTArray.h"
 #include "nsIFrame.h"
 #include "nsStringBuffer.h"
 #include "mozilla/dom/Element.h"
+#include "nsIEditorDocShell.h"
+#include "nsIEditor.h"
+#include "nsIHTMLEditor.h"
+#include "nsIDocShell.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsresult NS_NewDomSelection(nsISelection **aDomSelection);
 
 enum nsRangeIterationDirection {
   kDirectionOut = -1,
@@ -344,16 +348,52 @@ nsDocumentEncoder::GetMimeType(nsAString
 
 
 bool
 nsDocumentEncoder::IncludeInContext(nsINode *aNode)
 {
   return false;
 }
 
+static
+bool
+IsInvisibleBreak(nsINode *aNode) {
+  // xxxehsan: we should probably figure out a way to determine
+  // if a BR node is visible without using the editor.
+  Element* elt = aNode->AsElement();
+  if (!elt->IsHTML(nsGkAtoms::br) ||
+      !aNode->IsEditable()) {
+    return false;
+  }
+
+  // Grab the editor associated with the document
+  nsIDocument *doc = aNode->GetCurrentDoc();
+  if (doc) {
+    nsPIDOMWindow *window = doc->GetWindow();
+    if (window) {
+      nsIDocShell *docShell = window->GetDocShell();
+      if (docShell) {
+        nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
+        if (editorDocShell) {
+          nsCOMPtr<nsIEditor> editor;
+          editorDocShell->GetEditor(getter_AddRefs(editor));
+          nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
+          if (htmlEditor) {
+            bool isVisible = false;
+            nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aNode);
+            htmlEditor->BreakIsVisible(domNode, &isVisible);
+            return !isVisible;
+          }
+        }
+      }
+    }
+  }
+  return false;
+}
+
 nsresult
 nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
                                       PRInt32 aStartOffset,
                                       PRInt32 aEndOffset,
                                       nsAString& aStr,
                                       nsINode* aOriginalNode)
 {
   if (!IsVisibleNode(aNode))
@@ -376,16 +416,21 @@ nsDocumentEncoder::SerializeNodeStart(ns
   }
 
   // Either there was no fixed-up node,
   // or the caller did fixup themselves and aNode is already fixed
   if (!node)
     node = aNode;
   
   if (node->IsElement()) {
+    if ((mFlags & (nsIDocumentEncoder::OutputPreformatted |
+                   nsIDocumentEncoder::OutputDropInvisibleBreak)) &&
+        IsInvisibleBreak(node)) {
+      return NS_OK;
+    }
     Element* originalElement =
       aOriginalNode && aOriginalNode->IsElement() ?
         aOriginalNode->AsElement() : nsnull;
     mSerializer->AppendElementStart(node->AsElement(),
                                     originalElement, aStr);
     return NS_OK;
   }
 
@@ -1240,17 +1285,25 @@ nsHTMLCopyEncoder::Init(nsIDOMDocument* 
 
   mIsTextWidget = false;
   Initialize();
 
   mIsCopying = true;
   mDocument = do_QueryInterface(aDocument);
   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
 
-  mMimeType.AssignLiteral("text/html");
+  // Hack, hack! Traditionally, the caller passes text/unicode, which is
+  // treated as "guess text/html or text/plain" in this context. (It has a
+  // different meaning in other contexts. Sigh.) From now on, "text/plain"
+  // means forcing text/plain instead of guessing.
+  if (aMimeType.EqualsLiteral("text/plain")) {
+    mMimeType.AssignLiteral("text/plain");
+  } else {
+    mMimeType.AssignLiteral("text/html");
+  }
 
   // Make all links absolute when copying
   // (see related bugs #57296, #41924, #58646, #32768)
   mFlags = aFlags | OutputAbsoluteLinks;
 
   if (!mDocument->IsScriptEnabled())
     mFlags |= OutputNoScriptContent;
 
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1897,20 +1897,21 @@ GK_ATOM(x_tibt, "x-tibt")
 // used in gfxGDIFontList.h
 GK_ATOM(ko_xxx, "ko-xxx")
 GK_ATOM(x_central_euro, "x-central-euro")
 GK_ATOM(x_symbol, "x-symbol")
 
 // referenced in all.js
 GK_ATOM(x_user_def, "x-user-def")
 
-// additional languages that use Turkish-style case transformation
+// additional languages that have special case transformations
 GK_ATOM(az, "az")
 GK_ATOM(ba, "ba")
 GK_ATOM(crh, "crh")
+GK_ATOM(nl, "nl")
 
 // Names for editor transactions
 GK_ATOM(TypingTxnName, "Typing")
 GK_ATOM(IMETxnName, "IME")
 GK_ATOM(DeleteTxnName, "Deleting")
 
 // IPC stuff
 GK_ATOM(Remote, "remote")
--- a/content/base/src/nsHTMLContentSerializer.cpp
+++ b/content/base/src/nsHTMLContentSerializer.cpp
@@ -83,51 +83,16 @@ nsresult NS_NewHTMLContentSerializer(nsI
   nsHTMLContentSerializer* it = new nsHTMLContentSerializer();
   if (!it) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return CallQueryInterface(it, aSerializer);
 }
 
-static
-bool
-IsInvisibleBreak(nsIContent *aNode, nsIAtom *aTag, PRInt32 aNamespace) {
-  // xxxehsan: we should probably figure out a way to determine
-  // if a BR node is visible without using the editor.
-  if (!(aTag == nsGkAtoms::br && aNamespace == kNameSpaceID_XHTML) ||
-      !aNode->IsEditable()) {
-    return false;
-  }
-
-  // Grab the editor associated with the document
-  nsIDocument *doc = aNode->GetCurrentDoc();
-  if (doc) {
-    nsPIDOMWindow *window = doc->GetWindow();
-    if (window) {
-      nsIDocShell *docShell = window->GetDocShell();
-      if (docShell) {
-        nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
-        if (editorDocShell) {
-          nsCOMPtr<nsIEditor> editor;
-          editorDocShell->GetEditor(getter_AddRefs(editor));
-          nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
-          if (htmlEditor) {
-            bool isVisible = false;
-            nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aNode);
-            htmlEditor->BreakIsVisible(domNode, &isVisible);
-            return !isVisible;
-          }
-        }
-      }
-    }
-  }
-  return false;
-}
-
 nsHTMLContentSerializer::nsHTMLContentSerializer()
 {
     mIsHTMLSerializer = true;
 }
 
 nsHTMLContentSerializer::~nsHTMLContentSerializer()
 {
 }
@@ -258,21 +223,16 @@ nsHTMLContentSerializer::AppendElementSt
   bool forceFormat = false;
   if (!CheckElementStart(content, forceFormat, aStr)) {
     return NS_OK;
   }
 
   nsIAtom *name = content->Tag();
   PRInt32 ns = content->GetNameSpaceID();
 
-  if ((mFlags & nsIDocumentEncoder::OutputPreformatted) &&
-      IsInvisibleBreak(content, name, ns)) {
-    return NS_OK;
-  }
-
   bool lineBreakBeforeOpen = LineBreakBeforeOpen(ns, name);
 
   if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
     if (mColPos && lineBreakBeforeOpen) {
       AppendNewLineToString(aStr);
     }
     else {
       MaybeAddNewlineForRootNode(aStr);
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -100,16 +100,17 @@
 #include "nsIContentSecurityPolicy.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "jstypedarray.h"
 #include "nsStringBuffer.h"
 #include "nsDOMFile.h"
 #include "nsIFileChannel.h"
 #include "mozilla/Telemetry.h"
 #include "sampler.h"
+#include "mozilla/dom/bindings/XMLHttpRequestBinding.h"
 #include "nsIDOMFormData.h"
 
 #include "nsWrapperCacheInlines.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #define LOAD_STR "load"
@@ -478,16 +479,18 @@ nsXMLHttpRequest::nsXMLHttpRequest()
     mWarnAboutSyncHtml(false),
     mLoadLengthComputable(false), mLoadTotal(0),
     mFirstStartRequestSeen(false),
     mInLoadProgressEvent(false),
     mResultJSON(JSVAL_VOID),
     mResultArrayBuffer(nsnull)
 {
   nsLayoutStatics::AddRef();
+
+  SetIsDOMBinding();
 #ifdef DEBUG
   StaticAssertions();
 #endif
 }
 
 nsXMLHttpRequest::~nsXMLHttpRequest()
 {
   mState |= XML_HTTP_REQUEST_DELETED;
@@ -535,42 +538,42 @@ nsXMLHttpRequest::Init()
 
   nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
   nsCOMPtr<nsIPrincipal> subjectPrincipal;
   if (secMan) {
     nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
     NS_ENSURE_SUCCESS(rv, rv);
   }
   NS_ENSURE_STATE(subjectPrincipal);
-  mPrincipal = subjectPrincipal;
 
   nsIScriptContext* context = GetScriptContextFromJSContext(cx);
+  nsCOMPtr<nsPIDOMWindow> window;
   if (context) {
-    nsCOMPtr<nsPIDOMWindow> window =
-      do_QueryInterface(context->GetGlobalObject());
-    BindToOwner(window ? window->GetCurrentInnerWindow() : nsnull);
+    window = do_QueryInterface(context->GetGlobalObject());
+    if (window) {
+      window = window->GetCurrentInnerWindow();
+    }
   }
 
+  Construct(subjectPrincipal, window);
   return NS_OK;
 }
 /**
  * This Init method should only be called by C++ consumers.
  */
 NS_IMETHODIMP
 nsXMLHttpRequest::Init(nsIPrincipal* aPrincipal,
                        nsIScriptContext* aScriptContext,
                        nsPIDOMWindow* aOwnerWindow,
                        nsIURI* aBaseURI)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
-
-  mPrincipal = aPrincipal;
-  BindToOwner(aOwnerWindow ? aOwnerWindow->GetCurrentInnerWindow() : nsnull);
-  mBaseURI = aBaseURI;
-
+  Construct(aPrincipal,
+            aOwnerWindow ? aOwnerWindow->GetCurrentInnerWindow() : nsnull,
+            aBaseURI);
   return NS_OK;
 }
 
 /**
  * This Initialize method is called from XPConnect via nsIJSNativeInitializer.
  */
 NS_IMETHODIMP
 nsXMLHttpRequest::Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
@@ -581,19 +584,19 @@ nsXMLHttpRequest::Initialize(nsISupports
     NS_WARNING("Unexpected nsIJSNativeInitializer owner");
     return NS_OK;
   }
 
   // This XHR object is bound to a |window|,
   // so re-set principal and script context.
   nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal = do_QueryInterface(aOwner);
   NS_ENSURE_STATE(scriptPrincipal);
-  mPrincipal = scriptPrincipal->GetPrincipal();
-  BindToOwner(owner);
-  return NS_OK; 
+
+  Construct(scriptPrincipal->GetPrincipal(), owner);
+  return NS_OK;
 }
 
 void
 nsXMLHttpRequest::ResetResponse()
 {
   mResponseXML = nsnull;
   mResponseBody.Truncate();
   mResponseText.Truncate();
@@ -1082,16 +1085,25 @@ void
 nsXMLHttpRequest::StaticAssertions()
 {
 #define ASSERT_ENUM_EQUAL(_lc, _uc) \
   MOZ_STATIC_ASSERT(\
     bindings::prototypes::XMLHttpRequestResponseType::_lc \
       == bindings::prototypes::XMLHttpRequestResponseType::value(XML_HTTP_RESPONSE_TYPE_ ## _uc), \
     #_uc " should match")
 
+  ASSERT_ENUM_EQUAL(_empty, DEFAULT);
+  ASSERT_ENUM_EQUAL(arraybuffer, ARRAYBUFFER);
+  ASSERT_ENUM_EQUAL(blob, BLOB);
+  ASSERT_ENUM_EQUAL(document, DOCUMENT);
+  ASSERT_ENUM_EQUAL(json, JSON);
+  ASSERT_ENUM_EQUAL(text, TEXT);
+  ASSERT_ENUM_EQUAL(moz_chunked_text, CHUNKED_TEXT);
+  ASSERT_ENUM_EQUAL(moz_chunked_arraybuffer, CHUNKED_ARRAYBUFFER);
+  ASSERT_ENUM_EQUAL(moz_blob, MOZ_BLOB);
 #undef ASSERT_ENUM_EQUAL
 }
 #endif
 
 /* attribute AString responseType; */
 NS_IMETHODIMP nsXMLHttpRequest::SetResponseType(const nsAString& aResponseType)
 {
   nsXMLHttpRequest::ResponseType responseType;
@@ -1118,16 +1130,23 @@ NS_IMETHODIMP nsXMLHttpRequest::SetRespo
   }
 
   nsresult rv = NS_OK;
   SetResponseType(responseType, rv);
   return rv;
 }
 
 void
+nsXMLHttpRequest::SetResponseType(XMLHttpRequestResponseType aType,
+                                  nsresult& aRv)
+{
+  SetResponseType(ResponseType(aType), aRv);
+}
+
+void
 nsXMLHttpRequest::SetResponseType(nsXMLHttpRequest::ResponseType aResponseType,
                                   nsresult& aRv)
 {
   // If the state is not OPENED or HEADERS_RECEIVED raise an
   // INVALID_STATE_ERR exception and terminate these steps.
   if (!(mState & (XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT |
                   XML_HTTP_REQUEST_HEADERS_RECEIVED))) {
     aRv = NS_ERROR_DOM_INVALID_STATE_ERR;
@@ -2701,25 +2720,25 @@ GetRequestBody(nsIVariant* aBody, nsIInp
   string.Adopt(data, len);
 
   return GetRequestBody(string, aResult, aContentType, aCharset);
 }
 
 /* static */
 nsresult
 nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
-                                 const RequestBody* aBody,
+                                 const Nullable<RequestBody>& aBody,
                                  nsIInputStream** aResult,
                                  nsACString& aContentType, nsACString& aCharset)
 {
   if (aVariant) {
     return ::GetRequestBody(aVariant, aResult, aContentType, aCharset);
   }
 
-  const RequestBody& body = *aBody;
+  const RequestBody& body = aBody.Value();
   RequestBody::Value value = body.GetValue();
   switch (body.GetType()) {
     case nsXMLHttpRequest::RequestBody::ArrayBuffer:
     {
       return ::GetRequestBody(value.mArrayBuffer, aResult, aContentType, aCharset);
     }
     case nsXMLHttpRequest::RequestBody::Blob:
     {
@@ -2759,21 +2778,21 @@ nsXMLHttpRequest::GetRequestBody(nsIVari
   NS_NOTREACHED("Default cases exist for a reason");
   return NS_OK;
 }
 
 /* void send (in nsIVariant aBody); */
 NS_IMETHODIMP
 nsXMLHttpRequest::Send(nsIVariant *aBody)
 {
-  return Send(aBody, nsnull);
+  return Send(aBody, Nullable<RequestBody>());
 }
 
 nsresult
-nsXMLHttpRequest::Send(nsIVariant* aVariant, const RequestBody* aBody)
+nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
 {
   NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
 
   nsresult rv = CheckInnerWindowCorrectness();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Return error if we're already processing a request
   if (XML_HTTP_REQUEST_SENT & mState) {
@@ -2880,17 +2899,17 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
   mUploadTotal = 0;
   // By default we don't have any upload, so mark upload complete.
   mUploadComplete = true;
   mErrorLoad = false;
   mLoadLengthComputable = false;
   mLoadTotal = 0;
   mUploadProgress = 0;
   mUploadProgressMax = 0;
-  if ((aVariant || aBody) && httpChannel &&
+  if ((aVariant || !aBody.IsNull()) && httpChannel &&
       !method.EqualsLiteral("GET")) {
 
     nsCAutoString charset;
     nsCAutoString defaultContentType;
     nsCOMPtr<nsIInputStream> postDataStream;
 
     rv = GetRequestBody(aVariant, aBody, getter_AddRefs(postDataStream),
                         defaultContentType, charset);
@@ -3840,16 +3859,30 @@ nsXMLHttpRequest::GetInterface(const nsI
     return wwatch->GetPrompt(window, aIID,
                              reinterpret_cast<void**>(aResult));
 
   }
 
   return QueryInterface(aIID, aResult);
 }
 
+JS::Value
+nsXMLHttpRequest::GetInterface(JSContext* aCx, nsIJSIID* aIID, nsresult& aRv)
+{
+  const nsID* iid = aIID->GetID();
+  nsCOMPtr<nsISupports> result;
+  JS::Value v = JSVAL_NULL;
+  aRv = GetInterface(*iid, getter_AddRefs(result));
+  NS_ENSURE_SUCCESS(aRv, JSVAL_NULL);
+
+  JSObject* global = JS_GetGlobalForObject(aCx, GetWrapper());
+  aRv = nsContentUtils::WrapNative(aCx, global, result, iid, &v);
+  return NS_SUCCEEDED(aRv) ? v : JSVAL_NULL;
+}
+
 nsXMLHttpRequestUpload*
 nsXMLHttpRequest::GetUpload()
 {
   if (!mUpload) {
     mUpload = new nsXMLHttpRequestUpload(this);
   }
   return mUpload;
 }
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -62,124 +62,83 @@
 #include "nsIDOMNSEvent.h"
 #include "nsITimer.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsDOMProgressEvent.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsContentUtils.h"
 #include "nsDOMFile.h"
 #include "nsDOMBlobBuilder.h"
+#include "nsIPrincipal.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "mozilla/dom/bindings/XMLHttpRequestBinding.h"
+#include "mozilla/dom/bindings/XMLHttpRequestUploadBinding.h"
+
+#include "mozilla/Assertions.h"
 
 class nsILoadGroup;
 class AsyncVerifyRedirectCallbackForwarder;
 class nsIUnicodeDecoder;
 class nsIDOMFormData;
 
+#define IMPL_EVENT_HANDLER(_lowercase, _capitalized)                    \
+  JSObject* GetOn##_lowercase()                                         \
+  {                                                                     \
+    return GetListenerAsJSObject(mOn##_capitalized##Listener);          \
+  }                                                                     \
+  void SetOn##_lowercase(JSContext* aCx, JSObject* aCallback, nsresult& aRv) \
+  {                                                                     \
+    aRv = SetJSObjectListener(aCx, NS_LITERAL_STRING(#_lowercase),      \
+                              mOn##_capitalized##Listener,              \
+                              aCallback);                               \
+  }
+
 class nsXHREventTarget : public nsDOMEventTargetHelper,
                          public nsIXMLHttpRequestEventTarget
 {
 public:
+  typedef mozilla::dom::bindings::prototypes::XMLHttpRequestResponseType::value
+          XMLHttpRequestResponseType;
+
   virtual ~nsXHREventTarget() {}
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXHREventTarget,
                                            nsDOMEventTargetHelper)
   NS_DECL_NSIXMLHTTPREQUESTEVENTTARGET
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
-  JSObject* GetOnloadstart()
-  {
-    return GetListenerAsJSObject(mOnLoadStartListener);
-  }
-  JSObject* GetOnprogress()
-  {
-    return GetListenerAsJSObject(mOnProgressListener);
-  }
-  JSObject* GetOnabort()
-  {
-    return GetListenerAsJSObject(mOnAbortListener);
-  }
-  JSObject* GetOnerror()
-  {
-    return GetListenerAsJSObject(mOnErrorListener);
-  }
-  JSObject* GetOnload()
-  {
-    return GetListenerAsJSObject(mOnLoadListener);
-  }
-  JSObject* GetOntimeout()
-  {
-    return GetListenerAsJSObject(mOnTimeoutListener);
-  }
-  JSObject* GetOnloadend()
-  {
-    return GetListenerAsJSObject(mOnLoadendListener);
-  }
-  void SetOnloadstart(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("loadstart"),
-                              mOnLoadStartListener,
-                              aCallback);
-  }
-  void SetOnprogress(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("progress"),
-                              mOnProgressListener,
-                              aCallback);
-  }
-  void SetOnabort(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("abort"), mOnAbortListener,
-                              aCallback);
-  }
-  void SetOnerror(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("error"), mOnErrorListener,
-                              aCallback);
-  }
-  void SetOnload(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("load"), mOnLoadListener,
-                              aCallback);
-  }
-  void SetOntimeout(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("timeout"),
-                              mOnTimeoutListener,
-                              aCallback);
-  }
-  void SetOnloadend(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("loadend"),
-                              mOnLoadendListener,
-                              aCallback);
-  }
-
+  IMPL_EVENT_HANDLER(loadstart, LoadStart)
+  IMPL_EVENT_HANDLER(progress, Progress)
+  IMPL_EVENT_HANDLER(abort, Abort)
+  IMPL_EVENT_HANDLER(error, Error)
+  IMPL_EVENT_HANDLER(load, Load)
+  IMPL_EVENT_HANDLER(timeout, Timeout)
+  IMPL_EVENT_HANDLER(loadend, Loadend)
+  
   virtual void DisconnectFromOwner();
 protected:
   static inline JSObject* GetListenerAsJSObject(nsDOMEventListenerWrapper* aWrapper)
   {
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder =
         do_QueryInterface(aWrapper->GetInner());
     JSObject* obj;
     return holder && NS_SUCCEEDED(holder->GetJSObject(&obj)) ? obj : nsnull;
   }
-  inline nsresult SetJSObjectListener(const nsAString& aType,
+  inline nsresult SetJSObjectListener(JSContext* aCx,
+                                      const nsAString& aType,
                                       nsRefPtr<nsDOMEventListenerWrapper>& aWrapper,
                                       JSObject* aCallback)
   {
-    nsresult rv;
-    nsIScriptContext* context = GetContextForEventHandlers(&rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
     nsCOMPtr<nsIDOMEventListener> listener;
     if (aCallback) {
-      rv = nsContentUtils::XPConnect()->WrapJS(context->GetNativeContext(),
-                                               aCallback,
-                                               NS_GET_IID(nsIDOMEventListener),
-                                               getter_AddRefs(listener));
+      nsresult rv =
+        nsContentUtils::XPConnect()->WrapJS(aCx,
+                                            aCallback,
+                                            NS_GET_IID(nsIDOMEventListener),
+                                            getter_AddRefs(listener));
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return RemoveAddEventListener(aType, aWrapper, listener);
   }
 
   nsRefPtr<nsDOMEventListenerWrapper> mOnLoadListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
@@ -192,22 +151,33 @@ protected:
 
 class nsXMLHttpRequestUpload : public nsXHREventTarget,
                                public nsIXMLHttpRequestUpload
 {
 public:
   nsXMLHttpRequestUpload(nsDOMEventTargetHelper* aOwner)
   {
     BindToOwner(aOwner);
+    SetIsDOMBinding();
   }                                         
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::)
   NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
   NS_DECL_NSIXMLHTTPREQUESTUPLOAD
 
+  virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
+                               bool *triedToWrap)
+  {
+    return mozilla::dom::bindings::prototypes::XMLHttpRequestUpload::Wrap(cx, scope, this, triedToWrap);
+  }
+  nsISupports* GetParentObject()
+  {
+    return GetOwner();
+  }
+
   bool HasListeners()
   {
     return mListenerManager && mListenerManager->HasListeners();
   }
 };
 
 class nsXMLHttpRequest : public nsXHREventTarget,
                          public nsIXMLHttpRequest,
@@ -220,16 +190,53 @@ class nsXMLHttpRequest : public nsXHREve
                          public nsIJSNativeInitializer,
                          public nsITimerCallback
 {
   friend class nsXHRParseEndListener;
 public:
   nsXMLHttpRequest();
   virtual ~nsXMLHttpRequest();
 
+  virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
+                               bool *triedToWrap)
+  {
+    return mozilla::dom::bindings::prototypes::XMLHttpRequest::Wrap(cx, scope, this, triedToWrap);
+  }
+  nsISupports* GetParentObject()
+  {
+    return GetOwner();
+  }
+
+  // The WebIDL parser converts constructors into methods called _Constructor.
+  static already_AddRefed<nsXMLHttpRequest>
+  _Constructor(nsISupports* aGlobal, nsresult& aRv)
+  {
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal);
+    nsCOMPtr<nsIScriptObjectPrincipal> principal = do_QueryInterface(aGlobal);
+    if (!window || ! principal) {
+      aRv = NS_ERROR_FAILURE;
+      return NULL;
+    }
+
+    nsRefPtr<nsXMLHttpRequest> req = new nsXMLHttpRequest();
+    req->Construct(principal->GetPrincipal(), window);
+    return req.forget();
+  }
+
+  void Construct(nsIPrincipal* aPrincipal,
+                 nsPIDOMWindow* aOwnerWindow,
+                 nsIURI* aBaseURI = NULL)
+  {
+    MOZ_ASSERT(aPrincipal);
+    MOZ_ASSERT_IF(aOwnerWindow, aOwnerWindow->IsInnerWindow());
+    mPrincipal = aPrincipal;
+    BindToOwner(aOwnerWindow);
+    mBaseURI = aBaseURI;
+  }
+
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIXMLHttpRequest
   NS_DECL_NSIXMLHTTPREQUEST
 
   // nsIJSXMLHttpRequest
   NS_IMETHOD GetOnuploadprogress(nsIDOMEventListener** aOnuploadprogress);
   NS_IMETHOD SetOnuploadprogress(nsIDOMEventListener* aOnuploadprogress);
@@ -260,26 +267,17 @@ public:
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
 
 #ifdef DEBUG
   void StaticAssertions();
 #endif
 
   // event handler
-  JSObject* GetOnreadystatechange()
-  {
-    return GetListenerAsJSObject(mOnReadystatechangeListener);
-  }
-  void SetOnreadystatechange(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("readystatechange"),
-                              mOnReadystatechangeListener,
-                              aCallback);
-  }
+  IMPL_EVENT_HANDLER(readystatechange, Readystatechange)
 
   // states
   uint16_t GetReadyState();
 
   // request
   void Open(const nsAString& aMethod, const nsAString& aUrl, bool aAsync,
             const nsAString& aUser, const nsAString& aPassword, nsresult& aRv)
   {
@@ -363,31 +361,35 @@ private:
     }
 
   private:
     Type mType;
     Value mValue;
   };
 
   static nsresult GetRequestBody(nsIVariant* aVariant,
-                                 const RequestBody* aBody,
+                                 const Nullable<RequestBody>& aBody,
                                  nsIInputStream** aResult,
                                  nsACString& aContentType,
                                  nsACString& aCharset);
 
-  nsresult Send(nsIVariant* aVariant, const RequestBody* aBody);
+  nsresult Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody);
+  nsresult Send(const Nullable<RequestBody>& aBody)
+  {
+    return Send(nsnull, aBody);
+  }
   nsresult Send(const RequestBody& aBody)
   {
-    return Send(nsnull, &aBody);
+    return Send(Nullable<RequestBody>(aBody));
   }
 
 public:
   void Send(nsresult& aRv)
   {
-    aRv = Send(nsnull, nsnull);
+    aRv = Send(Nullable<RequestBody>());
   }
   void Send(JSObject* aArrayBuffer, nsresult& aRv)
   {
     NS_ASSERTION(aArrayBuffer, "Null should go to string version");
     aRv = Send(RequestBody(aArrayBuffer));
   }
   void Send(nsIDOMBlob* aBlob, nsresult& aRv)
   {
@@ -444,30 +446,38 @@ public:
     }
   }
   void GetAllResponseHeaders(nsString& aResponseHeaders);
   void OverrideMimeType(const nsAString& aMimeType)
   {
     // XXX Should we do some validation here?
     mOverrideMimeType = aMimeType;
   }
+  XMLHttpRequestResponseType GetResponseType()
+  {
+    return XMLHttpRequestResponseType(mResponseType);
+  }
+  void SetResponseType(XMLHttpRequestResponseType aType, nsresult& aRv);
   JS::Value GetResponse(JSContext* aCx, nsresult& aRv);
   void GetResponseText(nsString& aResponseText, nsresult& aRv);
   nsIDocument* GetResponseXML(nsresult& aRv);
 
   bool GetMozBackgroundRequest();
   void SetMozBackgroundRequest(bool aMozBackgroundRequest, nsresult& aRv);
   bool GetMultipart();
   void SetMultipart(bool aMultipart, nsresult& aRv);
 
   nsIChannel* GetChannel()
   {
     return mChannel;
   }
 
+  // We need a GetInterface callable from JS for chrome JS
+  JS::Value GetInterface(JSContext*aCx, nsIJSIID* aIID, nsresult& aRv);
+
   // This creates a trusted readystatechange event, which is not cancelable and
   // doesn't bubble.
   static nsresult CreateReadystatechangeEvent(nsIDOMEvent** aDOMEvent);
   // For backwards compatibility aPosition should contain the headers for upload
   // and aTotalSize is LL_MAXUINT when unknown. Both those values are
   // used by nsXMLHttpProgressEvent. Normal progress event should not use
   // headers in aLoaded and aTotal is 0 when unknown.
   void DispatchProgressEvent(nsDOMEventTargetHelper* aTarget,
@@ -707,16 +717,18 @@ protected:
   struct RequestHeader
   {
     nsCString header;
     nsCString value;
   };
   nsTArray<RequestHeader> mModifiedRequestHeaders;
 };
 
+#undef IMPL_EVENT_HANDLER
+
 // helper class to expose a progress DOM Event
 
 class nsXMLHttpProgressEvent : public nsIDOMProgressEvent,
                                public nsIDOMLSProgressEvent,
                                public nsIDOMNSEvent,
                                public nsIPrivateDOMEvent
 {
 public:
--- a/content/base/test/test_bug383430.html
+++ b/content/base/test/test_bug383430.html
@@ -20,13 +20,13 @@ https://bugzilla.mozilla.org/show_bug.cg
 /** Test for Bug 383430 **/
 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
 var req = new XMLHttpRequest();
 req.mozBackgroundRequest = true;
 req.open("GET", window.location.href);
 req.send(null);
 
-ok(req.channel.loadGroup == null, "loadGroup is null");
+ok(SpecialPowers.wrap(req).channel.loadGroup == null, "loadGroup is null");
 </script>
 </pre>
 </body>
 </html>
--- a/content/base/test/test_bug393968.html
+++ b/content/base/test/test_bug393968.html
@@ -18,18 +18,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 393968 **/
 var req = new XMLHttpRequest();
 req.open("POST", window.location.href);
 req.setRequestHeader("Content-Type", "text/plain; charset=us-ascii; boundary=01234567890");
 req.send("Some text");
 
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-is(req.channel
+is(SpecialPowers.wrap(req).channel
       .QueryInterface(Components.interfaces.nsIHttpChannel)
       .getRequestHeader("Content-Type"),
    "text/plain; charset=UTF-8; boundary=01234567890",
    "Headers should match");
 
 </script>
 </pre>
 </body>
--- a/content/base/test/test_bug397234.html
+++ b/content/base/test/test_bug397234.html
@@ -19,18 +19,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 397234 **/
 var req = new XMLHttpRequest();
 req.open("POST", window.location.href);
 // Capitalization of charet param is on purpose!
 req.setRequestHeader("Content-Type", "text/plain; charset='uTf-8'");
 req.send("Some text");
 
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-is(req.channel
+is(SpecialPowers.wrap(req).channel
       .QueryInterface(Components.interfaces.nsIHttpChannel)
       .getRequestHeader("Content-Type"),
    "text/plain; charset='uTf-8'",
    "Headers should match");
 
 </script>
 </pre>
 </body>
--- a/content/base/test/test_bug413974.html
+++ b/content/base/test/test_bug413974.html
@@ -18,18 +18,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 413974 **/
 var req = new XMLHttpRequest();
 req.open("POST", window.location.href);
 req.setRequestHeader("Content-Type", "text/plain; boundary=01234567890");
 req.send("Some text");
 
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-is(req.channel
+is(SpecialPowers.wrap(req).channel
       .QueryInterface(Components.interfaces.nsIHttpChannel)
       .getRequestHeader("Content-Type"),
    "text/plain; charset=UTF-8; boundary=01234567890",
    "Charset should come before boundary");
 </script>
 </pre>
 </body>
 </html>
--- a/content/base/test/test_bug422537.html
+++ b/content/base/test/test_bug422537.html
@@ -31,17 +31,17 @@ var body = [
   "foo",
   isupports_string
 ];
 
 for each (var i in body) {
   var xhr = new XMLHttpRequest();
   xhr.open("POST", url, true);
   xhr.send(i);
-  var chan = xhr.channel;
+  var chan = SpecialPowers.unwrap(SpecialPowers.wrap(xhr).channel);
   if (!(chan instanceof Components.interfaces.nsIUploadChannel))
     throw "Must be an upload channel";
   var stream = chan.uploadStream;
   if (!stream || !(stream instanceof Components.interfaces.nsISeekableStream))
     throw "Stream must be seekable";
   // the following is a no-op, but should not throw an exception
   stream.seek(Components.interfaces.nsISeekableStream.NS_SEEK_CUR, 0);
 }
--- a/content/base/test/test_bug431701.html
+++ b/content/base/test/test_bug431701.html
@@ -93,18 +93,17 @@ addLoadEvent(function() {
   for (var i = 0; i < tests.length; ++i) {
     doTest(i);
   }
 
   // Now check what xhr does
   var xhr = new XMLHttpRequest();
   xhr.open("POST", document.location.href);
   xhr.send(createDoc());
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  is(xhr.channel.QueryInterface(Components.interfaces.nsIHttpChannel)
+  is(SpecialPowers.wrap(xhr).channel.QueryInterface(Components.interfaces.nsIHttpChannel)
                 .getRequestHeader("Content-Type"),
      "application/xml; charset=UTF-8", "Testing correct type on the wire");
   xhr.abort();
                      
   SimpleTest.finish();
 });
 
 
--- a/content/base/test/test_bug475156.html
+++ b/content/base/test/test_bug475156.html
@@ -12,18 +12,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
 var path = "http://mochi.test:8888/tests/content/base/test/";
 
 function fromCache(xhr)
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var ch = xhr.channel.QueryInterface(Components.interfaces.nsICachingChannel);
+  var ch = SpecialPowers.wrap(xhr).channel.QueryInterface(Components.interfaces.nsICachingChannel);
   return ch.isFromCache();  
 }
 
 var tests = [
   // First just init the file with an ETag
   {
     init: function(xhr) 
     {
--- a/content/base/test/test_copypaste.html
+++ b/content/base/test/test_copypaste.html
@@ -226,16 +226,21 @@ if (false) {
   // ============ NOSCRIPT should not be copied
 
   copyChildrenToClipboard("div13");
   testSelectionToString("__");
   testClipboardValue("text/unicode", "__");
   testClipboardValue("text/html", "<div id=\"div13\">__</div>");
   testPasteText("__");
 
+  // ============ converting cell boundaries to tabs in tables
+
+  copyToClipboard($("tr1"));
+  testClipboardValue("text/unicode", "foo\tbar");
+
   // ============ manipulating Selection in oncopy
 
   copyRangeToClipboard($("div11").childNodes[0],0, $("div11").childNodes[1],2);
   testClipboardValue("text/unicode", "Xdiv11");
   testClipboardValue("text/html", "<div><p>X<span>div</span>11</p></div>");
   setTimeout(function(){testSelectionToString("div11")},0);
 
   setTimeout(function(){
@@ -315,11 +320,13 @@ x.appendChild(document.createTextNode('d
 x.appendChild(document.createTextNode('10'))
 </script>
 
 <div id="div11" oncopy="modifySelection('X')"><span>div</span>11</div>
 <div id="div12" oncopy="modifySelection('X<b style=\'display:none\'>Y</b>')"><span>div</span>12</div>
 
 <div id="div13">_<noscript>FAIL</noscript>_</div>
 
+<table><tr id=tr1><td>foo</td><td>bar</td></tr></table>
+
 </div>
 </body>
 </html>
--- a/content/base/test/test_xhr_forbidden_headers.html
+++ b/content/base/test/test_xhr_forbidden_headers.html
@@ -50,37 +50,37 @@ var i, request;
 
 // Try setting headers in unprivileged context
 request = new XMLHttpRequest();
 request.open("GET", window.location.href);
 for (i = 0; i < headers.length; i++)
   request.setRequestHeader(headers[i], "test" + i);
 
 // Read out headers
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-var channel = request.channel.QueryInterface(Components.interfaces.nsIHttpChannel);
+var channel = SpecialPowers.wrap(request).channel.QueryInterface(Components.interfaces.nsIHttpChannel);
 for (i = 0; i < headers.length; i++) {
   // Retrieving Content-Length will throw an exception
   var value = null;
   try {
     value = channel.getRequestHeader(headers[i]);
   }
   catch(e) {}
 
   isnot(value, "test" + i, "Setting " + headers[i] + " header in unprivileged context");
 }
 
 // Try setting headers in privileged context
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 request = new XMLHttpRequest();
 request.open("GET", window.location.href);
 for (i = 0; i < headers.length; i++)
   request.setRequestHeader(headers[i], "test" + i);
 
 // Read out headers
-var channel = request.channel.QueryInterface(Components.interfaces.nsIHttpChannel);
+var channel = SpecialPowers.wrap(request).channel.QueryInterface(Components.interfaces.nsIHttpChannel);
 for (i = 0; i < headers.length; i++) {
   var value = channel.getRequestHeader(headers[i]);
   is(value, "test" + i, "Setting " + headers[i] + " header in privileged context");
 }
 </script>
 </pre>
 </body>
 </html>
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -574,24 +574,16 @@ WebGLContext::InitAndValidateGL()
         mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
         mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
     } else {
         gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mGLMaxTextureSize);
         gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mGLMaxCubeMapTextureSize);
         gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
         gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
     }
-    
-#ifdef XP_MACOSX
-    if (gl->Vendor() == gl::GLContext::VendorIntel) {
-        // bug 684882, corruption in large cube maps on Intel Mac driver.
-        // Is reported to only affect Mac OS < 10.7.2 but don't want to rely on that yet.
-        mGLMaxCubeMapTextureSize = NS_MIN(mGLMaxCubeMapTextureSize, 512);
-    }
-#endif
 
     if (MinCapabilityMode()) {
         mGLMaxFragmentUniformVectors = MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS;
         mGLMaxVertexUniformVectors = MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS;
         mGLMaxVaryingVectors = MINVALUE_GL_MAX_VARYING_VECTORS;
     } else {
         if (gl->HasES2Compatibility()) {
             gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors);
--- a/content/events/src/nsDOMEventTargetHelper.h
+++ b/content/events/src/nsDOMEventTargetHelper.h
@@ -72,16 +72,37 @@ class nsDOMEventTargetHelper : public ns
 {
 public:
   nsDOMEventTargetHelper() : mOwner(nsnull), mHasOrHasHadOwner(false) {}
   virtual ~nsDOMEventTargetHelper();
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMEventTargetHelper)
 
   NS_DECL_NSIDOMEVENTTARGET
+  void AddEventListener(const nsAString& aType,
+                        nsIDOMEventListener* aCallback, // XXX nullable
+                        bool aCapture, Nullable<bool>& aWantsUntrusted,
+                        nsresult& aRv)
+  {
+    aRv = AddEventListener(aType, aCallback, aCapture,
+                           !aWantsUntrusted.IsNull() && aWantsUntrusted.Value(),
+                           aWantsUntrusted.IsNull() ? 1 : 2);
+  }
+  void RemoveEventListener(const nsAString& aType,
+                           nsIDOMEventListener* aCallback,
+                           bool aCapture, nsresult& aRv)
+  {
+    aRv = RemoveEventListener(aType, aCallback, aCapture);
+  }
+  bool DispatchEvent(nsIDOMEvent* aEvent, nsresult& aRv)
+  {
+    bool result = false;
+    aRv = DispatchEvent(aEvent, &result);
+    return result;
+  }
 
   void GetParentObject(nsIScriptGlobalObject **aParentObject)
   {
     if (mOwner) {
       CallQueryInterface(mOwner, aParentObject);
     }
     else {
       *aParentObject = nsnull;
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -272,16 +272,20 @@ public:
   static CanPlayStatus GetCanPlay(const nsAString& aType);
 
   // Returns true if we should handle this MIME type when it appears
   // as an <object> or as a toplevel page. If, in practice, our support
   // for the type is more limited than appears in the wild, we should return
   // false here even if CanHandleMediaType would return true.
   static bool ShouldHandleMediaType(const char* aMIMEType);
 
+#ifdef MOZ_RAW
+  static bool IsRawEnabled();
+#endif
+
 #ifdef MOZ_OGG
   static bool IsOggEnabled();
   static bool IsOggType(const nsACString& aType);
   static const char gOggTypes[3][16];
   static char const *const gOggCodecs[3];
 #endif
 
 #ifdef MOZ_WAVE
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -1707,24 +1707,25 @@ static const char gRawTypes[][16] = {
   "video/x-raw",
   "video/x-raw-yuv"
 };
 
 static const char* gRawCodecs[] = {
   nsnull
 };
 
-static bool IsRawEnabled()
+bool
+nsHTMLMediaElement::IsRawEnabled()
 {
   return Preferences::GetBool("media.raw.enabled");
 }
 
 static bool IsRawType(const nsACString& aType)
 {
-  if (!IsRawEnabled()) {
+  if (!nsHTMLMediaElement::IsRawEnabled()) {
     return false;
   }
 
   for (PRUint32 i = 0; i < ArrayLength(gRawTypes); ++i) {
     if (aType.EqualsASCII(gRawTypes[i])) {
       return true;
     }
   }
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -145,18 +145,16 @@ using namespace mozilla::dom;
 #include "prtime.h"
 
 // Find/Search Includes
 const PRInt32 kForward  = 0;
 const PRInt32 kBackward = 1;
 
 //#define DEBUG_charset
 
-#define NS_USE_NEW_PLAIN_TEXT 1
-
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 
 PRUint32       nsHTMLDocument::gWyciwygSessionCnt = 0;
 
 // this function will return false if the command is not recognized
 // inCommandID will be converted as necessary for internal operations
 // inParam will be converted as necessary for internal operations
 // outParam will be Empty if no parameter is needed or if returning a boolean
@@ -555,61 +553,66 @@ nsresult
 nsHTMLDocument::StartDocumentLoad(const char* aCommand,
                                   nsIChannel* aChannel,
                                   nsILoadGroup* aLoadGroup,
                                   nsISupports* aContainer,
                                   nsIStreamListener **aDocListener,
                                   bool aReset,
                                   nsIContentSink* aSink)
 {
+  if (!aCommand) {
+    MOZ_NOT_REACHED("Command is mandatory");
+    return NS_ERROR_INVALID_POINTER;
+  }
+  if (aSink) {
+    MOZ_NOT_REACHED("Got a sink override. Should not happen for HTML doc.");
+    return NS_ERROR_INVALID_ARG;
+  }
+  if (!mIsRegularHTML) {
+    MOZ_NOT_REACHED("Must not set HTML doc to XHTML mode before load start.");
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+
   nsCAutoString contentType;
   aChannel->GetContentType(contentType);
 
-  bool viewSource = aCommand && !nsCRT::strcmp(aCommand, "view-source");
-  bool plainText = (contentType.EqualsLiteral(TEXT_PLAIN) ||
+  bool view = !strcmp(aCommand, "view") ||
+              !strcmp(aCommand, "external-resource");
+  bool viewSource = !strcmp(aCommand, "view-source");
+  bool asData = !strcmp(aCommand, kLoadAsData);
+  if(!(view || viewSource || asData)) {
+    MOZ_NOT_REACHED("Bad parser command");
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  bool html = contentType.EqualsLiteral(TEXT_HTML);
+  bool xhtml = !html && contentType.Equals("application/xhtml+xml");
+  bool plainText = !html && !xhtml && (contentType.EqualsLiteral(TEXT_PLAIN) ||
     contentType.EqualsLiteral(TEXT_CSS) ||
     contentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
     contentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
     contentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
     contentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
     contentType.EqualsLiteral(TEXT_JAVASCRIPT));
-  bool loadAsHtml5 = nsHtml5Module::sEnabled || viewSource || plainText;
-  if (!NS_USE_NEW_PLAIN_TEXT && !viewSource) {
-    plainText = false;
-  }
-
-  NS_ASSERTION(!(plainText && aSink),
-               "Someone tries to load plain text into a custom sink.");
-
-  if (aSink) {
-    loadAsHtml5 = false;
+  if (!(html || xhtml || plainText || viewSource)) {
+    MOZ_NOT_REACHED("Channel with bad content type.");
+    return NS_ERROR_INVALID_ARG;
   }
 
-  if (contentType.Equals("application/xhtml+xml") && !viewSource) {
-    // We're parsing XHTML as XML, remember that.
-
-    mIsRegularHTML = false;
-    mCompatMode = eCompatibility_FullStandards;
-    loadAsHtml5 = false;
-  }
-#ifdef DEBUG
-  else {
-    NS_ASSERTION(mIsRegularHTML,
-                 "Hey, someone forgot to reset mIsRegularHTML!!!");
-  }
-#endif
-  
-  if (loadAsHtml5 && !viewSource &&
-      (!(contentType.EqualsLiteral("text/html") || plainText) &&
-      aCommand && !nsCRT::strcmp(aCommand, "view"))) {
-    loadAsHtml5 = false;
+  bool loadAsHtml5 = true;
+
+  if (!viewSource && xhtml) {
+      // We're parsing XHTML as XML, remember that.
+      mIsRegularHTML = false;
+      mCompatMode = eCompatibility_FullStandards;
+      loadAsHtml5 = false;
   }
   
   // TODO: Proper about:blank treatment is bug 543435
-  if (loadAsHtml5 && aCommand && !nsCRT::strcmp(aCommand, "view")) {
+  if (loadAsHtml5 && view) {
     // mDocumentURI hasn't been set, yet, so get the URI from the channel
     nsCOMPtr<nsIURI> uri;
     aChannel->GetOriginalURI(getter_AddRefs(uri));
     // Adapted from nsDocShell:
     // GetSpec can be expensive for some URIs, so check the scheme first.
     bool isAbout = false;
     if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
       nsCAutoString str;
@@ -617,24 +620,16 @@ nsHTMLDocument::StartDocumentLoad(const 
       if (str.EqualsLiteral("about:blank")) {
         loadAsHtml5 = false;    
       }
     }
   }
   
   CSSLoader()->SetCompatibilityMode(mCompatMode);
   
-  bool needsParser = true;
-  if (aCommand)
-  {
-    if (!nsCRT::strcmp(aCommand, "view delayedContentLoad")) {
-      needsParser = false;
-    }
-  }
-
   nsresult rv = nsDocument::StartDocumentLoad(aCommand,
                                               aChannel, aLoadGroup,
                                               aContainer,
                                               aDocListener, aReset);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
@@ -644,34 +639,32 @@ nsHTMLDocument::StartDocumentLoad(const 
   nsCOMPtr<nsIURI> uri;
   rv = aChannel->GetURI(getter_AddRefs(uri));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   nsCOMPtr<nsICachingChannel> cachingChan = do_QueryInterface(aChannel);
 
-  if (needsParser) {
-    if (loadAsHtml5) {
-      mParser = nsHtml5Module::NewHtml5Parser();
-      if (plainText) {
-        if (viewSource) {
-          mParser->MarkAsNotScriptCreated("view-source-plain");
-        } else {
-          mParser->MarkAsNotScriptCreated("plain-text");
-        }
-      } else if (viewSource && !contentType.EqualsLiteral("text/html")) {
-        mParser->MarkAsNotScriptCreated("view-source-xml");
+  if (loadAsHtml5) {
+    mParser = nsHtml5Module::NewHtml5Parser();
+    if (plainText) {
+      if (viewSource) {
+        mParser->MarkAsNotScriptCreated("view-source-plain");
       } else {
-        mParser->MarkAsNotScriptCreated(aCommand);
+        mParser->MarkAsNotScriptCreated("plain-text");
       }
+    } else if (viewSource && !html) {
+      mParser->MarkAsNotScriptCreated("view-source-xml");
     } else {
-      mParser = do_CreateInstance(kCParserCID, &rv);
-      NS_ENSURE_SUCCESS(rv, rv);
+      mParser->MarkAsNotScriptCreated(aCommand);
     }
+  } else {
+    mParser = do_CreateInstance(kCParserCID, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   PRInt32 textType = GET_BIDI_OPTION_TEXTTYPE(GetBidiOptions());
 
   // Look for the parent document.  Note that at this point we don't have our
   // content viewer set up yet, and therefore do not have a useful
   // mParentDocument.
 
@@ -847,65 +840,48 @@ nsHTMLDocument::StartDocumentLoad(const 
                  "How did those end up different here?  wyciwyg channels are "
                  "not nsICachingChannel");
     rv = cachingChan->SetCacheTokenCachedCharset(charset);
     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "cannot SetMetaDataElement");
     rv = NS_OK; // don't propagate error
   }
 
   // Set the parser as the stream listener for the document loader...
-  if (mParser) {
-    rv = NS_OK;
-    nsCOMPtr<nsIStreamListener> listener = mParser->GetStreamListener();
-    listener.forget(aDocListener);
+  rv = NS_OK;
+  nsCOMPtr<nsIStreamListener> listener = mParser->GetStreamListener();
+  listener.forget(aDocListener);
 
 #ifdef DEBUG_charset
-    printf(" charset = %s source %d\n",
-          charset.get(), charsetSource);
+  printf(" charset = %s source %d\n",
+        charset.get(), charsetSource);
 #endif
-    mParser->SetDocumentCharset(parserCharset, parserCharsetSource);
-    mParser->SetCommand(aCommand);
-
-    // create the content sink
-    nsCOMPtr<nsIContentSink> sink;
-
-    if (aSink) {
-      NS_ASSERTION(!loadAsHtml5, "Panic: We are loading as HTML5 and someone tries to set an external sink!");
-      sink = aSink;
+  mParser->SetDocumentCharset(parserCharset, parserCharsetSource);
+  mParser->SetCommand(aCommand);
+
+  if (!IsHTML()) {
+    MOZ_ASSERT(!loadAsHtml5);
+    nsCOMPtr<nsIXMLContentSink> xmlsink;
+    NS_NewXMLContentSink(getter_AddRefs(xmlsink), this, uri,
+                         docShell, aChannel);
+    mParser->SetContentSink(xmlsink);
+  } else {
+    if (loadAsHtml5) {
+      nsHtml5Module::Initialize(mParser, this, uri, docShell, aChannel);
     } else {
-      if (!IsHTML()) {
-        nsCOMPtr<nsIXMLContentSink> xmlsink;
-        rv = NS_NewXMLContentSink(getter_AddRefs(xmlsink), this, uri,
-                                  docShell, aChannel);
-
-        sink = xmlsink;
-      } else {
-        if (loadAsHtml5) {
-          nsHtml5Module::Initialize(mParser, this, uri, docShell, aChannel);
-          sink = mParser->GetContentSink();
-        } else {
-          nsCOMPtr<nsIHTMLContentSink> htmlsink;
-
-          rv = NS_NewHTMLContentSink(getter_AddRefs(htmlsink), this, uri,
-                                     docShell, aChannel);
-
-          sink = htmlsink;
-        }
-      }
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      NS_ASSERTION(sink,
-                   "null sink with successful result from factory method");
+      // about:blank *only*
+      nsCOMPtr<nsIHTMLContentSink> htmlsink;
+      NS_NewHTMLContentSink(getter_AddRefs(htmlsink), this, uri,
+                            docShell, aChannel);
+      mParser->SetContentSink(htmlsink);
     }
-
-    mParser->SetContentSink(sink);
-    // parser the content of the URI
-    mParser->Parse(uri, nsnull, (void *)this);
   }
 
+  // parser the content of the URI
+  mParser->Parse(uri, nsnull, (void *)this);
+
   return rv;
 }
 
 void
 nsHTMLDocument::StopDocumentLoad()
 {
   BlockOnload();
 
@@ -1555,45 +1531,23 @@ nsHTMLDocument::Open(const nsAString& aC
     mDocumentBaseURI = baseURI;
   }
 
   // Store the security info of the caller now that we're done
   // resetting the document.
   mSecurityInfo = securityInfo;
 
   mParserAborted = false;
-  bool loadAsHtml5 = nsHtml5Module::sEnabled;
-  if (loadAsHtml5) {
-    mParser = nsHtml5Module::NewHtml5Parser();
-    rv = NS_OK;
-  } else {
-    mParser = do_CreateInstance(kCParserCID, &rv);  
-  }
+  mParser = nsHtml5Module::NewHtml5Parser();
+  nsHtml5Module::Initialize(mParser, this, uri, shell, channel);
+  rv = NS_OK;
 
   // This will be propagated to the parser when someone actually calls write()
   SetContentTypeInternal(contentType);
 
-  if (NS_SUCCEEDED(rv)) {
-    if (loadAsHtml5) {
-      nsHtml5Module::Initialize(mParser, this, uri, shell, channel);
-    } else {
-      nsCOMPtr<nsIHTMLContentSink> sink;
-
-      rv = NS_NewHTMLContentSink(getter_AddRefs(sink), this, uri, shell,
-                                 channel);
-      if (NS_FAILED(rv)) {
-        // Don't use a parser without a content sink.
-        mParser = nsnull;
-        return rv;
-      }
-
-      mParser->SetContentSink(sink);
-    }
-  }
-
   // Prepare the docshell and the document viewer for the impending
   // out of band document.write()
   shell->PrepareForNewContentModel();
 
   // Now check whether we were opened with a "replace" argument.  If
   // so, we need to tell the docshell to not create a new history
   // entry for this load. Otherwise, make sure that we're doing a normal load,
   // not whatever type of load was previously done on this docshell.
@@ -2266,31 +2220,27 @@ nsHTMLDocument::GenerateParserKey(void)
   if (!mScriptLoader) {
     // If we don't have a script loader, then the parser probably isn't parsing
     // anything anyway, so just return null.
     return nsnull;
   }
 
   // The script loader provides us with the currently executing script element,
   // which is guaranteed to be unique per script.
-  if (nsHtml5Module::sEnabled) {
-    nsIScriptElement* script = mScriptLoader->GetCurrentParserInsertedScript();
-    if (script && mParser && mParser->IsScriptCreated()) {
-      nsCOMPtr<nsIParser> creatorParser = script->GetCreatorParser();
-      if (creatorParser != mParser) {
-        // Make scripts that aren't inserted by the active parser of this document
-        // participate in the context of the script that document.open()ed 
-        // this document.
-        return nsnull;
-      }
+  nsIScriptElement* script = mScriptLoader->GetCurrentParserInsertedScript();
+  if (script && mParser && mParser->IsScriptCreated()) {
+    nsCOMPtr<nsIParser> creatorParser = script->GetCreatorParser();
+    if (creatorParser != mParser) {
+      // Make scripts that aren't inserted by the active parser of this document
+      // participate in the context of the script that document.open()ed
+      // this document.
+      return nsnull;
     }
-    return script;
-  } else {
-    return mScriptLoader->GetCurrentScript();
   }
+  return script;
 }
 
 /* attribute DOMString designMode; */
 NS_IMETHODIMP
 nsHTMLDocument::GetDesignMode(nsAString & aDesignMode)
 {
   if (HasFlag(NODE_IS_EDITABLE)) {
     aDesignMode.AssignLiteral("on");
--- a/content/media/ogg/nsOggDecoder.h
+++ b/content/media/ogg/nsOggDecoder.h
@@ -39,13 +39,18 @@
 #if !defined(nsOggDecoder_h_)
 #define nsOggDecoder_h_
 
 #include "nsBuiltinDecoder.h"
 
 class nsOggDecoder : public nsBuiltinDecoder
 {
 public:
-  virtual nsMediaDecoder* Clone() { return new nsOggDecoder(); }
+  virtual nsMediaDecoder* Clone() {
+    if (!nsHTMLMediaElement::IsOggEnabled()) {
+      return nsnull;
+    }
+    return new nsOggDecoder();
+  }
   virtual nsDecoderStateMachine* CreateStateMachine();
 };
 
 #endif
--- a/content/media/raw/nsRawDecoder.h
+++ b/content/media/raw/nsRawDecoder.h
@@ -37,13 +37,18 @@
 #if !defined(nsRawDecoder_h_)
 #define nsRawDecoder_h_
 
 #include "nsBuiltinDecoder.h"
 
 class nsRawDecoder : public nsBuiltinDecoder
 {
 public:
-  virtual nsMediaDecoder* Clone() { return new nsRawDecoder(); }
+  virtual nsMediaDecoder* Clone() { 
+    if (!nsHTMLMediaElement::IsRawEnabled()) {
+      return nsnull;
+    }    
+    return new nsRawDecoder();
+  }
   virtual nsDecoderStateMachine* CreateStateMachine();
 };
 
 #endif
--- a/content/media/wave/nsWaveDecoder.h
+++ b/content/media/wave/nsWaveDecoder.h
@@ -50,13 +50,18 @@
  * require extending nsWaveDecoder to support parsing the newer
  * WAVE_FORMAT_EXTENSIBLE chunk format.
 **/
 
 
 class nsWaveDecoder : public nsBuiltinDecoder
 {
 public:
-   virtual nsMediaDecoder* Clone() { return new nsWaveDecoder(); }
-   virtual nsDecoderStateMachine* CreateStateMachine();
+  virtual nsMediaDecoder* Clone() {
+    if (!nsHTMLMediaElement::IsWaveEnabled()) {
+      return nsnull;
+    }
+    return new nsWaveDecoder();
+  }
+  virtual nsDecoderStateMachine* CreateStateMachine();
 };
 
 #endif
--- a/content/media/webm/nsWebMDecoder.h
+++ b/content/media/webm/nsWebMDecoder.h
@@ -39,13 +39,18 @@
 #if !defined(nsWebMDecoder_h_)
 #define nsWebMDecoder_h_
 
 #include "nsBuiltinDecoder.h"
 
 class nsWebMDecoder : public nsBuiltinDecoder
 {
 public:
-  virtual nsMediaDecoder* Clone() { return new nsWebMDecoder(); }
+  virtual nsMediaDecoder* Clone() {
+    if (!nsHTMLMediaElement::IsWebMEnabled()) {
+      return nsnull;
+    }
+    return new nsWebMDecoder();
+  }
   virtual nsDecoderStateMachine* CreateStateMachine();
 };
 
 #endif
--- a/content/xbl/src/Makefile.in
+++ b/content/xbl/src/Makefile.in
@@ -85,11 +85,12 @@ LOCAL_INCLUDES	= \
 		-I$(srcdir)/../../html/document/src \
 		-I$(srcdir)/../../xml/document/src \
 		-I$(srcdir)/../../xul/content/src \
 		-I$(srcdir)/../../xul/document/src \
 		-I$(srcdir)/../../events/src \
 		-I$(srcdir)/../../../layout/style \
 		-I$(srcdir)/../../../dom/base \
 		-I$(topsrcdir)/xpcom/ds \
+		-I$(topsrcdir)/js/xpconnect/src \
 		$(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/content/xbl/src/nsXBLDocumentInfo.cpp
+++ b/content/xbl/src/nsXBLDocumentInfo.cpp
@@ -54,20 +54,23 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsContentUtils.h"
 #include "nsDOMJSUtils.h"
 #include "mozilla/Services.h"
 #include "xpcpublic.h"
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 #include "nsCCUncollectableMarker.h"
+#include "mozilla/dom/bindings/Utils.h"
 
 using namespace mozilla::scache;
 using namespace mozilla;
 
+using mozilla::dom::bindings::DestroyProtoOrIfaceCache;
+
 static const char kXBLCachePrefix[] = "xblcache";
 
 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 // An XBLDocumentInfo object has a special context associated with it which we can use to pre-compile 
 // properties and methods of XBL bindings against.
 class nsXBLDocGlobalObject : public nsIScriptGlobalObject,
                              public nsIScriptObjectPrincipal
@@ -175,16 +178,18 @@ nsXBLDocGlobalObject_finalize(JSContext 
 
   nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeThis));
 
   if (sgo)
     sgo->OnFinalize(obj);
 
   // The addref was part of JSObject construction
   NS_RELEASE(nativeThis);
+
+  DestroyProtoOrIfaceCache(obj);
 }
 
 static JSBool
 nsXBLDocGlobalObject_resolve(JSContext *cx, JSObject *obj, jsid id)
 {
   JSBool did_resolve = JS_FALSE;
   return JS_ResolveStandardClass(cx, obj, id, &did_resolve);
 }
--- a/content/xul/document/src/Makefile.in
+++ b/content/xul/document/src/Makefile.in
@@ -71,11 +71,13 @@ LOCAL_INCLUDES	= -I$(srcdir)/../../../ba
 		  -I$(srcdir)/../../../../layout/base \
 		  -I$(srcdir)/../../../../layout/generic \
 		  -I$(srcdir)/../../../../layout/style \
 		  -I$(srcdir)/../../../../layout/xul/base/src \
 		  -I$(srcdir)/../../../xml/document/src \
 		  -I$(srcdir)/../../../xbl/src \
 		  -I$(srcdir)/../../../events/src \
 		  -I$(topsrcdir)/xpcom/ds \
+		  -I$(topsrcdir)/js/xpconnect/src \
+		  -I$(topsrcdir)/dom/base \
 		  $(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -61,16 +61,19 @@
 #include "mozilla/FunctionTimer.h"
 #include "nsIDOMScriptObjectFactory.h"
 #include "nsDOMCID.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentUtils.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
 #include "xpcpublic.h"
+#include "mozilla/dom/bindings/Utils.h"
+
+using mozilla::dom::bindings::DestroyProtoOrIfaceCache;
 
 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
                      NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 
 class nsXULPDGlobalObject : public nsIScriptGlobalObject,
                             public nsIScriptObjectPrincipal
 {
@@ -124,16 +127,18 @@ nsXULPDGlobalObject_finalize(JSContext *
     nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeThis));
 
     if (sgo) {
         sgo->OnFinalize(obj);
     }
 
     // The addref was part of JSObject construction
     NS_RELEASE(nativeThis);
+
+    DestroyProtoOrIfaceCache(obj);
 }
 
 
 JSBool
 nsXULPDGlobalObject_resolve(JSContext *cx, JSObject *obj, jsid id)
 {
     JSBool did_resolve = JS_FALSE;
 
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -71,16 +71,17 @@ DIRS = \
   $(NULL)
 
 DIRS += \
   interfaces/apps \
   $(NULL)
 
 DIRS += \
   base \
+  bindings \
   battery \
   contacts \
   power \
   settings \
   sms \
   src \
   locales \
   network \
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -943,17 +943,17 @@ NS_IMETHODIMP Navigator::GetMozNotificat
 
 NS_IMETHODIMP
 Navigator::GetMozBattery(nsIDOMMozBatteryManager** aBattery)
 {
   if (!mBatteryManager) {
     *aBattery = nsnull;
 
     nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
-    NS_ENSURE_TRUE(win->GetDocShell(), NS_OK);
+    NS_ENSURE_TRUE(win && win->GetDocShell(), NS_OK);
 
     mBatteryManager = new battery::BatteryManager();
     mBatteryManager->Init(win);
   }
 
   NS_ADDREF(*aBattery = mBatteryManager);
 
   return NS_OK;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -52,16 +52,18 @@
 #include "jsprvtd.h"    // we are using private JS typedefs...
 #include "jsdbgapi.h"
 #include "WrapperFactory.h"
 #include "AccessCheck.h"
 
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
 
+#include "mozilla/dom/bindings/Common.h"
+
 #include "nscore.h"
 #include "nsDOMClassInfo.h"
 #include "nsCRT.h"
 #include "nsCRTGlue.h"
 #include "nsIServiceManager.h"
 #include "nsICategoryManager.h"
 #include "nsIComponentRegistrar.h"
 #include "nsXPCOM.h"
@@ -635,34 +637,32 @@ DOMCI_DATA(DOMConstructor, void)
     nsnull,                                                                   \
     nsnull,                                                                   \
     nsnull,                                                                   \
     _flags,                                                                   \
     true,                                                                  \
     0,                                                                        \
     false,                                                                 \
     false,                                                                 \
-    NULL,                                                                     \
     NS_DEFINE_CLASSINFO_DATA_DEBUG(_class)                                    \
   },
 
 #define NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA_WITH_NAME(_class, _name,         \
                                                        _helper, _flags)       \
   { #_name,                                                                   \
     nsnull,                                                                   \
     { _helper::doCreate },                                                    \
     nsnull,                                                                   \
     nsnull,                                                                   \
     nsnull,                                                                   \
     _flags,                                                                   \
     true,                                                                  \
     0,                                                                        \
     true,                                                                  \
     false,                                                                 \
-    NULL,                                                                     \
     NS_DEFINE_CLASSINFO_DATA_DEBUG(_class)                                    \
   },
 
 #define NS_DEFINE_CLASSINFO_DATA(_class, _helper, _flags)                     \
   NS_DEFINE_CLASSINFO_DATA_WITH_NAME(_class, _class, _helper, _flags)
 
 #define NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(_class, _helper, _flags)          \
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA_WITH_NAME(_class, _class, _helper, \
@@ -4479,17 +4479,21 @@ nsDOMClassInfo::Init()
   RegisterExternalClasses();
 
   sDisableDocumentAllSupport =
     Preferences::GetBool("browser.dom.document.all.disabled");
 
   sDisableGlobalScopePollutionSupport =
     Preferences::GetBool("browser.dom.global_scope_pollution.disabled");
 
-  mozilla::dom::binding::Register(sClassInfoData);
+  // Proxy bindings
+  mozilla::dom::binding::Register(nameSpaceManager);
+
+  // Non-proxy bindings
+  mozilla::dom::bindings::Register(nameSpaceManager);
 
   sIsInitialized = true;
 
   return NS_OK;
 }
 
 // static
 PRInt32
@@ -6585,16 +6589,25 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
       return rv;
     }
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeInterface) {
     // We're resolving a name of a DOM interface for which there is no
     // direct DOM class, create a constructor object...
 
+    // Lookup new DOM bindings.
+    mozilla::dom::binding::DefineInterface define =
+      name_struct->mDefineDOMInterface;
+    if (define && mozilla::dom::binding::DefineConstructor(cx, obj, define, &rv)) {
+      *did_resolve = NS_SUCCEEDED(rv);
+
+      return rv;
+    }
+
     nsRefPtr<nsDOMConstructor> constructor;
     rv = nsDOMConstructor::Create(class_name,
                                   nsnull,
                                   name_struct,
                                   static_cast<nsPIDOMWindow*>(aWin),
                                   getter_AddRefs(constructor));
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -6642,17 +6655,17 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
       if (!nsEventSource::PrefEnabled()) {
         return NS_OK;
       }
     }
 
     // Lookup new DOM bindings.
     if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
       mozilla::dom::binding::DefineInterface define =
-        sClassInfoData[name_struct->mDOMClassInfoID].mDefineDOMInterface;
+        name_struct->mDefineDOMInterface;
       if (define && mozilla::dom::binding::DefineConstructor(cx, obj, define, &rv)) {
         *did_resolve = NS_SUCCEEDED(rv);
 
         return rv;
       }
     }
 
     // Create the XPConnect prototype for our classinfo, PostCreateProto will
@@ -6681,16 +6694,26 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
     *did_resolve = NS_SUCCEEDED(rv);
 
     return rv;
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
     // We don't have a XPConnect prototype object, let ResolvePrototype create
     // one.
+
+    // Lookup new DOM bindings.
+    mozilla::dom::binding::DefineInterface define =
+      name_struct->mDefineDOMInterface;
+    if (define && mozilla::dom::binding::DefineConstructor(cx, obj, define, &rv)) {
+      *did_resolve = NS_SUCCEEDED(rv);
+
+      return rv;
+    }
+
     return ResolvePrototype(sXPConnect, aWin, cx, obj, class_name, nsnull,
                             name_struct, nameSpaceManager, nsnull, true,
                             did_resolve);
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
     const nsGlobalNameStruct *alias_struct =
       nameSpaceManager->GetConstructorProto(name_struct);
@@ -7851,20 +7874,16 @@ nsEventTargetSH::PreCreate(nsISupports *
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEventTargetSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                              JSObject *obj, jsid id, jsval *vp, bool *_retval)
 {
-  if (id == sAddEventListener_id) {
-    return NS_OK;
-  }
-
   nsEventTargetSH::PreserveWrapper(GetNative(wrapper, obj));
 
   return NS_OK;
 }
 
 void
 nsEventTargetSH::PreserveWrapper(nsISupports *aNative)
 {
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -98,18 +98,16 @@ struct nsDOMClassInfoData
                                   // so be sure to mask if necessary!
   const nsIID *mProtoChainInterface;
   const nsIID **mInterfaces;
   PRUint32 mScriptableFlags : 31; // flags must not use more than 31 bits!
   PRUint32 mHasClassInterface : 1;
   PRUint32 mInterfacesBitmap;
   bool mChromeOnly;
   bool mDisabled;
-  // For new style DOM bindings.
-  mozilla::dom::binding::DefineInterface mDefineDOMInterface;
 #ifdef NS_DEBUG
   PRUint32 mDebugID;
 #endif
 };
 
 struct nsExternalDOMClassInfoData : public nsDOMClassInfoData
 {
   const nsCID *mConstructorCID;
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -103,16 +103,17 @@
 #define FORCE_PR_LOG 1
 #endif
 #include "prlog.h"
 #include "prthread.h"
 
 #include "mozilla/FunctionTimer.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/dom/bindings/Utils.h"
 
 #include "sampler.h"
 
 using namespace mozilla;
 
 const size_t gStackSize = 8192;
 
 #ifdef PR_LOGGING
@@ -2008,22 +2009,26 @@ nsJSContext::GetGlobalObject()
     // If this assertion hits then it means that we have a window object as
     // our global, but we never called CreateOuterObject.
     NS_ASSERTION(inner == global, "Shouldn't be able to innerize here");
   }
 #endif
 
   JSClass *c = JS_GetClass(global);
 
-  if (!c || ((~c->flags) & (JSCLASS_HAS_PRIVATE |
-                            JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
+  // Whenever we end up with globals that are JSCLASS_IS_DOMJSCLASS
+  // and have an nsISupports DOM object, we will need to modify this
+  // check here.
+  MOZ_ASSERT(!(c->flags & JSCLASS_IS_DOMJSCLASS));
+  if ((~c->flags) & (JSCLASS_HAS_PRIVATE |
+                     JSCLASS_PRIVATE_IS_NSISUPPORTS)) {
     return nsnull;
   }
-
-  nsISupports *priv = (nsISupports *)js::GetObjectPrivate(global);
+  
+  nsISupports *priv = static_cast<nsISupports*>(js::GetObjectPrivate(global));
 
   nsCOMPtr<nsIXPConnectWrappedNative> wrapped_native =
     do_QueryInterface(priv);
 
   nsCOMPtr<nsIScriptGlobalObject> sgo;
   if (wrapped_native) {
     // The global object is a XPConnect wrapped native, the native in
     // the wrapper might be the nsIScriptGlobalObject
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -56,16 +56,18 @@
 #include "nsIXPConnect.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsPIDOMWindow.h"
 
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
 
+#include "mozilla/dom/bindings/Utils.h"
+
 JSBool
 nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
                               PRUint32* aLineno)
 {
   // Get the current filename and line number
   JSStackFrame* frame = nsnull;
   JSScript* script = nsnull;
   do {
@@ -94,30 +96,33 @@ nsJSUtils::GetCallingLocation(JSContext*
   }
 
   return JS_FALSE;
 }
 
 nsIScriptGlobalObject *
 nsJSUtils::GetStaticScriptGlobal(JSContext* aContext, JSObject* aObj)
 {
-  nsISupports* supports;
   JSClass* clazz;
   JSObject* glob = aObj; // starting point for search
 
   if (!glob)
     return nsnull;
 
   glob = JS_GetGlobalForObject(aContext, glob);
   NS_ABORT_IF_FALSE(glob, "Infallible returns null");
 
   clazz = JS_GetClass(glob);
 
-  if (!clazz ||
-      !(clazz->flags & JSCLASS_HAS_PRIVATE) ||
+  // Whenever we end up with globals that are JSCLASS_IS_DOMJSCLASS
+  // and have an nsISupports DOM object, we will need to modify this
+  // check here.
+  MOZ_ASSERT(!(clazz->flags & JSCLASS_IS_DOMJSCLASS));
+  nsISupports* supports;
+  if (!(clazz->flags & JSCLASS_HAS_PRIVATE) ||
       !(clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) ||
       !(supports = (nsISupports*)::JS_GetPrivate(glob))) {
     return nsnull;
   }
 
   // We might either have a window directly (e.g. if the global is a
   // sandbox whose script object principal pointer is a window), or an
   // XPCWrappedNative for a window.  We could also have other
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -798,8 +798,17 @@ nsScriptNameSpaceManager::Observe(nsISup
 
   // TODO: we could observe NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID
   // and NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID but we are safe without it.
   // See bug 600460.
 
   return NS_OK;
 }
 
+void
+nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAString& aName,
+    mozilla::dom::binding::DefineInterface aDefineDOMInterface)
+{
+  nsGlobalNameStruct* s = LookupNameInternal(aName);
+  if (s) {
+    s->mDefineDOMInterface = aDefineDOMInterface;
+  }
+}
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -92,16 +92,19 @@ struct nsGlobalNameStruct
   union {
     PRInt32 mDOMClassInfoID; // eTypeClassConstructor
     nsIID mIID; // eTypeInterface, eTypeClassProto
     nsExternalDOMClassInfoData* mData; // eTypeExternalClassInfo
     ConstructorAlias* mAlias; // eTypeExternalConstructorAlias
     nsCID mCID; // All other types...
   };
 
+  // For new style DOM bindings.
+  mozilla::dom::binding::DefineInterface mDefineDOMInterface;
+
 private:
 
   // copy constructor
 };
 
 
 class nsIScriptContext;
 class nsICategoryManager;
@@ -161,17 +164,20 @@ public:
                              const nsIID *aProtoChainInterface,
                              const nsIID **aInterfaces,
                              PRUint32 aScriptableFlags,
                              bool aHasClassInterface,
                              const nsCID *aConstructorCID);
 
   nsGlobalNameStruct* GetConstructorProto(const nsGlobalNameStruct* aStruct);
 
-protected:
+  void RegisterDefineDOMInterface(const nsAString& aName,
+    mozilla::dom::binding::DefineInterface aDefineDOMInterface);
+
+private:
   // Adds a new entry to the hash and returns the nsGlobalNameStruct
   // that aKey will be mapped to. If mType in the returned
   // nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey
   // already existed.
   nsGlobalNameStruct *AddToHash(PLDHashTable *aTable, const char *aKey,
                                 const PRUnichar **aClassName = nsnull);
 
   nsresult FillHash(nsICategoryManager *aCategoryManager,
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -42,16 +42,26 @@
 #include "nsCycleCollectionParticipant.h"
 
 struct JSObject;
 struct JSContext;
 class XPCWrappedNativeScope;
 
 typedef PRUptrdiff PtrBits;
 
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+class DOMBindingBase;
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
+
 #define NS_WRAPPERCACHE_IID \
 { 0x6f3179a1, 0x36f7, 0x4a5c, \
   { 0x8c, 0xf1, 0xad, 0xc8, 0x7c, 0xde, 0x3e, 0x87 } }
 
 /**
  * Class to store the wrapper for an object. This can only be used with objects
  * that only have one non-security wrapper at a time (for an XPCWrappedNative
  * this is usually ensured by setting an explicit parent in the PreCreate hook
@@ -67,26 +77,28 @@ typedef PRUptrdiff PtrBits;
  * object in the cache.
  *
  * The cache can store 2 types of objects:
  *
  *  If WRAPPER_IS_DOM_BINDING is not set (IsDOMBinding() returns false):
  *    - a slim wrapper or the JSObject of an XPCWrappedNative wrapper
  *
  *  If WRAPPER_IS_DOM_BINDING is set (IsDOMBinding() returns true):
- *    - a DOM binding object (proxy)
+ *    - a DOM binding object (regular JS object or proxy)
  *
  * The finalizer for the wrapper clears the cache.
  *
  * A number of the methods are implemented in nsWrapperCacheInlines.h because we
  * have to include some JS headers that don't play nicely with the rest of the
  * codebase. Include nsWrapperCacheInlines.h if you need to call those methods.
  */
 class nsWrapperCache
 {
+  friend class mozilla::dom::workers::DOMBindingBase;
+
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_WRAPPERCACHE_IID)
 
   nsWrapperCache() : mWrapperPtrBits(0)
   {
   }
   ~nsWrapperCache()
   {
@@ -212,17 +224,17 @@ private:
    * NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER,
    * NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS and
    * NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER).
    */
   enum { WRAPPER_BIT_PRESERVED = 1 << 0 };
 
   /**
    * If this bit is set then the wrapper for the native object is a DOM binding
-   * (proxy).
+   * (regular JS object or proxy).
    */
   enum { WRAPPER_IS_DOM_BINDING = 1 << 1 };
 
   enum { kWrapperBitMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_DOM_BINDING) };
 
   PtrBits mWrapperPtrBits;
 };
 
new file mode 100644
--- /dev/null
+++ b/dom/bindings/BindingGen.py
@@ -0,0 +1,73 @@
+# 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 Configuration import *
+from Codegen import CGBindingRoot, replaceFileIfChanged
+# import Codegen in general, so we can set a variable on it
+import Codegen
+
+def generate_binding_header(config, outputprefix, webidlfile):
+    """
+    |config| Is the configuration object.
+    |outputprefix| is a prefix to use for the header guards and filename.
+    """
+
+    filename = outputprefix + ".h"
+    root = CGBindingRoot(config, outputprefix, webidlfile)
+    if replaceFileIfChanged(filename, root.declare()):
+        print "Generating binding header: %s" % (filename)
+
+def generate_binding_cpp(config, outputprefix, webidlfile):
+    """
+    |config| Is the configuration object.
+    |outputprefix| is a prefix to use for the header guards and filename.
+    """
+
+    filename = outputprefix + ".cpp"
+    root = CGBindingRoot(config, outputprefix, webidlfile)
+    if replaceFileIfChanged(filename, root.define()):
+        print "Generating binding implementation: %s" % (filename)
+
+def main():
+
+    # Parse arguments.
+    from optparse import OptionParser
+    usagestring = "usage: %prog [header|cpp] configFile outputPrefix webIDLFile"
+    o = OptionParser(usage=usagestring)
+    o.add_option("--verbose-errors", action='store_true', default=False,
+                 help="When an error happens, display the Python traceback.")
+    o.add_option("--use-jsop-accessors", action='store_true', default=False,
+                 dest='useJSOPAccessors',
+                 help="Use JSPropertyOps instead of JSNatives for getters and setters")
+    (options, args) = o.parse_args()
+    Codegen.generateNativeAccessors = not options.useJSOPAccessors
+
+    if len(args) != 4 or (args[0] != "header" and args[0] != "cpp"):
+        o.error(usagestring)
+    buildTarget = args[0]
+    configFile = os.path.normpath(args[1])
+    outputPrefix = args[2]
+    webIDLFile = os.path.normpath(args[3])
+
+    # Load the parsing results
+    f = open('ParserResults.pkl', 'rb')
+    parserData = cPickle.load(f)
+    f.close()
+
+    # Create the configuration data.
+    config = Configuration(configFile, parserData)
+
+    # Generate the prototype classes.
+    if buildTarget == "header":
+        generate_binding_header(config, outputPrefix, webIDLFile);
+    elif buildTarget == "cpp":
+        generate_binding_cpp(config, outputPrefix, webIDLFile);
+    else:
+        assert False # not reached
+
+if __name__ == '__main__':
+    main()
new file mode 100644
--- /dev/null
+++ b/dom/bindings/Bindings.conf
@@ -0,0 +1,233 @@
+# 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.
+#
+# Valid fields for all descriptors:
+#   * nativeType - The native type (concrete class or XPCOM interface) that
+#                  instances of this interface will unwrap to (required).
+#   * headerFile - The file in which the nativeType is declared (defaults
+#                  to an educated guess).
+#   * castable - Indicates whether the value in the wrapper can be cast to
+#                nativeType, or whether it needs to be QI-ed (defaults to True
+#                for everything but callback interfaces).
+#   * concrete - Indicates whether there exist objects with this interface as
+#                their primary interface (defaults to True).
+#   * prefable - Indicates whether this binding is subject to the about:config
+#                pref, or whether it's always enabled (defaults to False).
+#   * workers - Indicates whether the descriptor is intended to be used for
+#               worker threads (defaults to false).
+#   * customTrace - The native class will use a custom trace hook (defaults to
+#                   true for workers, false otherwise).
+#   * customFinalize - The native class will use a custom finalize hook
+#                      (defaults to true for workers, false otherwise).
+#   * notflattened - The native type does not have nsIClassInfo, so when
+#                    wrapping it the right IID needs to be passed in.
+#
+#   The following fields are either a string, an array (defaults to an empty
+#   array) or a dictionary with three possible keys (all, getterOnly and
+#   setterOnly) each having such an array as the value
+#
+#   * infallible - attributes and methods specified in the .webidl file that
+#                  cannot fail and therefore do not require the final nsresult&
+#                  argument
+#   * implicitJSContext - attributes and methods specified in the .webidl file
+#                         that require a JSContext as the first argument
+#   * resultNotAddRefed - attributes and methods specified in the .webidl file
+#                         that do not AddRef the return value
+
+DOMInterfaces = {
+
+'XMLHttpRequest': [
+{
+    'nativeType': 'nsXMLHttpRequest',
+    'prefable': True,
+    'infallible': {
+        'all': [
+            'readyState', 'withCredentials', 'abort', 'statusText',
+            'getAllResponseHeaders', 'overrideMimeType', 'mozBackgroundRequest',
+            'multipart', 'channel', 'upload', 'status'
+        ],
+        'getterOnly': [
+            'responseType', 'timeout', 'onreadystatechange'
+        ]
+    },
+    'implicitJSContext': {
+        'all': [
+            'response', 'getInterface'
+        ],
+        'setterOnly': [
+            'onreadystatechange'
+        ]
+    },
+    'resultNotAddRefed': [ 'upload', 'responseXML' ]
+},
+{
+    'workers': True,
+    'nativeType': 'mozilla::dom::workers::XMLHttpRequest',
+    'headerFile': 'mozilla/dom/workers/bindings/XMLHttpRequest.h',
+    'infallible': [
+        'readyState', 'statusText'
+    ]
+}],
+
+'XMLHttpRequestUpload': [
+{
+    'nativeType': 'nsXMLHttpRequestUpload',
+    'headerFile': 'nsXMLHttpRequest.h',
+    'prefable': True
+},
+{
+    'workers': True,
+    'nativeType': 'mozilla::dom::workers::XMLHttpRequestUpload',
+    'headerFile': 'mozilla/dom/workers/bindings/XMLHttpRequestUpload.h'
+}],
+
+'MozChannel': [
+{
+    'nativeType': 'nsIChannel',
+    'prefable': True,
+    'castable': False,
+    'notflattened': True
+},
+{
+    'workers': True,
+    'nativeType': 'JSObject',
+    'headerFile': 'jsapi.h',
+    'castable': False
+}],
+
+'InputStream': [
+{
+    'nativeType': 'nsIInputStream',
+    'prefable': True,
+    'castable': False,
+    'notflattened': True
+},
+{
+    'workers': True,
+    'nativeType': 'JSObject',
+    'headerFile': 'jsapi.h',
+    'castable': False
+}],
+
+'Document': [
+{
+    'nativeType': 'nsIDocument',
+    'prefable': True,
+    'castable': False
+},
+{
+    'workers': True,
+    'nativeType': 'JSObject',
+    'headerFile': 'jsapi.h',
+    'castable': False
+}],
+
+'Blob': [
+{
+    'nativeType': 'nsIDOMBlob',
+    'headerFile': 'nsIDOMFile.h',
+    'prefable': True,
+    'castable': False
+},
+{
+    'workers': True,
+    'nativeType': 'JSObject',
+    'headerFile': 'jsapi.h',
+    'castable': False
+}],
+
+'FormData': [
+{
+    'nativeType': 'nsIDOMFormData',
+    'prefable': True,
+    'castable': False
+},
+{
+    'workers': True,
+    'nativeType': 'JSObject',
+    'headerFile': 'jsapi.h',
+    'castable': False
+}],
+
+'EventTarget': [
+{
+    'nativeType': 'nsDOMEventTargetHelper',
+    'hasInstanceInterface': 'nsIDOMEventTarget',
+    'concrete': False,
+    'prefable': True,
+},
+{
+    'workers': True,
+    'nativeType': 'mozilla::dom::workers::EventTarget',
+    'headerFile': 'mozilla/dom/workers/bindings/EventTarget.h',
+    'concrete': False
+}],
+
+'Event': [
+{
+    'nativeType': 'nsIDOMEvent',
+    'prefable': True,
+    'castable': False
+},
+{
+    'workers': True,
+    'nativeType': 'JSObject',
+    'headerFile': 'jsapi.h',
+    'castable': False
+}],
+
+'EventListener': [
+{
+    'nativeType': 'nsIDOMEventListener',
+    'prefable': True
+},
+{
+    'workers': True,
+    'nativeType': 'JSObject',
+    'headerFile': 'jsapi.h'
+}],
+
+'XMLHttpRequestEventTarget': [
+{
+    'nativeType': 'nsXHREventTarget',
+    'headerFile': 'nsXMLHttpRequest.h',
+    'concrete': False,
+    'prefable': True,
+    'infallible': {
+        'getterOnly': [
+            'onabort', 'onerror', 'onload', 'onloadstart', 'onprogress',
+            'ontimeout', 'onloadend'
+        ]
+    },
+    'implicitJSContext': {
+        'setterOnly': [
+            'onabort', 'onerror', 'onload', 'onloadstart', 'onprogress',
+            'ontimeout', 'onloadend'
+        ]
+    }
+},
+{
+    'workers': True,
+    'concrete': False,
+    'nativeType': 'mozilla::dom::workers::XMLHttpRequestEventTarget',
+    'headerFile': 'mozilla/dom/workers/bindings/XMLHttpRequestEventTarget.h'
+}],
+
+'IID': [
+{
+    'nativeType': 'nsIJSIID',
+    'headerFile': 'xpcjsid.h',
+    'prefable': True,
+    'castable': False
+},
+{
+    'workers': True,
+    'nativeType': 'JSObject',
+    'headerFile': 'jsapi.h',
+    'castable': False
+}],
+
+}
new file mode 100644
--- /dev/null
+++ b/dom/bindings/Codegen.py
@@ -0,0 +1,2982 @@
+# 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 os
+import string
+
+from WebIDL import *
+
+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 = '_Construct'
+HASINSTANCE_HOOK_NAME = '_HasInstance'
+
+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:
+        oldFile = open(filename, 'rb')
+        oldFileContents = ''.join(oldFile.readlines())
+        oldFile.close()
+    except:
+        pass
+
+    if newContents == oldFileContents:
+        return False
+
+    f = open(filename, 'wb')
+    f.write(newContents)
+    f.close()
+
+def toStringBool(arg):
+    return str(not not arg).lower()
+
+class CGThing():
+    """
+    Abstract base class 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 CGNativePropertyHooks(CGThing):
+    """
+    Generate a NativePropertyHooks for a given descriptor
+    """
+    def __init__(self, descriptor):
+        CGThing.__init__(self)
+        self.descriptor = descriptor
+    def declare(self):
+        return "  extern const NativePropertyHooks NativeHooks;\n"
+    def define(self):
+        parent = self.descriptor.interface.parent
+        parentHooks = "&" + parent.identifier.name + "::NativeHooks" if parent else 'NULL'
+        return """
+const NativePropertyHooks NativeHooks = { ResolveProperty, EnumerateProperties, %s };
+""" % parentHooks
+
+class CGDOMJSClass(CGThing):
+    """
+    Generate a DOMJSClass for a given descriptor
+    """
+    def __init__(self, descriptor):
+        CGThing.__init__(self)
+        self.descriptor = descriptor
+    def declare(self):
+        return "  extern DOMJSClass Class;\n"
+    def define(self):
+        traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else 'NULL'
+        protoList = ['id::' + proto for proto in self.descriptor.prototypeChain]
+        # Pad out the list to the right length with _ID_Count so we
+        # guarantee that all the lists are the same length.  _ID_Count
+        # is never the ID of any prototype, so it's safe to use as
+        # padding.
+        while len(protoList) < self.descriptor.config.maxProtoChainLength:
+            protoList.append('id::_ID_Count')
+        prototypeChainString = ', '.join(protoList)
+        return """
+DOMJSClass Class = {
+  { "%s",
+    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1),
+    %s, /* addProperty */
+    JS_PropertyStub,       /* delProperty */
+    JS_PropertyStub,       /* getProperty */
+    JS_StrictPropertyStub, /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    %s, /* finalize */
+    NULL,                  /* checkAccess */
+    NULL,                  /* call */
+    NULL,                  /* construct */
+    NULL,                  /* hasInstance */
+    %s, /* trace */
+    JSCLASS_NO_INTERNAL_MEMBERS
+  },
+  { %s },
+  -1, %s, DOM_OBJECT_SLOT,
+  &NativeHooks
+};
+""" % (self.descriptor.interface.identifier.name,
+       ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.workers else 'JS_PropertyStub',
+       FINALIZE_HOOK_NAME, traceHook, prototypeChainString,
+       str(self.descriptor.nativeIsISupports).lower())
+
+class CGPrototypeJSClass(CGThing):
+    def __init__(self, descriptor):
+        CGThing.__init__(self)
+        self.descriptor = descriptor
+    def declare(self):
+        # We're purely for internal consumption
+        return ""
+    def define(self):
+        return """
+static JSClass PrototypeClass = {
+  "%s Prototype", 0,
+  JS_PropertyStub,       /* addProperty */
+  JS_PropertyStub,       /* delProperty */
+  JS_PropertyStub,       /* getProperty */
+  JS_StrictPropertyStub, /* setProperty */
+  JS_EnumerateStub,
+  JS_ResolveStub,
+  JS_ConvertStub,
+  NULL,                  /* finalize */
+  NULL,                  /* checkAccess */
+  NULL,                  /* call */
+  NULL,                  /* construct */
+  NULL,                  /* hasInstance */
+  NULL,                  /* trace */
+  JSCLASS_NO_INTERNAL_MEMBERS
+};
+""" % (self.descriptor.interface.identifier.name)
+
+class CGInterfaceObjectJSClass(CGThing):
+    def __init__(self, descriptor):
+        CGThing.__init__(self)
+        self.descriptor = descriptor
+    def declare(self):
+        # We're purely for internal consumption
+        return ""
+    def define(self):
+        ctorname = "NULL" if not self.descriptor.interface.ctor() else CONSTRUCT_HOOK_NAME
+        hasinstance = "NULL" if not self.descriptor.hasInstanceInterface else HASINSTANCE_HOOK_NAME
+        return """
+static JSClass InterfaceObjectClass = {
+  "Function", 0,
+  JS_PropertyStub,       /* addProperty */
+  JS_PropertyStub,       /* delProperty */
+  JS_PropertyStub,       /* getProperty */
+  JS_StrictPropertyStub, /* setProperty */
+  JS_EnumerateStub,
+  JS_ResolveStub,
+  JS_ConvertStub,
+  NULL,                  /* finalize */
+  NULL,                  /* checkAccess */
+  %s, /* call */
+  %s, /* construct */
+  %s, /* hasInstance */
+  NULL,                  /* trace */
+  JSCLASS_NO_INTERNAL_MEMBERS
+};
+""" % (ctorname, ctorname, hasinstance)
+
+class CGList(CGThing):
+    """
+    Generate code for a list of GCThings.  Just concatenates them together, with
+    an optional joiner string.  "\n" is a common joiner.
+    """
+    def __init__(self, children, joiner=""):
+        CGThing.__init__(self)
+        self.children = children
+        self.joiner = joiner
+    def append(self, child):
+        self.children.append(child)
+    def prepend(self, child):
+        self.children.insert(0, child)
+    def declare(self):
+        return self.joiner.join([child.declare() for child in self.children])
+    def define(self):
+        return self.joiner.join([child.define() for child in self.children])
+
+class CGGeneric(CGThing):
+    """
+    A class that spits out a fixed string into the codegen.  Can spit out a
+    separate string for the declaration too.
+    """
+    def __init__(self, define="", declare=""):
+        self.declareText = declare
+        self.defineText = define
+    def declare(self):
+        return self.declareText
+    def define(self):
+        return self.defineText
+
+# We'll want to insert the indent at the beginnings of lines, but we
+# don't want to indent empty lines.  So only indent lines that have a
+# non-newline character on them.
+lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
+class CGIndenter(CGThing):
+    """
+    A class that takes another CGThing and generates code that indents that
+    CGThing by some number of spaces.  The default indent is two spaces.
+    """
+    def __init__(self, child, indentLevel=2):
+        CGThing.__init__(self)
+        self.child = child
+        self.indent = " " * indentLevel
+    def declare(self):
+        decl = self.child.declare()
+        if decl is not "":
+            return re.sub(lineStartDetector, self.indent, decl)
+        else:
+            return ""
+    def define(self):
+        defn = self.child.define()
+        if defn is not "":
+            return re.sub(lineStartDetector, 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,
+                 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, declareOnly=False):
+        pre = "namespace %s {\n" % namespace
+        post = "} // namespace %s\n" % namespace
+        CGWrapper.__init__(self, child, pre=pre, post=post,
+                           declareOnly=declareOnly)
+    @staticmethod
+    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),
+                           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
+        CGWrapper.__init__(self, child,
+                           declarePre='#ifndef %s\n#define %s\n\n' % (define, define),
+                           declarePost='\n#endif // %s\n' % define)
+
+class CGHeaders(CGWrapper):
+    """
+    Generates the appropriate include statements.
+    """
+    def __init__(self, descriptors, declareIncludes, defineIncludes, child):
+        """
+        Builds a set of includes to cover |descriptors|.
+
+        Also includes the files in |declareIncludes| in the header
+        file and the files in |defineIncludes| in the .cpp.
+        """
+
+        # Determine the filenames for which we need headers.
+        interfaceDeps = [d.interface for d in descriptors]
+        ancestors = []
+        for iface in interfaceDeps:
+            while iface.parent:
+                ancestors.append(iface.parent)
+                iface = iface.parent
+        interfaceDeps.extend(ancestors)
+        bindingIncludes = set(self.getInterfaceFilename(d) for d in interfaceDeps)
+
+        # Grab all the implementation declaration files we need.
+        implementationIncludes = 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 = set()
+        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 = []
+            for s in signatures:
+                assert len(s) == 2
+                (returnType, arguments) = s
+                types.append(returnType)
+                types.extend([a.type for a in arguments])
+
+            attrs = [a for a in members if a.isAttr()]
+            types.extend([a.type for a in attrs])
+
+            for t in types:
+                if t.unroll().isInterface():
+                    if t.unroll().isArrayBuffer():
+                        bindingHeaders.add("jstypedarray.h")
+                    else:
+                        typeDesc = d.getDescriptor(t.unroll().inner.identifier.name)
+                        if typeDesc is not None:
+                            implementationIncludes.add(typeDesc.headerFile)
+                            bindingHeaders.add(self.getInterfaceFilename(typeDesc.interface))
+
+        # 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(sorted(set(defineIncludes) |
+                                                           bindingIncludes |
+                                                           bindingHeaders |
+                                                           implementationIncludes)))
+    @staticmethod
+    def getInterfaceFilename(interface):
+        basename = os.path.basename(interface.filename())
+        return 'mozilla/dom/bindings/' + \
+               basename.replace('.webidl', 'Binding.h')
+
+class Argument():
+    """
+    A class for outputting the type and name of an argument
+    """
+    def __init__(self, argType, name):
+        self.argType = argType
+        self.name = name
+    def __str__(self):
+        return self.argType + ' ' + self.name
+
+class CGAbstractMethod(CGThing):
+    """
+    An abstract class for generating code for a method.  Subclasses
+    should override definition_body to create the actual code.
+
+    descriptor is the descriptor for the interface the method is associated with
+
+    name is the name of the method as a string
+
+    returnType is the IDLType of the return value
+
+    args is a list of Argument objects
+
+    inline should be True to generate an inline method, whose body is
+    part of the declaration.
+
+    static should be True to generate a static method, which only has
+    a definition.
+    """
+    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):
+        decorators = []
+        if self.inline:
+            decorators.append('inline')
+        if self.static:
+            decorators.append('static')
+        decorators.append(self.returnType)
+        return ' '.join(decorators)
+    def declare(self):
+        if self.inline:
+            return self._define()
+        return "\n  %s %s(%s);\n" % (self._decorators(), self.name, self._argstring())
+    def _define(self):
+        return self.definition_prologue() + "\n" + self.definition_body() + self.definition_epilogue()
+    def define(self):
+        return "" if self.inline else self._define()
+    def definition_prologue(self):
+        maybeNewline = " " if self.inline else "\n"
+        return "\n%s%s%s(%s)\n{" % (self._decorators(), maybeNewline,
+                                    self.name, self._argstring())
+    def definition_epilogue(self):
+        return "\n}\n"
+    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, descriptor, name, returnType, args):
+        CGAbstractMethod.__init__(self, descriptor, name, returnType, args,
+                                  inline=False, static=True)
+    def declare(self):
+        # We only have implementation
+        return ""
+
+class CGAbstractClassHook(CGAbstractStaticMethod):
+    """
+    Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
+    'this' unwrapping as it assumes that the unwrapped type is always known.
+    """
+    def __init__(self, descriptor, name, returnType, args):
+        CGAbstractStaticMethod.__init__(self, descriptor, name, returnType,
+                                        args)
+
+    def definition_body_prologue(self):
+        return """
+  MOZ_ASSERT(js::GetObjectJSClass(obj) == Class.ToJSClass());
+  %s* self = UnwrapDOMObject<%s>(obj, Class.ToJSClass());
+""" % (self.descriptor.nativeType, self.descriptor.nativeType)
+
+    def definition_body(self):
+        return self.definition_body_prologue() + self.generate_code()
+
+    def generate_code(self):
+        # Override me
+        assert(False)
+
+class CGAddPropertyHook(CGAbstractClassHook):
+    """
+    A hook for addProperty, used to preserve our wrapper from GC.
+    """
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'obj'),
+                Argument('jsid', 'id'), Argument('jsval*', 'vp')]
+        CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME,
+                                     'JSBool', args)
+
+    def generate_code(self):
+        return """
+  JSCompartment* compartment = js::GetObjectCompartment(obj);
+  xpc::CompartmentPrivate* priv =
+    static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(compartment));
+  if (!priv->RegisterDOMExpandoObject(obj)) {
+    return false;
+  }
+  self->SetPreservingWrapper(true);
+  return true;"""
+
+class CGClassFinalizeHook(CGAbstractClassHook):
+    """
+    A hook for finalize, used to release our native object.
+    """
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'obj')]
+        CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
+                                     'void', args)
+
+    def generate_code(self):
+        if self.descriptor.customFinalize:
+            return """  if (self) {
+    self->%s(%s);
+  }""" % (self.name, self.args[0].name)
+        if self.descriptor.workers:
+            release = "self->Release();"
+        else:
+            assert self.descriptor.nativeIsISupports
+            release = """
+  XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
+  if (rt) {
+    rt->DeferredRelease(NativeToSupports(self));
+  } else {
+    NS_RELEASE(self);
+  }"""
+        return """
+  self->ClearWrapper();
+  %s""" % (release)
+
+class CGClassTraceHook(CGAbstractClassHook):
+    """
+    A hook to trace through our native object; used for GC and CC
+    """
+    def __init__(self, descriptor):
+        args = [Argument('JSTracer*', 'trc'), Argument('JSObject*', 'obj')]
+        CGAbstractClassHook.__init__(self, descriptor, TRACE_HOOK_NAME, 'void',
+                                     args)
+
+    def generate_code(self):
+        return """  if (self) {
+    self->%s(%s);
+  }""" % (self.name, self.args[0].name)
+
+class CGClassConstructHook(CGAbstractStaticMethod):
+    """
+    JS-visible constructor for our objects
+    """
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'), Argument('JS::Value*', 'vp')]
+        CGAbstractStaticMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME,
+                                        'JSBool', args)
+        self._ctor = self.descriptor.interface.ctor()
+
+    def define(self):
+        if not self._ctor:
+            return ""
+        return CGAbstractStaticMethod.define(self)
+
+    def definition_body(self):
+        return self.generate_code()
+
+    def generate_code(self):
+        preamble = """
+  JSObject* obj = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
+"""
+        preArgs = ""
+        if self.descriptor.workers:
+            preArgs = "cx, obj, "
+        else:
+            preamble += """
+  nsISupports* global;
+  xpc_qsSelfRef globalRef;
+  {
+    nsresult rv;
+    JS::Value val = OBJECT_TO_JSVAL(obj);
+    rv = xpc_qsUnwrapArg<nsISupports>(cx, val, &global, &globalRef.ptr, &val);
+    if (NS_FAILED(rv)) {
+      return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
+    }
+  }
+"""
+            preArgs = "global, "
+
+        name = "_" + self._ctor.identifier.name
+        nativeName = "_" + MakeNativeName(self._ctor.identifier.name)
+        nativeName = self.descriptor.binaryNames.get(name, nativeName)
+        callGenerator = CGMethodCall(preArgs, nativeName, True,
+                                     self.descriptor, self._ctor, {})
+        return preamble + callGenerator.define();
+
+class CGClassHasInstanceHook(CGAbstractStaticMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'obj'),
+                Argument('const jsval*', 'v'), Argument('JSBool*', 'bp')]
+        CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
+                                        'JSBool', args)
+
+    def define(self):
+        if not self.descriptor.hasInstanceInterface:
+            return ""
+        return CGAbstractStaticMethod.define(self)
+
+    def definition_body(self):
+        return self.generate_code()
+
+    def generate_code(self):
+        return """  if (!v->isObject()) {
+    *bp = false;
+    return true;
+  }
+
+  jsval protov;
+  if (!JS_GetProperty(cx, obj, "prototype", &protov))
+    return false;
+  if (!protov.isObject()) {
+    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE,
+                         "%s");
+    return false;
+  }
+  obj = &protov.toObject();
+
+  JSObject* instance = &v->toObject();
+  JSObject* proto = JS_GetPrototype(instance);
+  while (proto) {
+    if (proto == obj) {
+      *bp = true;
+      return true;
+    }
+    proto = JS_GetPrototype(proto);
+  }
+
+  nsISupports* native =
+    nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, instance);
+  nsCOMPtr<%s> qiResult = do_QueryInterface(native);
+  *bp = !!qiResult;
+  return true;
+""" % (self.descriptor.name, self.descriptor.hasInstanceInterface)
+
+def isChromeOnly(m):
+    return m.extendedAttribute("ChromeOnly")
+
+class PropertyDefiner:
+    """
+    A common superclass for defining things on prototype objects.
+
+    Subclasses should implement generateArray to generate the actual arrays of
+    things we're defining.  They should also set self.chrome to the list of
+    things exposed to chrome and self.regular to the list of things exposed to
+    web pages.  self.chrome must be a superset of self.regular but also include
+    all the ChromeOnly stuff.
+    """
+    def __init__(self, descriptor, name):
+        self.descriptor = descriptor
+        self.name = name
+    def hasChromeOnly(self):
+        return len(self.chrome) > len(self.regular)
+    def hasNonChromeOnly(self):
+        return len(self.regular) > 0
+    def variableName(self, chrome):
+        if chrome and self.hasChromeOnly():
+            return "sChrome" + self.name
+        if self.hasNonChromeOnly():
+            return "s" + self.name
+        return "NULL"
+    def __str__(self):
+        str = self.generateArray(self.regular, self.variableName(False))
+        if self.hasChromeOnly():
+            str += self.generateArray(self.chrome, self.variableName(True))
+        return str
+
+class MethodDefiner(PropertyDefiner):
+    """
+    A class for defining methods on a prototype object.
+    """
+    def __init__(self, descriptor, name, static):
+        PropertyDefiner.__init__(self, descriptor, name)
+
+        # 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(arguments) for (retType, arguments) in signatures])
+
+        methods = [m for m in descriptor.interface.members if
+                   m.isMethod() and m.isStatic() == static]
+        self.chrome = [{"name": m.identifier.name,
+                        "length": methodLength(m),
+                        "flags": "JSPROP_ENUMERATE"} for m in methods]
+        self.regular = [{"name": m.identifier.name,
+                         "length": methodLength(m),
+                         "flags": "JSPROP_ENUMERATE"}
+                        for m in methods if not isChromeOnly(m)]
+        if not descriptor.interface.parent and not static and not descriptor.workers:
+            self.chrome.append({"name": 'QueryInterface',
+                                "length": 1,
+                                "flags": "0"})
+            self.regular.append({"name": 'QueryInterface',
+                                 "length": 1,
+                                 "flags": "0"})
+
+        if static:
+            if not descriptor.interface.hasInterfaceObject():
+                # static methods go on the interface object
+                assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
+        else:
+            if not descriptor.interface.hasInterfacePrototypeObject():
+                # non-static methods go on the interface prototype object
+                assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
+
+    @staticmethod
+    def generateArray(array, name):
+        if len(array) == 0:
+            return ""
+
+        funcdecls = ['  JS_FN("%s", %s, %s, %s)' %
+                     (m["name"], m["name"], m["length"], m["flags"])
+                     for m in array]
+        # And add our JS_FS_END
+        funcdecls.append('  JS_FS_END')
+
+        return ("static JSFunctionSpec %s[] = {\n" +
+                ',\n'.join(funcdecls) + "\n" +
+                "};\n\n" +
+                "static jsid %s_ids[%i] = { JSID_VOID };\n\n") % (name, name, len(array))
+
+class AttrDefiner(PropertyDefiner):
+    def __init__(self, descriptor, name):
+        PropertyDefiner.__init__(self, descriptor, name)
+        self.name = name
+        self.chrome = [m for m in descriptor.interface.members if m.isAttr()]
+        self.regular = [m for m in self.chrome if not isChromeOnly(m)]
+
+    @staticmethod
+    def generateArray(array, name):
+        if len(array) == 0:
+            return ""
+
+        def flags(attr):
+            flags = "JSPROP_SHARED | JSPROP_ENUMERATE"
+            if generateNativeAccessors:
+                flags = "JSPROP_NATIVE_ACCESSORS | " + flags
+            elif attr.readonly:
+                return "JSPROP_READONLY | " + flags
+            return flags
+
+        def getter(attr):
+            return "get_" + attr.identifier.name
+
+        def setter(attr):
+            if attr.readonly:
+                return "NULL"
+            return "set_" + attr.identifier.name
+
+        attrdecls = ['  { "%s", 0, %s, (JSPropertyOp)%s, (JSStrictPropertyOp)%s }' %
+                     (attr.identifier.name, flags(attr), getter(attr),
+                      setter(attr)) for attr in array]
+        attrdecls.append('  { 0, 0, 0, 0, 0 }')
+
+        return ("static JSPropertySpec %s[] = {\n" +
+                ',\n'.join(attrdecls) + "\n" +
+                "};\n\n" +
+                "static jsid %s_ids[%i] = { JSID_VOID };\n\n") % (name, name, len(array))
+
+class ConstDefiner(PropertyDefiner):
+    """
+    A class for definining constants on the interface object
+    """
+    def __init__(self, descriptor, name):
+        PropertyDefiner.__init__(self, descriptor, name)
+        self.name = name
+        self.chrome = [m for m in descriptor.interface.members if m.isConst()]
+        self.regular = [m for m in self.chrome if not isChromeOnly(m)]
+
+    @staticmethod
+    def generateArray(array, name):
+        if len(array) == 0:
+            return ""
+
+        constdecls = ['  { "%s", %s }' %
+                      (const.identifier.name,
+                       convertConstIDLValueToJSVal(const.value))
+                      for const in array]
+        constdecls.append('  { 0, JSVAL_VOID }')
+
+        return ("static ConstantSpec %s[] = {\n" +
+                ',\n'.join(constdecls) + "\n" +
+                "};\n\n" +
+                "static jsid %s_ids[%i] = { JSID_VOID };\n\n") % (name, name, len(array))
+
+class PropertyArrays():
+    def __init__(self, descriptor):
+        self.staticMethods = MethodDefiner(descriptor, "StaticMethods", True)
+        self.methods = MethodDefiner(descriptor, "Methods", False)
+        self.attrs = AttrDefiner(descriptor, "Attributes")
+        self.consts = ConstDefiner(descriptor, "Constants")
+
+    @staticmethod
+    def arrayNames():
+        return [ "staticMethods", "methods", "attrs", "consts" ]
+
+    def hasChromeOnly(self):
+        return reduce(lambda b, a: b or getattr(self, a).hasChromeOnly(),
+                      self.arrayNames(), False)
+    def variableNames(self, chrome):
+        names = {}
+        for array in self.arrayNames():
+            names[array] = getattr(self, array).variableName(chrome)
+        return names
+    def __str__(self):
+        define = ""
+        for array in self.arrayNames():
+            define += str(getattr(self, array))
+        return define
+
+class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
+    """
+    Generate the CreateInterfaceObjects method for an interface descriptor.
+
+    properties should be a PropertyArrays instance.
+    """
+    def __init__(self, descriptor, properties):
+        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
+        CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'JSObject*', args)
+        self.properties = properties
+    def definition_body(self):
+        protoChain = self.descriptor.prototypeChain
+        if len(protoChain) == 1:
+            getParentProto = "JS_GetObjectPrototype(aCx, aGlobal)"
+        else:
+            parentProtoName = self.descriptor.prototypeChain[-2]
+            getParentProto = "%s::GetProtoObject(aCx, aGlobal)" % (parentProtoName)
+
+        needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
+        needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject()
+
+        # if we don't need to create anything, why are we generating this?
+        assert needInterfaceObject or needInterfacePrototypeObject
+
+        idsToInit = []
+        for var in self.properties.arrayNames():
+            props = getattr(self.properties, var)
+            if props.hasNonChromeOnly():
+                idsToInit.append(props.variableName(False))
+            if props.hasChromeOnly() and not self.descriptor.workers:
+                idsToInit.append(props.variableName(True))
+        initIds = ""
+        if len(idsToInit) > 0:
+            init = ' ||\n       '.join(["!InitIds(aCx, %s, %s_ids)" % (varname, varname)
+                                        for varname in idsToInit])
+            if len(idsToInit) > 1:
+                init = '(' + init + ')'
+            initIds = ("  if (%s_ids[0] == JSID_VOID &&\n" +
+                       "      %s) {\n" +
+                       "    %s_ids[0] = JSID_VOID;\n"
+                       "    return NULL;\n"
+                       "  }\n\n") % (idsToInit[0], init, idsToInit[0])
+            
+        getParentProto = ("  JSObject* parentProto = %s;\n" +
+                          "  if (!parentProto) {\n" +
+                          "    return NULL;\n" +
+                          "  }") % getParentProto
+
+        call = """return bindings::CreateInterfaceObjects(aCx, aGlobal, parentProto,
+                                          %s, %s,
+                                          %%(methods)s, %%(attrs)s, %%(consts)s, %%(staticMethods)s,
+                                          %s);""" % (
+            "&PrototypeClass" if needInterfacePrototypeObject else "NULL",
+            "&InterfaceObjectClass" if needInterfaceObject else "NULL",
+            '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL")
+
+        if self.properties.hasChromeOnly():
+            if self.descriptor.workers:
+                accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
+            else:
+                accessCheck = "xpc::AccessCheck::isChrome(js::GetObjectCompartment(aGlobal))"
+            chrome = """
+
+  if (%s) {
+    %s
+  }
+""" % (accessCheck, call.replace("\n  ", "\n    ") % self.properties.variableNames(True))
+        else:
+            chrome = ""
+        return initIds + getParentProto + chrome + "\n  " + call % self.properties.variableNames(False)
+
+class CGGetPerInterfaceObject(CGAbstractMethod):
+    """
+    A method for getting a per-interface object (a prototype object or interface
+    constructor object).
+    """
+    def __init__(self, descriptor, name, idPrefix=""):
+        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
+        CGAbstractMethod.__init__(self, descriptor, name,
+                                  'JSObject*', args, inline=True)
+        self.id = idPrefix + "id::" + self.descriptor.name
+    def definition_body(self):
+        return """
+  /* Make sure our global is sane.  Hopefully we can remove this sometime */
+  if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) {
+    return NULL;
+  }
+  /* Check to see whether the interface objects are already installed */
+  JSObject** protoOrIfaceArray = GetProtoOrIfaceArray(aGlobal);
+  JSObject* cachedObject = protoOrIfaceArray[%s];
+  if (!cachedObject) {
+    protoOrIfaceArray[%s] = cachedObject = CreateInterfaceObjects(aCx, aGlobal);
+  }
+
+  /* cachedObject might _still_ be null, but that's OK */
+  return cachedObject;""" % (self.id, self.id)
+
+class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
+    """
+    A method for getting the interface prototype object.
+    """
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
+        CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject")
+    def definition_body(self):
+        return """
+  /* Get the interface prototype object for this class.  This will create the
+     object as needed. */""" + CGGetPerInterfaceObject.definition_body(self)
+
+class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
+    """
+    A method for getting the interface constructor object.
+    """
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
+        CGGetPerInterfaceObject.__init__(self, descriptor, "GetConstructorObject", "constructors::")
+    def definition_body(self):
+        return """
+  /* Get the interface object for this class.  This will create the object as
+     needed. */""" + CGGetPerInterfaceObject.definition_body(self)
+
+def CheckPref(descriptor, scopeName, varName, retval, wrapperCache = None):
+    """
+    Check whether bindings should be enabled for this descriptor.  If not, set
+    varName to false and return retval.
+    """
+    if not descriptor.prefable:
+        return ""
+    if wrapperCache:
+       wrapperCache = "%s->ClearIsDOMBinding();\n" % (wrapperCache)
+    else:
+        wrapperCache = ""
+    return """
+  if (!%s->ParisBindingsEnabled()) {
+%s    %s = false;
+    return %s;
+  }
+""" % (scopeName, wrapperCache, varName, retval)
+
+class CGDefineDOMInterfaceMethod(CGAbstractMethod):
+    """
+    A method for resolve hooks to try to lazily define the interface object for
+    a given interface.
+    """
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'aCx'), Argument('XPCWrappedNativeScope*', 'aScope'),
+                Argument('bool*', 'aEnabled')]
+        CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'bool', args)
+
+    def declare(self):
+        if self.descriptor.workers:
+            return ''
+        return CGAbstractMethod.declare(self)
+
+    def define(self):
+        if self.descriptor.workers:
+            return ''
+        return CGAbstractMethod.define(self)
+
+    def definition_body(self):
+        if self.descriptor.interface.hasInterfacePrototypeObject():
+            # We depend on GetProtoObject defining an interface constructor
+            # object as needed.
+            getter = "GetProtoObject"
+        else:
+            getter = "GetConstructorObject"
+
+        return CheckPref(self.descriptor, "aScope", "*aEnabled", "false") + """
+  *aEnabled = true;
+  return !!%s(aCx, aScope->GetGlobalJSObject());""" % (getter)
+
+class CGNativeToSupportsMethod(CGAbstractStaticMethod):
+    """
+    A method to cast our native to an nsISupports.  We do it by casting up the
+    interface chain in hopes of getting to something that singly-inherits from
+    nsISupports.
+    """
+    def __init__(self, descriptor):
+        args = [Argument(descriptor.nativeType + '*', 'aNative')]
+        CGAbstractStaticMethod.__init__(self, descriptor, 'NativeToSupports', 'nsISupports*', args)
+
+    def definition_body(self):
+        cast = "aNative"
+        whitespace = ""
+        addspace = ""
+        for proto in reversed(self.descriptor.prototypeChain[:-1]):
+            d = self.descriptor.getDescriptor(proto)
+            cast = "static_cast<%s*>(%s)" % (d.nativeType, whitespace + cast)
+            addspace += "  "
+            whitespace = "\n  " + addspace
+        return """
+  return %s;""" % (cast)
+
+class CGWrapMethod(CGAbstractMethod):
+    def __init__(self, descriptor):
+        # XXX can we wrap if we don't have an interface prototype object?
+        assert descriptor.interface.hasInterfacePrototypeObject()
+        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
+                Argument(descriptor.nativeType + '*', 'aObject'),
+                Argument('bool*', 'aTriedToWrap')]
+        CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
+
+    def definition_body(self):
+        if self.descriptor.workers:
+            return """
+  *aTriedToWrap = true;
+  return aObject->GetJSObject();"""
+
+        return """
+  *aTriedToWrap = true;
+
+  JSObject* parent = bindings::WrapNativeParent(aCx, aScope, aObject->GetParentObject());
+  if (!parent) {
+    return NULL;
+  }
+
+  JSAutoEnterCompartment ac;
+  if (js::GetGlobalForObjectCrossCompartment(parent) != aScope) {
+    if (!ac.enter(aCx, parent)) {
+      return NULL;
+    }
+  }
+
+  XPCWrappedNativeScope* scope =
+    XPCWrappedNativeScope::FindInJSObjectScope(aCx, parent);
+  if (!scope) {
+    return NULL;
+  }
+%s
+  JSObject* proto = GetProtoObject(aCx, scope->GetGlobalJSObject());
+  if (!proto) {
+    return NULL;
+  }
+
+  JSObject* obj = JS_NewObject(aCx, &Class.mBase, proto, parent);
+  if (!obj) {
+    return NULL;
+  }
+
+  js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
+  NS_ADDREF(aObject);
+
+  aObject->SetWrapper(obj);
+
+  return obj;""" % (CheckPref(self.descriptor, "scope", "*aTriedToWrap", "NULL", "aObject"))
+
+builtinNames = {
+    IDLType.Tags.bool: 'bool',
+    IDLType.Tags.int8: 'int8_t',
+    IDLType.Tags.int16: 'int16_t',
+    IDLType.Tags.int32: 'int32_t',
+    IDLType.Tags.int64: 'int64_t',
+    IDLType.Tags.uint8: 'uint8_t',
+    IDLType.Tags.uint16: 'uint16_t',
+    IDLType.Tags.uint32: 'uint32_t',
+    IDLType.Tags.uint64: 'uint64_t',
+    IDLType.Tags.float: 'float',
+    IDLType.Tags.double: 'double'
+}
+
+class CastableObjectUnwrapper():
+    """
+    A class for unwrapping an object named by the "source" argument
+    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):
+        assert descriptor.castable
+        self.substitution = { "type" : descriptor.nativeType,
+                              "protoID" : "id::" + descriptor.name,
+                              "source" : source,
+                              "target" : target,
+                              "codeOnFailure" : codeOnFailure }
+
+    def __str__(self):
+        return string.Template(
+"""  {
+    nsresult rv = UnwrapObject<${protoID}>(cx, ${source}, &${target});
+    if (NS_FAILED(rv)) {
+      ${codeOnFailure}
+    }
+  }""").substitute(self.substitution)
+
+class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
+    """
+    As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
+    """
+    def __init__(self, descriptor, source, target):
+        CastableObjectUnwrapper.__init__(self, descriptor, source, target,
+                                         "return Throw<%s>(cx, rv);" %
+                                         toStringBool(not descriptor.workers))
+
+class CallbackObjectUnwrapper:
+    """
+    A class for unwrapping objects implemented in JS.
+
+    |source| is the JSObject we want to use in native code.
+    |target| is an nsCOMPtr of the appropriate type in which we store the result.
+    """
+    def __init__(self, descriptor, source, target, codeOnFailure=None):
+        if codeOnFailure is None:
+            codeOnFailure = ("return Throw<%s>(cx, rv);" %
+                             toStringBool(not descriptor.workers))
+        self.descriptor = descriptor
+        self.substitution = { "nativeType" : descriptor.nativeType,
+                              "source" : source,
+                              "target" : target,
+                              "codeOnFailure" :  codeOnFailure }
+
+    def __str__(self):
+        if self.descriptor.workers:
+            return string.Template("""
+    ${target} = ${source};""").substitute(self.substitution)
+
+        return string.Template("""
+    nsresult rv;
+    XPCCallContext ccx(JS_CALLER, cx);
+    if (!ccx.IsValid()) {
+      rv = NS_ERROR_XPC_BAD_CONVERT_JS;
+      ${codeOnFailure}
+    }
+
+    const nsIID& iid = NS_GET_IID(${nativeType});
+    nsRefPtr<nsXPCWrappedJS> wrappedJS;
+    rv = nsXPCWrappedJS::GetNewOrUsed(ccx, ${source}, iid,
+                                      NULL, getter_AddRefs(wrappedJS));
+    if (NS_FAILED(rv) || !wrappedJS) {
+      ${codeOnFailure}
+    }
+
+    ${target} = do_QueryObject(wrappedJS.get());
+    if (!${target}) {
+      ${codeOnFailure}
+    }""").substitute(self.substitution)
+
+def getArgumentConversionTemplate(type, descriptor):
+    if type.isSequence() or type.isArray():
+        raise TypeError("Can't handle sequence or array arguments yet")
+
+    if descriptor is not None:
+        assert(type.isInterface())
+        # This is an interface that we implement as a concrete class
+        # or an XPCOM interface.
+        argIsPointer = type.nullable() or type.unroll().inner.isExternal()
+        if argIsPointer:
+            nameSuffix = ""
+        else:
+            nameSuffix = "_ptr"
+
+        # If we're going to QI, we want an nsCOMPtr.  But note that XPConnect
+        # unwrapping may or may not QI, and we don't know whether it will.  So
+        # we use a raw pointer for the isExternal() case, and if a ref is needed
+        # it'll be handled by the xpc_qsSelfRef we put on the stack later.
+        if descriptor.castable or type.unroll().inner.isExternal() or descriptor.workers:
+            declType = "  ${typeName}*"
+        else:
+            declType = "  nsCOMPtr<${typeName}>"
+        template = declType + " ${name}%s;\n" % nameSuffix
+
+        # We have to be very careful here to put anything that might need to
+        # hold references across the C++ call in |template| and not
+        # |templateBody|, since things in |templateBody| will go out of scope
+        # before the call happens.
+        templateBody = "  if (${argVal}.isObject()) {"
+        if descriptor.castable:
+            templateBody += str(FailureFatalCastableObjectUnwrapper(
+                    descriptor,
+                    "&${argVal}.toObject()",
+                    "${name}"+nameSuffix)).replace("\n", "\n  ") + "\n"
+        elif descriptor.interface.isCallback():
+            templateBody += str(CallbackObjectUnwrapper(
+                    descriptor,
+                    "&${argVal}.toObject()",
+                    "${name}"+nameSuffix)) + "\n"
+        elif descriptor.workers:
+            templateBody += """
+    ${name}%s = &${argVal}.toObject();
+    MOZ_ASSERT(${name}%s);
+""" % (nameSuffix, nameSuffix)
+        else:
+            template += "  xpc_qsSelfRef tmpRef_${name};\n"
+            template += "  jsval tmpVal_${name} = ${argVal};\n"
+            templateBody += """
+    ${typeName}* tmp;
+    if (NS_FAILED(xpc_qsUnwrapArg<${typeName}>(cx, ${argVal}, &tmp, &tmpRef_${name}.ptr,
+                                               &tmpVal_${name}))) {
+      return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
+    }
+    MOZ_ASSERT(tmp);
+    ${name}%s = tmp;
+""" % (toStringBool(not descriptor.workers), nameSuffix)
+
+        if type.nullable():
+            templateBody += (
+                "  } else if (${argVal}.isNullOrUndefined()) {\n"
+                "    ${name}%s = NULL;\n" % nameSuffix)
+
+        templateBody += (
+            "  } else {\n"
+            "    return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
+            "  }\n" % toStringBool(not descriptor.workers))
+
+        template += templateBody
+
+        if not argIsPointer:
+            template += "  ${typeName} &${name} = *${name}_ptr;\n"
+            
+        return template
+
+    if type.isArrayBuffer():
+        template = (
+            "  JSObject* ${name};\n"
+            "  if (${argVal}.isObject() && JS_IsArrayBufferObject(&${argVal}.toObject())) {\n"
+            "    ${name} = &${argVal}.toObject();\n"
+            "  }")
+        if type.nullable():
+            template += (
+                " else if (${argVal}.isNullOrUndefined()) {\n"
+                "    ${name} = NULL;\n"
+                "  }")
+
+        template += (
+            # XXXbz We don't know whether we're on workers, so play it safe
+            " else {\n"
+            "    return Throw<false>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
+            "  }")
+
+        return template
+
+    if type.isInterface():
+        raise TypeError("Interface type with no descriptor: " + type)
+
+    if type.isString():
+        # XXXbz Need to figure out string behavior based on extended args?  Also, how to
+        # detect them?
+
+        # For nullable strings that are not otherwise annotated, null
+        # and undefined become null strings.
+        if type.nullable():
+            nullBehavior = "eNull"
+            undefinedBehavior = "eNull"
+        else:
+            nullBehavior = "eDefaultNullBehavior"
+            undefinedBehavior = "eDefaultUndefinedBehavior"
+
+        return (
+            "  xpc_qsDOMString ${name}(cx, ${argVal}, ${argPtr},\n"
+            "                       xpc_qsDOMString::%s,\n"
+            "                       xpc_qsDOMString::%s);\n"
+            "  if (!${name}.IsValid()) {\n"
+            "    return false;\n"
+            "  }\n" % (nullBehavior, undefinedBehavior))
+
+    if type.isEnum():
+        if type.nullable():
+            raise TypeError("We don't support nullable enumerated arguments "
+                            "yet")
+        enum = type.inner.identifier.name
+        return (
+            "  %(enumtype)s ${name};\n"
+            "  {\n"
+            "    bool ok;\n"
+            "    ${name} = static_cast<%(enumtype)s>(FindEnumStringIndex(cx, ${argVal}, %(values)s, &ok));\n"
+            "    if (!ok) {\n"
+            "      return false;\n"
+            "    }\n"
+            "  }" % { "enumtype" : enum + "::value",
+                      "values" : enum + "::strings" })
+
+    if type.isCallback():
+        # XXXbz we're going to assume that callback types are always
+        # nullable and always have [TreatNonCallableAsNull] for now.
+        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"
+            "  if (${argVal}.isNullOrUndefined()) {\n"
+            "    ${name}.SetNull();\n"
+            "  } else"
+            )
+        replacements["finalValueSetter"] = "${name}.SetValue"
+    else:
+        replacements["declareArg"] = "  ${typeName} ${name};\n"
+        replacements["finalValueSetter"] = "${name} = "
+
+    replacements["intermediateCast"] = ""
+        
+    if tag == IDLType.Tags.bool:
+        replacements["jstype"] = "JSBool"
+        replacements["converter"] = "JS_ValueToBoolean"
+    elif tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
+                 IDLType.Tags.uint16, IDLType.Tags.int32, IDLType.Tags.uint32]:
+        # XXXbz need to add support for [EnforceRange] and [Clamp]
+        # The output of JS_ValueToECMAInt32 is determined as follows:
+        #   1) The value is converted to a double
+        #   2) Anything that's not a finite double returns 0
+        #   3) The double is rounded towards zero to the nearest integer
+        #   4) The resulting integer is reduced mod 2^32.  The output of this
+        #      operation is an integer in the range [0, 2^32).
+        #   5) If the resulting number is >= 2^31, 2^32 is subtracted from it.
+        #
+        # The result of all this is a number in the range [-2^31, 2^31)
+        #
+        # WebIDL conversions for the 8-bit, 16-bit, and 32-bit integer types
+        # are defined in the same way, except that step 4 uses reduction mod
+        # 2^8 and 2^16 for the 8-bit and 16-bit types respectively, and step 5
+        # is only done for the signed types.
+        #
+        # C/C++ define integer conversion semantics to unsigned types as taking
+        # your input integer mod (1 + largest value representable in the
+        # unsigned type).  Since 2^32 is zero mod 2^8, 2^16, and 2^32,
+        # converting to the unsigned int of the relevant width will correctly
+        # perform step 4; in particular, the 2^32 possibly subtracted in step 5
+        # will become 0.
+        #
+        # Once we have step 4 done, we're just going to assume 2s-complement
+        # representation and cast directly to the type we really want.
+        #
+        # So we can cast directly for all unsigned types and for int32_t; for
+        # the smaller-width signed types we need to cast through the
+        # corresponding unsigned type.
+        replacements["jstype"] = "int32_t"
+        replacements["converter"] = "JS::ToInt32"
+        if tag is IDLType.Tags.int8:
+            replacements["intermediateCast"] = "(uint8_t)"
+        elif tag is IDLType.Tags.int16:
+            replacements["intermediateCast"] = "(uint16_t)"
+        else:
+            replacements["intermediateCast"] = ""
+    elif tag is IDLType.Tags.int64:
+        # XXXbz this may not match what WebIDL says to do in terms of reducing
+        # mod 2^64.  Should we check?
+        replacements["jstype"] = "PRInt64"
+        replacements["converter"] = "xpc_qsValueToInt64"
+    elif tag is IDLType.Tags.uint64:
+        # XXXbz this may not match what WebIDL says to do in terms of reducing
+        # mod 2^64.  Should we check?
+        replacements["jstype"] = "PRUint64"
+        replacements["converter"] = "xpc_qsValueToUint64"
+    elif tag in [IDLType.Tags.float, IDLType.Tags.double]:
+        replacements["jstype"] = "double"
+        replacements["converter"] = "JS::ToNumber"
+    else:
+        raise TypeError("Unknown primitive type '%s'" % type);
+
+    # We substitute the %(name)s things here.  Our caller will
+    # substitute the ${name} things.
+    return ("  %(jstype)s ${name}_jstype;\n"
+            "%(declareArg)s" # No leading whitespace or newline here, on purpose
+            "  if (%(converter)s(cx, ${argVal}, &${name}_jstype)) {\n"
+            "    %(finalValueSetter)s((${typeName})%(intermediateCast)s${name}_jstype);\n"
+            "  } else {\n"
+            "    return false;\n"
+            "  }\n" % replacements)
+
+def convertConstIDLValueToJSVal(value):
+    if isinstance(value, IDLNullValue):
+        return "JSVAL_NULL"
+    tag = value.type.tag()
+    if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
+               IDLType.Tags.uint16, IDLType.Tags.int32]:
+        return "INT_TO_JSVAL(%s)" % (value.value)
+    if tag == IDLType.Tags.uint32:
+        return "UINT_TO_JSVAL(%s)" % (value.value)
+    if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
+        return "DOUBLE_TO_JSVAL(%s)" % (value.value)
+    if tag == IDLType.Tags.bool:
+        return "JSVAL_TRUE" if value.value else "JSVAL_FALSE"
+    if tag in [IDLType.Tags.float, IDLType.Tags.double]:
+        return "DOUBLE_TO_JSVAL(%s)" % (value.value)
+    raise TypeError("Const value of unhandled type: " + value.type)
+
+def convertIDLDefaultValueToJSVal(value):
+    if value.type:
+        tag = value.type.tag()
+        if tag == IDLType.Tags.domstring:
+            assert False # Not implemented!
+    return convertConstIDLValueToJSVal(value)
+
+unindenter = re.compile("^  ", re.MULTILINE)
+class CGArgumentConverter(CGThing):
+    """
+    A class that takes an IDL argument object, its index in the
+    argument list, and the argv and argc strings and generates code to
+    unwrap the argument to the right native type.
+    """
+    def __init__(self, argument, index, argv, argc, descriptorProvider):
+        CGThing.__init__(self)
+        self.argument = argument
+        # XXXbz should optional jsval args get JSVAL_VOID? What about
+        # others?
+        self.replacementVariables = {
+            "index" : index,
+            "argc" : argc,
+            "argv" : argv,
+            "defaultValue" : "JSVAL_NULL",
+            "name" : "arg%d" % index
+            }
+        if argument.optional:
+            if argument.defaultValue:
+                self.replacementVariables["defaultValue"] = convertIDLDefaultValueToJSVal(argument.defaultValue)
+            self.replacementVariables["argVal"] = string.Template(
+                "(${index} < ${argc} ? ${argv}[${index}] : ${defaultValue})"
+                ).substitute(self.replacementVariables)
+            self.replacementVariables["argPtr"] = string.Template(
+                "(${index} < ${argc} ? &${argv}[${index}] : NULL)"
+                ).substitute(self.replacementVariables)
+        else:
+            self.replacementVariables["argVal"] = string.Template(
+                "${argv}[${index}]"
+                ).substitute(self.replacementVariables)
+            self.replacementVariables["argPtr"] = (
+                "&" + self.replacementVariables["argVal"])
+        self.descriptor = None
+        if argument.type.isPrimitive():
+            self.replacementVariables["typeName"] = builtinNames[argument.type.tag()]
+        elif argument.type.isInterface() and not argument.type.isArrayBuffer():
+            descriptor = descriptorProvider.getDescriptor(
+                argument.type.unroll().inner.identifier.name)
+            self.descriptor = descriptor
+            self.replacementVariables["typeName"] = descriptor.nativeType
+
+    def define(self):
+        return string.Template(
+            re.sub(unindenter,
+                   "",
+                   getArgumentConversionTemplate(self.argument.type,
+                                                 self.descriptor))
+            ).substitute(self.replacementVariables)
+
+def getWrapTemplateForTypeImpl(type, result, descriptorProvider,
+                               resultAlreadyAddRefed):
+    if type is None or type.isVoid():
+        return """
+  ${jsvalRef} = JSVAL_VOID;
+  return true;"""
+
+    if type.isSequence() or type.isArray():
+        raise TypeError("Can't handle sequence or array return values yet")
+
+    if type.isInterface() and not type.isArrayBuffer():
+        descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name)
+        wrappingCode = ("""
+  if (!%s) {
+    ${jsvalRef} = JSVAL_NULL;
+    return true;
+  }""" % result) if type.nullable() else ""
+        if descriptor.castable and not type.unroll().inner.isExternal():
+            wrappingCode += """
+  if (WrapNewBindingObject(cx, obj, %s, ${jsvalPtr})) {
+    return true;
+  }""" % result
+            if descriptor.workers:
+                # Worker bindings can only fail to wrap as a new-binding object
+                # if they already threw an exception
+                wrappingCode += """
+  MOZ_ASSERT(JS_IsExceptionPending(cx));
+  return false;"""
+            else:
+                # Try old-style wrapping for non-worker bindings
+                wrappingCode += """
+  return HandleNewBindingWrappingFailure(cx, obj, %s, ${jsvalPtr});""" % result
+        else:
+            if descriptor.notflattened:
+                getIID = "&NS_GET_IID(%s), " % descriptor.nativeType
+            else:
+                getIID = ""
+            wrappingCode += """
+  return WrapObject(cx, obj, %s, %s${jsvalPtr});""" % (result, getIID)
+        return wrappingCode
+
+    if type.isString():
+        if type.nullable():
+            return """
+  return xpc::StringToJsval(cx, %s, ${jsvalPtr});""" % result
+        else:
+            return """
+  return xpc::NonVoidStringToJsval(cx, %s, ${jsvalPtr});""" % result
+
+    if type.isEnum():
+        if type.nullable():
+            raise TypeError("We don't support nullable enumerated return types "
+                            "yet")
+        return """
+  MOZ_ASSERT(uint32_t(%(result)s) < ArrayLength(%(strings)s));
+  JSString* result_str = JS_NewStringCopyN(cx, %(strings)s[uint32_t(%(result)s)].value, %(strings)s[uint32_t(%(result)s)].length);
+  if (!result_str) {
+    return false;
+  }
+  ${jsvalRef} = JS::StringValue(result_str);
+  return true;""" % { "result" : result,
+                      "strings" : type.inner.identifier.name + "::strings" }
+
+    if type.isCallback() and not type.isInterface():
+        # XXXbz we're going to assume that callback types are always
+        # nullable and always have [TreatNonCallableAsNull] for now.
+        return """
+  ${jsvalRef} = JS::ObjectOrNullValue(%s);
+  return true;""" % result
+
+    if type.tag() == IDLType.Tags.any:
+        return """
+  ${jsvalRef} = %s;\n
+  return true;""" % result
+
+    if not type.isPrimitive():
+        raise TypeError("Need to learn to wrap %s" % type)
+
+    if type.nullable():
+        return """
+  if (%s.IsNull()) {
+    ${jsvalRef} = JSVAL_NULL;
+    return true;
+  }
+%s""" % (result, getWrapTemplateForTypeImpl(type.inner, "%s.Value()" % result,
+                                            descriptorProvider,
+                                            resultAlreadyAddRefed))
+    
+    tag = type.tag()
+    
+    if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
+               IDLType.Tags.uint16, IDLType.Tags.int32]:
+        return """
+  ${jsvalRef} = INT_TO_JSVAL(int32_t(%s));
+  return true;""" % result
+
+    elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64, IDLType.Tags.float,
+                 IDLType.Tags.double]:
+        # XXXbz will cast to double do the "even significand" thing that webidl
+        # calls for for 64-bit ints?  Do we care?
+        return """
+  return JS_NewNumberValue(cx, double(%s), ${jsvalPtr});""" % result
+
+    elif tag == IDLType.Tags.uint32:
+        return """
+  ${jsvalRef} = UINT_TO_JSVAL(%s);
+  return true;""" % result
+
+    elif tag == IDLType.Tags.bool:
+        return """
+  ${jsvalRef} = BOOLEAN_TO_JSVAL(%s);
+  return true;""" % result
+
+    else:
+        raise TypeError("Need to learn to wrap primitive: %s" % type)
+
+def getWrapTemplateForType(type, descriptorProvider, resultAlreadyAddRefed):
+    return getWrapTemplateForTypeImpl(type, "result", descriptorProvider,
+                                      resultAlreadyAddRefed)
+
+class CGCallGenerator(CGThing):
+    """
+    A class to generate an actual call to a C++ object.  Assumes that the C++
+    object is stored in a variable named "self".
+    """
+    def __init__(self, errorReport, argCount, argsPre, returnType,
+                 resultAlreadyAddRefed, descriptorProvider, nativeMethodName, static):
+        CGThing.__init__(self)
+
+        isFallible = errorReport is not None
+
+        args = CGList([CGGeneric("arg" + str(i)) for i in range(argCount)], ", ")
+        resultOutParam = returnType is not None and returnType.isString()
+        # Return values that go in outparams go here
+        if resultOutParam:
+            args.append(CGGeneric("result"))
+        if isFallible:
+            args.append(CGGeneric("rv"))
+
+        if returnType is None or returnType.isVoid():
+            # Nothing to declare
+            result = None
+        elif returnType.isPrimitive() and returnType.tag() in builtinNames:
+            result = CGGeneric(builtinNames[returnType.tag()])
+            if returnType.nullable():
+                result = CGWrapper(result, pre="Nullable<", post=">")
+        elif returnType.isString():
+            result = CGGeneric("nsString")
+        elif returnType.isEnum():
+            if returnType.nullable():
+                raise TypeError("We don't support nullable enum return values")
+            result = CGGeneric(returnType.inner.identifier.name + "::value")
+        elif returnType.isInterface() and not returnType.isArrayBuffer():
+            result = CGGeneric(descriptorProvider.getDescriptor(
+                returnType.unroll().inner.identifier.name).nativeType)
+            if resultAlreadyAddRefed:
+                result = CGWrapper(result, pre="nsRefPtr<", post=">")
+            else:
+                result = CGWrapper(result, post="*")
+        elif returnType.isCallback():
+            # XXXbz we're going to assume that callback types are always
+            # nullable for now.
+            result = CGGeneric("JSObject*")
+        elif returnType.tag() is IDLType.Tags.any:
+            result = CGGeneric("JS::Value")
+        else:
+            raise TypeError("Don't know how to declare return value for %s" %
+                            returnType)
+
+        # Build up our actual call
+        self.cgRoot = CGList([], "\n")
+
+        call = CGGeneric(nativeMethodName)
+        if static:
+            call = CGWrapper(call, pre="%s::" % (descriptorProvider.getDescriptor(
+                returnType.unroll().inner.identifier.name).nativeType))
+        else: 
+            call = CGWrapper(call, pre="self->")
+        call = CGList([call, CGWrapper(args, pre="(" + argsPre, post=");")])
+        if result is not None:
+            result = CGWrapper(result, post=" result;")
+            self.cgRoot.prepend(result)
+            if not resultOutParam:
+                call = CGWrapper(call, pre="result = ")
+
+        call = CGWrapper(call)
+        self.cgRoot.append(call)
+
+        if isFallible:
+            self.cgRoot.prepend(CGGeneric("nsresult rv = NS_OK;"))
+            self.cgRoot.append(CGGeneric("if (NS_FAILED(rv)) {"))
+            self.cgRoot.append(CGIndenter(CGGeneric(errorReport)))
+            self.cgRoot.append(CGGeneric("}"))
+
+    def define(self):
+        return self.cgRoot.define()
+
+class CGPerSignatureCall(CGThing):
+    """
+    This class handles the guts of generating code for a particular
+    call signature.  A call signature consists of four things:
+
+    1) A return type, which can be None to indicate that there is no
+       actual return value (e.g. this is an attribute setter) or an
+       IDLType if there's an IDL type involved (including |void|).
+    2) An argument list, which is allowed to be empty.
+    3) A name of a native method to call.
+    4) Whether or not this method is static.
+
+    We also need to know whether this is a method or a getter/setter
+    to do error reporting correctly.
+
+    The idlNode parameter can be either a method or an attr. We can query
+    |idlNode.identifier| in both cases, so we can be agnostic between the two.
+    """
+    # XXXbz For now each entry in the argument list is either an
+    # IDLArgument or a FakeArgument, but longer-term we may want to
+    # have ways of flagging things like JSContext* or optional_argc in
+    # there.
+
+    def __init__(self, returnType, argsPre, arguments, nativeMethodName, static,
+                 descriptor, idlNode, extendedAttributes, argConversionStartsAt=0):
+        CGThing.__init__(self)
+        self.returnType = returnType
+        self.descriptor = descriptor
+        self.idlNode = idlNode
+        self.extendedAttributes = extendedAttributes
+        # Default to already_AddRefed on the main thread, raw pointer in workers
+        self.resultAlreadyAddRefed = not descriptor.workers and not 'resultNotAddRefed' in self.extendedAttributes
+        self.argsPre = "cx, " if 'implicitJSContext' in self.extendedAttributes else ""
+        self.argsPre += argsPre
+        self.argCount = len(arguments)
+        if self.argCount > argConversionStartsAt:
+            # Insert our argv in there
+            cgThings = [CGGeneric(self.getArgvDecl())]
+        else:
+            cgThings = []
+        cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgv(),
+                                             self.getArgc(), self.descriptor) for
+                         i in range(argConversionStartsAt, self.argCount)])
+
+        cgThings.append(CGCallGenerator(
+                    self.getErrorReport() if self.isFallible() else None,
+                    self.argCount, self.argsPre, returnType,
+                    self.resultAlreadyAddRefed, descriptor, nativeMethodName,
+                    static))
+        self.cgRoot = CGList(cgThings, "\n")
+
+    def getArgv(self):
+        return "argv" if self.argCount > 0 else ""
+    def getArgvDecl(self):
+        return "\nJS::Value* argv = JS_ARGV(cx, vp);\n"
+    def getArgc(self):
+        return "argc"
+
+    def isFallible(self):
+        return not 'infallible' in self.extendedAttributes
+
+    def wrap_return_value(self):
+        resultTemplateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp'}
+        return string.Template(
+            re.sub(unindenter,
+                   "",
+                   getWrapTemplateForType(self.returnType, self.descriptor,
+                                          self.resultAlreadyAddRefed))
+            ).substitute(resultTemplateValues)
+
+    def getErrorReport(self):
+        return 'return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'\
+               % (toStringBool(not self.descriptor.workers),
+                  self.descriptor.interface.identifier.name,
+                  self.idlNode.identifier.name)
+
+    def define(self):
+        return (self.cgRoot.define() + self.wrap_return_value())
+
+class CGSwitch(CGList):
+    """
+    A class to generate code for a switch statement.
+
+    Takes three constructor arguments: an expression, a list of cases,
+    and an optional default.
+
+    Each case is a CGCase.  The default is a CGThing for the body of
+    the default case, if any.
+    """
+    def __init__(self, expression, cases, default=None):
+        CGList.__init__(self, [CGIndenter(c) for c in cases], "\n")
+        self.prepend(CGWrapper(CGGeneric(expression),
+                               pre="switch (", post=") {"));
+        if default is not None:
+            self.append(
+                CGIndenter(
+                    CGWrapper(
+                        CGIndenter(default),
+                        pre="default: {\n",
+                        post="\n  break;\n}"
+                        )
+                    )
+                )
+                        
+        self.append(CGGeneric("}"))
+
+class CGCase(CGList):
+    """
+    A class to generate code for a case statement.
+
+    Takes three constructor arguments: an expression, a CGThing for
+    the body (allowed to be None if there is no body), and an optional
+    argument (defaulting to False) for whether to fall through.
+    """
+    def __init__(self, expression, body, fallThrough=False):
+        CGList.__init__(self, [], "\n")
+        self.append(CGWrapper(CGGeneric(expression), pre="case ", post=": {"))
+        if body is not None:
+            self.append(CGIndenter(body))
+        if fallThrough:
+            self.append(CGIndenter(CGGeneric("/* Fall through */")))
+        else:
+            self.append(CGIndenter(CGGeneric("break;")))
+        self.append(CGGeneric("}"))
+
+class CGMethodCall(CGThing):
+    """
+    A class to generate selection of a method signature from a set of
+    signatures and generation of a call to that signature.
+    """
+    def __init__(self, argsPre, nativeMethodName, static, descriptor, method,
+                 extendedAttributes):
+        CGThing.__init__(self)
+
+        def requiredArgCount(signature):
+            arguments = signature[1]
+            if len(arguments) == 0:
+                return 0
+            requiredArgs = len(arguments)
+            while requiredArgs and arguments[requiredArgs-1].optional:
+                requiredArgs -= 1
+            return requiredArgs
+
+        def maxSigLength(signatures):
+            return max([len(s[1]) for s in signatures])
+
+        def signaturesForArgCount(i, signatures):
+            return filter(
+                lambda s: len(s[1]) == i or (len(s[1]) > i and
+                                             s[1][i].optional),
+                    signatures)
+
+        def findDistinguishingIndex(argCount, signatures):
+            def isValidDistinguishingIndex(idx, signatures):
+                for firstSigIndex in range(0, len(signatures)):
+                    for secondSigIndex in range(0, firstSigIndex):
+                        firstType = signatures[firstSigIndex][1][idx].type
+                        secondType = signatures[secondSigIndex][1][idx].type
+                        if not firstType.isDistinguishableFrom(secondType):
+                            return False
+                return True
+            for idx in range(0, argCount):
+                if isValidDistinguishingIndex(idx, signatures):
+                    return idx
+            return -1
+
+        def getPerSignatureCall(signature, argConversionStartsAt=0):
+            return CGPerSignatureCall(signature[0], argsPre, signature[1],
+                                      nativeMethodName, static, descriptor,
+                                      method, extendedAttributes,
+                                      argConversionStartsAt)
+            
+
+        signatures = method.signatures()
+        if len(signatures) == 1:
+            # Special case: we can just do a per-signature method call
+            # here for our one signature and not worry about switching
+            # on anything.
+            signature = signatures[0]
+            self.cgRoot = CGList([ CGIndenter(getPerSignatureCall(signature)) ])
+            requiredArgs = requiredArgCount(signature)
+            if requiredArgs > 0:
+                self.cgRoot.prepend(
+                    CGWrapper(
+                        CGIndenter(
+                            CGGeneric(
+                                "if (argc < %d) {\n"
+                                "  return Throw<%s>(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);\n"
+                                "}" % (requiredArgs,
+                                       toStringBool(not descriptor.workers)))
+                            ),
+                        pre="\n", post="\n")
+                    )
+            return
+
+        # Need to find the right overload
+        maxSigArgs = maxSigLength(signatures)
+        allowedArgCounts = [ i for i in range(0, maxSigArgs+1)
+                             if len(signaturesForArgCount(i, signatures)) != 0 ]
+
+        argCountCases = []
+        for argCount in allowedArgCounts:
+            possibleSignatures = signaturesForArgCount(argCount, signatures)
+            if len(possibleSignatures) == 1:
+                # easy case!
+                signature = possibleSignatures[0]
+
+                # (possibly) important optimization: if signature[1] has >
+                # argCount arguments and signature[1][argCount] is optional and
+                # there is only one signature for argCount+1, then the
+                # signature for argCount+1 is just ourselves and we can fall
+                # through.
+                if (len(signature[1]) > argCount and
+                    signature[1][argCount].optional and
+                    (argCount+1) in allowedArgCounts and
+                    len(signaturesForArgCount(argCount+1, signatures)) == 1):
+                    argCountCases.append(
+                        CGCase(str(argCount), None, True))
+                else:
+                    argCountCases.append(
+                        CGCase(str(argCount), getPerSignatureCall(signature)))
+                continue
+
+            distinguishingIndex = findDistinguishingIndex(argCount,
+                                                          possibleSignatures)
+            if distinguishingIndex == -1:
+                raise TypeError(("Signatures with %s arguments for " +
+                                 descriptor.interface.identifier.name + "." +
+                                 method.identifier.name +
+                                 " are not distinguishable") % argCount)
+
+            for idx in range(0, distinguishingIndex):
+                firstSigType = possibleSignatures[0][1][idx].type
+                for sigIdx in range(1, len(possibleSignatures)):
+                    if possibleSignatures[sigIdx][1][idx].type != firstSigType:
+                        raise TypeError(("Signatures with %d arguments for " +
+                                         descriptor.interface.identifier.name +
+                                         "." + method.identifier.name +
+                                         " have different types at index %d" +
+                                         " which is before distinguishing" +
+                                         " index %d") % (argCount,
+                                                         idx,
+                                                         distinguishingIndex))
+
+            # Convert all our arguments up to the distinguishing index.
+            # Doesn't matter which of the possible signatures we use, since
+            # they all have the same types up to that point; just use
+            # possibleSignatures[0]
+            caseBody = [CGGeneric("JS::Value* argv_start = JS_ARGV(cx, vp);")]
+            caseBody.extend([ CGArgumentConverter(possibleSignatures[0][1][i],
+                                                  i, "argv_start", "argc",
+                                                  descriptor) for i in
+                              range(0, distinguishingIndex) ])
+
+            # Select the right overload from our set.
+            distinguishingArg = "argv_start[%d]" % distinguishingIndex
+
+            def pickFirstSignature(condition, filterLambda):
+                sigs = filter(filterLambda, possibleSignatures)
+                assert len(sigs) < 2
+                if len(sigs) > 0:
+                    if condition is None:
+                        caseBody.append(
+                            getPerSignatureCall(sigs[0], distinguishingIndex))
+                    else:
+                        caseBody.append(CGGeneric("if (" + condition + ") {"))
+                        caseBody.append(CGIndenter(
+                                getPerSignatureCall(sigs[0], distinguishingIndex)))
+                        caseBody.append(CGGeneric("}"))
+                    return True
+                return False
+
+            # First check for null or undefined
+            pickFirstSignature("%s.isNullOrUndefined()" % distinguishingArg,
+                               lambda s: s[1][distinguishingIndex].type.nullable())
+
+            # XXXbz Now we're supposed to check for distinguishingArg being
+            # an array or a platform object that supports indexed
+            # properties... skip that last for now.  It's a bit of a pain.
+            pickFirstSignature("%s.isObject() && IsArrayLike(cx, &%s.toObject()" %
+                               (distinguishingArg, distinguishingArg),
+                               lambda s:
+                                   (s[1][distinguishingIndex].type.isArray() or
+                                    s[1][distinguishingIndex].type.isSequence() or
+                                    s[1][distinguishingIndex].type.isObject()))
+
+            # Now check for distinguishingArg being a platform object.
+            # We can actually check separately for array buffers and
+            # other things.
+            # XXXbz Do we need to worry about security
+            # wrappers around the array buffer?
+            pickFirstSignature("%s.isObject() && JS_IsArrayBufferObject(&%s.toObject())" %
+                               (distinguishingArg, distinguishingArg),
+                               lambda s: (s[1][distinguishingIndex].type.isArrayBuffer() or
+                                          s[1][distinguishingIndex].type.isObject()))
+            
+            interfacesSigs = [
+                s for s in possibleSignatures
+                if (s[1][distinguishingIndex].type.isObject() or
+                    (s[1][distinguishingIndex].type.isInterface() and
+                     not s[1][distinguishingIndex].type.isArrayBuffer() and
+                     not s[1][distinguishingIndex].type.isCallback())) ]
+            # There might be more than one of these; we need to check
+            # which ones we unwrap to.
+            
+            if len(interfacesSigs) > 0:
+                caseBody.append(CGGeneric("if (%s.isObject() &&\n"
+                                          "    IsPlatformObject(cx, &%s.toObject())) {" %
+                                          (distinguishingArg, distinguishingArg)))
+                for sig in interfacesSigs:
+                    caseBody.append(CGIndenter(CGGeneric("do {")));
+                    type = sig[1][distinguishingIndex].type
+                    
+                    # XXXbz this duplicates some argument-unwrapping code!
+                    interfaceDesc = descriptor.getDescriptor(
+                        type.unroll().inner.identifier.name)
+                    argIsPointer = (type.nullable() or
+                                    type.unroll().inner.isExternal())
+                    if argIsPointer:
+                        nameSuffix = ""
+                    else:
+                        nameSuffix = "_ptr"
+                    if (interfaceDesc.castable or
+                        type.unroll().inner.isExternal() or
+                        interfaceDesc.workers):
+                            declType = "  ${typeName}*"
+                    else:
+                        declType = "  nsCOMPtr<${typeName}>"
+                    template = declType + " ${name}%s;\n" % nameSuffix
+                    if interfaceDesc.castable:
+                        template += str(CastableObjectUnwrapper(
+                                interfaceDesc,
+                                "&${argVal}.toObject()",
+                                "${name}"+nameSuffix,
+                                "break;")) + "\n"
+                    elif interfaceDesc.workers:
+                        template += """
+    ${name}%s = &${argVal}.toObject();
+    MOZ_ASSERT(${name}%s);
+""" % (nameSuffix, nameSuffix)
+                    else:
+                        template += "  xpc_qsSelfRef tmpRef_${name};\n"
+                        template += "  jsval tmpVal_${name} = ${argVal};\n"
+                        template += """
+  ${typeName}* tmp;
+  if (NS_FAILED(xpc_qsUnwrapArg<${typeName}>(cx, ${argVal}, &tmp, &tmpRef_${name}.ptr,
+                                             &tmpVal_${name}))) {
+    break;
+  }
+  MOZ_ASSERT(tmp);
+  ${name}%s = tmp;
+""" % nameSuffix
+
+                    if not argIsPointer:
+                        template += "  ${typeName} &${name} = *${name}_ptr;\n"
+
+                    testCode = string.Template(template).substitute(
+                        {
+                            "typeName": interfaceDesc.nativeType,
+                            "name" : "arg%d" % distinguishingIndex,
+                            "argVal" : distinguishingArg
+                            }
+                        )
+                    caseBody.append(CGIndenter(CGGeneric(testCode)));
+                    # If we got this far, we know we unwrapped to the right
+                    # interface, so just do the call.  Start conversion with
+                    # distinguishingIndex + 1, since we already converted
+                    # distinguishingIndex.
+                    caseBody.append(CGIndenter(CGIndenter(
+                            getPerSignatureCall(sig, distinguishingIndex + 1))))
+                    caseBody.append(CGIndenter(CGGeneric("} while (0);")))
+
+                caseBody.append(CGGeneric("}"))
+
+            # Check for Date objects
+            # XXXbz Do we need to worry about security wrappers around the Date?
+            pickFirstSignature("%s.isObject() && JS_ObjectIsDate(cx, &%s.toObject())" %
+                               (distinguishingArg, distinguishingArg),
+                               lambda s: (s[1][distinguishingIndex].type.isDate() or
+                                          s[1][distinguishingIndex].type.isObject()))
+
+            # Check for vanilla JS objects
+            # XXXbz Do we need to worry about security wrappers?
+            pickFirstSignature("%s.isObject() && !IsPlatformObject(cx, &%s.toObject())" %
+                               (distinguishingArg, distinguishingArg),
+                               lambda s: (s[1][distinguishingIndex].type.isCallback() or
+                                          s[1][distinguishingIndex].type.isDictionary() or
+                                          s[1][distinguishingIndex].type.isObject()))
+
+            # The remaining cases are mutually exclusive.  The
+            # pickFirstSignature calls are what change caseBody
+            # Check for strings or enums
+            if pickFirstSignature(None,
+                                  lambda s: (s[1][distinguishingIndex].type.isString() or
+                                             s[1][distinguishingIndex].type.isEnum())):
+                pass
+            # Check for primitives
+            elif pickFirstSignature(None,
+                                    lambda s: s[1][distinguishingIndex].type.isPrimitive()):
+                pass
+            # Check for "any"
+            elif pickFirstSignature(None,
+                                    lambda s: s[1][distinguishingIndex].type.isAny()):
+                pass
+            else:
+                # Just throw; we have no idea what we're supposed to
+                # do with this.
+                caseBody.append(CGGeneric("return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);" %
+                                          toStringBool(not descriptor.workers)))
+
+            argCountCases.append(CGCase(str(argCount),
+                                        CGList(caseBody, "\n")))
+
+        overloadCGThings = []
+        overloadCGThings.append(
+            CGGeneric("unsigned argcount = NS_MIN(argc, %du);" %
+                      maxSigArgs))
+        overloadCGThings.append(
+            CGSwitch("argcount",
+                     argCountCases,
+                     CGGeneric("return Throw<%s>(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);" %
+                               toStringBool(not descriptor.workers))))
+        overloadCGThings.append(
+                CGGeneric('MOZ_NOT_REACHED("We have an always-returning default case");\n'
+                          'return false;'))
+        self.cgRoot = CGWrapper(CGIndenter(CGList(overloadCGThings, "\n")),
+                                pre="\n")
+
+    def define(self):
+        return self.cgRoot.define()
+
+class CGGetterSetterCall(CGPerSignatureCall):
+    """
+    A class to generate a native object getter or setter call for a
+    particular IDL getter or setter.
+    """
+    def __init__(self, returnType, arguments, nativeMethodName, descriptor,
+                 attr, extendedAttributes):
+        CGPerSignatureCall.__init__(self, returnType, "", arguments,
+                                    nativeMethodName, False, descriptor, attr,
+                                    extendedAttributes)
+    def getArgv(self):
+        if generateNativeAccessors:
+            return CGPerSignatureCall.getArgv(self)
+        return "vp"
+
+class CGGetterCall(CGGetterSetterCall):
+    """
+    A class to generate a native object getter call for a particular IDL
+    getter.
+    """
+    def __init__(self, returnType, nativeMethodName, descriptor, attr,
+                 extendedAttributes):
+        CGGetterSetterCall.__init__(self, returnType, [], nativeMethodName,
+                                    descriptor, attr, extendedAttributes)
+    def getArgc(self):
+        if generateNativeAccessors:
+            return CGGetterSetterCall.getArgc()
+        return "0"
+    def getArgvDecl(self):
+        if generateNativeAccessors:
+            return CGPerSignatureCall.getArgvDecl(self)
+        # We just get our stuff from vp
+        return ""
+
+class FakeArgument():
+    def __init__(self, type):
+        self.type = type
+        self.optional = False
+
+class CGSetterCall(CGGetterSetterCall):
+    """
+    A class to generate a native object setter call for a particular IDL
+    setter.
+    """
+    def __init__(self, argType, nativeMethodName, descriptor, attr,
+                 extendedAttributes):
+        CGGetterSetterCall.__init__(self, None, [FakeArgument(argType)],
+                                    nativeMethodName, descriptor, attr,
+                                    extendedAttributes)
+    def wrap_return_value(self):
+        if generateNativeAccessors:
+            return CGGetterSetterCall.wrap_return_value(self)
+        # We have no return value
+        return "\nreturn true;"
+    def getArgc(self):
+        if generateNativeAccessors:
+            return CGGetterSetterCall.getArgc(self)
+        return "1"
+    def getArgvDecl(self):
+        if generateNativeAccessors:
+            return (CGPerSignatureCall.getArgvDecl(self) +
+                    "jsval undef = JS::UndefinedValue();\n"
+                    "if (argc == 0) {\n"
+                    "  argv = &undef;\n"
+                    "  argc = 1;\n"
+                    "}")
+        # We just get our stuff from vp
+        return ""
+
+class CGAbstractBindingMethod(CGAbstractStaticMethod):
+    """
+    Common class to generate the JSNatives for all our methods, getters, and
+    setters.  This will generate the function declaration and unwrap the
+    |this| object.  Subclasses are expected to override the generate_code
+    function to do the rest of the work.  This function should return a
+    CGThing which is already properly indented.
+    """
+    def __init__(self, descriptor, name, args, extendedAttributes):
+        self.extendedAttributes = extendedAttributes
+        CGAbstractStaticMethod.__init__(self, descriptor, name, "JSBool", args)
+
+    def definition_body(self):
+        unwrapThis = CGGeneric(
+            str(FailureFatalCastableObjectUnwrapper(self.descriptor, "obj", "self")))
+        return CGList([ self.getThis(), unwrapThis,
+                        self.generate_code() ], "\n").define()
+
+    def getThis(self):
+        return CGIndenter(
+            CGGeneric("JSObject* obj = JS_THIS_OBJECT(cx, vp);\n"
+                      "if (!obj) {\n"
+                      "  return false;\n"
+                      "}\n"
+                      "\n"
+                      "%s* self;" % self.descriptor.nativeType))
+
+    def generate_code(self):
+        assert(False) # Override me
+
+def MakeNativeName(name):
+    return name[0].upper() + name[1:]
+
+class CGNativeMethod(CGAbstractBindingMethod):
+    """
+    A class for generating the C++ code for an IDL method..
+    """
+    def __init__(self, descriptor, method):
+        self.method = method
+        baseName = method.identifier.name
+        args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
+                Argument('JS::Value*', 'vp')]
+        CGAbstractBindingMethod.__init__(self, descriptor, baseName, args,
+                                         descriptor.getExtendedAttributes(method))
+    def generate_code(self):
+        name = self.method.identifier.name
+        nativeName = self.descriptor.binaryNames.get(name, MakeNativeName(name))
+        return CGMethodCall("", nativeName, self.method.isStatic(),
+                            self.descriptor, self.method,
+                            self.extendedAttributes)
+
+class CGNativeGetter(CGAbstractBindingMethod):
+    """
+    A class for generating the C++ code for an IDL attribute getter.
+    """
+    def __init__(self, descriptor, attr):
+        self.attr = attr
+        name = 'get_' + attr.identifier.name
+        if generateNativeAccessors:
+            args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
+                    Argument('JS::Value*', 'vp')]
+        else:
+            args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'obj'),
+                    Argument('jsid', 'id'), Argument('JS::Value*', 'vp')]
+        CGAbstractBindingMethod.__init__(self, descriptor, name, args,
+                                         descriptor.getExtendedAttributes(self.attr, getter=True))
+
+    def getThis(self):
+        if generateNativeAccessors:
+            return CGAbstractBindingMethod.getThis(self)
+        return CGIndenter(
+            CGGeneric("%s* self;" % self.descriptor.nativeType))
+
+    def generate_code(self):
+
+        nativeMethodName = "Get" + MakeNativeName(self.attr.identifier.name)
+        return CGIndenter(CGGetterCall(self.attr.type, nativeMethodName, self.descriptor,
+                                       self.attr, self.extendedAttributes))
+
+class CGNativeSetter(CGAbstractBindingMethod):
+    """
+    A class for generating the C++ code for an IDL attribute setter.
+    """
+    def __init__(self, descriptor, attr):
+        self.attr = attr
+        baseName = attr.identifier.name
+        name = 'set_' + attr.identifier.name
+        if generateNativeAccessors:
+            args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
+                    Argument('JS::Value*', 'vp')]
+        else:
+            args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'obj'),
+                    Argument('jsid', 'id'), Argument('JSBool', 'strict'),
+                    Argument('JS::Value*', 'vp')]
+        CGAbstractBindingMethod.__init__(self, descriptor, name, args,
+                                         descriptor.getExtendedAttributes(self.attr, setter=True))
+
+    def getThis(self):
+        if generateNativeAccessors:
+            return CGAbstractBindingMethod.getThis(self)
+        return CGIndenter(
+            CGGeneric("%s* self;" % self.descriptor.nativeType))
+
+    def generate_code(self):
+        nativeMethodName = "Set" + MakeNativeName(self.attr.identifier.name)
+        return CGIndenter(CGSetterCall(self.attr.type, nativeMethodName, self.descriptor,
+                                       self.attr, self.extendedAttributes))
+
+def getEnumValueName(value):
+    # Some enum values can be empty strings.  Others might have weird
+    # characters in them.  Deal with the former by returning "_empty",
+    # deal with possible name collisions from that by throwing if the
+    # enum value is actually "_empty", and throw on any value
+    # containing chars other than [a-z] or '-' for now. Replace '-' with '_'.
+    value = value.replace('-', '_')
+    if value == "_empty":
+        raise SyntaxError('"_empty" is not an IDL enum value we support yet')
+    if value == "":
+        return "_empty"
+    if not re.match("^[a-z_]+$", value):
+        raise SyntaxError('Enum value "' + value + '" contains characters '
+                          'outside [a-z_]')
+    return value
+
+class CGEnum(CGThing):
+    def __init__(self, enum):
+        CGThing.__init__(self)
+        self.enum = enum
+
+    def declare(self):
+        return """
+  enum value {
+    %s
+  };
+
+  extern const EnumEntry strings[%d];
+""" % (",\n    ".join(map(getEnumValueName, self.enum.values())),
+       len(self.enum.values()) + 1)
+
+    def define(self):
+        return """
+  const EnumEntry strings[%d] = {
+    %s,
+    { NULL, 0 }
+  };
+""" % (len(self.enum.values()) + 1,
+       ",\n    ".join(['{"' + val + '", ' + str(len(val)) + '}' for val in self.enum.values()]))
+
+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 CGResolveProperty(CGAbstractMethod):
+    def __init__(self, descriptor, properties):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
+                Argument('jsid', 'id'), Argument('bool', 'set'),
+                Argument('JSPropertyDescriptor*', 'desc')]
+        CGAbstractMethod.__init__(self, descriptor, "ResolveProperty", "bool", args)
+        self.properties = properties
+    def definition_body(self):
+        str = ""
+
+        varNames = self.properties.variableNames(True)
+
+        methods = self.properties.methods
+        if methods.hasNonChromeOnly() or methods.hasChromeOnly():
+            str += """  for (size_t i = 0; i < ArrayLength(%(methods)s_ids); ++i) {
+    if (id == %(methods)s_ids[i]) {
+      JSFunction *fun = JS_NewFunctionById(cx, %(methods)s[i].call, %(methods)s[i].nargs, 0, wrapper, id);
+      if (!fun)
+          return false;
+      JSObject *funobj = JS_GetFunctionObject(fun);
+      desc->value.setObject(*funobj);
+      desc->attrs = %(methods)s[i].flags;
+      desc->obj = wrapper;
+      desc->setter = nsnull;
+      desc->getter = nsnull;
+      return true;
+    }
+  }
+
+""" % varNames
+
+        attrs = self.properties.attrs
+        if attrs.hasNonChromeOnly() or attrs.hasChromeOnly():
+            str += """  for (size_t i = 0; i < ArrayLength(%(attrs)s_ids); ++i) {
+    if (id == %(attrs)s_ids[i]) {
+      desc->attrs = %(attrs)s[i].flags;
+      desc->obj = wrapper;
+      desc->setter = %(attrs)s[i].setter;
+      desc->getter = %(attrs)s[i].getter;
+      return true;
+    }
+  }
+
+""" % varNames
+
+        return str + "  return true;"
+
+class CGEnumerateProperties(CGAbstractMethod):
+    def __init__(self, descriptor, properties):
+        args = [Argument('JS::AutoIdVector&', 'props')]
+        CGAbstractMethod.__init__(self, descriptor, "EnumerateProperties", "bool", args)
+        self.properties = properties
+    def definition_body(self):
+        str = ""
+
+        varNames = self.properties.variableNames(True)
+
+        methods = self.properties.methods
+        if methods.hasNonChromeOnly() or methods.hasChromeOnly():
+            str += """  for (size_t i = 0; i < sizeof(%(methods)s_ids); ++i) {
+    if ((%(methods)s[i].flags & JSPROP_ENUMERATE) &&
+        !props.append(%(methods)s_ids[i])) {
+      return false;
+    }
+  }
+
+""" % varNames
+
+        attrs = self.properties.attrs
+        if attrs.hasNonChromeOnly() or attrs.hasChromeOnly():
+            str += """  for (size_t i = 0; i < sizeof(%(attrs)s_ids); ++i) {
+    if ((%(attrs)s[i].flags & JSPROP_ENUMERATE) &&
+        !props.append(%(attrs)s_ids[i])) {
+      return false;
+    }
+  }
+
+""" % varNames
+
+        return str + "  return true;"
+
+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('NativeType', descriptor.nativeType)]
+        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.nativeType]
+        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)
+
+        assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
+
+        cgThings = []
+        if descriptor.interface.hasInterfacePrototypeObject():
+            cgThings.extend([CGNativeMethod(descriptor, m) for m in
+                             descriptor.interface.members if
+                             m.isMethod() and not m.isStatic()])
+            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])
+
+        if descriptor.concrete:
+            if not descriptor.workers:
+                cgThings.append(CGAddPropertyHook(descriptor))
+
+            # Always have a finalize hook, regardless of whether the class wants a
+            # custom hook.
+            if descriptor.nativeIsISupports:
+                cgThings.append(CGNativeToSupportsMethod(descriptor))
+            cgThings.append(CGClassFinalizeHook(descriptor))
+
+            # Only generate a trace hook if the class wants a custom hook.
+            if (descriptor.customTrace):
+                cgThings.append(CGClassTraceHook(descriptor))
+
+        if descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject():
+            cgThings.append(CGNativePropertyHooks(descriptor))
+        if descriptor.concrete:
+            cgThings.append(CGDOMJSClass(descriptor))
+
+        if descriptor.interface.hasInterfaceObject():
+            cgThings.append(CGClassConstructHook(descriptor))
+            cgThings.append(CGClassHasInstanceHook(descriptor))
+            cgThings.append(CGInterfaceObjectJSClass(descriptor))
+
+        if descriptor.interface.hasInterfacePrototypeObject():
+            cgThings.append(CGPrototypeJSClass(descriptor))
+
+        properties = PropertyArrays(descriptor)
+        cgThings.append(CGGeneric(define=str(properties)))
+        cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
+        if descriptor.interface.hasInterfacePrototypeObject():
+            cgThings.append(CGIndenter(CGGetProtoObjectMethod(descriptor)))
+        else:
+            cgThings.append(CGIndenter(CGGetConstructorObjectMethod(descriptor)))
+
+        if descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject():
+            cgThings.append(CGResolveProperty(descriptor, properties))
+            cgThings.append(CGEnumerateProperties(descriptor, properties))
+
+        if descriptor.interface.hasInterfaceObject():
+            cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
+
+        if descriptor.concrete:
+            cgThings.append(CGWrapMethod(descriptor))
+
+        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 = []
+
+        # Account for explicit enum values.
+        entries = []
+        for i in range(0, len(names)):
+            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('_' + enumName + '_Count')
+
+        # Indent.
+        entries = ['  ' + e for e in entries]
+
+        # Build the enum body.
+        enumstr = comment + 'enum %s\n{\n%s\n};\n' % (enumName, ',\n'.join(entries))
+        curr = CGGeneric(declare=enumstr)
+
+        # Add some whitespace padding.
+        curr = CGWrapper(curr, pre='\n',post='\n')
+
+        # Add the namespace.
+        curr = CGNamespace(namespace, curr)
+
+        # Add the typedef
+        typedef = '\ntypedef %s::%s %s;\n\n' % (namespace, enumName, enumName)
+        curr = CGList([curr, CGGeneric(declare=typedef)])
+
+        # Save the result.
+        self.node = curr
+
+    def declare(self):
+        return self.node.declare()
+    def define(self):
+        assert False # Only for headers.
+
+class CGRegisterProtos(CGAbstractMethod):
+    def __init__(self, config):
+        CGAbstractMethod.__init__(self, None, 'Register', 'void',
+                                  [Argument('nsScriptNameSpaceManager*', 'aNameSpaceManager')])
+        self.config = config
+
+    def _defineMacro(self):
+       return """
+#define REGISTER_PROTO(_dom_class) \\
+  aNameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING(#_dom_class), prototypes::_dom_class::DefineDOMInterface);\n\n"""
+    def _undefineMacro(self):
+        return "\n#undef REGISTER_PROTO"
+    def _registerProtos(self):
+        lines = ["REGISTER_PROTO(%s);" % desc.name
+                 for desc in self.config.getDescriptors(hasInterfaceObject=True,
+                                                        isExternal=False,
+                                                        workers=False)]
+        return '\n'.join(lines) + '\n'
+    def definition_body(self):
+        return self._defineMacro() + self._registerProtos() + self._undefineMacro()
+
+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)
+
+        forwardDeclares = [CGClassForwardDeclare('XPCWrappedNativeScope')]
+
+        for x in descriptors:
+            nativeType = x.nativeType
+            components = x.nativeType.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)
+
+        descriptorsWithPrototype = filter(lambda d: d.interface.hasInterfacePrototypeObject(),
+                                          descriptors)
+        traitsClasses = [CGPrototypeTraitsClass(d) for d in descriptorsWithPrototype]
+
+        # 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 descriptorsWithPrototype
+                              if d.uniqueImplementation])
+
+        # Wrap all of that in our namespaces.
+        if len(traitsClasses) > 0:
+            traitsClasses = CGNamespace.build(['mozilla', 'dom', 'bindings'],
+                                     CGWrapper(CGList(traitsClasses),
+                                               declarePre='\n'),
+                                               declareOnly=True)
+            traitsClasses = CGWrapper(traitsClasses, declarePost='\n')
+        else:
+            traitsClasses = CGGeneric()
+
+        # 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 descriptors])
+        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(descriptors,
+                         ['mozilla/dom/bindings/Utils.h',
+                          'DOMJSClass.h'],
+                         ['mozilla/dom/bindings/Nullable.h',
+                          'XPCQuickStubs.h',
+                          'AccessCheck.h',
+                          'WorkerPrivate.h',
+                          'nsContentUtils.h'],
+                         curr)
+
+        # Add include guards.
+        curr = CGIncludeGuard(prefix, curr)
+
+        # Add the auto-generated comment.
+        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
+
+        # Store the final result.
+        self.root = curr
+
+    def declare(self):
+        return stripTrailingWhitespace(self.root.declare())
+    def define(self):
+        return stripTrailingWhitespace(self.root.define())
+
+
+class GlobalGenRoots():
+    """
+    Roots for global codegen.
+
+    To generate code, call the method associated with the target, and then
+    call the appropriate define/declare method.
+    """
+
+    @staticmethod
+    def PrototypeList(config):
+
+        # Prototype ID enum.
+        protos = [d.name for d in config.getDescriptors(hasInterfacePrototypeObject=True)]
+        idEnum = CGNamespacedEnum('id', 'ID', protos, [0])
+        idEnum = CGList([idEnum])
+        idEnum.append(CGGeneric(declare="const unsigned MaxProtoChainLength = " +
+                                str(config.maxProtoChainLength) + ";\n\n"))
+
+        # Wrap all of that in our namespaces.
+        idEnum = CGNamespace.build(['mozilla', 'dom', 'bindings', 'prototypes'],
+                                   CGWrapper(idEnum, pre='\n'))
+        idEnum = CGWrapper(idEnum, post='\n')
+
+        curr = CGList([idEnum])
+
+        # Constructor ID enum.
+        constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True,
+                                                              hasInterfacePrototypeObject=False)]
+        idEnum = CGNamespacedEnum('id', 'ID', constructors, [0])
+
+        # Wrap all of that in our namespaces.
+        idEnum = CGNamespace.build(['mozilla', 'dom', 'bindings', 'constructors'],
+                                   CGWrapper(idEnum, pre='\n'))
+        idEnum = CGWrapper(idEnum, post='\n')
+
+        curr.append(idEnum)
+
+        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.append(traitsDecl)
+
+        # Add include guards.
+        curr = CGIncludeGuard('PrototypeList', curr)
+
+        # Add the auto-generated comment.
+        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
+
+        # Done.
+        return curr
+
+    @staticmethod
+    def Common(config):
+
+        # TODO - Generate the methods we want
+        curr = CGRegisterProtos(config)
+
+        # Wrap all of that in our namespaces.
+        curr = CGNamespace.build(['mozilla', 'dom', 'bindings'],
+                                 CGWrapper(curr, post='\n'))
+        curr = CGWrapper(curr, post='\n')
+
+        # Add the includes
+        defineIncludes = [CGHeaders.getInterfaceFilename(desc.interface)
+                          for desc in config.getDescriptors(hasInterfaceObject=True,
+                                                            workers=False)]
+        defineIncludes.append('nsScriptNameSpaceManager.h')
+        curr = CGHeaders([], [], defineIncludes, curr)
+
+        # Add include guards.
+        curr = CGIncludeGuard('Common', curr)
+
+        # Done.
+        return curr
new file mode 100644
--- /dev/null
+++ b/dom/bindings/Configuration.py
@@ -0,0 +1,186 @@
+# 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 = {}
+        self.maxProtoChainLength = 0;
+        for thing in parseData:
+            if not thing.isInterface(): continue
+            iface = thing
+            if iface.identifier.name not in config: continue
+            self.interfaces[iface.identifier.name] = iface
+            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 nativeType 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 getDescriptors(self, **filters):
+        """Gets the descriptors that match the given filters."""
+        curr = self.descriptors
+        for key, val in filters.iteritems():
+            if key == 'webIDLFile':
+                getter = lambda x: x.interface.filename()
+            elif key == 'hasInterfaceObject':
+                getter = lambda x: (not x.interface.isExternal() and
+                                    x.interface.hasInterfaceObject())
+            elif key == 'hasInterfacePrototypeObject':
+                getter = lambda x: (not x.interface.isExternal() and
+                                    x.interface.hasInterfacePrototypeObject())
+            elif key == 'hasInterfaceOrInterfacePrototypeObject':
+                getter = lambda x: x.hasInterfaceOrInterfacePrototypeObject()
+            elif key == 'isCallback':
+                getter = lambda x: x.interface.isCallback()
+            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)
+
+class Descriptor:
+    """
+    Represents a single descriptor for an interface. See Bindings.conf.
+    """
+    def __init__(self, config, interface, desc):
+        self.config = config
+        self.interface = interface
+
+        # Read the desc, and fill in the relevant defaults.
+        self.nativeType = desc['nativeType']
+        self.hasInstanceInterface = desc.get('hasInstanceInterface', None)
+
+        headerDefault = self.nativeType
+        headerDefault = headerDefault.split("::")[-1] + ".h"
+        self.headerFile = desc.get('headerFile', headerDefault)
+
+        castableDefault = not self.interface.isCallback()
+        self.castable = desc.get('castable', castableDefault)
+
+        self.notflattened = desc.get('notflattened', False)
+
+        # If we're concrete, we need to crawl our ancestor interfaces and mark
+        # them as having a concrete descendant.
+        self.concrete = desc.get('concrete', True)
+        if self.concrete:
+            iface = self.interface
+            while iface:
+                iface.setUserData('hasConcreteDescendant', True)
+                iface = iface.parent
+
+        self.prefable = desc.get('prefable', False)
+
+        self.workers = desc.get('workers', False)
+        self.nativeIsISupports = not self.workers
+        self.customTrace = desc.get('customTrace', self.workers)
+        self.customFinalize = desc.get('customFinalize', self.workers)
+
+        def make_name(name):
+            return name + "_workers" if self.workers else name
+        self.name = make_name(interface.identifier.name)
+
+        # self.extendedAttributes is a dict of dicts, keyed on
+        # all/getterOnly/setterOnly and then on member name. Values are an
+        # array of extended attributes.
+        self.extendedAttributes = { 'all': {}, 'getterOnly': {}, 'setterOnly': {} }
+
+        def addExtendedAttribute(attribute, config):
+            def add(key, members, attribute):
+                for member in members:
+                    self.extendedAttributes[key].setdefault(member, []).append(attribute)
+
+            if isinstance(config, dict):
+                for key in ['all', 'getterOnly', 'setterOnly']:
+                    add(key, config.get(key, []), attribute)
+            elif isinstance(config, list):
+                add('all', config, attribute)
+            else:
+                assert isinstance(config, string)
+                add('all', [config], attribute)
+
+        for attribute in ['infallible', 'implicitJSContext', 'resultNotAddRefed']:
+            addExtendedAttribute(attribute, desc.get(attribute, {}))
+
+        self.binaryNames = desc.get('binaryNames', {})
+
+        # Build the prototype chain.
+        self.prototypeChain = []
+        parent = interface
+        while parent:
+            self.prototypeChain.insert(0, make_name(parent.identifier.name))
+            parent = parent.parent
+        config.maxProtoChainLength = max(config.maxProtoChainLength,
+                                         len(self.prototypeChain))
+
+    def hasInterfaceOrInterfacePrototypeObject(self):
+
+        # Forward-declared interfaces don't need either interface object or
+        # interface prototype object as they're going to use QI (on main thread)
+        # or be passed as a JSObject (on worker threads).
+        if self.interface.isExternal():
+            return False
+
+        return self.interface.hasInterfaceObject() or self.interface.hasInterfacePrototypeObject()
+
+    def getDescriptor(self, interfaceName):
+        """
+        Gets the appropriate descriptor for the given interface name given the
+        context of the current descriptor. This selects the appropriate
+        implementation for cases like workers.
+        """
+        iface = self.config.getInterface(interfaceName)
+        descriptors = self.config.getDescriptors(interface=iface)
+
+        # The only filter we currently have is workers vs non-workers.
+        matches = filter(lambda x: x.workers is self.workers, descriptors)
+
+        # After filtering, we should have exactly one result.
+        if len(matches) is not 1:
+            raise TypeError("For " + interfaceName + " found " +
+                            str(len(matches)) + " matches");
+        return matches[0]
+
+    def getExtendedAttributes(self, member, getter=False, setter=False):
+        name = member.identifier.name
+        if member.isMethod():
+            return self.extendedAttributes['all'].get(name, [])
+
+        assert member.isAttr()
+        assert bool(getter) != bool(setter)
+        key = 'getterOnly' if getter else 'setterOnly'
+        return self.extendedAttributes['all'].get(name, []) + self.extendedAttributes[key].get(name, [])
new file mode 100644
--- /dev/null
+++ b/dom/bindings/DOMJSClass.h
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; 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/. */
+
+#ifndef mozilla_dom_bindings_DOMJSClass_h
+#define mozilla_dom_bindings_DOMJSClass_h
+
+#include "jsapi.h"
+#include "jsfriendapi.h"
+
+#include "mozilla/dom/bindings/PrototypeList.h" // auto-generated
+
+// For non-global objects we use slot 0 for holding the raw object.
+#define DOM_OBJECT_SLOT 0
+
+// All DOM globals must have two slots at DOM_GLOBAL_OBJECT_SLOT and
+// DOM_PROTOTYPE_SLOT. We have to start at 1 past JSCLASS_GLOBAL_SLOT_COUNT
+// because XPConnect uses that one.
+#define DOM_GLOBAL_OBJECT_SLOT (JSCLASS_GLOBAL_SLOT_COUNT + 1)
+#define DOM_PROTOTYPE_SLOT (JSCLASS_GLOBAL_SLOT_COUNT + 2)
+
+// We use these flag bits for the new bindings.
+#define JSCLASS_IS_DOMJSCLASS JSCLASS_USERBIT1
+#define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT2
+
+namespace mozilla {
+namespace dom {
+namespace bindings {
+
+typedef bool
+(* ResolveProperty)(JSContext* cx, JSObject* wrapper, jsid id, bool set,
+                    JSPropertyDescriptor* desc);
+typedef bool
+(* EnumerateProperties)(JS::AutoIdVector& props);
+
+struct NativePropertyHooks
+{
+  ResolveProperty mResolveProperty;
+  EnumerateProperties mEnumerateProperties;
+
+  const NativePropertyHooks *mProtoHooks;
+};
+
+// Special JSClass for reflected DOM objects.
+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::_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.
+  // XXXkhuey this is unused and needs to die.
+  const int16_t mGetWrapperCacheVTableOffset;
+
+  // We store the DOM object in a reserved slot whose index is mNativeSlot.
+  // Sometimes it's an nsISupports and sometimes it's not; this class tells
+  // us which it is.
+  const bool mDOMObjectIsISupports;
+
+  // The slot to use to get the object reference from the object
+  const size_t mNativeSlot;
+
+  const NativePropertyHooks* mNativeHooks;
+
+  static DOMJSClass* FromJSClass(JSClass* base) {
+    MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS);
+    return reinterpret_cast<DOMJSClass*>(base);
+  }
+  static const DOMJSClass* FromJSClass(const JSClass* base) {
+    MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS);
+    return reinterpret_cast<const DOMJSClass*>(base);
+  }
+
+  static DOMJSClass* FromJSClass(js::Class* base) {
+    return FromJSClass(Jsvalify(base));
+  }
+  static const DOMJSClass* FromJSClass(const js::Class* base) {
+    return FromJSClass(Jsvalify(base));
+  }
+
+  JSClass* ToJSClass() { return &mBase; }
+};
+
+inline JSObject**
+GetProtoOrIfaceArray(JSObject* global)
+{
+  MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL);
+  return static_cast<JSObject**>(
+    js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).toPrivate());
+}
+
+} // namespace bindings
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_bindings_DOMJSClass_h */
new file mode 100644
--- /dev/null
+++ b/dom/bindings/GlobalGen.py
@@ -0,0 +1,81 @@
+# 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/.
+
+# 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 Configuration import *
+from Codegen import GlobalGenRoots, replaceFileIfChanged
+# import Codegen in general, so we can set a variable on it
+import Codegen
+
+def generate_file(config, name, action):
+
+    root = getattr(GlobalGenRoots, name)(config)
+    if action is 'declare':
+        filename = name + '.h'
+        code = root.declare()
+    else:
+        assert action is 'define'
+        filename = name + '.cpp'
+        code = root.define()
+
+    if replaceFileIfChanged(filename, code):
+        print "Generating %s" % (filename)
+    else:
+        print "%s hasn't changed - not touching it" % (filename)
+
+def main():
+    # Parse arguments.
+    from optparse import OptionParser
+    usageString = "usage: %prog [options] webidldir [files]"
+    o = OptionParser(usage=usageString)
+    o.add_option("--cachedir", dest='cachedir', default=None,
+                 help="Directory in which to cache lex/parse tables.")
+    o.add_option("--verbose-errors", action='store_true', default=False,
+                 help="When an error happens, display the Python traceback.")
+    o.add_option("--use-jsop-accessors", action='store_true', default=False,
+                 dest='useJSOPAccessors',
+                 help="Use JSPropertyOps instead of JSNatives for getters and setters")
+    (options, args) = o.parse_args()
+    Codegen.generateNativeAccessors = not options.useJSOPAccessors
+
+    if len(args) < 2:
+        o.error(usageString)
+
+    configFile = args[0]
+    baseDir = args[1]
+    fileList = args[2:]
+
+    # Parse the WebIDL.
+    parser = WebIDL.Parser(options.cachedir)
+    for filename in fileList:
+        fullPath = os.path.normpath(os.path.join(baseDir, filename))
+        f = open(fullPath, 'rb')
+        lines = f.readlines()
+        f.close()
+        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()
+
+    # Load the configuration.
+    config = Configuration(configFile, parserResults)
+
+    # Generate the prototype list.
+    generate_file(config, 'PrototypeList', 'declare')
+
+    # Generate the common code.
+    generate_file(config, 'Common', 'declare')
+    generate_file(config, 'Common', 'define')
+
+if __name__ == '__main__':
+    main()
new file mode 100644
--- /dev/null
+++ b/dom/bindings/Makefile.in
@@ -0,0 +1,122 @@
+# 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/.
+
+DEPTH            = ../..
+topsrcdir        = @top_srcdir@
+srcdir           = @srcdir@
+VPATH            = @srcdir@
+
+MODULE           = dom
+LIBRARY_NAME     = dombindings_s
+LIBXUL_LIBRARY   = 1
+FORCE_STATIC_LIB = 1
+EXPORT_LIBRARY   = 1
+
+include $(topsrcdir)/config/config.mk
+
+# Define USE_JSOP_ACCESSORS to a nonempty string like "yes" to use them
+USE_JSOP_ACCESSORS = 
+ifdef USE_JSOP_ACCESSORS
+DEFINES += -DUSE_JSOP_ACCESSORS
+ACCESSOR_OPT = --use-jsop-accessors
+else
+ACCESSOR_OPT =
+endif
+
+# Need this to find all our DOM source files.
+include $(topsrcdir)/dom/dom-config.mk
+
+include $(topsrcdir)/dom/webidl/WebIDL.mk
+
+binding_include_path := mozilla/dom/bindings
+binding_header_files := $(subst .webidl,Binding.h,$(webidl_files))
+binding_cpp_files := $(subst .webidl,Binding.cpp,$(webidl_files))
+
+globalgen_targets := \
+  PrototypeList.h \
+  Common.h \
+  Common.cpp \
+  $(NULL)
+
+CPPSRCS = \
+  $(binding_cpp_files) \
+  $(filter %.cpp, $(globalgen_targets)) \
+  Utils.cpp \
+  $(NULL)
+
+EXPORTS_NAMESPACES = $(binding_include_path)
+
+EXPORTS_$(binding_include_path) = \
+  DOMJSClass.h \
+  PrototypeList.h \
+  Common.h \
+  Nullable.h \
+  Utils.h \
+  $(binding_header_files) \
+  $(NULL)
+
+LOCAL_INCLUDES += -I$(topsrcdir)/js/xpconnect/src \
+  -I$(topsrcdir)/js/xpconnect/wrappers
+
+TEST_DIRS += test
+
+include $(topsrcdir)/config/rules.mk
+
+bindinggen_dependencies := \
+  BindingGen.py \
+  Bindings.conf \
+  Configuration.py \
+  Codegen.py \
+  ParserResults.pkl \
+  $(GLOBAL_DEPS) \
+  $(NULL)
+
+$(binding_header_files): %Binding.h: $(bindinggen_dependencies) \
+                                     $(webidl_base)/%.webidl \
+                                     $(NULL)
+	$(PYTHON) $(topsrcdir)/config/pythonpath.py \
+    -I$(topsrcdir)/other-licenses/ply -I$(srcdir)/parser \
+    $(srcdir)/BindingGen.py $(ACCESSOR_OPT) header $(srcdir)/Bindings.conf $*Binding \
+    $(webidl_base)/$*.webidl
+
+$(binding_cpp_files): %Binding.cpp: $(bindinggen_dependencies) \
+                                    $(webidl_base)/%.webidl \
+                                    $(NULL)
+	$(PYTHON) $(topsrcdir)/config/pythonpath.py \
+    -I$(topsrcdir)/other-licenses/ply -I$(srcdir)/parser \
+    $(srcdir)/BindingGen.py $(ACCESSOR_OPT) cpp $(srcdir)/Bindings.conf $*Binding \
+    $(webidl_base)/$*.webidl
+
+$(globalgen_targets): ParserResults.pkl
+
+CACHE_DIR = _cache
+
+globalgen_dependencies := \
+  GlobalGen.py \
+  Bindings.conf \
+  Configuration.py \
+  Codegen.py \
+  $(CACHE_DIR)/.done \
+  $(GLOBAL_DEPS) \
+  $(NULL)
+
+$(CACHE_DIR)/.done:
+	$(MKDIR) -p $(CACHE_DIR)
+	@$(TOUCH) $@
+
+ParserResults.pkl: $(globalgen_dependencies) \
+                   $(addprefix $(webidl_base)/, $(webidl_files))
+	$(PYTHON_PATH) -I$(topsrcdir)/other-licenses/ply -I$(srcdir)/parser \
+    $(srcdir)/GlobalGen.py $(ACCESSOR_OPT) $(srcdir)/Bindings.conf $(webidl_base) \
+    --cachedir=$(CACHE_DIR) \
+    $(webidl_files)
+
+GARBAGE += \
+  $(binding_header_files) \
+  $(binding_cpp_files) \
+  $(globalgen_targets) \
+  ParserResults.pkl \
+  webidlyacc.py \
+  parser.out \
+  $(NULL)
new file mode 100644
--- /dev/null
+++ b/dom/bindings/Nullable.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
+/* vim: set ts=2 sw=2 et tw=79: */
+/* 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/. */
+
+#ifndef mozilla_dom_bindings_Nullable_h
+#define mozilla_dom_bindings_Nullable_h
+
+#include "mozilla/Assertions.h"
+
+namespace mozilla {
+namespace dom {
+namespace bindings {
+
+// Support for nullable types
+template <typename T>
+struct Nullable
+{
+private:
+  T mValue;
+  bool mIsNull;
+
+public:
+  Nullable()
+    : mIsNull(true)
+  {}
+
+  Nullable(T aValue)
+    : mValue(aValue)
+    , mIsNull(false)
+  {}
+
+  void SetValue(T aValue) {
+    mValue = aValue;
+    mIsNull = false;
+  }
+
+  void SetNull() {
+    mIsNull = true;
+  }
+
+  T Value() const {
+    MOZ_ASSERT(!mIsNull);
+    return mValue;
+  }
+
+  bool IsNull() const {
+    return mIsNull;
+  }
+};
+
+} // namespace bindings
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_bindings_Nullable_h */
new file mode 100644
--- /dev/null
+++ b/dom/bindings/Utils.cpp
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
+/* vim: set ts=2 sw=2 et tw=79: */
+/* 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/. */
+
+#include "Utils.h"
+
+namespace mozilla {
+namespace dom {
+namespace bindings {
+
+static bool
+DefineConstants(JSContext* cx, JSObject* obj, ConstantSpec* cs)
+{
+  for (; cs->name; ++cs) {
+    JSBool ok =
+      JS_DefineProperty(cx, obj, cs->name, cs->value, NULL, NULL,
+                        JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
+    if (!ok) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static JSObject*
+CreateInterfaceObject(JSContext* cx, JSObject* global,
+                      JSClass* constructorClass, JSObject* proto,
+                      JSFunctionSpec* staticMethods, ConstantSpec* constants,
+                      const char* name)
+{
+  JSObject* functionProto = JS_GetFunctionPrototype(cx, global);
+  if (!functionProto) {
+    return NULL;
+  }
+
+  JSObject* constructor =
+    JS_NewObject(cx, constructorClass, functionProto, global);
+  if (!constructor) {
+    return NULL;
+  }
+
+  if (staticMethods && !JS_DefineFunctions(cx, constructor, staticMethods)) {
+    return NULL;
+  }
+
+  if (constants && !DefineConstants(cx, constructor, constants)) {
+    return NULL;
+  }
+
+  if (proto && !JS_LinkConstructorAndPrototype(cx, constructor, proto)) {
+    return NULL;
+  }
+
+  // This is Enumerable: False per spec.
+  if (!JS_DefineProperty(cx, global, name, OBJECT_TO_JSVAL(constructor), NULL,
+                         NULL, 0)) {
+    return NULL;
+  }
+
+  return constructor;
+}
+
+static JSObject*
+CreateInterfacePrototypeObject(JSContext* cx, JSObject* global,
+                               JSObject* parentProto, JSClass* protoClass,
+                               JSFunctionSpec* methods,
+                               JSPropertySpec* properties,
+                               ConstantSpec* constants)
+{
+  JSObject* ourProto = JS_NewObject(cx, protoClass, parentProto, global);
+  if (!ourProto) {
+    return NULL;
+  }
+
+  if (methods && !JS_DefineFunctions(cx, ourProto, methods)) {
+    return NULL;
+  }
+
+  if (properties && !JS_DefineProperties(cx, ourProto, properties)) {
+    return NULL;
+  }
+
+  if (constants && !DefineConstants(cx, ourProto, constants)) {
+    return NULL;
+  }
+
+  return ourProto;
+}
+
+JSObject*
+CreateInterfaceObjects(JSContext *cx, JSObject *global, JSObject *parentProto,
+                       JSClass *protoClass, JSClass *constructorClass,
+                       JSFunctionSpec *methods, JSPropertySpec *properties,
+                       ConstantSpec *constants, JSFunctionSpec *staticMethods,
+                       const char* name)
+{
+  MOZ_ASSERT(protoClass || constructorClass, "Need at least one class!");
+  MOZ_ASSERT(!(methods || properties) || protoClass,
+             "Methods or properties but no protoClass!");
+  MOZ_ASSERT(!staticMethods || constructorClass,
+             "Static methods but no constructorClass!");
+  MOZ_ASSERT(bool(name) == bool(constructorClass),
+             "Must have name precisely when we have an interface object");
+
+  JSObject* proto;
+  if (protoClass) {
+    proto = CreateInterfacePrototypeObject(cx, global, parentProto, protoClass,
+                                           methods, properties, constants);
+    if (!proto) {
+      return NULL;
+    }
+  }
+  else {
+    proto = NULL;
+  }
+
+  JSObject* interface;
+  if (constructorClass) {
+    interface = CreateInterfaceObject(cx, global, constructorClass, proto,
+                                      staticMethods, constants, name);
+    if (!interface) {
+      return NULL;
+    }
+  }
+
+  return protoClass ? proto : interface;
+}
+
+static bool
+NativeInterface2JSObjectAndThrowIfFailed(XPCLazyCallContext& aLccx,
+                                         JSContext* aCx,
+                                         JS::Value* aRetval,
+                                         xpcObjectHelper& aHelper,
+                                         const nsIID* aIID,
+                                         bool aAllowNativeWrapper)
+{
+  nsresult rv;
+  if (!XPCConvert::NativeInterface2JSObject(aLccx, aRetval, NULL, aHelper, aIID,
+                                            NULL, aAllowNativeWrapper, &rv)) {
+    // I can't tell if NativeInterface2JSObject throws JS exceptions
+    // or not.  This is a sloppy stab at the right semantics; the
+    // method really ought to be fixed to behave consistently.
+    if (!JS_IsExceptionPending(aCx)) {
+      Throw<true>(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
+    }
+    return false;
+  }
+  return true;
+}
+
+bool
+DoHandleNewBindingWrappingFailure(JSContext* cx, JSObject* scope,
+                                  nsISupports* value, JS::Value* vp)
+{
+  if (JS_IsExceptionPending(cx)) {
+    return false;
+  }
+
+  XPCLazyCallContext lccx(JS_CALLER, cx, scope);
+
+  if (value) {
+    xpcObjectHelper helper(value);
+    return NativeInterface2JSObjectAndThrowIfFailed(lccx, cx, vp, helper, NULL,
+                                                    true);
+  }
+
+  return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
+}
+
+// Only set allowNativeWrapper to false if you really know you need it, if in
+// doubt use true. Setting it to false disables security wrappers.
+bool
+XPCOMObjectToJsval(JSContext* cx, JSObject* scope, xpcObjectHelper &helper,
+                   const nsIID* iid, bool allowNativeWrapper, JS::Value* rval)
+{
+  XPCLazyCallContext lccx(JS_CALLER, cx, scope);
+
+  if (!NativeInterface2JSObjectAndThrowIfFailed(lccx, cx, rval, helper, iid,
+                                                allowNativeWrapper)) {
+    return false;
+  }
+
+#ifdef DEBUG
+  JSObject* jsobj = JSVAL_TO_OBJECT(*rval);
+  if (jsobj && !js::GetObjectParent(jsobj))
+    NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
+                 "Why did we recreate this wrapper?");
+#endif
+
+  return true;
+}
+
+JSBool
+QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
+{
+  JS::Value thisv = JS_THIS(cx, vp);
+  if (thisv == JSVAL_NULL)
+    return false;
+
+  JSObject* obj = JSVAL_TO_OBJECT(thisv);
+  JSClass* clasp = js::GetObjectJSClass(obj);
+  if (!IsDOMClass(clasp)) {
+    return Throw<true>(cx, NS_ERROR_FAILURE);
+  }
+
+  nsISupports* native = UnwrapDOMObject<nsISupports>(obj, clasp);
+
+  if (argc < 1) {
+    return Throw<true>(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
+  }
+
+  JS::Value* argv = JS_ARGV(cx, vp);
+  if (!argv[0].isObject()) {
+    return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
+  }
+
+  nsIJSIID* iid;
+  xpc_qsSelfRef iidRef;
+  if (NS_FAILED(xpc_qsUnwrapArg<nsIJSIID>(cx, argv[0], &iid, &iidRef.ptr,
+                                          &argv[0]))) {
+    return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
+  }
+  MOZ_ASSERT(iid);
+
+  if (iid->GetID()->Equals(NS_GET_IID(nsIClassInfo))) {
+    nsresult rv;
+    nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(native, &rv);
+    if (NS_FAILED(rv)) {
+      return Throw<true>(cx, rv);
+    }
+
+    return WrapObject(cx, obj, ci, &NS_GET_IID(nsIClassInfo), vp);
+  }
+  
+  // Lie, otherwise we need to check classinfo or QI
+  *vp = thisv;
+  return true;
+}
+
+} // namespace bindings
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/bindings/Utils.h
@@ -0,0 +1,508 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
+/* vim: set ts=2 sw=2 et tw=79: */
+/* 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/. */
+
+#ifndef mozilla_dom_bindings_Utils_h__
+#define mozilla_dom_bindings_Utils_h__
+
+#include "mozilla/dom/bindings/DOMJSClass.h"
+
+#include "jsapi.h"
+#include "jstypedarray.h"
+
+#include "XPCQuickStubs.h"
+#include "XPCWrapper.h"
+#include "nsTraceRefcnt.h"
+#include "nsWrapperCacheInlines.h"
+
+namespace mozilla {
+namespace dom {
+namespace bindings {
+
+template<bool mainThread>
+inline bool
+Throw(JSContext* cx, nsresult rv)
+{
+  // XXX Introduce exception machinery.
+  if (mainThread) {
+    XPCThrower::Throw(rv, cx);
+  } else {
+    if (!JS_IsExceptionPending(cx)) {
+      JS_ReportError(cx, "Exception thrown (nsresult = %x).", rv);
+    }
+  }
+  return false;
+}
+
+template<bool mainThread>
+inline bool
+ThrowMethodFailedWithDetails(JSContext* cx, nsresult rv,
+                             const char* /* ifaceName */,
+                             const char* /* memberName */)
+{
+  return Throw<mainThread>(cx, rv);
+}
+
+inline bool
+IsDOMClass(const JSClass* clasp)
+{
+  return clasp->flags & JSCLASS_IS_DOMJSCLASS;
+}
+
+template <class T>
+inline T*
+UnwrapDOMObject(JSObject* obj, const JSClass* clasp)
+{
+  MOZ_ASSERT(IsDOMClass(clasp));
+  MOZ_ASSERT(JS_GetClass(obj) == clasp);
+
+  size_t slot = DOMJSClass::FromJSClass(clasp)->mNativeSlot;
+  MOZ_ASSERT((slot == DOM_OBJECT_SLOT &&
+              !(clasp->flags & JSCLASS_DOM_GLOBAL)) ||
+             (slot == DOM_GLOBAL_OBJECT_SLOT &&
+              (clasp->flags & JSCLASS_DOM_GLOBAL)));
+
+  JS::Value val = js::GetReservedSlot(obj, slot);
+  // XXXbz/khuey worker code tries to unwrap interface objects (which have
+  // nothing here).  That needs to stop.
+  // XXX We don't null-check UnwrapObject's result; aren't we going to crash
+  // anyway?
+  if (val.isUndefined()) {
+    return NULL;
+  }
+  
+  return static_cast<T*>(val.toPrivate());
+}
+
+template <class T>
+inline T*
+UnwrapDOMObject(JSObject* obj, const js::Class* clasp)
+{
+  return UnwrapDOMObject<T>(obj, Jsvalify(clasp));
+}
+
+// Some callers don't want to set an exception when unwrappin fails
+// (for example, overload resolution uses unwrapping to tell what sort
+// of thing it's looking at).
+template <prototypes::ID PrototypeID, class T>
+inline nsresult
+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;
+    }
+
+    obj = XPCWrapper::Unwrap(cx, obj, false);
+    if (!obj) {
+      return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
+    }
+    MOZ_ASSERT(!js::IsWrapper(obj));
+    clasp = js::GetObjectJSClass(obj);
+    if (!IsDOMClass(clasp)) {
+      /* We don't have a DOM object */
+      return NS_ERROR_XPC_BAD_CONVERT_JS;
+    }
+  }
+
+  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[PrototypeTraits<PrototypeID>::Depth] ==
+      PrototypeID) {
+    *value = UnwrapDOMObject<T>(obj, clasp);
+    return NS_OK;
+  }
+
+  /* It's the wrong sort of DOM object */
+  return NS_ERROR_XPC_BAD_CONVERT_JS;
+}
+
+inline bool
+IsArrayLike(JSContext* cx, JSObject* obj)
+{
+  MOZ_ASSERT(obj);
+  // For simplicity, check for security wrappers up front
+  if (js::IsWrapper(obj)) {
+    obj = XPCWrapper::Unwrap(cx, obj, false);
+    if (!obj) {
+      // Let's say it's not
+      return false;
+    }
+  }
+
+  // XXXbz need to detect platform objects (including listbinding
+  // ones) with indexGetters here!
+  return JS_IsArrayObject(cx, obj);
+}
+
+inline bool
+IsPlatformObject(JSContext* cx, JSObject* obj)
+{
+  // XXXbz Should be treating list-binding objects as platform objects
+  // too?  The one consumer so far wants non-array-like platform
+  // objects, so listbindings that have an indexGetter should test
+  // false from here.  Maybe this function should have a different
+  // name?
+  MOZ_ASSERT(obj);
+  // Fast-path the common case
+  JSClass* clasp = js::GetObjectJSClass(obj);
+  if (IsDOMClass(clasp)) {
+    return true;
+  }
+  // Now for simplicity check for security wrappers before anything else
+  if (js::IsWrapper(obj)) {
+    obj = XPCWrapper::Unwrap(cx, obj, false);
+    if (!obj) {
+      // Let's say it's not
+      return false;
+    }
+    clasp = js::GetObjectJSClass(obj);
+  }
+  return IS_WRAPPER_CLASS(js::Valueify(clasp)) || IsDOMClass(clasp) ||
+    JS_IsArrayBufferObject(obj);
+}
+
+template <class T>
+inline nsresult
+UnwrapObject(JSContext* cx, JSObject* obj, T* *value)
+{
+  return UnwrapObject<static_cast<prototypes::ID>(
+           PrototypeIDMap<T>::PrototypeID)>(cx, obj, value);
+}
+
+const size_t kProtoOrIfaceCacheCount =
+  prototypes::id::_ID_Count + constructors::id::_ID_Count;
+
+inline void
+AllocateProtoOrIfaceCache(JSObject* obj)
+{
+  MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
+  MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
+
+  // Important: The () at the end ensure zero-initialization
+  JSObject** protoOrIfaceArray = new JSObject*[kProtoOrIfaceCacheCount]();
+
+  js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
+                      JS::PrivateValue(protoOrIfaceArray));
+}
+
+inline void
+DestroyProtoOrIfaceCache(JSObject* obj)
+{
+  MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
+
+  JSObject** protoOrIfaceArray = GetProtoOrIfaceArray(obj);
+
+  delete [] protoOrIfaceArray;
+}
+
+struct ConstantSpec
+{
+  const char* name;
+  JS::Value value;
+};
+
+/*
+ * Create a DOM interface object (if constructorClass is non-null) and/or a
+ * DOM interface prototype object (if protoClass is non-null).
+ *
+ * parentProto is the prototype to use for the interface prototype object.
+ * protoClass is the JSClass to use for the interface prototype object.
+ *            This is null if we should not create an interface prototype
+ *            object.
+ * constructorClass is the JSClass to use for the interface object.
+ *                  This is null if we should not create an interface object.
+ * methods and properties are to be defined on the interface prototype object;
+ *                        these arguments are allowed to be null if there are no
+ *                        methods or properties respectively.
+ * constants are to be defined on the interface object and on the interface
+ *           prototype object; allowed to be null if there are no constants.
+ * staticMethods are to be defined on the interface object; allowed to be null
+ *               if there are no static methods.
+ *
+ * At least one of protoClass and constructorClass should be non-null.
+ * If constructorClass is non-null, the resulting interface object will be
+ * defined on the given global with property name |name|, which must also be
+ * non-null.
+ *
+ * returns the interface prototype object if protoClass is non-null, else it
+ * returns the interface object.
+ */
+JSObject*
+CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* parentProto,
+                       JSClass* protoClass, JSClass* constructorClass,
+                       JSFunctionSpec* methods, JSPropertySpec* properties,
+                       ConstantSpec* constants, JSFunctionSpec* staticMethods,
+                       const char* name);
+
+template <class T>
+inline bool
+WrapNewBindingObject(JSContext* cx, JSObject* scope, T* value, JS::Value* vp)
+{
+  JSObject* obj = value->GetWrapper();
+  if (obj && js::GetObjectCompartment(obj) == js::GetObjectCompartment(scope)) {
+    *vp = JS::ObjectValue(*obj);
+    return true;
+  }
+
+  if (!obj) {
+    bool triedToWrap;
+    obj = value->WrapObject(cx, scope, &triedToWrap);
+    if (!obj) {
+      // At this point, obj is null, so just return false.  We could
+      // try to communicate triedToWrap to the caller, but in practice
+      // callers seem to be testing JS_IsExceptionPending(cx) to
+      // figure out whether WrapObject() threw instead.
+      return false;
+    }
+  }
+
+  // Now make sure that |obj| is wrapped for the compartment of |scope|
+  // correctly.  That means entering the compartment of |scope|.
+  JSAutoEnterCompartment ac;
+  if (!ac.enter(cx, scope)) {
+    return false;
+  }
+  *vp = JS::ObjectValue(*obj);
+  return JS_WrapValue(cx, vp);
+}
+
+// Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
+template <template <class> class SmartPtr, class T>
+inline bool
+WrapNewBindingObject(JSContext* cx, JSObject* scope, const SmartPtr<T>& value,
+                     JS::Value* vp)
+{
+  return WrapNewBindingObject(cx, scope, value.get(), vp);
+}
+
+/**
+ * A method to handle new-binding wrap failure, by possibly falling back to
+ * wrapping as a non-new-binding object.
+ */
+bool
+DoHandleNewBindingWrappingFailure(JSContext* cx, JSObject* scope,
+                                  nsISupports* value, JS::Value* vp);
+
+/**
+ * An easy way to call the above when you have a value which
+ * multiply-inherits from nsISupports.
+ */
+template <class T>
+bool
+HandleNewBindingWrappingFailure(JSContext* cx, JSObject* scope, T* value,
+                                JS::Value* vp)
+{
+  nsCOMPtr<nsISupports> val;
+  CallQueryInterface(value, getter_AddRefs(val));
+  return DoHandleNewBindingWrappingFailure(cx, scope, val, vp);
+}
+
+// Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
+template <template <class> class SmartPtr, class T>
+MOZ_ALWAYS_INLINE bool
+HandleNewBindingWrappingFailure(JSContext* cx, JSObject* scope,
+                                const SmartPtr<T>& value, JS::Value* vp)
+{
+  return HandleNewBindingWrappingFailure(cx, scope, value.get(), vp);
+}
+
+struct EnumEntry {
+  const char* value;
+  size_t length;
+};
+
+inline int
+FindEnumStringIndex(JSContext* cx, JS::Value v, const EnumEntry* values, bool* ok)
+{
+  // JS_StringEqualsAscii is slow as molasses, so don't use it here.
+  JSString* str = JS_ValueToString(cx, v);
+  if (!str) {
+    *ok = false;
+    return 0;
+  }
+  JS::Anchor<JSString*> anchor(str);
+  size_t length;
+  const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
+  if (!chars) {
+    *ok = false;
+    return 0;
+  }
+  int i = 0;
+  for (const EnumEntry* value = values; value->value; ++value, ++i) {
+    if (length != value->length) {
+      continue;
+    }
+
+    bool equal = true;
+    const char* val = value->value;
+    for (size_t j = 0; j != length; ++j) {
+      if (unsigned(val[j]) != unsigned(chars[j])) {
+        equal = false;
+        break;
+      }
+    }
+
+    if (equal) {
+      *ok = true;
+      return i;
+    }
+  }
+
+  // XXX we don't know whether we're on the main thread, so play it safe
+  *ok = Throw<false>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
+  return 0;
+}
+
+inline nsWrapperCache*
+GetWrapperCache(nsWrapperCache* cache)
+{
+  return cache;
+}
+
+// nsGlobalWindow implements nsWrapperCache, but doesn't always use it. Don't
+// try to use it without fixing that first.
+class nsGlobalWindow;
+inline nsWrapperCache*
+GetWrapperCache(nsGlobalWindow* not_allowed);
+
+inline nsWrapperCache*
+GetWrapperCache(void* p)
+{
+  return NULL;
+}
+
+// Only set allowNativeWrapper to false if you really know you need it, if in
+// doubt use true. Setting it to false disables security wrappers.
+bool
+XPCOMObjectToJsval(JSContext* cx, JSObject* scope, xpcObjectHelper &helper,
+                   const nsIID* iid, bool allowNativeWrapper, JS::Value* rval);
+
+template<class T>
+inline bool
+WrapObject(JSContext* cx, JSObject* scope, T* p, nsWrapperCache* cache,
+           const nsIID* iid, JS::Value* vp)
+{
+  if (xpc_FastGetCachedWrapper(cache, scope, vp))
+    return true;
+  qsObjectHelper helper(p, cache);
+  return XPCOMObjectToJsval(cx, scope, helper, iid, true, vp);
+}
+
+template<class T>
+inline bool
+WrapObject(JSContext* cx, JSObject* scope, T* p, const nsIID* iid,
+           JS::Value* vp)
+{
+  return WrapObject(cx, scope, p, GetWrapperCache(p), iid, vp);
+}
+
+template<class T>
+inline bool
+WrapObject(JSContext* cx, JSObject* scope, T* p, JS::Value* vp)
+{
+  return WrapObject(cx, scope, p, NULL, vp);
+}
+
+template<class T>
+inline bool
+WrapObject(JSContext* cx, JSObject* scope, nsCOMPtr<T> &p, const nsIID* iid,
+           JS::Value* vp)
+{
+  return WrapObject(cx, scope, p.get(), iid, vp);
+}
+
+template<class T>
+inline bool
+WrapObject(JSContext* cx, JSObject* scope, nsCOMPtr<T> &p, JS::Value* vp)
+{
+  return WrapObject(cx, scope, p, NULL, vp);
+}
+
+template<class T>
+inline bool
+WrapObject(JSContext* cx, JSObject* scope, nsRefPtr<T> &p, const nsIID* iid,
+           JS::Value* vp)
+{
+  return WrapObject(cx, scope, p.get(), iid, vp);
+}
+
+template<class T>
+inline bool
+WrapObject(JSContext* cx, JSObject* scope, nsRefPtr<T> &p, JS::Value* vp)
+{
+  return WrapObject(cx, scope, p, NULL, vp);
+}
+
+template<>
+inline bool
+WrapObject<JSObject>(JSContext* cx, JSObject* scope, JSObject* p, JS::Value* vp)
+{
+  vp->setObjectOrNull(p);
+  return true;
+}
+
+template<class T>
+static inline JSObject*
+WrapNativeParent(JSContext* cx, JSObject* scope, T* p)
+{
+  if (!p)
+    return scope;
+
+  nsWrapperCache* cache = GetWrapperCache(p);
+  JSObject* obj;
+  if (cache && (obj = cache->GetWrapper())) {
+#ifdef DEBUG
+    qsObjectHelper helper(p, cache);
+    JS::Value debugVal;
+
+    bool ok = XPCOMObjectToJsval(cx, scope, helper, NULL, false, &debugVal);
+    NS_ASSERTION(ok && JSVAL_TO_OBJECT(debugVal) == obj,
+                 "Unexpected object in nsWrapperCache");
+#endif
+    return obj;
+  }
+
+  qsObjectHelper helper(p, cache);
+  JS::Value v;
+  return XPCOMObjectToJsval(cx, scope, helper, NULL, false, &v) ?
+         JSVAL_TO_OBJECT(v) :
+         NULL;
+}
+
+// Spec needs a name property
+template <typename Spec>
+static bool
+InitIds(JSContext* cx, Spec* specs, jsid* ids)
+{
+  Spec* spec = specs;
+  do {
+    JSString *str = ::JS_InternString(cx, spec->name);
+    if (!str) {
+      return false;
+    }
+
+    *ids = INTERNED_STRING_TO_JSID(cx, str);
+  } while (++ids, (++spec)->name);
+
+  return true;
+}
+
+JSBool
+QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
+
+} // namespace bindings
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_bindings_Utils_h__ */
new file mode 100644
--- /dev/null
+++ b/dom/bindings/parser/README
@@ -0,0 +1,1 @@
+A WebIDL parser written in Python to be used in Mozilla.
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/bindings/parser/UPSTREAM
@@ -0,0 +1,1 @@
+http://dev.w3.org/cvsweb/~checkout~/2006/webapi/WebIDL/Overview.html?rev=1.409;content-type=text%2Fhtml%3b+charset=utf-8
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/bindings/parser/WebIDL.py
@@ -0,0 +1,2872 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is WebIDL Parser.
+#
+# The Initial Developer of the Original Code is
+# the Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Kyle Huey <me@kylehuey.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+""" A WebIDL parser. """
+
+from ply import lex, yacc
+import re
+
+# Machinery
+
+def parseInt(literal):
+    string = literal
+    sign = 0
+    base = 0
+
+    if string[0] == '-':
+        sign = -1
+        string = string[1:]
+    else:
+        sign = 1
+
+    if string[0] == '0' and len(string) > 1:
+        if string[1] == 'x' or string[1] == 'X':
+            base = 16
+            string = string[2:]
+        else:
+            base = 8
+            string = string[1:]
+    else:
+        base = 10
+
+    value = int(string, base)
+    return value * sign
+
+# Magic for creating enums
+def M_add_class_attribs(attribs):
+    def foo(name, bases, dict_):
+        for v, k in attribs:
+            dict_[k] = v
+        return type(name, bases, dict_)
+    return foo
+
+def enum(*names):
+    class Foo(object):
+        __metaclass__ = M_add_class_attribs(enumerate(names))
+        def __setattr__(self, name, value):  # this makes it read-only
+            raise NotImplementedError
+    return Foo()
+
+class WebIDLError(Exception):
+    def __init__(self, message, location, warning=False):
+        self.message = message
+        self.location = location
+        self.warning = warning
+
+    def __str__(self):
+        return "%s: %s%s%s" % (self.warning and 'warning' or 'error',
+                               self.message, ", " if self.location else "",
+                               self.location)
+
+class Location(object):
+    _line = None
+
+    def __init__(self, lexer, lineno, lexpos, filename):
+        self._lineno = lineno
+        self._lexpos = lexpos
+        self._lexdata = lexer.lexdata
+        self._file = filename if filename else "<unknown>"
+
+    def __eq__(self, other):
+        return self._lexpos == other._lexpos and \
+               self._file == other._file
+
+    def resolve(self):
+        if self._line:
+            return
+
+        startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1
+        endofline = self._lexdata.find('\n', self._lexpos, self._lexpos + 80)
+        self._line = self._lexdata[startofline:endofline]
+        self._colno = self._lexpos - startofline
+
+    def pointerline(self):
+        def i():
+            for i in xrange(0, self._colno):
+                yield " "
+            yield "^"
+
+        return "".join(i())
+
+    def get(self):
+        self.resolve()
+        return "%s line %s:%s" % (self._file, self._lineno, self._colno)
+
+    def __str__(self):
+        self.resolve()
+        return "%s line %s:%s\n%s\n%s" % (self._file, self._lineno, self._colno,
+                                          self._line, self.pointerline())
+
+class BuiltinLocation(object):
+    def __init__(self, text):
+        self.msg = text
+
+    def get(self):
+        return self.msg
+
+    def __str__(self):
+        return self.get()
+
+
+# Data Model
+
+class IDLObject(object):
+    def __init__(self, location):
+        self.location = location
+        self.userData = dict()
+
+    def filename(self):
+        return self.location._file
+
+    def isInterface(self):
+        return False
+
+    def isEnum(self):
+        return False
+
+    def isCallback(self):
+        return False
+
+    def isType(self):
+        return False
+
+    def getUserData(self, key, default):
+        return self.userData.get(key, default)
+
+    def setUserData(self, key, value):
+        self.userData[key] = value
+
+    def addExtendedAttributes(self, attrs):
+        assert False # Override me!
+
+    def handleExtendedAttribute(self, attr, value):
+        assert False # Override me!
+
+class IDLScope(IDLObject):
+    def __init__(self, location, parentScope, identifier):
+        IDLObject.__init__(self, location)
+
+        self.parentScope = parentScope
+        if identifier:
+            assert isinstance(identifier, IDLIdentifier)
+            self._name = identifier
+        else:
+            self._name = None
+
+        self._dict = {}
+
+    def __str__(self):
+        return self.QName()
+
+    def QName(self):
+        if self._name:
+            return self._name.QName() + "::"
+        return "::"
+
+    def ensureUnique(self, identifier, object):
+        assert isinstance(identifier, IDLUnresolvedIdentifier)
+        assert not object or isinstance(object, IDLObjectWithIdentifier)
+        assert not object or object.identifier == identifier
+
+        if identifier.name in self._dict:
+            if not object:
+                return
+
+            # ensureUnique twice with the same object is not allowed
+            assert object != self._dict[identifier.name]
+
+            replacement = self.resolveIdentifierConflict(self, identifier,
+                                                         self._dict[identifier.name],
+                                                         object)
+            self._dict[identifier.name] = replacement
+            return
+
+        assert object
+
+        self._dict[identifier.name] = object
+
+    def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject):
+        if isinstance(originalObject, IDLExternalInterface) and \
+           isinstance(newObject, IDLExternalInterface) and \
+           originalObject.identifier.name == newObject.identifier.name:
+            return originalObject
+            
+        # Default to throwing, derived classes can override.
+        conflictdesc = "\n\t%s at %s\n\t%s at %s" % \
+          (originalObject, originalObject.location, newObject, newObject.location)
+
+        raise WebIDLError(
+            "Multiple unresolvable definitions of identifier '%s' in scope '%s%s"
+            % (identifier.name, str(self), conflictdesc), "")
+
+    def _lookupIdentifier(self, identifier):
+        return self._dict[identifier.name]
+
+    def lookupIdentifier(self, identifier):
+        assert isinstance(identifier, IDLIdentifier)
+        assert identifier.scope == self
+        return self._lookupIdentifier(identifier)
+
+class IDLIdentifier(IDLObject):
+    def __init__(self, location, scope, name):
+        IDLObject.__init__(self, location)
+
+        self.name = name
+        assert isinstance(scope, IDLScope)
+        self.scope = scope
+
+    def __str__(self):
+        return self.QName()
+
+    def QName(self):
+        return self.scope.QName() + self.name
+
+    def __hash__(self):
+        return self.QName().__hash__()
+
+    def __eq__(self, other):
+        return self.QName() == other.QName()
+
+    def object(self):
+        return self.scope.lookupIdentifier(self)
+
+class IDLUnresolvedIdentifier(IDLObject):
+    def __init__(self, location, name, allowDoubleUnderscore = False,
+                 allowForbidden = False):
+        IDLObject.__init__(self, location)
+
+        assert len(name) > 0
+
+        if name[:2] == "__" and not allowDoubleUnderscore:
+            raise WebIDLError("Identifiers beginning with __ are reserved",
+                              location)
+        if name[0] == '_' and not allowDoubleUnderscore:
+            name = name[1:]
+        if name in ["prototype", "constructor", "toString"] and not allowForbidden:
+            raise WebIDLError("Cannot use reserved identifier '%s'" % (name),
+                              location)
+
+        self.name = name
+
+    def __str__(self):
+        return self.QName()
+
+    def QName(self):
+        return "<unresolved scope>::" + self.name
+
+    def resolve(self, scope, object):
+        assert isinstance(scope, IDLScope)
+        assert not object or isinstance(object, IDLObjectWithIdentifier)
+        assert not object or object.identifier == self
+
+        scope.ensureUnique(self, object)
+
+        identifier = IDLIdentifier(self.location, scope, self.name)
+        if object:
+            object.identifier = identifier
+        return identifier
+
+class IDLObjectWithIdentifier(IDLObject):
+    def __init__(self, location, parentScope, identifier):
+        IDLObject.__init__(self, location)
+
+        assert isinstance(identifier, IDLUnresolvedIdentifier)
+
+        self.identifier = identifier
+
+        if parentScope:
+            self.resolve(parentScope)
+
+    def resolve(self, parentScope):
+        assert isinstance(parentScope, IDLScope)
+        assert isinstance(self.identifier, IDLUnresolvedIdentifier)
+        self.identifier.resolve(parentScope, self)
+
+class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope):
+    def __init__(self, location, parentScope, identifier):
+        assert isinstance(identifier, IDLUnresolvedIdentifier)
+
+        IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
+        IDLScope.__init__(self, location, parentScope, self.identifier)
+
+class IDLParentPlaceholder(IDLObjectWithIdentifier):
+    def __init__(self, location, identifier):
+        assert isinstance(identifier, IDLUnresolvedIdentifier)
+        IDLObjectWithIdentifier.__init__(self, location, None, identifier)
+
+    def finish(self, scope):
+        try:
+            scope._lookupIdentifier(self.identifier)
+        except:
+            raise WebIDLError("Unresolved type '%s'." % self.identifier, self.location)
+
+        iface = self.identifier.resolve(scope, None)
+        return scope.lookupIdentifier(iface)
+
+class IDLExternalInterface(IDLObjectWithIdentifier):
+    def __init__(self, location, parentScope, identifier):
+        assert isinstance(identifier, IDLUnresolvedIdentifier)
+        assert isinstance(parentScope, IDLScope)
+        self.parent = None
+        IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
+        IDLObjectWithIdentifier.resolve(self, parentScope)
+
+    def finish(self, scope):
+        pass
+
+    def isExternal(self):
+        return True
+
+    def isInterface(self):
+        return True
+
+    def addExtendedAttributes(self, attrs):
+        assert len(attrs) == 0
+
+    def resolve(self, parentScope):
+        pass
+
+class IDLInterface(IDLObjectWithScope):
+    def __init__(self, location, parentScope, name, parent, members):
+        assert isinstance(parentScope, IDLScope)
+        assert isinstance(name, IDLUnresolvedIdentifier)
+        assert not parent or isinstance(parent, IDLParentPlaceholder)
+
+        self.parent = parent
+        self._callback = False
+
+        self.members = list(members) # clone the list
+        assert iter(self.members) # Assert it's iterable
+
+        IDLObjectWithScope.__init__(self, location, parentScope, name)
+
+    def __str__(self):
+        return "Interface '%s'" % self.identifier.name
+
+    def ctor(self):
+        identifier = IDLUnresolvedIdentifier(self.location, "constructor",
+                                             allowForbidden=True)
+        try:
+            return self._lookupIdentifier(identifier)
+        except:
+            return None
+
+    def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject):
+        assert isinstance(scope, IDLScope)
+        assert isinstance(originalObject, IDLInterfaceMember)
+        assert isinstance(newObject, IDLInterfaceMember)
+
+        if originalObject.tag != IDLInterfaceMember.Tags.Method or \
+           newObject.tag != IDLInterfaceMember.Tags.Method:
+            # Call the base class method, which will throw
+            IDLScope.resolveIdentifierConflict(self, identifier, originalObject,
+                                               newObject)
+            assert False # Not reached
+
+        retval = originalObject.addOverload(newObject)
+        # Might be a ctor, which isn't in self.members
+        if newObject in self.members:
+            self.members.remove(newObject)
+        return retval
+
+    def finish(self, scope):
+        if hasattr(self, "_finished"):
+            return
+
+        self._finished = True
+
+        assert not self.parent or isinstance(self.parent, IDLParentPlaceholder)
+        parent = self.parent.finish(scope) if self.parent else None
+        assert not parent or isinstance(parent, IDLInterface)
+
+        self.parent = parent
+
+        assert iter(self.members)
+        members = None
+
+        if self.parent:
+            self.parent.finish(scope)
+            assert iter(self.parent.members)
+
+            members = list(self.parent.members)
+            members.extend(self.members)
+        else:
+            members = list(self.members)
+
+        SpecialType = enum(
+            'NamedGetter',
+            'NamedSetter',
+            'NamedCreator',
+            'NamedDeleter',
+            'IndexedGetter',
+            'IndexedSetter',
+            'IndexedCreator',
+            'IndexedDeleter'
+        )
+
+        specialMembersSeen = [False for i in range(8)]
+
+        def memberNotOnParentChain(member, iface):
+            assert iface
+
+            if not iface.parent:
+                return True
+
+            assert isinstance(iface.parent, IDLInterface)
+            if member in iface.parent.members:
+                return False
+            return memberNotOnParentChain(member, iface.parent)
+
+        for member in members:
+            if memberNotOnParentChain(member, self):
+                member.resolve(self)
+                
+            if member.tag == IDLInterfaceMember.Tags.Method:
+                if member.isGetter():
+                    if member.isNamed():
+                        if specialMembersSeen[SpecialType.NamedGetter]:
+                            raise WebIDLError("Multiple named getters on %s" % (self),
+                                              self.location)
+                        specialMembersSeen[SpecialType.NamedGetter] = True
+                    else:
+                        assert member.isIndexed()
+                        if specialMembersSeen[SpecialType.IndexedGetter]:
+                            raise WebIDLError("Multiple indexed getters on %s" % (self),
+                                              self.location)
+                        specialMembersSeen[SpecialType.IndexedGetter] = True
+                if member.isSetter():
+                    if member.isNamed():
+                        if specialMembersSeen[SpecialType.NamedSetter]:
+                            raise WebIDLError("Multiple named setters on %s" % (self),
+                                              self.location)
+                        specialMembersSeen[SpecialType.NamedSetter] = True
+                    else:
+                        assert member.isIndexed()
+                        if specialMembersSeen[SpecialType.IndexedSetter]:
+                            raise WebIDLError("Multiple indexed setters on %s" % (self),
+                                              self.location)
+                        specialMembersSeen[SpecialType.IndexedSetter] = True
+                if member.isCreator():
+                    if member.isNamed():
+                        if specialMembersSeen[SpecialType.NamedCreator]:
+                            raise WebIDLError("Multiple named creators on %s" % (self),
+                                              self.location)
+                        specialMembersSeen[SpecialType.NamedCreator] = True
+                    else:
+                        assert member.isIndexed()
+                        if specialMembersSeen[SpecialType.IndexedCreator]:
+                            raise WebIDLError("Multiple indexed creators on %s" % (self),
+                                              self.location)
+                        specialMembersSeen[SpecialType.IndexedCreator] = True
+                if member.isDeleter():
+                    if member.isNamed():
+                        if specialMembersSeen[SpecialType.NamedDeleter]:
+                            raise WebIDLError("Multiple named deleters on %s" % (self),
+                                              self.location)
+                        specialMembersSeen[SpecialType.NamedDeleter] = True
+                    else:
+                        assert member.isIndexed()
+                        if specialMembersSeen[SpecialType.IndexedDeleter]:
+                            raise WebIDLError("Multiple indexed Deleters on %s" % (self),
+                                              self.location)
+                        specialMembersSeen[SpecialType.IndexedDeleter] = True
+
+        for member in self.members:
+            member.finish(scope)
+
+    def isInterface(self):
+        return True
+
+    def isExternal(self):
+        return False
+
+    def setCallback(self, value):
+        self._callback = value
+
+    def isCallback(self):
+        return self._callback
+
+    def inheritanceDepth(self):
+        depth = 0
+        parent = self.parent
+        while parent:
+            depth = depth + 1
+            parent = parent.parent
+        return depth
+
+    def hasConstants(self):
+        return reduce(lambda b, m: b or m.isConst(), self.members, False)
+
+    def hasInterfaceObject(self):
+        if self.isCallback():
+            return self.hasConstants()
+        return not hasattr(self, "_noInterfaceObject")
+
+    def hasInterfacePrototypeObject(self):
+        return not self.isCallback()
+
+    def addExtendedAttributes(self, attrs):
+        self._extendedAttrDict = {}
+        for attr in attrs:
+            attrlist = list(attr)
+            identifier = attrlist.pop(0)
+
+            # Special cased attrs
+            if identifier == "TreatNonCallableAsNull":
+                raise WebIDLError("TreatNonCallableAsNull cannot be specified on interfaces",
+                                  self.location)
+            elif identifier == "NoInterfaceObject":
+                if self.ctor():
+                    raise WebIDLError("Constructor and NoInterfaceObject are incompatible",
+                                      self.location)
+
+                self._noInterfaceObject = True
+            elif identifier == "Constructor":
+                if not self.hasInterfaceObject():
+                    raise WebIDLError("Constructor and NoInterfaceObject are incompatible",
+                                      self.location)
+
+                args = attrlist[0] if len(attrlist) else []
+
+                retType = IDLWrapperType(self.location, self)
+                
+                identifier = IDLUnresolvedIdentifier(self.location, "constructor",
+                                                     allowForbidden=True)
+
+                method = IDLMethod(self.location, identifier, retType, args,
+                                   False, False, False, False, False, False,
+                                   False, False)
+
+                method.resolve(self)
+
+            self._extendedAttrDict[identifier] = attrlist if len(attrlist) else 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)
+
+        IDLObjectWithIdentifier.__init__(self, location, parentScope, name)
+        self._values = values
+
+    def values(self):
+        return self._values
+
+    def finish(self, scope):
+        pass
+
+    def isEnum(self):
+        return True
+
+    def addExtendedAttributes(self, attrs):
+        assert len(attrs) == 0
+
+class IDLType(IDLObject):
+    Tags = enum(
+        # The integer types
+        'int8',
+        'uint8',
+        'int16',
+        'uint16',
+        'int32',
+        'uint32',
+        'int64',
+        'uint64',
+        # Additional primitive types
+        'bool',
+        'float',
+        'double',
+        # Other types
+        'any',
+        'domstring',
+        'object',
+        'date',
+        'void',
+        # Funny stuff
+        'interface',
+        'dictionary',
+        'enum',
+        'callback'
+        )
+
+    def __init__(self, location, name):
+        IDLObject.__init__(self, location)
+        self.name = name
+        self.builtin = False
+
+    def __eq__(self, other):
+        return other and self.name == other.name and self.builtin == other.builtin
+
+    def __str__(self):
+        return str(self.name)
+
+    def isType(self):
+        return True
+
+    def nullable(self):
+        return False
+
+    def isPrimitive(self):
+        return False
+
+    def isString(self):
+        return False
+
+    def isVoid(self):
+        return self.name == "Void"
+
+    def isSequence(self):
+        return False
+
+    def isArray(self):
+        return False
+
+    def isArrayBuffer(self):
+        return False
+
+    def isDictionary(self):
+        return False
+
+    def isInterface(self):
+        return False
+
+    def isAny(self):
+        return self.tag() == IDLType.Tags.any
+
+    def isDate(self):
+        return self.tag() == IDLType.Tags.date
+
+    def isObject(self):
+        return self.tag() == IDLType.Tags.object
+
+    def isComplete(self):
+        return True
+
+    def tag(self):
+        assert False # Override me!
+
+    def treatNonCallableAsNull(self):
+        if not (self.nullable() and self.tag() == IDLType.Tags.callback):
+            raise WebIDLError("Type %s cannot be TreatNonCallableAsNull" % self,
+                              self.location)
+
+        return hasattr(self, "_treatNonCallableAsNull")
+
+    def markTreatNonCallableAsNull(self):
+        assert not self.treatNonCallableAsNull()
+        self._treatNonCallableAsNull = True
+
+    def addExtendedAttributes(self, attrs):
+        assert len(attrs) == 0
+
+    def resolveType(self, parentScope):
+        pass
+
+    def unroll(self):
+        return self
+
+    def isDistinguishableFrom(self, other):
+        raise TypeError("Can't tell whether a generic type is or is not "
+                        "distinguishable from other things")
+
+class IDLUnresolvedType(IDLType):
+    """
+        Unresolved types are interface types 
+    """
+
+    def __init__(self, location, name):
+        IDLType.__init__(self, location, name)
+
+    def isComplete(self):
+        return False
+
+    def complete(self, scope):
+        obj = None
+        try:
+            obj = scope._lookupIdentifier(self.name)
+        except:
+            raise WebIDLError("Unresolved type '%s'." % self.name, self.location)
+
+        assert obj
+        if obj.isType():
+            return obj
+
+        name = self.name.resolve(scope, None)
+        return IDLWrapperType(self.location, obj)
+
+    def isDistinguishableFrom(self, other):
+        raise TypeError("Can't tell whether an unresolved type is or is not "
+                        "distinguishable from other things")
+
+class IDLNullableType(IDLType):
+    def __init__(self, location, innerType):
+        assert not innerType.isVoid()
+        assert not innerType.nullable()
+        assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any]
+
+        IDLType.__init__(self, location, innerType.name)
+        self.inner = innerType
+        self.builtin = False
+
+    def __eq__(self, other):
+        return isinstance(other, IDLNullableType) and self.inner == other.inner
+
+    def __str__(self):
+        return self.inner.__str__() + "OrNull"
+
+    def nullable(self):
+        return True
+
+    def isCallback(self):
+        return self.inner.isCallback()
+
+    def isPrimitive(self):
+        return self.inner.isPrimitive()
+
+    def isString(self):
+        return self.inner.isString()
+
+    def isVoid(self):
+        return False
+
+    def isSequence(self):
+        return self.inner.isSequence()
+
+    def isArray(self):
+        return self.inner.isArray()
+
+    def isDictionary(self):
+        return self.inner.isDictionary()
+
+    def isInterface(self):
+        return self.inner.isInterface()
+
+    def isEnum(self):
+        return self.inner.isEnum()
+
+    def tag(self):
+        return self.inner.tag()
+
+    def resolveType(self, parentScope):
+        assert isinstance(parentScope, IDLScope)
+        self.inner.resolveType(parentScope)
+
+    def isComplete(self):
+        return self.inner.isComplete()
+
+    def complete(self, scope):
+        self.inner = self.inner.complete(scope)
+        self.name = self.inner.name
+        return self
+
+    def unroll(self):
+        return self.inner
+
+    def isDistinguishableFrom(self, other):
+        if other.nullable():
+            # Can't tell which type null should become
+            return False
+        return self.inner.isDistinguishableFrom(other)
+
+class IDLSequenceType(IDLType):
+    def __init__(self, location, parameterType):
+        assert not parameterType.isVoid()
+
+        IDLType.__init__(self, location, parameterType.name)
+        self.inner = parameterType
+        self.builtin = False
+
+    def __eq__(self, other):
+        return isinstance(other, IDLSequenceType) and self.inner == other.inner
+
+    def __str__(self):
+        return self.inner.__str__() + "Sequence"
+
+    def nullable(self):
+        return False
+
+    def isPrimitive(self):
+        return self.inner.isPrimitive()
+
+    def isString(self):
+        return self.inner.isString()
+
+    def isVoid(self):
+        return False
+
+    def isSequence(self):
+        return True
+
+    def isArray(self):
+        return self.inner.isArray()
+
+    def isDictionary(self):
+        return self.inner.isDictionary()
+
+    def isInterface(self):
+        return self.inner.isInterface()
+
+    def isEnum(self):
+        return self.inner.isEnum();
+
+    def tag(self):
+        return self.inner.tag()
+
+    def resolveType(self, parentScope):
+        assert isinstance(parentScope, IDLScope)
+        self.inner.resolveType(parentScope)
+
+    def isComplete(self):
+        return self.inner.isComplete()
+
+    def complete(self, scope):
+        self.inner = self.inner.complete(scope)
+        return self
+
+    def unroll(self):
+        return self.inner
+
+    def isDistinguishableFrom(self, other):
+        return (other.isPrimitive() or other.isString() or other.isEnum() or
+                other.isDictionary() or other.isDate() or
+                # XXXbz we should also be checking for indexed
+                # properties on interfaces
+                (other.isInterface() and not other.isCallback() and
+                 not other.isArrayBuffer()))
+
+class IDLArrayType(IDLType):
+    def __init__(self, location, parameterType):
+        assert not parameterType.isVoid()
+        if parameterType.isSequence():
+            raise WebIDLError("Array type cannot parameterize over a sequence type",
+                              location)
+        if parameterType.isDictionary():
+            raise WebIDLError("Array type cannot parameterize over a dictionary type",
+                              location)
+
+        IDLType.__init__(self, location, parameterType.name)
+        self.inner = parameterType
+        self.builtin = False
+
+    def __eq__(self, other):
+        return isinstance(other, IDLArrayType) and self.inner == other.inner
+
+    def __str__(self):
+        return self.inner.__str__() + "Array"
+
+    def nullable(self):
+        return False
+
+    def isPrimitive(self):
+        return self.inner.isPrimitive()
+
+    def isString(self):
+        return self.inner.isString()
+
+    def isVoid(self):
+        return False
+
+    def isSequence(self):
+        assert not self.inner.isSequence()
+        return self.inner.isSequence()
+
+    def isArray(self):
+        return True
+
+    def isDictionary(self):
+        assert not self.inner.isDictionary()
+        return self.inner.isDictionary()
+
+    def isInterface(self):
+        return self.inner.isInterface()
+
+    def isEnum(self):
+        return self.inner.isEnum()
+
+    def tag(self):
+        return self.inner.tag()
+
+    def resolveType(self, parentScope):
+        assert isinstance(parentScope, IDLScope)
+        self.inner.resolveType(parentScope)
+
+    def isComplete(self):
+        return self.inner.isComplete()
+
+    def complete(self, scope):
+        self.inner = self.inner.complete(scope)
+        return self
+
+    def unroll(self):
+        return self.inner
+
+    def isDistinguishableFrom(self, other):
+        return (other.isPrimitive() or other.isString() or other.isEnum() or
+                other.isDictionary() or other.isDate() or
+                # XXXbz we should also be checking for indexed
+                # properties on interfaces
+                (other.isInterface() and not other.isCallback() and
+                 not other.isArrayBuffer()))
+
+class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
+    def __init__(self, location, innerType, name):
+        IDLType.__init__(self, location, innerType.name)
+
+        identifier = IDLUnresolvedIdentifier(location, name)
+
+        IDLObjectWithIdentifier.__init__(self, location, None, identifier)
+
+        self.inner = innerType
+        self.name = name
+        self.builtin = False
+
+    def __eq__(self, other):
+        return isinstance(other, IDLTypedefType) and self.inner == other.inner
+
+    def __str__(self):
+        return self.identifier.name
+
+    def nullable(self):
+        return self.inner.nullable()
+
+    def isPrimitive(self):
+        return self.inner.isPrimitive()
+
+    def isString(self):
+        return self.inner.isString()
+
+    def isVoid(self):
+        return self.inner.isVoid()
+
+    def isSequence(self):
+        return self.inner.isSequence()
+
+    def isArray(self):
+        return self.inner.isArray()
+
+    def isDictionary(self):
+        return self.inner.isDictionary()
+
+    def isInterface(self):
+        return self.inner.isInterface()
+
+    def resolve(self, parentScope):
+        assert isinstance(parentScope, IDLScope)
+        IDLObjectWithIdentifier.resolve(self, parentScope)
+
+    def tag(self):
+        return self.inner.tag()
+
+    def unroll(self):
+        return self.inner
+
+    def isDistinguishableFrom(self, other):
+        return self.inner.isDistinguishableFrom(other)
+
+class IDLWrapperType(IDLType):
+    def __init__(self, location, inner):
+        IDLType.__init__(self, location, inner.identifier.name)
+        self.inner = inner
+        self.name = inner.identifier
+        self.builtin = False
+
+    def __eq__(self, other):
+        return other and self.name == other.name and self.builtin == other.builtin
+
+    def __str__(self):
+        return str(self.name.name) + " (Wrapper)"
+
+    def nullable(self):
+        return False
+
+    def isPrimitive(self):
+        return False
+
+    def isString(self):
+        return False
+
+    def isVoid(self):
+        return False
+
+    def isSequence(self):
+        return False
+
+    def isArray(self):
+        return False
+
+    def isDictionary(self):
+        return False
+
+    def isInterface(self):
+        return isinstance(self.inner, IDLInterface) or \
+               isinstance(self.inner, IDLExternalInterface)
+
+    def isEnum(self):
+        return isinstance(self.inner, IDLEnum)
+
+    def isComplete(self):
+        return True
+
+    def tag(self):
+        if self.isInterface():
+            return IDLType.Tags.interface
+        elif self.isEnum():
+            return IDLType.Tags.enum
+        else:
+            assert False
+
+    def isDistinguishableFrom(self, other):
+        assert self.isInterface() or self.isEnum()
+        if self.isEnum():
+            return (other.isInterface() or other.isObject() or
+                    other.isCallback() or other.isDictionary() or
+                    other.isSequence() or other.isArray() or
+                    other.isDate())
+        if other.isPrimitive() or other.isString() or other.isEnum():
+            return True
+        # XXXbz need to check that the interfaces can't be implemented
+        # by the same object
+        if other.isInterface():
+            return (self != other and
+                    (not self.isCallback() or not other.isCallback()))
+        if other.isDictionary() or other.isCallback():
+            return not self.isCallback()
+        if other.isSequence() or other.isArray():
+            # XXXbz should also check self for enumerated properties
+            # and the like
+            return not self.isCallback()
+
+class IDLBuiltinType(IDLType):
+
+    Types = enum(
+        # The integer types
+        'byte',
+        'octet',
+        'short',
+        'unsigned_short',
+        'long',
+        'unsigned_long',
+        'long_long',
+        'unsigned_long_long',
+        # Additional primitive types
+        'boolean',
+        'float',
+        'double',
+        # Other types
+        'any',
+        'domstring',
+        'object',
+        'date',
+        'void',
+        # Funny stuff
+        'ArrayBuffer'
+        )
+
+    TagLookup = {
+            Types.byte: IDLType.Tags.int8,
+            Types.octet: IDLType.Tags.uint8,
+            Types.short: IDLType.Tags.int16,
+            Types.unsigned_short: IDLType.Tags.uint16,
+            Types.long: IDLType.Tags.int32,
+            Types.unsigned_long: IDLType.Tags.uint32,
+            Types.long_long: IDLType.Tags.int64,
+            Types.unsigned_long_long: IDLType.Tags.uint64,
+            Types.boolean: IDLType.Tags.bool,
+            Types.float: IDLType.Tags.float,
+            Types.double: IDLType.Tags.double,
+            Types.any: IDLType.Tags.any,
+            Types.domstring: IDLType.Tags.domstring,
+            Types.object: IDLType.Tags.object,
+            Types.date: IDLType.Tags.date,
+            Types.void: IDLType.Tags.void,
+            Types.ArrayBuffer: IDLType.Tags.interface
+        }
+
+    def __init__(self, location, name, type):
+        IDLType.__init__(self, location, name)
+        self.builtin = True
+        self.type = type
+
+    def isPrimitive(self):
+        return self.type <= IDLBuiltinType.Types.double
+
+    def isString(self):
+        return self.type == IDLBuiltinType.Types.domstring
+
+    def isInteger(self):
+        return self.type <= IDLBuiltinType.Types.unsigned_long_long
+
+    def isArrayBuffer(self):
+        return self.type == IDLBuiltinType.Types.ArrayBuffer
+
+    def isInterface(self):
+        # ArrayBuffers are interface types per the TypedArray spec,
+        # 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 tag(self):
+        return IDLBuiltinType.TagLookup[self.type]
+
+    def isDistinguishableFrom(self, other):
+        if self.isPrimitive() or self.isString():
+            return (other.isInterface() or other.isObject() or
+                    other.isCallback() or other.isDictionary() or
+                    other.isSequence() or other.isArray() or
+                    other.isDate())
+        if self.isAny():
+            # Can't tell "any" apart from anything
+            return False
+        if self.isObject():
+            return other.isPrimitive() or other.isString() or other.isEnum()
+        if self.isDate():
+            return (other.isPrimitive() or other.isString() or other.isEnum() or
+                    other.isInterface() or other.isCallback() or
+                    other.isDictionary() or other.isSequence() or
+                    other.isArray())
+        if self.isVoid():
+            return not other.isVoid()
+        # Not much else we could be!
+        assert self.isArrayBuffer()
+        # Like interfaces, but we know we're not a callback and we
+        # know that we have indexed properties.
+        # XXXbz this should be checking for indexed properties on
+        # other when other.isInterface()
+        return (other.isPrimitive() or other.isString() or other.isEnum() or
+                other.isCallback() or other.isDictionary() or other.isDate() or
+                (other.isInterface() and not other.isArrayBuffer()))
+
+BuiltinTypes = {
+      IDLBuiltinType.Types.byte:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "Byte",
+                         IDLBuiltinType.Types.byte),
+      IDLBuiltinType.Types.octet:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "Octet",
+                         IDLBuiltinType.Types.octet),
+      IDLBuiltinType.Types.short:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "Short",
+                         IDLBuiltinType.Types.short),
+      IDLBuiltinType.Types.unsigned_short:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedShort",
+                         IDLBuiltinType.Types.unsigned_short),
+      IDLBuiltinType.Types.long:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "Long",
+                         IDLBuiltinType.Types.long),
+      IDLBuiltinType.Types.unsigned_long:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedLong",
+                         IDLBuiltinType.Types.unsigned_long),
+      IDLBuiltinType.Types.long_long:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "LongLong",
+                         IDLBuiltinType.Types.long_long),
+      IDLBuiltinType.Types.unsigned_long_long:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedLongLong",
+                         IDLBuiltinType.Types.unsigned_long_long),
+      IDLBuiltinType.Types.boolean:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "Boolean",
+                         IDLBuiltinType.Types.boolean),
+      IDLBuiltinType.Types.float:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float",
+                         IDLBuiltinType.Types.float),
+      IDLBuiltinType.Types.double:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "Double",
+                         IDLBuiltinType.Types.double),
+      IDLBuiltinType.Types.any:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "Any",
+                         IDLBuiltinType.Types.any),
+      IDLBuiltinType.Types.domstring:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "String",
+                         IDLBuiltinType.Types.domstring),
+      IDLBuiltinType.Types.object:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "Object",
+                         IDLBuiltinType.Types.object),
+      IDLBuiltinType.Types.date:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "Date",
+                         IDLBuiltinType.Types.date),
+      IDLBuiltinType.Types.void:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "Void",
+                         IDLBuiltinType.Types.void),
+      IDLBuiltinType.Types.ArrayBuffer:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBuffer",
+                         IDLBuiltinType.Types.ArrayBuffer)
+    }
+
+
+integerTypeSizes = {
+        IDLBuiltinType.Types.byte: (-128, 127),
+        IDLBuiltinType.Types.octet:  (0, 255),
+        IDLBuiltinType.Types.short: (-32768, 32767),
+        IDLBuiltinType.Types.unsigned_short: (0, 65535),
+        IDLBuiltinType.Types.long: (-2147483648, 2147483647),
+        IDLBuiltinType.Types.unsigned_long: (0, 4294967295),
+        IDLBuiltinType.Types.long_long: (-9223372036854775808,
+                                         9223372036854775807),
+        IDLBuiltinType.Types.unsigned_long_long: (0, 18446744073709551615)
+    }
+
+def matchIntegerValueToType(value):
+    for type, extremes in integerTypeSizes.items():
+        (min, max) = extremes
+        if value <= max and value >= min:
+            return BuiltinTypes[type]
+
+    return None
+
+def checkDistinguishability(argset1, argset2):
+    assert isinstance(argset1, list) and isinstance(argset2, list)
+
+class IDLValue(IDLObject):
+    def __init__(self, location, type, value):
+        IDLObject.__init__(self, location)
+        self.type = type
+        assert isinstance(type, IDLType)
+
+        self.value = value
+
+    def coerceToType(self, type, location):
+        if type == self.type:
+            return self # Nothing to do
+
+        # If the type allows null, rerun this matching on the inner type
+        if type.nullable():
+            innerValue = self.coerceToType(type.inner, location)
+            return IDLValue(self.location, type, innerValue.value)
+
+        # Else, see if we can coerce to 'type'.
+        if self.type.isInteger():
+            if not self.type.isInteger():
+                raise WebIDLError("Cannot coerce type %s to type %s." %
+                                  (self.type, type), location)
+
+            # We're both integer types.  See if we fit.
+
+            (min, max) = integerTypeSizes[type.type]
+            if self.value <= max and self.value >= min:
+                # Promote
+                return IDLValue(self.location, type, self.value)
+            else:
+                raise WebIDLError("Value %s is out of range for type %s." %
+                                  (self.value, type), location)
+        else:
+            pass
+
+        assert False # Not implemented!
+
+class IDLNullValue(IDLObject):
+    def __init__(self, location):
+        IDLObject.__init__(self, location)
+        self.type = None
+        self.value = None
+
+    def coerceToType(self, type, location):
+        if not isinstance(type, IDLNullableType):
+            raise WebIDLError("Cannot coerce null value to type %s." % type,
+                              location)
+
+        nullValue = IDLNullValue(self.location)
+        nullValue.type = type
+        return nullValue
+        
+
+class IDLInterfaceMember(IDLObjectWithIdentifier):
+
+    Tags = enum(
+        'Const',
+        'Attr',
+        'Method'
+    )
+
+    def __init__(self, location, identifier, tag):
+        IDLObjectWithIdentifier.__init__(self, location, None, identifier)
+        self.tag = tag
+
+    def isMethod(self):
+        return self.tag == IDLInterfaceMember.Tags.Method
+
+    def isAttr(self):
+        return self.tag == IDLInterfaceMember.Tags.Attr
+
+    def isConst(self):
+        return self.tag == IDLInterfaceMember.Tags.Const
+
+    def addExtendedAttributes(self, attrs):
+        self._extendedAttrDict = {}
+        for attr in attrs:
+            attrlist = list(attr)
+            identifier = attrlist.pop(0)
+            self.handleExtendedAttribute(identifier, attrlist)
+            self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
+
+    def handleExtendedAttribute(self, name, list):
+        pass
+
+    def extendedAttribute(self, name):
+        return self._extendedAttrDict.get(name, None)
+
+class IDLConst(IDLInterfaceMember):
+    def __init__(self, location, identifier, type, value):
+        IDLInterfaceMember.__init__(self, location, identifier,
+                                    IDLInterfaceMember.Tags.Const)
+
+        assert isinstance(type, IDLType)
+        self.type = type
+
+        # The value might not match the type
+        coercedValue = value.coerceToType(self.type, location)
+        assert coercedValue
+
+        self.value = coercedValue
+
+    def __str__(self):
+        return "'%s' const '%s'" % (self.type, self.identifier)
+
+    def finish(self, scope):
+        assert self.type.isComplete()
+
+class IDLAttribute(IDLInterfaceMember):
+    def __init__(self, location, identifier, type, readonly, inherit):
+        IDLInterfaceMember.__init__(self, location, identifier,
+                                    IDLInterfaceMember.Tags.Attr)
+
+        assert isinstance(type, IDLType)
+        self.type = type
+        self.readonly = readonly
+        self.inherit = inherit
+
+        if readonly and inherit:
+            raise WebIDLError("An attribute cannot be both 'readonly' and 'inherit'",
+                              self.location)
+
+    def __str__(self):
+        return "'%s' attribute '%s'" % (self.type, self.identifier)
+
+    def finish(self, scope):
+        if not self.type.isComplete():
+            t = self.type.complete(scope)
+
+            assert not isinstance(t, IDLUnresolvedType)
+            assert not isinstance(t.name, IDLUnresolvedIdentifier)
+            self.type = t
+
+    def handleExtendedAttribute(self, name, list):
+        if name == "TreatNonCallableAsNull":
+            self.type.markTreatNonCallableAsNull();
+        IDLInterfaceMember.handleExtendedAttribute(self, name, list)
+
+    def resolve(self, parentScope):
+        assert isinstance(parentScope, IDLScope)
+        self.type.resolveType(parentScope)
+        IDLObjectWithIdentifier.resolve(self, parentScope)
+
+class IDLArgument(IDLObjectWithIdentifier):
+    def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False):
+        IDLObjectWithIdentifier.__init__(self, location, None, identifier)
+
+        assert isinstance(type, IDLType)
+        self.type = type
+
+        if defaultValue:
+            defaultValue = defaultValue.coerceToType(type, location)
+            assert defaultValue
+
+        self.optional = optional
+        self.defaultValue = defaultValue
+        self.variadic = variadic
+
+        assert not variadic or optional
+
+    def addExtendedAttributes(self, attrs):
+        assert len(attrs) == 0
+
+class IDLCallbackType(IDLType, IDLObjectWithScope):
+    def __init__(self, location, parentScope, identifier, returnType, arguments):
+        assert isinstance(returnType, IDLType)
+
+        IDLType.__init__(self, location, identifier.name)
+
+        self._returnType = returnType
+        # Clone the list
+        self._arguments = list(arguments)
+
+        IDLObjectWithScope.__init__(self, location, parentScope, identifier)
+
+        for (returnType, arguments) in self.signatures():
+            for argument in arguments:
+                argument.resolve(self)
+
+    def isCallback(self):
+        return True
+
+    def signatures(self):
+        return [(self._returnType, self._arguments)]
+
+    def tag(self):
+        return IDLType.Tags.callback
+
+    def finish(self, scope):
+        if not self._returnType.isComplete():
+            type = returnType.complete(scope)
+
+            assert not isinstance(type, IDLUnresolvedType)
+            assert not isinstance(type.name, IDLUnresolvedIdentifier)
+            self._returnType = type
+
+        for argument in self._arguments:
+            if argument.type.isComplete():
+                continue
+
+            type = argument.type.complete(scope)
+
+            assert not isinstance(type, IDLUnresolvedType)
+            assert not isinstance(type.name, IDLUnresolvedIdentifier)
+            argument.type = type
+
+    def isDistinguishableFrom(self, other):
+        return (other.isPrimitive() or other.isString() or other.isEnum() or
+                (other.isInterface() and not other.isCallback()) or
+                other.isDate())
+
+class IDLMethod(IDLInterfaceMember, IDLScope):
+
+    Special = enum(
+        'None',
+        'Getter',
+        'Setter',
+        'Creator',
+        'Deleter',
+        'LegacyCaller',
+        'Stringifier',
+        'Static'
+    )
+
+    TypeSuffixModifier = enum(
+        'None',
+        'QMark',
+        'Brackets'
+    )
+
+    NamedOrIndexed = enum(
+        'Neither',
+        'Named',
+        'Indexed'
+    )
+
+    def __init__(self, location, identifier, returnType, arguments,
+                 static, getter, setter, creator, deleter, specialType, legacycaller,
+                 stringifier):
+        IDLInterfaceMember.__init__(self, location, identifier,
+                                    IDLInterfaceMember.Tags.Method)
+
+        self._hasOverloads = False
+
+        assert isinstance(returnType, IDLType)
+        self._returnType = [returnType]
+
+        assert isinstance(static, bool)
+        self._static = static
+        assert isinstance(getter, bool)
+        self._getter = getter
+        assert isinstance(setter, bool)
+        self._setter = setter
+        assert isinstance(creator, bool)
+        self._creator = creator
+        assert isinstance(deleter, bool)
+        self._deleter = deleter
+        assert isinstance(legacycaller, bool)
+        self._legacycaller = legacycaller
+        assert isinstance(stringifier, bool)
+        self._stringifier = stringifier
+        self._specialType = specialType
+
+        # Clone the list
+        self._arguments = [list(arguments)]
+
+        self.assertSignatureConstraints()
+
+    def __str__(self):
+        return "Method '%s'" % self.identifier
+
+    def assertSignatureConstraints(self):
+        if self._getter or self._deleter:
+            assert len(self._arguments) == 1
+            assert self._arguments[0][0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] or \
+                   self._arguments[0][0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]
+            assert not self._arguments[0][0].optional and not self._arguments[0][0].variadic
+            assert not self._returnType[0].isVoid()
+
+        if self._setter or self._creator:
+            assert len(self._arguments[0]) == 2
+            assert self._arguments[0][0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] or \
+                   self._arguments[0][0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]
+            assert not self._arguments[0][0].optional and not self._arguments[0][0].variadic
+            assert not self._arguments[0][1].optional and not self._arguments[0][1].variadic
+            assert self._arguments[0][1].type == self._returnType[0]
+
+        if self._stringifier:
+            assert len(self._arguments[0]) == 0
+            assert self._returnType[0] == BuiltinTypes[IDLBuiltinType.Types.domstring]
+
+        inOptionalArguments = False
+        sawVariadicArgument = False
+
+        assert len(self._arguments) == 1
+        arguments = self._arguments[0]
+
+        for argument in arguments:
+            # Only the last argument can be variadic
+            assert not sawVariadicArgument
+            # Once we see an optional argument, there can't be any non-optional
+            # arguments.
+            if inOptionalArguments:
+                assert argument.optional
+            inOptionalArguments = argument.optional
+            sawVariadicArgument = argument.variadic
+
+    def isStatic(self):
+        return self._static
+
+    def isGetter(self):
+        return self._getter
+
+    def isSetter(self):
+        return self._setter
+
+    def isCreator(self):
+        return self._creator
+
+    def isDeleter(self):
+        return self._deleter
+
+    def isNamed(self):
+        assert self._specialType == IDLMethod.NamedOrIndexed.Named or \
+               self._specialType == IDLMethod.NamedOrIndexed.Indexed
+        return self._specialType == IDLMethod.NamedOrIndexed.Named
+
+    def isIndexed(self):
+        assert self._specialType == IDLMethod.NamedOrIndexed.Named or \
+               self._specialType == IDLMethod.NamedOrIndexed.Indexed
+        return self._specialType == IDLMethod.NamedOrIndexed.Indexed
+
+    def isLegacycaller(self):
+        return self._legacycaller
+
+    def isStringifier(self):
+        return self._stringifier
+
+    def hasOverloads(self):
+        return self._hasOverloads
+
+    def resolve(self, parentScope):
+        assert isinstance(parentScope, IDLScope)
+        IDLObjectWithIdentifier.resolve(self, parentScope)
+        IDLScope.__init__(self, self.location, parentScope, self.identifier)
+        for (returnType, arguments) in self.signatures():
+            for argument in arguments:
+                argument.resolve(self)
+
+    def addOverload(self, method):
+        checkDistinguishability(self._arguments, method._arguments)
+
+        assert len(method._returnType) == 1
+        assert len(method._arguments) == 1
+
+        self._returnType.extend(method._returnType)
+        self._arguments.extend(method._arguments)
+
+        self._hasOverloads = True
+
+        if self.isStatic() != method.isStatic():
+            raise WebIDLError("Overloaded identifier %s appears with different values of the 'static' attribute" % method1.identifier,
+                              method.location)
+
+        if self.isLegacycaller() != method.isLegacycaller():
+            raise WebIDLError("Overloaded identifier %s appears with different values of the 'legacycaller' attribute" % method1.identifier,
+                              method.location)
+
+        # Can't overload special things!
+        assert not self.isGetter()
+        assert not method.isGetter()
+        assert not self.isSetter()
+        assert not method.isSetter()
+        assert not self.isCreator()
+        assert not method.isCreator()
+        assert not self.isDeleter()
+        assert not method.isDeleter()
+        assert not self.isStringifier()
+        assert not method.isStringifier()
+
+        return self
+
+    def signatures(self):
+        assert len(self._returnType) == len(self._arguments)
+        return zip(self._returnType, self._arguments)
+
+    def finish(self, scope):
+        for index, returnType in enumerate(self._returnType):
+            if returnType.isComplete():
+                continue
+
+            type = returnType.complete(scope)
+
+            assert not isinstance(type, IDLUnresolvedType)
+            assert not isinstance(type.name, IDLUnresolvedIdentifier)
+            self._returnType[index] = type
+
+        for arguments in self._arguments:
+            for argument in arguments:
+                if argument.type.isComplete():
+                    continue
+
+                type = argument.type.complete(scope)
+
+                assert not isinstance(type, IDLUnresolvedType)
+                assert not isinstance(type.name, IDLUnresolvedIdentifier)
+                argument.type = type
+
+# Parser
+
+class Tokenizer(object):
+    tokens = [
+        "INTEGER",
+        "FLOAT",
+        "IDENTIFIER",
+        "STRING",
+        "WHITESPACE",
+        "OTHER"
+        ]
+
+    def t_INTEGER(self, t):
+        r'-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)'
+        try:
+            t.value = parseInt(t.value)
+        except:
+            raise WebIDLError("Invalid integer literal",
+                              Location(lexer=self.lexer,
+                                       lineno=self.lexer.lineno,
+                                       lexpos=self.lexer.lexpos,
+                                       filename=self._filename))
+        return t
+
+    def t_FLOAT(self, t):
+        r'-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)'
+        assert False
+        return t
+
+    def t_IDENTIFIER(self, t):
+        r'[A-Z_a-z][0-9A-Z_a-z]*'
+        t.type = self.keywords.get(t.value, 'IDENTIFIER')
+        return t
+
+    def t_STRING(self, t):
+        r'"[^"]*"'
+        t.value = t.value[1:-1]
+        return t
+
+    def t_WHITESPACE(self, t):
+        r'[\t\n\r ]+|[\t\n\r ]*((//[^\n]*|/\*.*?\*/)[\t\n\r ]*)+'
+        pass
+
+    def t_ELLIPSIS(self, t):
+        r'\.\.\.'
+        t.type = self.keywords.get(t.value)
+        return t
+
+    def t_OTHER(self, t):
+        r'[^\t\n\r 0-9A-Z_a-z]'
+        t.type = self.keywords.get(t.value, 'OTHER')
+        return t
+
+    keywords = {
+        "module": "MODULE",
+        "interface": "INTERFACE",
+        "partial": "PARTIAL",
+        "dictionary": "DICTIONARY",
+        "exception": "EXCEPTION",
+        "enum": "ENUM",
+        "callback": "CALLBACK",
+        "typedef": "TYPEDEF",
+        "implements": "IMPLEMENTS",
+        "const": "CONST",
+        "null": "NULL",
+        "true": "TRUE",
+        "false": "FALSE",
+        "stringifier": "STRINGIFIER",
+        "attribute": "ATTRIBUTE",
+        "readonly": "READONLY",
+        "inherit": "INHERIT",
+        "static": "STATIC",
+        "getter": "GETTER",
+        "setter": "SETTER",
+        "creator": "CREATOR",
+        "deleter": "DELETER",
+        "legacycaller": "LEGACYCALLER",
+        "optional": "OPTIONAL",
+        "...": "ELLIPSIS",
+        "::": "SCOPE",
+        "Date": "DATE",
+        "DOMString": "DOMSTRING",
+        "any": "ANY",
+        "boolean": "BOOLEAN",
+        "byte": "BYTE",
+        "double": "DOUBLE",
+        "float": "FLOAT_",
+        "long": "LONG",
+        "object": "OBJECT",
+        "octet": "OCTET",
+        "optional": "OPTIONAL",
+        "sequence": "SEQUENCE",
+        "short": "SHORT",
+        "unsigned": "UNSIGNED",
+        "void": "VOID",
+        ":": "COLON",
+        ";": "SEMICOLON",
+        "{": "LBRACE",
+        "}": "RBRACE",
+        "(": "LPAREN",
+        ")": "RPAREN",
+        "[": "LBRACKET",
+        "]": "RBRACKET",
+        "?": "QUESTIONMARK",
+        ",": "COMMA",
+        "=": "EQUALS",
+        "<": "LT",
+        ">": "GT",
+        "ArrayBuffer": "ARRAYBUFFER"
+        }
+
+    tokens.extend(keywords.values())
+
+    def t_error(self, t):
+        raise WebIDLError("Unrecognized Input",
+               Location(lexer=self.lexer,
+                        lineno=self.lexer.lineno,
+                        lexpos=self.lexer.lexpos,
+                        filename = self.filename))
+
+    def __init__(self, outputdir):
+        self.lexer = lex.lex(object=self,
+                             outputdir=outputdir,
+                             lextab='webidllex',
+                             reflags=re.DOTALL)
+
+class Parser(Tokenizer):
+    def getLocation(self, p, i):
+        return Location(self.lexer, p.lineno(i), p.lexpos(i), self._filename)
+
+    def globalScope(self):
+        return self._globalScope
+
+    # The p_Foo functions here must match the WebIDL spec's grammar.
+    # It's acceptable to split things at '|' boundaries.
+    def p_Definitions(self, p):
+        """ 
+            Definitions : ExtendedAttributeList Definition Definitions
+        """
+        if p[2]:
+            p[0] = [p[2]]
+            p[2].addExtendedAttributes(p[1])
+        else:
+            assert not p[1]
+            p[0] = []
+
+        p[0].extend(p[3])
+
+    def p_DefinitionsEmpty(self, p):
+        """
+            Definitions :
+        """
+        p[0] = []
+
+    def p_Definition(self, p):
+        """
+            Definition : CallbackOrInterface
+                       | PartialInterface
+                       | Dictionary
+                       | Exception
+                       | Enum
+                       | Typedef
+                       | ImplementsStatement
+        """
+        p[0] = p[1]
+        assert p[1] # We might not have implemented something ...
+
+    def p_CallbackOrInterfaceCallback(self, p):
+        """
+            CallbackOrInterface : CALLBACK CallbackRestOrInterface
+        """
+        if p[2].isInterface():
+            assert isinstance(p[2], IDLInterface)
+            p[2].setCallback(True)
+
+        p[0] = p[2]
+
+    def p_CallbackOrInterfaceInterface(self, p):
+        """
+            CallbackOrInterface : Interface
+        """
+        p[0] = p[1]
+
+    def p_CallbackRestOrInterface(self, p):
+        """
+            CallbackRestOrInterface : CallbackRest
+                                    | Interface
+        """
+        assert p[1]
+        p[0] = p[1]
+
+    def p_Interface(self, p):
+        """
+            Interface : INTERFACE IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON
+        """
+        location = self.getLocation(p, 1)
+        identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
+
+        members = p[5]
+        p[0] = IDLInterface(location, self.globalScope(), identifier, p[3], members)
+
+    def p_InterfaceForwardDecl(self, p):
+        """
+            Interface : INTERFACE IDENTIFIER SEMICOLON
+        """
+        location = self.getLocation(p, 1)
+        identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
+
+        try:
+            if self.globalScope()._lookupIdentifier(identifier):
+                p[0] = self.globalScope()._lookupIdentifier(identifier)
+                return
+        except:
+            pass
+
+        p[0] = IDLExternalInterface(location, self.globalScope(), identifier)
+
+    def p_PartialInterface(self, p):
+        """
+            PartialInterface : PARTIAL INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
+        """
+        pass
+
+    def p_Inheritance(self, p):
+        """
+            Inheritance : COLON ScopedName
+        """
+        p[0] = IDLParentPlaceholder(self.getLocation(p, 2), p[2])
+
+    def p_InheritanceEmpty(self, p):
+        """
+            Inheritance :
+        """
+        pass
+
+    def p_InterfaceMembers(self, p):
+        """
+            InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers
+        """
+        p[0] = [p[2]] if p[2] else []
+
+        assert not p[1] or p[2]
+        p[2].addExtendedAttributes(p[1])
+
+        p[0].extend(p[3])
+
+    def p_InterfaceMembersEmpty(self, p):
+        """
+            InterfaceMembers :
+        """
+        p[0] = []
+
+    def p_InterfaceMember(self, p):
+        """
+            InterfaceMember : Const
+                            | AttributeOrOperation
+        """
+        p[0] = p[1]
+
+    def p_Dictionary(self, p):
+        """
+            Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON
+        """
+        pass
+
+    def p_DictionaryMembers(self, p):
+        """
+            DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers
+                             |
+        """
+        pass
+
+    def p_DictionaryMember(self, p):
+        """
+            DictionaryMember : Type IDENTIFIER DefaultValue SEMICOLON
+        """
+        pass
+
+    def p_DefaultValue(self, p):
+        """
+            DefaultValue : EQUALS ConstValue
+                         |
+        """
+        if len(p) > 1:
+            p[0] = p[2]
+        else:
+            p[0] = None
+
+    def p_Exception(self, p):
+        """
+            Exception : EXCEPTION IDENTIFIER Inheritance LBRACE ExceptionMembers RBRACE SEMICOLON
+        """
+        pass
+
+    def p_Enum(self, p):
+        """
+            Enum : ENUM IDENTIFIER LBRACE EnumValueList RBRACE SEMICOLON
+        """
+        location = self.getLocation(p, 1)
+        identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
+
+        values = p[4]
+        assert values
+        p[0] = IDLEnum(location, self.globalScope(), identifier, values)
+
+    def p_EnumValueList(self, p):
+        """
+            EnumValueList : STRING EnumValues
+        """
+        p[0] = [p[1]]
+        p[0].extend(p[2])
+
+    def p_EnumValues(self, p):
+        """
+            EnumValues : COMMA STRING EnumValues
+        """
+        p[0] = [p[2]]
+        p[0].extend(p[3])
+
+    def p_EnumValuesEmpty(self, p):
+        """
+            EnumValues :
+        """
+        p[0] = []
+
+    def p_CallbackRest(self, p):
+        """
+            CallbackRest : IDENTIFIER EQUALS ReturnType LPAREN ArgumentList RPAREN SEMICOLON
+        """
+        identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
+        p[0] = IDLCallbackType(self.getLocation(p, 1), self.globalScope(),
+                               identifier, p[3], p[5])
+
+    def p_ExceptionMembers(self, p):
+        """
+            ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers
+                             |
+        """
+        pass
+
+    def p_Typedef(self, p):
+        """
+            Typedef : TYPEDEF Type IDENTIFIER SEMICOLON
+        """
+        typedef = IDLTypedefType(self.getLocation(p, 1), p[2], p[3])
+        typedef.resolve(self.globalScope())
+        p[0] = typedef
+
+    def p_ImplementsStatement(self, p):
+        """
+            ImplementsStatement : ScopedName IMPLEMENTS ScopedName SEMICOLON
+        """
+        pass
+
+    def p_Const(self, p):
+        """
+            Const : CONST ConstType IDENTIFIER EQUALS ConstValue SEMICOLON
+        """
+        location = self.getLocation(p, 1)
+        type = p[2]
+        identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3])
+        value = p[5]
+        p[0] = IDLConst(location, identifier, type, value)
+
+    def p_ConstValueBoolean(self, p):
+        """
+            ConstValue : BooleanLiteral
+        """
+        location = self.getLocation(p, 1)
+        booleanType = BuiltinTypes[IDLBuiltinType.Types.boolean]
+        p[0] = IDLValue(location, booleanType, p[1])
+
+    def p_ConstValueInteger(self, p):
+        """
+            ConstValue : INTEGER
+        """
+        location = self.getLocation(p, 1)
+
+        # We don't know ahead of time what type the integer literal is.
+        # Determine the smallest type it could possibly fit in and use that.
+        integerType = matchIntegerValueToType(p[1])
+        if integerType == None:
+            raise WebIDLError("Integer literal out of range", location)
+
+        p[0] = IDLValue(location, integerType, p[1])
+
+    def p_ConstValueFloat(self, p):
+        """
+            ConstValue : FLOAT
+        """
+        assert False
+        pass
+
+    def p_ConstValueString(self, p):
+        """
+            ConstValue : STRING
+        """
+        assert False
+        pass
+
+    def p_ConstValueNull(self, p):
+        """
+            ConstValue : NULL
+        """
+        p[0] = IDLNullValue(self.getLocation(p, 1))
+
+    def p_BooleanLiteralTrue(self, p):
+        """
+            BooleanLiteral : TRUE
+        """
+        p[0] = True
+
+    def p_BooleanLiteralFalse(self, p):
+        """
+            BooleanLiteral : FALSE
+        """
+        p[0] = False
+
+    def p_AttributeOrOperationStringifier(self, p):
+        """
+            AttributeOrOperation : STRINGIFIER StringifierAttributeOrOperation
+        """
+        assert False # Not implemented
+        pass
+
+    def p_AttributeOrOperation(self, p):
+        """
+            AttributeOrOperation : Attribute
+                                 | Operation
+        """
+        p[0] = p[1]
+
+    def p_StringifierAttributeOrOperation(self, p):
+        """
+            StringifierAttributeOrOperation : Attribute
+                                            | OperationRest
+                                            | SEMICOLON
+        """
+        pass
+
+    def p_Attribute(self, p):
+        """
+            Attribute : Inherit ReadOnly ATTRIBUTE AttributeType IDENTIFIER SEMICOLON
+        """
+        location = self.getLocation(p, 3)
+        inherit = p[1]
+        readonly = p[2]
+        t = p[4]
+        identifier = IDLUnresolvedIdentifier(self.getLocation(p, 5), p[5])
+        p[0] = IDLAttribute(location, identifier, t, readonly, inherit)
+
+    def p_ReadOnly(self, p):
+        """
+            ReadOnly : READONLY
+        """
+        p[0] = True
+
+    def p_ReadOnlyEmpty(self, p):
+        """
+            ReadOnly :
+        """
+        p[0] = False
+
+    def p_Inherit(self, p):
+        """
+            Inherit : INHERIT
+        """
+        p[0] = True
+
+    def p_InheritEmpty(self, p):
+        """
+            Inherit :
+        """
+        p[0] = False
+
+    def p_Operation(self, p):
+        """
+            Operation : Qualifiers OperationRest
+        """
+        qualifiers = p[1]
+
+        # Disallow duplicates in the qualifier set
+        if not len(set(qualifiers)) == len(qualifiers):
+            raise WebIDLError("Duplicate qualifiers are not allowed",
+                              self.getLocation(p, 1))
+
+        static = True if IDLMethod.Special.Static in p[1] else False
+        # If static is there that's all that's allowed.  This is disallowed
+        # by the parser, so we can assert here.
+        assert not static or len(qualifiers) == 1
+
+        getter = True if IDLMethod.Special.Getter in p[1] else False
+        setter = True if IDLMethod.Special.Setter in p[1] else False
+        creator = True if IDLMethod.Special.Creator in p[1] else False
+        deleter = True if IDLMethod.Special.Deleter in p[1] else False
+        legacycaller = True if IDLMethod.Special.LegacyCaller in p[1] else False
+
+        if getter or deleter:
+            if setter or creator:
+                raise WebIDLError("getter and deleter are incompatible with setter and creator",
+                                  self.getLocation(p, 1))
+
+        (returnType, identifier, arguments) = p[2]
+
+        assert isinstance(returnType, IDLType)
+
+        specialType = IDLMethod.NamedOrIndexed.Neither
+
+        if getter or deleter:
+            if len(arguments) != 1:
+                raise WebIDLError("%s has wrong number of arguments" %
+                                  ("getter" if getter else "deleter"),
+                                  self.getLocation(p, 2))
+            argType = arguments[0].type
+            if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]:
+                specialType = IDLMethod.NamedOrIndexed.Named
+            elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]:
+                specialType = IDLMethod.NamedOrIndexed.Indexed
+            else:
+                raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" %
+                                  ("getter" if getter else "deleter"),
+                                  arguments[0].location)
+            if arguments[0].optional or arguments[0].variadic:
+                raise WebIDLError("%s cannot have %s argument" %
+                                  ("getter" if getter else "deleter",
+                                   "optional" if arguments[0].optional else "variadic"),
+                                   arguments[0].location)
+            if returnType.isVoid():
+                raise WebIDLError("%s cannot have void return type" %
+                                  ("getter" if getter else "deleter"),
+                                  self.getLocation(p, 2))
+        if setter or creator:
+            if len(arguments) != 2:
+                raise WebIDLError("%s has wrong number of arguments" %
+                                  ("setter" if setter else "creator"),
+                                  self.getLocation(p, 2))
+            argType = arguments[0].type
+            if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]:
+                specialType = IDLMethod.NamedOrIndexed.Named
+            elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]:
+                specialType = IDLMethod.NamedOrIndexed.Indexed
+            else:
+                raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" %
+                                  ("setter" if setter else "creator"),
+                                  arguments[0].location)
+            if arguments[0].optional or arguments[0].variadic:
+                raise WebIDLError("%s cannot have %s argument" %
+                                  ("setter" if setter else "creator",
+                                   "optional" if arguments[0].optional else "variadic"),
+                                   arguments[0].location)
+            if arguments[1].optional or arguments[1].variadic:
+                raise WebIDLError("%s cannot have %s argument" %
+                                  ("setter" if setter else "creator",
+                                   "optional" if arguments[1].optional else "variadic"),
+                                   arguments[1].location)
+            if returnType.isVoid():
+                raise WebIDLError("%s cannot have void return type" %
+                                  ("setter" if setter else "creator"),
+                                  self.getLocation(p, 2))
+            if not arguments[1].type == returnType:
+                raise WebIDLError("%s return type and second argument type must match" %
+                                  ("setter" if setter else "creator"),
+                                  self.getLocation(p, 2))
+
+        inOptionalArguments = False
+        variadicArgument = False
+        for argument in arguments:
+            # Only the last argument can be variadic
+            if variadicArgument:
+                raise WebIDLError("Only the last argument can be variadic",
+                                  variadicArgument.location)
+            # Once we see an optional argument, there can't be any non-optional
+            # arguments.
+            if inOptionalArguments and not argument.optional:
+                raise WebIDLError("Cannot have a non-optional argument following an optional argument",
+                                  argument.location)
+            inOptionalArguments = argument.optional
+            variadicArgument = argument if argument.variadic else None
+
+        # identifier might be None.  This is only permitted for special methods.
+        # NB: Stringifiers are handled elsewhere.
+        if not identifier:
+            if not getter and not setter and not creator and \
+               not deleter and not legacycaller:
+                raise WebIDLError("Identifier required for non-special methods",
+                                  self.getLocation(p, 2))
+
+            location = BuiltinLocation("<auto-generated-identifier>")
+            identifier = IDLUnresolvedIdentifier(location, "__%s%s%s%s%s%s" %
+                ("named" if specialType == IDLMethod.NamedOrIndexed.Named else \
+                 "indexed" if specialType == IDLMethod.NamedOrIndexed.Indexed else "",
+                 "getter" if getter else "",
+                 "setter" if setter else "",
+                 "deleter" if deleter else "",
+                 "creator" if creator else "",
+                 "legacycaller" if legacycaller else ""), allowDoubleUnderscore=True)
+
+        method = IDLMethod(self.getLocation(p, 2), identifier, returnType, arguments,
+                           static, getter, setter, creator, deleter, specialType,
+                           legacycaller, False)
+        p[0] = method
+
+    def p_QualifiersStatic(self, p):
+        """
+            Qualifiers : STATIC
+        """
+        p[0] = [IDLMethod.Special.Static]
+
+    def p_QualifiersSpecials(self, p):
+        """
+            Qualifiers : Specials
+        """
+        p[0] = p[1]
+
+    def p_Specials(self, p):
+        """
+            Specials : Special Specials
+        """
+        p[0] = [p[1]]
+        p[0].extend(p[2])
+
+    def p_SpecialsEmpty(self, p):
+        """
+            Specials :
+        """
+        p[0] = []
+
+    def p_SpecialGetter(self, p):
+        """
+            Special : GETTER
+        """
+        p[0] = IDLMethod.Special.Getter
+
+    def p_SpecialSetter(self, p):
+        """
+            Special : SETTER
+        """
+        p[0] = IDLMethod.Special.Setter
+
+    def p_SpecialCreator(self, p):
+        """
+            Special : CREATOR
+        """
+        p[0] = IDLMethod.Special.Creator
+
+    def p_SpecialDeleter(self, p):
+        """
+            Special : DELETER
+        """
+        p[0] = IDLMethod.Special.Deleter
+
+    def p_SpecialLegacyCaller(self, p):
+        """
+            Special : LEGACYCALLER
+        """
+        p[0] = IDLMethod.Special.LegacyCaller
+
+    def p_OperationRest(self, p):
+        """
+            OperationRest : ReturnType OptionalIdentifier LPAREN ArgumentList RPAREN SEMICOLON
+        """
+        p[0] = (p[1], p[2], p[4])
+
+    def p_OptionalIdentifier(self, p):
+        """
+            OptionalIdentifier : IDENTIFIER
+        """
+        p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
+
+    def p_OptionalIdentifierEmpty(self, p):
+        """
+            OptionalIdentifier :
+        """
+        pass
+
+    def p_ArgumentList(self, p):
+        """
+            ArgumentList : Argument Arguments
+        """
+        p[0] = [p[1]] if p[1] else []
+        p[0].extend(p[2])
+
+    def p_ArgumentListEmpty(self, p):
+        """
+            ArgumentList :
+        """
+        p[0] = []
+
+    def p_Arguments(self, p):
+        """
+            Arguments : COMMA Argument Arguments
+        """
+        p[0] = [p[2]] if p[2] else []
+        p[0].extend(p[3])
+
+    def p_ArgumentsEmpty(self, p):
+        """
+            Arguments :
+        """
+        p[0] = []
+
+    def p_Argument(self, p):
+        """
+            Argument : ExtendedAttributeList Optional Type Ellipsis IDENTIFIER DefaultValue
+        """
+        t = p[3]
+        assert isinstance(t, IDLType)
+        identifier = IDLUnresolvedIdentifier(self.getLocation(p, 5), p[5])
+
+        optional = p[2]
+        variadic = p[4]
+        defaultValue = p[6]
+
+        if not optional and defaultValue:
+            raise WebIDLError("Mandatory arguments can't have a default value.",
+                              self.getLocation(p, 6))
+
+        if variadic:
+            if optional:
+                raise WebIDLError("Variadic arguments should not be marked optional.",
+                                  self.getLocation(p, 2))
+            optional = variadic
+
+        p[0] = IDLArgument(self.getLocation(p, 5), identifier, t, optional, defaultValue, variadic)
+        p[0].addExtendedAttributes(p[1])
+
+    def p_Optional(self, p):
+        """
+            Optional : OPTIONAL
+        """
+        p[0] = True
+
+    def p_OptionalEmpty(self, p):
+        """
+            Optional :
+        """
+        p[0] = False
+
+    def p_Ellipsis(self, p):
+        """
+            Ellipsis : ELLIPSIS
+        """
+        p[0] = True
+
+    def p_EllipsisEmpty(self, p):
+        """
+            Ellipsis :
+        """
+        p[0] = False
+
+    def p_ExceptionMember(self, p):
+        """
+            ExceptionMember : Const
+                            | ExceptionField
+        """
+        pass
+
+    def p_ExceptionField(self, p):
+        """
+            ExceptionField : AttributeType IDENTIFIER SEMICOLON
+        """
+        pass
+
+    def p_ExtendedAttributeList(self, p):
+        """
+            ExtendedAttributeList : LBRACKET ExtendedAttribute ExtendedAttributes RBRACKET
+        """
+        p[0] = [p[2]]
+        if p[3]:
+            p[0].extend(p[3])
+
+    def p_ExtendedAttributeListEmpty(self, p):
+        """
+            ExtendedAttributeList :
+        """
+        p[0] = []
+
+    def p_ExtendedAttribute(self, p):
+        """
+            ExtendedAttribute : ExtendedAttributeNoArgs
+                              | ExtendedAttributeArgList
+                              | ExtendedAttributeIdent
+                              | ExtendedAttributeNamedArgList
+        """
+        p[0] = p[1]
+
+    def p_ExtendedAttributeEmpty(self, p):
+        """
+            ExtendedAttribute :
+        """
+        pass
+
+    def p_ExtendedAttributes(self, p):
+        """
+            ExtendedAttributes : COMMA ExtendedAttribute ExtendedAttributes
+        """
+        p[0] = [p[2]] if p[2] else []
+        p[0].extend(p[3])
+
+    def p_ExtendedAttributesEmpty(self, p):
+        """
+            ExtendedAttributes :
+        """
+        p[0] = []
+
+    def p_Other(self, p):
+        """
+            Other : INTEGER
+                  | FLOAT
+                  | IDENTIFIER
+                  | STRING
+                  | OTHER
+                  | ELLIPSIS
+                  | COLON
+                  | SCOPE
+                  | SEMICOLON
+                  | LT
+                  | EQUALS
+                  | GT
+                  | QUESTIONMARK
+                  | DATE
+                  | DOMSTRING
+                  | ANY
+                  | ATTRIBUTE
+                  | BOOLEAN
+                  | BYTE
+                  | LEGACYCALLER
+                  | CONST
+                  | CREATOR
+                  | DELETER
+                  | DOUBLE
+                  | EXCEPTION
+                  | FALSE
+                  | FLOAT_
+                  | GETTER
+                  | IMPLEMENTS
+                  | INHERIT
+                  | INTERFACE
+