Fix for bug 768692 (Move DOM list binding generation to the new DOM binding codegen). r=bzbarsky.
authorPeter Van der Beken <peterv@propagandism.org>
Tue, 22 May 2012 15:46:20 +0200
changeset 108608 cd86e0d61c3facabea95de41947273a143c9d95c
parent 108607 455ed4a415aa930e7bd3916362a0dd6b2e32c8e0
child 108609 96cd349f463be14d49ed4f2d0a0eadac130d0a96
push id1490
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 18:29:50 +0000
treeherdermozilla-beta@f335e7dacdc1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs768692
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Fix for bug 768692 (Move DOM list binding generation to the new DOM binding codegen). r=bzbarsky.
caps/src/nsScriptSecurityManager.cpp
content/base/src/FragmentOrElement.cpp
content/base/src/nsContentList.cpp
content/base/src/nsDOMFile.cpp
content/base/src/nsDOMSettableTokenList.cpp
content/base/src/nsDOMTokenList.cpp
content/events/src/nsPaintRequest.h
content/html/content/src/HTMLPropertiesCollection.cpp
content/html/content/src/nsClientRect.cpp
content/html/content/src/nsHTMLFormElement.cpp
content/html/content/src/nsHTMLSelectElement.cpp
content/html/content/src/nsHTMLTableElement.cpp
content/svg/content/src/DOMSVGLengthList.cpp
content/svg/content/src/DOMSVGNumberList.cpp
content/svg/content/src/DOMSVGPathSegList.cpp
content/svg/content/src/DOMSVGPointList.cpp
content/svg/content/src/DOMSVGTransformList.cpp
content/xbl/src/nsBindingManager.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsScriptNameSpaceManager.cpp
dom/base/nsScriptNameSpaceManager.h
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/bindings/Configuration.py
dom/bindings/DOMJSClass.h
dom/bindings/DOMJSProxyHandler.cpp
dom/bindings/DOMJSProxyHandler.h
dom/bindings/Errors.msg
dom/bindings/Makefile.in
dom/bindings/parser/WebIDL.py
dom/bindings/test/TestBindingHeader.h
dom/bindings/test/TestCodeGen.webidl
dom/workers/Worker.cpp
dom/workers/WorkerScope.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCJSID.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/codegen.py
js/xpconnect/src/dombindings.cpp
js/xpconnect/src/dombindings.h
js/xpconnect/src/dombindingsgen.py
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2394,20 +2394,17 @@ nsScriptSecurityManager::old_doGetObject
             if (result) {
                 break;
             }
         } else {
             nsISupports *priv;
             if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
                                      JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
                 priv = (nsISupports *) js::GetObjectPrivate(aObj);
-            } else if (IsDOMClass(jsClass) &&
-                       DOMJSClass::FromJSClass(jsClass)->mDOMObjectIsISupports) {
-                priv = UnwrapDOMObject<nsISupports>(aObj);
-            } else {
+            } else if (!UnwrapDOMObjectToISupports(aObj, priv)) {
                 priv = nullptr;
             }
 
             if (aAllowShortCircuit) {
                 nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
                     do_QueryInterface(priv);
 
                 NS_ASSERTION(!xpcWrapper ||
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -386,17 +386,17 @@ NS_INTERFACE_TABLE_HEAD(nsChildContentLi
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsChildContentList)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NodeList)
 NS_INTERFACE_MAP_END
 
 JSObject*
 nsChildContentList::WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
 {
-  return mozilla::dom::binding::NodeList::create(cx, scope, this, triedToWrap);
+  return mozilla::dom::oldproxybindings::NodeList::create(cx, scope, this, triedToWrap);
 }
 
 NS_IMETHODIMP
 nsChildContentList::GetLength(uint32_t* aLength)
 {
   *aLength = mNode ? mNode->GetChildCount() : 0;
 
   return NS_OK;
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -157,17 +157,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsBaseCo
 
 NS_IMPL_ADDREF_INHERITED(nsSimpleContentList, nsBaseContentList)
 NS_IMPL_RELEASE_INHERITED(nsSimpleContentList, nsBaseContentList)
 
 JSObject*
 nsSimpleContentList::WrapObject(JSContext *cx, JSObject *scope,
                                 bool *triedToWrap)
 {
-  return mozilla::dom::binding::NodeList::create(cx, scope, this, triedToWrap);
+  return mozilla::dom::oldproxybindings::NodeList::create(cx, scope, this, triedToWrap);
 }
 
 // nsFormContentList
 
 nsFormContentList::nsFormContentList(nsIContent *aForm,
                                      nsBaseContentList& aContentList)
   : nsSimpleContentList(aForm)
 {
@@ -473,17 +473,17 @@ nsContentList::~nsContentList()
     // Clean up mData
     (*mDestroyFunc)(mData);
   }
 }
 
 JSObject*
 nsContentList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::HTMLCollection::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::HTMLCollection::create(cx, scope, this,
                                                        triedToWrap);
 }
 
 DOMCI_DATA(ContentList, nsContentList)
 
 // QueryInterface implementation for nsContentList
 NS_INTERFACE_TABLE_HEAD(nsContentList)
   NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsContentList)
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -683,17 +683,17 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileList)
 
 JSObject*
 nsDOMFileList::WrapObject(JSContext *cx, JSObject *scope,
                           bool *triedToWrap)
 {
-  return mozilla::dom::binding::FileList::create(cx, scope, this, triedToWrap);
+  return mozilla::dom::oldproxybindings::FileList::create(cx, scope, this, triedToWrap);
 }
 
 nsIDOMFile*
 nsDOMFileList::GetItemAt(uint32_t aIndex)
 {
   return mFiles.SafeObjectAt(aIndex);
 }
 
--- a/content/base/src/nsDOMSettableTokenList.cpp
+++ b/content/base/src/nsDOMSettableTokenList.cpp
@@ -46,11 +46,11 @@ nsDOMSettableTokenList::SetValue(const n
 
   return mElement->SetAttr(kNameSpaceID_None, mAttrAtom, aValue, true);
 }
 
 JSObject*
 nsDOMSettableTokenList::WrapObject(JSContext *cx, JSObject *scope,
                                    bool *triedToWrap)
 {
-  return mozilla::dom::binding::DOMSettableTokenList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::DOMSettableTokenList::create(cx, scope, this,
                                                              triedToWrap);
 }
--- a/content/base/src/nsDOMTokenList.cpp
+++ b/content/base/src/nsDOMTokenList.cpp
@@ -267,12 +267,12 @@ nsDOMTokenList::ToString(nsAString& aRes
   mElement->GetAttr(kNameSpaceID_None, mAttrAtom, aResult);
 
   return NS_OK;
 }
 
 JSObject*
 nsDOMTokenList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::DOMTokenList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::DOMTokenList::create(cx, scope, this,
                                                      triedToWrap);
 }
 
--- a/content/events/src/nsPaintRequest.h
+++ b/content/events/src/nsPaintRequest.h
@@ -41,17 +41,17 @@ public:
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPaintRequestList)
   NS_DECL_NSIDOMPAINTREQUESTLIST
   
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::PaintRequestList::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::PaintRequestList::create(cx, scope, this,
                                                            triedToWrap);
   }
 
   nsISupports* GetParentObject()
   {
     return mParent;
   }
 
--- a/content/html/content/src/HTMLPropertiesCollection.cpp
+++ b/content/html/content/src/HTMLPropertiesCollection.cpp
@@ -103,17 +103,17 @@ HTMLPropertiesCollection::SetDocument(ns
   mNamedItemEntries.EnumerateRead(SetPropertyListDocument, aDocument);
   mIsDirty = true;
 }
 
 JSObject*
 HTMLPropertiesCollection::WrapObject(JSContext* cx, JSObject* scope,
                                      bool* triedToWrap)
 {
-  return mozilla::dom::binding::HTMLPropertiesCollection::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::HTMLPropertiesCollection::create(cx, scope, this,
                                                                  triedToWrap);
 }
 
 NS_IMETHODIMP
 HTMLPropertiesCollection::GetLength(uint32_t* aLength)
 {
   EnsureFresh();
   *aLength = mProperties.Length();
@@ -421,17 +421,17 @@ PropertyNodeList::GetParentObject()
 {
   return mParent;
 }
 
 JSObject*
 PropertyNodeList::WrapObject(JSContext *cx, JSObject *scope,
                              bool *triedToWrap)
 {
-  return mozilla::dom::binding::PropertyNodeList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::PropertyNodeList::create(cx, scope, this,
                                                          triedToWrap);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(PropertyNodeList)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PropertyNodeList)
   // SetDocument(nullptr) ensures that we remove ourselves as a mutation observer
   tmp->SetDocument(nullptr);
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParent)
--- a/content/html/content/src/nsClientRect.cpp
+++ b/content/html/content/src/nsClientRect.cpp
@@ -101,17 +101,17 @@ nsIDOMClientRect*
 nsClientRectList::GetItemAt(uint32_t aIndex)
 {
   return mArray.SafeObjectAt(aIndex);
 }
 
 JSObject*
 nsClientRectList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::ClientRectList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::ClientRectList::create(cx, scope, this,
                                                        triedToWrap);
 }
 
 static double
 RoundFloat(double aValue)
 {
   return floor(aValue + 0.5);
 }
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -116,17 +116,17 @@ public:
    * @return NS_OK or NS_ERROR_OUT_OF_MEMORY.
    */
   nsresult GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const;
 
   // nsWrapperCache
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::HTMLCollection::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::HTMLCollection::create(cx, scope, this,
                                                          triedToWrap);
   }
 
   nsHTMLFormElement* mForm;  // WEAK - the form owns me
 
   nsTArray<nsGenericHTMLFormElement*> mElements;  // Holds WEAK references - bug 36639
 
   // This array holds on to all form controls that are not contained
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -2010,17 +2010,17 @@ NS_INTERFACE_MAP_END
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHTMLOptionCollection)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHTMLOptionCollection)
 
 
 JSObject*
 nsHTMLOptionCollection::WrapObject(JSContext *cx, JSObject *scope,
                                    bool *triedToWrap)
 {
-  return mozilla::dom::binding::HTMLOptionsCollection::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::HTMLOptionsCollection::create(cx, scope, this,
                                                               triedToWrap);
 }
 
 NS_IMETHODIMP
 nsHTMLOptionCollection::GetLength(uint32_t* aLength)
 {
   *aLength = mElements.Length();
 
--- a/content/html/content/src/nsHTMLTableElement.cpp
+++ b/content/html/content/src/nsHTMLTableElement.cpp
@@ -51,17 +51,17 @@ public:
   NS_IMETHOD    ParentDestroyed();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TableRowsCollection)
 
   // nsWrapperCache
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::HTMLCollection::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::HTMLCollection::create(cx, scope, this,
                                                          triedToWrap);
   }
 
 protected:
   // Those rows that are not in table sections
   nsHTMLTableElement* mParent;
   nsRefPtr<nsContentList> mOrphanRows;  
 };
--- a/content/svg/content/src/DOMSVGLengthList.cpp
+++ b/content/svg/content/src/DOMSVGLengthList.cpp
@@ -71,17 +71,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLengthList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLengthList)
 NS_INTERFACE_MAP_END
 
 JSObject*
 DOMSVGLengthList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGLengthList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGLengthList::create(cx, scope, this,
                                                       triedToWrap);
 }
 
 nsIDOMSVGLength*
 DOMSVGLengthList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGNumberList.cpp
+++ b/content/svg/content/src/DOMSVGNumberList.cpp
@@ -72,17 +72,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGNumberList)
 NS_INTERFACE_MAP_END
 
 
 JSObject*
 DOMSVGNumberList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGNumberList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGNumberList::create(cx, scope, this,
                                                       triedToWrap);
 }
 
 nsIDOMSVGNumber*
 DOMSVGNumberList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGPathSegList.cpp
+++ b/content/svg/content/src/DOMSVGPathSegList.cpp
@@ -79,17 +79,17 @@ DOMSVGPathSegList::~DOMSVGPathSegList()
     InternalAList().GetAnimValKey() :
     InternalAList().GetBaseValKey();
   sSVGPathSegListTearoffTable.RemoveTearoff(key);
 }
 
 JSObject*
 DOMSVGPathSegList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGPathSegList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGPathSegList::create(cx, scope, this,
                                                        triedToWrap);
 }
 
 nsIDOMSVGPathSeg*
 DOMSVGPathSegList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGPointList.cpp
+++ b/content/svg/content/src/DOMSVGPointList.cpp
@@ -98,17 +98,17 @@ DOMSVGPointList::~DOMSVGPointList()
     InternalAList().GetAnimValKey() :
     InternalAList().GetBaseValKey();
   sSVGPointListTearoffTable.RemoveTearoff(key);
 }
 
 JSObject*
 DOMSVGPointList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGPointList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGPointList::create(cx, scope, this,
                                                      triedToWrap);
 }
 
 nsIDOMSVGPoint*
 DOMSVGPointList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGTransformList.cpp
+++ b/content/svg/content/src/DOMSVGTransformList.cpp
@@ -72,17 +72,17 @@ NS_INTERFACE_MAP_END
 
 //----------------------------------------------------------------------
 // DOMSVGTransformList methods:
 
 JSObject*
 DOMSVGTransformList::WrapObject(JSContext *cx, JSObject *scope,
                                 bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGTransformList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGTransformList::create(cx, scope, this,
                                                          triedToWrap);
 }
 
 nsIDOMSVGTransform*
 DOMSVGTransformList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/xbl/src/nsBindingManager.cpp
+++ b/content/xbl/src/nsBindingManager.cpp
@@ -75,17 +75,17 @@ public:
   int32_t GetInsertionPointCount() { return mElements->Length(); }
 
   nsXBLInsertionPoint* GetInsertionPointAt(int32_t i) { return static_cast<nsXBLInsertionPoint*>(mElements->ElementAt(i)); }
   void RemoveInsertionPointAt(int32_t i) { mElements->RemoveElementAt(i); }
 
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::NodeList::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::NodeList::create(cx, scope, this,
                                                    triedToWrap);
   }
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ANONYMOUS_CONTENT_LIST_IID)
 private:
   nsCOMPtr<nsIContent> mContent;
   nsInsertionPointList* mElements;
 };
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -538,16 +538,17 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "LockedFile.h"
 #include "GeneratedEvents.h"
 #include "mozilla/Likely.h"
 #include "nsDebug.h"
 
 #undef None // something included above defines this preprocessor symbol, maybe Xlib headers
 #include "WebGLContext.h"
 #include "nsICanvasRenderingContextInternal.h"
+#include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
   "chrome://global/locale/dom/dom.properties";
@@ -4570,22 +4571,23 @@ nsDOMClassInfo::Init()
   RegisterExternalClasses();
 
   sDisableDocumentAllSupport =
     Preferences::GetBool("browser.dom.document.all.disabled");
 
   sDisableGlobalScopePollutionSupport =
     Preferences::GetBool("browser.dom.global_scope_pollution.disabled");
 
-  // Proxy bindings
-  mozilla::dom::binding::Register(nameSpaceManager);
-
   // Non-proxy bindings
   mozilla::dom::Register(nameSpaceManager);
 
+  // This needs to happen after the call to mozilla::dom::Register, because we
+  // overwrite some values.
+  mozilla::dom::oldproxybindings::Register(nameSpaceManager);
+
   if (!AzureCanvasEnabled()) {
     nameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING("CanvasRenderingContext2D"), NULL);
   }
 
   sIsInitialized = true;
 
   return NS_OK;
 }
@@ -6741,25 +6743,25 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
     }
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
       name_struct->mType == nsGlobalNameStruct::eTypeInterface ||
       name_struct->mType == nsGlobalNameStruct::eTypeClassProto ||
       name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
     // Lookup new DOM bindings.
-    mozilla::dom::binding::DefineInterface define =
+    mozilla::dom::DefineInterface define =
       name_struct->mDefineDOMInterface;
     if (define) {
       if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
           !ConstructorEnabled(name_struct, aWin)) {
         return NS_OK;
       }
 
-      if (mozilla::dom::binding::DefineConstructor(cx, obj, define, &rv)) {
+      if (mozilla::dom::DefineConstructor(cx, obj, define, &rv)) {
         *did_resolve = NS_SUCCEEDED(rv);
 
         return rv;
       }
     }
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeInterface) {
@@ -8786,19 +8788,19 @@ nsHTMLDocumentSH::GetDocumentAllNodeList
   // in a reserved slot (0) on the document.all JSObject.
   nsresult rv = NS_OK;
 
   jsval collection = JS_GetReservedSlot(obj, 0);
 
   if (!JSVAL_IS_PRIMITIVE(collection)) {
     // We already have a node list in our reserved slot, use it.
     JSObject *obj = JSVAL_TO_OBJECT(collection);
-    if (mozilla::dom::binding::HTMLCollection::objIsWrapper(obj)) {
+    if (mozilla::dom::oldproxybindings::HTMLCollection::objIsWrapper(obj)) {
       nsIHTMLCollection *native =
-        mozilla::dom::binding::HTMLCollection::getNative(obj);
+        mozilla::dom::oldproxybindings::HTMLCollection::getNative(obj);
       NS_ADDREF(*nodeList = static_cast<nsContentList*>(native));
     }
     else {
       nsISupports *native = sXPConnect->GetNativeOfWrapper(cx, obj);
       if (native) {
         NS_ADDREF(*nodeList = nsContentList::FromSupports(native));
       }
       else {
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -776,17 +776,17 @@ nsScriptNameSpaceManager::Observe(nsISup
   // and NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID but we are safe without it.
   // See bug 600460.
 
   return NS_OK;
 }
 
 void
 nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
-    mozilla::dom::binding::DefineInterface aDefineDOMInterface)
+    mozilla::dom::DefineInterface aDefineDOMInterface)
 {
   nsGlobalNameStruct *s = AddToHash(&mGlobalNames, &aName);
   if (s) {
     if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
       s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
     }
     s->mDefineDOMInterface = aDefineDOMInterface;
   }
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -62,17 +62,17 @@ struct nsGlobalNameStruct
     int32_t mDOMClassInfoID; // eTypeClassConstructor
     nsIID mIID; // eTypeInterface, eTypeClassProto
     nsExternalDOMClassInfoData* mData; // eTypeExternalClassInfo
     ConstructorAlias* mAlias; // eTypeExternalConstructorAlias
     nsCID mCID; // All other types except eTypeNewDOMBinding
   };
 
   // For new style DOM bindings.
-  mozilla::dom::binding::DefineInterface mDefineDOMInterface;
+  mozilla::dom::DefineInterface mDefineDOMInterface;
 
 private:
 
   // copy constructor
 };
 
 
 class nsIScriptContext;
@@ -134,17 +134,17 @@ public:
                              const nsIID **aInterfaces,
                              uint32_t aScriptableFlags,
                              bool aHasClassInterface,
                              const nsCID *aConstructorCID);
 
   nsGlobalNameStruct* GetConstructorProto(const nsGlobalNameStruct* aStruct);
 
   void RegisterDefineDOMInterface(const nsAFlatString& aName,
-    mozilla::dom::binding::DefineInterface aDefineDOMInterface);
+    mozilla::dom::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 nsAString *aKey,
                                 const PRUnichar **aClassName = nullptr);
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdarg.h>
 
 #include "BindingUtils.h"
 
+#include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "XPCQuickStubs.h"
 
 namespace mozilla {
 namespace dom {
 
 JSErrorFormatString ErrorFormatString[] = {
 #define MSG_DEF(_name, _argc, _str) \
@@ -237,17 +238,17 @@ CreateInterfacePrototypeObject(JSContext
 
   return ourProto;
 }
 
 JSObject*
 CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject *receiver,
                        JSObject* protoProto, JSClass* protoClass,
                        JSClass* constructorClass, JSNative constructor,
-                       unsigned ctorNargs, JSClass* instanceClass,
+                       unsigned ctorNargs, const DOMClass* domClass,
                        Prefable<JSFunctionSpec>* methods,
                        Prefable<JSPropertySpec>* properties,
                        Prefable<ConstantSpec>* constants,
                        Prefable<JSFunctionSpec>* staticMethods, const char* name)
 {
   MOZ_ASSERT(protoClass || constructorClass || constructor,
              "Need at least one class or a constructor!");
   MOZ_ASSERT(!(methods || properties) || protoClass,
@@ -262,17 +263,17 @@ CreateInterfaceObjects(JSContext* cx, JS
   if (protoClass) {
     proto = CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
                                            methods, properties, constants);
     if (!proto) {
       return NULL;
     }
 
     js::SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT,
-                        JS::PrivateValue(instanceClass));
+                        JS::PrivateValue(const_cast<DOMClass*>(domClass)));
   }
   else {
     proto = NULL;
   }
 
   JSObject* interface;
   if (constructorClass || constructor) {
     interface = CreateInterfaceObject(cx, global, receiver, constructorClass,
@@ -328,20 +329,18 @@ DoHandleNewBindingWrappingFailure(JSCont
 }
 
 // Can only be called with the immediate prototype of the instance object. Can
 // only be called on the prototype of an object known to be a DOM instance.
 JSBool
 InstanceClassHasProtoAtDepth(JSHandleObject protoObject, uint32_t protoID,
                              uint32_t depth)
 {
-  JSClass* instanceClass = static_cast<JSClass*>(
+  const DOMClass* domClass = static_cast<DOMClass*>(
     js::GetReservedSlot(protoObject, DOM_PROTO_INSTANCE_CLASS_SLOT).toPrivate());
-  MOZ_ASSERT(IsDOMClass(instanceClass));
-  DOMJSClass* domClass = DOMJSClass::FromJSClass(instanceClass);
   return (uint32_t)domClass->mInterfaceChain[depth] == protoID;
 }
 
 // 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)
@@ -372,24 +371,21 @@ QueryInterface(JSContext* cx, unsigned a
 
   // Get the object. It might be a security wrapper, in which case we do a checked
   // unwrap.
   JSObject* origObj = JSVAL_TO_OBJECT(thisv);
   JSObject* obj = js::UnwrapObjectChecked(cx, origObj);
   if (!obj)
       return false;
 
-  JSClass* clasp = js::GetObjectJSClass(obj);
-  if (!IsDOMClass(clasp) ||
-      !DOMJSClass::FromJSClass(clasp)->mDOMObjectIsISupports) {
+  nsISupports* native;
+  if (!UnwrapDOMObjectToISupports(obj, native)) {
     return Throw<true>(cx, NS_ERROR_FAILURE);
   }
 
-  nsISupports* native = UnwrapDOMObject<nsISupports>(obj);
-
   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);
   }
@@ -446,18 +442,19 @@ XrayResolveProperty(JSContext* cx, JSObj
       // Set i to be the index into our full list of ids/specs that we're
       // looking at now.
       size_t i = methods[prefIdx].specs - methodSpecs;
       for ( ; methodIds[i] != JSID_VOID; ++i) {
         if (id == methodIds[i]) {
           JSFunction *fun = JS_NewFunctionById(cx, methodSpecs[i].call.op,
                                                methodSpecs[i].nargs, 0,
                                                wrapper, id);
-          if (!fun)
-              return false;
+          if (!fun) {
+            return false;
+          }
           SET_JITINFO(fun, methodSpecs[i].call.info);
           JSObject *funobj = JS_GetFunctionObject(fun);
           desc->value.setObject(*funobj);
           desc->attrs = methodSpecs[i].flags;
           desc->obj = wrapper;
           desc->setter = nullptr;
           desc->getter = nullptr;
           return true;
@@ -585,10 +582,51 @@ XrayEnumerateProperties(JS::AutoIdVector
         }
       }
     }
   }
 
   return true;
 }
 
+bool
+GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
+                       JS::Value* vp)
+{
+  JSObject* proto = js::GetObjectProto(proxy);
+  if (!proto) {
+    *found = false;
+    return true;
+  }
+
+  JSBool hasProp;
+  if (!JS_HasPropertyById(cx, proto, id, &hasProp)) {
+    return false;
+  }
+
+  *found = hasProp;
+  if (!hasProp || !vp) {
+    return true;
+  }
+
+  return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp);
+}
+
+bool
+HasPropertyOnPrototype(JSContext* cx, JSObject* proxy, DOMProxyHandler* handler,
+                       jsid id)
+{
+  JSAutoEnterCompartment ac;
+  if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
+    proxy = js::UnwrapObject(proxy);
+    if (!ac.enter(cx, proxy)) {
+      return false;
+    }
+  }
+  MOZ_ASSERT(js::IsProxy(proxy) && js::GetProxyHandler(proxy) == handler);
+
+  bool found;
+  // We ignore an error from GetPropertyOnPrototype.
+  return !GetPropertyOnPrototype(cx, proxy, id, &found, NULL) || found;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_BindingUtils_h__
 #define mozilla_dom_BindingUtils_h__
 
 #include "mozilla/dom/DOMJSClass.h"
+#include "mozilla/dom/DOMJSProxyHandler.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/ErrorResult.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jswrapper.h"
 
 #include "nsIXPConnect.h"
@@ -73,72 +74,147 @@ IsDOMClass(const JSClass* clasp)
 }
 
 inline bool
 IsDOMClass(const js::Class* clasp)
 {
   return IsDOMClass(Jsvalify(clasp));
 }
 
+// It's ok for eRegularDOMObject and eProxyDOMObject to be the same, but
+// eNonDOMObject should always be different from the other two. This enum
+// shouldn't be used to differentiate between non-proxy and proxy bindings.
+enum DOMObjectSlot {
+  eNonDOMObject = -1,
+  eRegularDOMObject = DOM_OBJECT_SLOT,
+  eProxyDOMObject = DOM_PROXY_OBJECT_SLOT
+};
+
 template <class T>
 inline T*
-UnwrapDOMObject(JSObject* obj)
+UnwrapDOMObject(JSObject* obj, DOMObjectSlot slot)
 {
-  MOZ_ASSERT(IsDOMClass(JS_GetClass(obj)));
+  MOZ_ASSERT(slot != eNonDOMObject,
+             "Don't pass non-DOM objects to this function");
 
-  JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
+#ifdef DEBUG
+  if (IsDOMClass(js::GetObjectClass(obj))) {
+    MOZ_ASSERT(slot == eRegularDOMObject);
+  } else {
+    MOZ_ASSERT(js::IsObjectProxyClass(js::GetObjectClass(obj)) ||
+               js::IsFunctionProxyClass(js::GetObjectClass(obj)));
+    MOZ_ASSERT(js::GetProxyHandler(obj)->family() == ProxyFamily());
+    MOZ_ASSERT(slot == eProxyDOMObject);
+  }
+#endif
+
+  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());
 }
 
+// Only use this with a new DOM binding object (either proxy or regular).
+inline const DOMClass*
+GetDOMClass(JSObject* obj)
+{
+  js::Class* clasp = js::GetObjectClass(obj);
+  if (IsDOMClass(clasp)) {
+    return &DOMJSClass::FromJSClass(clasp)->mClass;
+  }
+
+  js::BaseProxyHandler* handler = js::GetProxyHandler(obj);
+  MOZ_ASSERT(handler->family() == ProxyFamily());
+  return &static_cast<DOMProxyHandler*>(handler)->mClass;
+}
+
+inline DOMObjectSlot
+GetDOMClass(JSObject* obj, const DOMClass*& result)
+{
+  js::Class* clasp = js::GetObjectClass(obj);
+  if (IsDOMClass(clasp)) {
+    result = &DOMJSClass::FromJSClass(clasp)->mClass;
+    return eRegularDOMObject;
+  }
+
+  if (js::IsObjectProxyClass(clasp) || js::IsFunctionProxyClass(clasp)) {
+    js::BaseProxyHandler* handler = js::GetProxyHandler(obj);
+    if (handler->family() == ProxyFamily()) {
+      result = &static_cast<DOMProxyHandler*>(handler)->mClass;
+      return eProxyDOMObject;
+    }
+  }
+
+  return eNonDOMObject;
+}
+
+inline bool
+UnwrapDOMObjectToISupports(JSObject* obj, nsISupports*& result)
+{
+  const DOMClass* clasp;
+  DOMObjectSlot slot = GetDOMClass(obj, clasp);
+  if (slot == eNonDOMObject || !clasp->mDOMObjectIsISupports) {
+    return false;
+  }
+ 
+  result = UnwrapDOMObject<nsISupports>(obj, slot);
+  return true;
+}
+
+inline bool
+IsDOMObject(JSObject* obj)
+{
+  js::Class* clasp = js::GetObjectClass(obj);
+  return IsDOMClass(clasp) ||
+         ((js::IsObjectProxyClass(clasp) || js::IsFunctionProxyClass(clasp)) &&
+          js::GetProxyHandler(obj)->family() == ProxyFamily());
+}
+
 // 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).
 // U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>).
 template <prototypes::ID PrototypeID, class T, typename U>
 inline nsresult
 UnwrapObject(JSContext* cx, JSObject* obj, U& value)
 {
   /* First check to see whether we have a DOM object */
-  JSClass* clasp = js::GetObjectJSClass(obj);
-  if (!IsDOMClass(clasp)) {
+  const DOMClass* domClass;
+  DOMObjectSlot slot = GetDOMClass(obj, domClass);
+  if (slot == eNonDOMObject) {
     /* 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 = xpc::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)) {
+    slot = GetDOMClass(obj, domClass);
+    if (slot == eNonDOMObject) {
       /* 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);
+    value = UnwrapDOMObject<T>(obj, slot);
     return NS_OK;
   }
 
   /* It's the wrong sort of DOM object */
   return NS_ERROR_XPC_BAD_CONVERT_JS;
 }
 
 inline bool
@@ -304,17 +380,17 @@ struct Prefable {
  *
  * returns the interface prototype object if protoClass is non-null, else it
  * returns the interface object.
  */
 JSObject*
 CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* receiver,
                        JSObject* protoProto, JSClass* protoClass,
                        JSClass* constructorClass, JSNative constructor,
-                       unsigned ctorNargs, JSClass* instanceClass,
+                       unsigned ctorNargs, const DOMClass* domClass,
                        Prefable<JSFunctionSpec>* methods,
                        Prefable<JSPropertySpec>* properties,
                        Prefable<ConstantSpec>* constants,
                        Prefable<JSFunctionSpec>* staticMethods, const char* name);
 
 template <class T>
 inline bool
 WrapNewBindingObject(JSContext* cx, JSObject* scope, T* value, JS::Value* vp)
@@ -550,16 +626,32 @@ GetParentPointer(T* aObject)
 }
 
 inline nsISupports*
 GetParentPointer(const ParentObject& aObject)
 {
   return ToSupports(aObject.mObject);
 }
 
+template<class T>
+inline void
+ClearWrapper(T* p, nsWrapperCache* cache)
+{
+  cache->ClearWrapper();
+}
+
+template<class T>
+inline void
+ClearWrapper(T* p, void*)
+{
+  nsWrapperCache* cache;
+  CallQueryInterface(p, &cache);
+  ClearWrapper(p, cache);
+}
+
 // Can only be called with the immediate prototype of the instance object. Can
 // only be called on the prototype of an object known to be a DOM instance.
 JSBool
 InstanceClassHasProtoAtDepth(JSHandleObject protoObject, uint32_t protoID,
                              uint32_t depth);
 
 // Only set allowNativeWrapper to false if you really know you need it, if in
 // doubt use true. Setting it to false disables security wrappers.
@@ -695,16 +787,24 @@ InitIds(JSContext* cx, Prefable<Spec>* p
   return true;
 }
 
 JSBool
 QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
 JSBool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
 
+bool
+GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
+                       JS::Value* vp);
+
+bool
+HasPropertyOnPrototype(JSContext* cx, JSObject* proxy, DOMProxyHandler* handler,
+                       jsid id);
+
 template<class T>
 class NonNull
 {
 public:
   NonNull()
 #ifdef DEBUG
     : inited(false)
 #endif
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -296,16 +296,62 @@ DOMInterfaces = {
         },
 
 'OnlyForUseInConstructor' : {
         'nativeType': 'mozilla::dom::OnlyForUseInConstructor',
         'headerFile': 'TestBindingHeader.h',
         'register': False
         },
 
+
+'TestIndexedGetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedGetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False,
+        'infallible': [ 'length' ]
+        },
+
+'TestNamedGetterInterface' : {
+        'nativeType': 'mozilla::dom::TestNamedGetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestIndexedAndNamedGetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedAndNamedGetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False,
+        'infallible': [ 'length' ]
+        },
+
+'TestIndexedSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestNamedSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestNamedSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestIndexedAndNamedSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedAndNamedSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestIndexedAndNamedGetterAndSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedAndNamedGetterAndSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False,
+        'infallible': [ 'length', '__stringifier' ],
+        'binaryNames': { '__stringifier': 'Stringify' }
+        },
 }
 
 # These are temporary, until they've been converted to use new DOM bindings
 def addExternalIface(iface, nativeType=None, headerFile=None):
     if nativeType is None:
         nativeType = 'nsIDOM' + iface
     domInterface = {
         'nativeType': nativeType,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -63,47 +63,53 @@ class CGNativePropertyHooks(CGThing):
     Generate a NativePropertyHooks for a given descriptor
     """
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
     def declare(self):
         if self.descriptor.workers:
             return ""
-        return "  extern const NativePropertyHooks NativeHooks;\n"
+        return "extern const NativePropertyHooks NativeHooks;\n"
     def define(self):
         if self.descriptor.workers:
             return ""
         parent = self.descriptor.interface.parent
         parentHooks = ("&" + toBindingNamespace(parent.identifier.name) + "::NativeHooks"
                        if parent else 'NULL')
         return """
 const NativePropertyHooks NativeHooks = { ResolveProperty, EnumerateProperties, %s };
 """ % parentHooks
 
+def DOMClass(descriptor):
+        protoList = ['prototypes::id::' + proto for proto in 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.
+        protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
+        prototypeChainString = ', '.join(protoList)
+        nativeHooks = "NULL" if descriptor.workers else "&NativeHooks"
+        return """{
+  { %s },
+  %s, %s
+}""" % (prototypeChainString, toStringBool(descriptor.nativeIsISupports),
+          nativeHooks)
+
 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"
+        return "extern DOMJSClass Class;\n"
     def define(self):
         traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else 'NULL'
-        protoList = ['prototypes::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('prototypes::id::_ID_Count')
-        prototypeChainString = ', '.join(protoList)
-        nativeHooks = "NULL" if self.descriptor.workers else "&NativeHooks"
         return """
 DOMJSClass Class = {
   { "%s",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1),
     %s, /* addProperty */
     JS_PropertyStub,       /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
@@ -113,36 +119,33 @@ DOMJSClass Class = {
     %s, /* finalize */
     NULL,                  /* checkAccess */
     NULL,                  /* call */
     NULL,                  /* hasInstance */
     NULL,                  /* construct */
     %s, /* trace */
     JSCLASS_NO_INTERNAL_MEMBERS
   },
-  { %s },
-  -1, %s,
-  %s
+  %s,
+  -1
 };
 """ % (self.descriptor.interface.identifier.name,
        ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.workers and self.descriptor.wrapperCache else 'JS_PropertyStub',
-       FINALIZE_HOOK_NAME, traceHook, prototypeChainString,
-       str(self.descriptor.nativeIsISupports).lower(),
-       nativeHooks)
+       FINALIZE_HOOK_NAME, traceHook,
+       CGIndenter(CGGeneric(DOMClass(self.descriptor))).define())
 
 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 = {
+        return """static JSClass PrototypeClass = {
   "%sPrototype",
   JSCLASS_HAS_RESERVED_SLOTS(1),
   JS_PropertyStub,       /* addProperty */
   JS_PropertyStub,       /* delProperty */
   JS_PropertyStub,       /* getProperty */
   JS_StrictPropertyStub, /* setProperty */
   JS_EnumerateStub,
   JS_ResolveStub,
@@ -197,22 +200,22 @@ class CGList(CGThing):
     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 join(self, generator):
+        return self.joiner.join(filter(lambda s: len(s) > 0, (child for child in generator)))
     def declare(self):
-        return self.joiner.join([child.declare() for child in self.children
-                                 if child is not None])
+        return self.join(child.declare() for child in self.children if child is not None)
     def define(self):
-        return self.joiner.join([child.define() for child in self.children
-                                 if child is not None])
+        return self.join(child.define() for child in self.children if child is not None)
 
 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
@@ -226,32 +229,33 @@ class CGGeneric(CGThing):
 # 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):
+    def __init__(self, child, indentLevel=2, declareOnly=False):
         CGThing.__init__(self)
         self.child = child
         self.indent = " " * indentLevel
+        self.declareOnly = declareOnly
     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 "":
+        if defn is not "" and not self.declareOnly:
             return re.sub(lineStartDetector, self.indent, defn)
         else:
-            return ""
+            return defn
 
 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, defineOnly=False, reindent=False):
@@ -280,16 +284,23 @@ class CGWrapper(CGThing):
         defn = self.child.define()
         if self.reindent:
             # We don't use lineStartDetector because we don't want to
             # insert whitespace at the beginning of our _first_ line.
             defn = stripTrailingWhitespace(
                 defn.replace("\n", "\n" + (" " * len(self.definePre))))
         return self.definePre + defn + self.definePost
 
+class CGIfWrapper(CGWrapper):
+    def __init__(self, child, condition):
+        pre = CGWrapper(CGGeneric(condition), pre="if (", post=") {\n",
+                        reindent=True)
+        CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
+                           post="\n}")
+
 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):
@@ -514,49 +525,64 @@ class CGAbstractMethod(CGThing):
 
     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.
 
+    alwaysInline should be True to generate an inline method annotated with
+    MOZ_ALWAYS_INLINE.
+
     static should be True to generate a static method, which only has
     a definition.
+
+    If templateArgs is not None it should be a list of strings containing
+    template arguments, and the function will be templatized using those
+    arguments.
     """
-    def __init__(self, descriptor, name, returnType, args, inline=False, static=False):
+    def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, templateArgs=None):
         CGThing.__init__(self)
         self.descriptor = descriptor
         self.name = name
         self.returnType = returnType
         self.args = args
         self.inline = inline
+        self.alwaysInline = alwaysInline
         self.static = static
+        self.templateArgs = templateArgs
     def _argstring(self):
         return ', '.join([str(a) for a in self.args])
+    def _template(self):
+        if self.templateArgs is None:
+            return ''
+        return 'template <%s>\n' % ', '.join(self.templateArgs)
     def _decorators(self):
         decorators = []
-        if self.inline:
+        if self.alwaysInline:
+            decorators.append('MOZ_ALWAYS_INLINE')
+        elif self.inline:
             decorators.append('inline')
         if self.static:
             decorators.append('static')
         decorators.append(self.returnType)
-        return ' '.join(decorators)
+        maybeNewline = " " if self.inline else "\n"
+        return ' '.join(decorators) + maybeNewline
     def declare(self):
         if self.inline:
             return self._define()
-        return "\n  %s %s(%s);\n" % (self._decorators(), self.name, self._argstring())
+        return "%s%s%s(%s);\n" % (self._template(), 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())
+        return "%s%s%s(%s)\n{" % (self._template(), self._decorators(),
+                                  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
@@ -575,17 +601,17 @@ class CGAbstractClassHook(CGAbstractStat
     '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 """
-  %s* self = UnwrapDOMObject<%s>(obj);
+  %s* self = UnwrapDOMObject<%s>(obj, eRegularDOMObject);
 """ % (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)
@@ -603,43 +629,45 @@ class CGAddPropertyHook(CGAbstractClassH
     def generate_code(self):
         # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=774279
         # Using a real trace hook might enable us to deal with non-nsISupports
         # wrappercached things here.
         assert self.descriptor.nativeIsISupports
         return """  nsContentUtils::PreserveWrapper(reinterpret_cast<nsISupports*>(self), self);
   return true;"""
 
+def finalizeHook(descriptor, hookName, context):
+    if descriptor.customFinalize:
+        return """if (self) {
+  self->%s(%s);
+}""" % (hookName, context)
+    clearWrapper = "ClearWrapper(self, self);\n" if descriptor.wrapperCache else ""
+    if descriptor.workers:
+        release = "self->Release();"
+    else:
+        assert descriptor.nativeIsISupports
+        release = """XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
+if (rt) {
+  rt->DeferredRelease(reinterpret_cast<nsISupports*>(self));
+} else {
+  NS_RELEASE(self);
+}"""
+    return clearWrapper + release
+
 class CGClassFinalizeHook(CGAbstractClassHook):
     """
     A hook for finalize, used to release our native object.
     """
     def __init__(self, descriptor):
         args = [Argument('JSFreeOp*', 'fop'), 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)
-        clearWrapper = "self->ClearWrapper();\n  " if self.descriptor.wrapperCache else ""
-        if self.descriptor.workers:
-            release = "self->Release();"
-        else:
-            assert self.descriptor.nativeIsISupports
-            release = """XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
-  if (rt) {
-    rt->DeferredRelease(reinterpret_cast<nsISupports*>(self));
-  } else {
-    NS_RELEASE(self);
-  }"""
-        return """
-  %s%s""" % (clearWrapper, release)
+        return CGIndenter(CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name))).define()
 
 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',
@@ -889,34 +917,56 @@ def methodLength(method):
 
 class MethodDefiner(PropertyDefiner):
     """
     A class for defining methods on a prototype object.
     """
     def __init__(self, descriptor, name, static):
         PropertyDefiner.__init__(self, descriptor, name)
 
+        # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
+        #       We should be able to check for special operations without an
+        #       identifier. For now we check if the name starts with __
         methods = [m for m in descriptor.interface.members if
-                   m.isMethod() and m.isStatic() == static]
+                   m.isMethod() and m.isStatic() == static and
+                   not m.isIdentifierLess()]
         self.chrome = [{"name": m.identifier.name,
                         "length": methodLength(m),
                         "flags": "JSPROP_ENUMERATE",
                         "pref": PropertyDefiner.getControllingPref(m) }
                        for m in methods]
         self.regular = [{"name": m.identifier.name,
                          "length": methodLength(m),
                          "flags": "JSPROP_ENUMERATE",
                          "pref": PropertyDefiner.getControllingPref(m) }
                         for m in methods if not isChromeOnly(m)]
+
+        # FIXME Check for an existing iterator on the interface first.
+        if any(m.isGetter() and m.isIndexed() for m in methods):
+            self.chrome.append({"name": 'iterator',
+                                "methodInfo": False,
+                                "nativeName": "JS_ArrayIterator",
+                                "length": 0,
+                                "flags": "JSPROP_ENUMERATE",
+                                "pref": None })
+            self.regular.append({"name": 'iterator',
+                                 "methodInfo": False,
+                                 "nativeName": "JS_ArrayIterator",
+                                 "length": 0,
+                                 "flags": "JSPROP_ENUMERATE",
+                                 "pref": None })
+
         if not descriptor.interface.parent and not static and not descriptor.workers:
             self.chrome.append({"name": 'QueryInterface',
+                                "methodInfo": False,
                                 "length": 1,
                                 "flags": "0",
                                 "pref": None })
             self.regular.append({"name": 'QueryInterface',
+                                 "methodInfo": False,
                                  "length": 1,
                                  "flags": "0",
                                  "pref": None })
 
         if static:
             if not descriptor.interface.hasInterfaceObject():
                 # static methods go on the interface object
                 assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
@@ -928,19 +978,22 @@ class MethodDefiner(PropertyDefiner):
     def generateArray(self, array, name, doIdArrays):
         if len(array) == 0:
             return ""
 
         def pref(m):
             return m["pref"]
 
         def specData(m):
-            isQI = (m["name"] == 'QueryInterface')
-            jitinfo = ("&%s_methodinfo" % m["name"]) if not isQI else "NULL"
-            accessor = "genericMethod" if not isQI else "QueryInterface"
+            if m.get("methodInfo", True):
+                jitinfo = ("&%s_methodinfo" % m["name"])
+                accessor = "genericMethod"
+            else:
+                jitinfo = "nullptr"
+                accessor = m.get("nativeName", m["name"])
             return (m["name"], accessor, jitinfo, m["length"], m["flags"])
 
         return self.generatePrefableArray(
             array, name,
             '  JS_FNINFO("%s", %s, %s, %s, %s)',
             '  JS_FS_END',
             'JSFunctionSpec',
             pref, specData, doIdArrays)
@@ -1101,58 +1154,66 @@ class CGCreateInterfaceObjectsMethod(CGA
             prefCache = CGWrapper(CGIndenter(CGList(prefCacheData, "\n")),
                                   pre=("static bool sPrefCachesInited = false;\n"
                                        "if (!sPrefCachesInited) {\n"
                                        "  sPrefCachesInited = true;\n"),
                                   post="\n}")
         else:
             prefCache = None
             
-        getParentProto = ("JSObject* parentProto = %s;\n"
-                          "if (!parentProto) {\n"
-                          "  return NULL;\n"
-                          "}") % getParentProto
+        getParentProto = ("JSObject* parentProto = %s;\n" +
+                          "if (!parentProto) {\n" +
+                          "  return NULL;\n" +
+                          "}\n") % getParentProto
 
         needInterfaceObjectClass = (needInterfaceObject and
                                     self.descriptor.hasInstanceInterface)
         needConstructor = (needInterfaceObject and
                            not self.descriptor.hasInstanceInterface)
         if self.descriptor.interface.ctor():
             constructHook = CONSTRUCT_HOOK_NAME
             constructArgs = methodLength(self.descriptor.interface.ctor())
         else:
             constructHook = "ThrowingConstructor"
             constructArgs = 0
 
-        call = CGGeneric(("return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,\n"
-                          "                                   %s, %s, %s, %d,\n"
-                          "                                   %s,\n"
-                          "                                   %%(methods)s, %%(attrs)s, %%(consts)s, %%(staticMethods)s,\n"
-                          "                                   %s);") % (
+        if self.descriptor.concrete:
+            if self.descriptor.proxy:
+                domClass = "&Class"
+            else:
+                domClass = "&Class.mClass"
+        else:
+            domClass = "nullptr"
+
+        call = """return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,
+                                   %s, %s, %s, %d,
+                                   %s,
+                                   %%(methods)s, %%(attrs)s,
+                                   %%(consts)s, %%(staticMethods)s,
+                                   %s);""" % (
             "&PrototypeClass" if needInterfacePrototypeObject else "NULL",
             "&InterfaceObjectClass" if needInterfaceObjectClass else "NULL",
             constructHook if needConstructor else "NULL",
             constructArgs,
-            "&Class.mBase" if self.descriptor.concrete else "NULL",
-            '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL"))
-
+            domClass,
+            '"' + 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))"
-            accessCheck = "if (" + accessCheck + ") {\n"
-            chrome = CGWrapper(CGGeneric((CGIndenter(call).define() % self.properties.variableNames(True))),
-                               pre=accessCheck, post="\n}")
+            chrome = CGIfWrapper(CGGeneric(call % self.properties.variableNames(True)),
+                                 accessCheck)
+            chrome = CGWrapper(chrome, pre="\n\n")
         else:
             chrome = None
 
         functionBody = CGList(
             [CGGeneric(getParentProto), initIds, prefCache, chrome,
-             CGGeneric(call.define() % self.properties.variableNames(False))],
+             CGGeneric(call % self.properties.variableNames(False))],
             "\n\n")
         return CGIndenter(functionBody).define()
 
 class CGGetPerInterfaceObject(CGAbstractMethod):
     """
     A method for getting a per-interface object (a prototype object or interface
     constructor object).
     """
@@ -1267,33 +1328,58 @@ class CGDefineDOMInterfaceMethod(CGAbstr
             getter = "GetConstructorObject"
 
         return ("  JSObject* global = JS_GetGlobalForObject(aCx, aReceiver);\n" +
                 CheckPref(self.descriptor, "global", "*aEnabled", "false") + 
                 """
   *aEnabled = true;
   return !!%s(aCx, global, aReceiver);""" % (getter))
 
-class CGWrapMethod(CGAbstractMethod):
+class CGIsMethod(CGAbstractMethod):
     def __init__(self, descriptor):
-        # XXX can we wrap if we don't have an interface prototype object?
+        args = [Argument('JSObject*', 'obj')]
+        CGAbstractMethod.__init__(self, descriptor, 'Is', 'bool', args)
+
+    def definition_body(self):
+        # Non-proxy implementation would check
+        #   js::GetObjectJSClass(obj) == &Class.mBase
+        return """  return IsProxy(obj);"""
+
+class CGWrapWithCacheMethod(CGAbstractMethod):
+    def __init__(self, descriptor):
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
                 Argument(descriptor.nativeType + '*', 'aObject'),
+                Argument('nsWrapperCache*', 'aCache'),
                 Argument('bool*', 'aTriedToWrap')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
 
     def definition_body(self):
         if self.descriptor.workers:
-            return """
-  *aTriedToWrap = true;
+            return """  *aTriedToWrap = true;
   return aObject->GetJSObject();"""
 
-        return """
-  *aTriedToWrap = true;
+        if self.descriptor.proxy:
+            create = """  JSObject *obj = NewProxyObject(aCx, &DOMProxyHandler::instance,
+                                 JS::PrivateValue(aObject), proto, parent);
+  if (!obj) {
+    return NULL;
+  }
+
+"""
+        else:
+            create = """  JSObject* obj = JS_NewObject(aCx, &Class.mBase, proto, parent);
+  if (!obj) {
+    return NULL;
+  }
+
+  js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
+"""
+
+        return """  *aTriedToWrap = true;
 
   JSObject* parent = WrapNativeParent(aCx, aScope, aObject->GetParentObject());
   if (!parent) {
     return NULL;
   }
 
   JSAutoEnterCompartment ac;
   if (js::GetGlobalForObjectCrossCompartment(parent) != aScope) {
@@ -1304,27 +1390,33 @@ class CGWrapMethod(CGAbstractMethod):
 
   JSObject* global = JS_GetGlobalForObject(aCx, parent);
 %s
   JSObject* proto = GetProtoObject(aCx, global, global);
   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));
+%s
   NS_ADDREF(aObject);
 
-  aObject->SetWrapper(obj);
-
-  return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aObject"))
+  aCache->SetWrapper(obj);
+
+  return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aCache"), create)
+
+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('T*', 'aObject'), Argument('bool*', 'aTriedToWrap')]
+        CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args, inline=True, templateArgs=["class T"])
+
+    def definition_body(self):
+        return "  return Wrap(aCx, aScope, aObject, aObject, aTriedToWrap);"
 
 class CGWrapNonWrapperCacheMethod(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')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
@@ -2200,17 +2292,17 @@ for (uint32_t i = 0; i < length; ++i) {
 
         template = ("if (!%s.Init(cx, %s)) {\n"
                     "  return false;\n"
                     "}" % (selfRef, val))
 
         return (template, declType, None, False)
 
     if not type.isPrimitive():
-        raise TypeError("Need conversion for argument type '%s'" % type)
+        raise TypeError("Need conversion for argument type '%s'" % str(type))
 
     # XXXbz need to add support for [EnforceRange] and [Clamp]
     typeName = builtinNames[type.tag()]
     if type.nullable():
         dataLoc = "${declName}.SetValue()"
         nullCondition = "${val}.isNullOrUndefined()"
         if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
             nullCondition = "!(${haveValue}) || " + nullCondition
@@ -2653,131 +2745,132 @@ def infallibleForAttr(attr, descriptorPr
                                   memberIsCreator(attr))[1]
 
 def typeNeedsCx(type):
     return (type is not None and
             (type.isCallback() or type.isAny() or type.isObject() or
              (type.isUnion() and
               any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes))))
 
-# Returns a CGThing containing the type of the return value, or None
-# if there is no need for a return value.
+# Returns a tuple consisting of a CGThing containing the type of the return
+# value, or None if there is no need for a return value, and a boolean signaling
+# whether the return value is passed in an out parameter.
 def getRetvalDeclarationForType(returnType, descriptorProvider,
                                 resultAlreadyAddRefed):
     if returnType is None or returnType.isVoid():
         # Nothing to declare
-        return None
+        return None, False
     if returnType.isPrimitive() and returnType.tag() in builtinNames:
         result = CGGeneric(builtinNames[returnType.tag()])
         if returnType.nullable():
             result = CGWrapper(result, pre="Nullable<", post=">")
-        return result
+        return result, False
     if returnType.isString():
-        return CGGeneric("nsString")
+        return CGGeneric("nsString"), True
     if returnType.isEnum():
         if returnType.nullable():
             raise TypeError("We don't support nullable enum return values")
-        return CGGeneric(returnType.inner.identifier.name)
+        return CGGeneric(returnType.inner.identifier.name), False
     if returnType.isGeckoInterface():
         result = CGGeneric(descriptorProvider.getDescriptor(
             returnType.unroll().inner.identifier.name).nativeType)
         if resultAlreadyAddRefed:
             result = CGWrapper(result, pre="nsRefPtr<", post=">")
         else:
             result = CGWrapper(result, post="*")
-        return result
+        return result, False
     if returnType.isCallback():
         # XXXbz we're going to assume that callback types are always
         # nullable for now.
-        return CGGeneric("JSObject*")
-    if returnType.isAny():
-        return CGGeneric("JS::Value")
+        return CGGeneric("JSObject*"), False
+    if returnType.tag() is IDLType.Tags.any:
+        return CGGeneric("JS::Value"), False
     if returnType.isObject():
-        return CGGeneric("JSObject*")
+        return CGGeneric("JSObject*"), False
     if returnType.isSequence():
         nullable = returnType.nullable()
         if nullable:
             returnType = returnType.inner
         # If our result is already addrefed, use the right type in the
         # sequence argument here.
-        result = getRetvalDeclarationForType(returnType.inner,
-                                             descriptorProvider,
-                                             resultAlreadyAddRefed)
+        (result, _) = getRetvalDeclarationForType(returnType.inner,
+                                                  descriptorProvider,
+                                                  resultAlreadyAddRefed)
         result = CGWrapper(result, pre="nsTArray< ", post=" >")
         if nullable:
             result = CGWrapper(result, pre="Nullable< ", post=" >")
-        return result
+        return result, True
     raise TypeError("Don't know how to declare return value for %s" %
                     returnType)
 
 def isResultAlreadyAddRefed(descriptor, extendedAttributes):
     # Default to already_AddRefed on the main thread, raw pointer in workers
     return not descriptor.workers and not 'resultNotAddRefed' in extendedAttributes
 
 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".
+    object is stored in a variable whose name is given by the |object| argument.
     """
     def __init__(self, errorReport, arguments, argsPre, returnType,
-                 extendedAttributes, descriptorProvider, nativeMethodName, static):
+                 extendedAttributes, descriptorProvider, nativeMethodName,
+                 static, object="self", declareResult=True):
         CGThing.__init__(self)
 
         isFallible = errorReport is not None
 
+        resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
+                                                        extendedAttributes)
+        (result, resultOutParam) = getRetvalDeclarationForType(returnType,
+                                                               descriptorProvider,
+                                                               resultAlreadyAddRefed)
+
         args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
-        for (i, a) in enumerate(arguments):
-            arg = "arg" + str(i)
+        for (a, name) in arguments:
             # This is a workaround for a bug in Apple's clang.
             if a.type.isObject() and not a.type.nullable() and not a.optional:
-                arg = "(JSObject&)" + arg
-            args.append(CGGeneric(arg))
-        resultOutParam = (returnType is not None and
-                          (returnType.isString() or returnType.isSequence()))
+                name = "(JSObject&)" + name
+            args.append(CGGeneric(name))
+
         # Return values that go in outparams go here
         if resultOutParam:
             args.append(CGGeneric("result"))
         if isFallible:
             args.append(CGGeneric("rv"))
 
-        resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
-                                                        extendedAttributes)
-        result = getRetvalDeclarationForType(returnType,
-                                             descriptorProvider,
-                                             resultAlreadyAddRefed)
         needsCx = (typeNeedsCx(returnType) or
-                   any(typeNeedsCx(a.type) for a in arguments) or
+                   any(typeNeedsCx(a.type) for (a, _) in arguments) or
                    'implicitJSContext' in extendedAttributes)
 
         if not "cx" in argsPre and needsCx:
             args.prepend(CGGeneric("cx"))
 
         # 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))
+            call = CGWrapper(call, pre="%s::" % descriptorProvider.nativeType)
         else: 
-            call = CGWrapper(call, pre="self->")
+            call = CGWrapper(call, pre="%s->" % object)
         call = CGList([call, CGWrapper(args, pre="(", post=");")])
         if result is not None:
-            result = CGWrapper(result, post=" result;")
-            self.cgRoot.prepend(result)
+            if declareResult:
+                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("ErrorResult rv;"))
             self.cgRoot.append(CGGeneric("if (rv.Failed()) {"))
-            self.cgRoot.append(CGIndenter(CGGeneric(errorReport)))
+            self.cgRoot.append(CGIndenter(errorReport))
             self.cgRoot.append(CGGeneric("}"))
 
     def define(self):
         return self.cgRoot.define()
 
 class MethodNotCreatorError(Exception):
     def __init__(self, typename):
         self.typename = typename
@@ -2825,27 +2918,29 @@ class CGPerSignatureCall(CGThing):
             cgThings = []
         cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgv(),
                                              self.getArgc(), self.descriptor,
                                              invalidEnumValueFatal=not setter) for
                          i in range(argConversionStartsAt, self.argCount)])
 
         cgThings.append(CGCallGenerator(
                     self.getErrorReport() if self.isFallible() else None,
-                    self.arguments, self.argsPre, returnType,
+                    self.getArguments(), self.argsPre, returnType,
                     self.extendedAttributes, 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 getArguments(self):
+        return [(a, "arg" + str(i)) for (i, a) in enumerate(self.arguments)]
 
     def isFallible(self):
         return not 'infallible' in self.extendedAttributes
 
     def wrap_return_value(self):
         isCreator = memberIsCreator(self.idlNode)
         if isCreator:
             # We better be returning addrefed things!
@@ -2860,20 +2955,20 @@ class CGPerSignatureCall(CGThing):
         except MethodNotCreatorError, err:
             assert not isCreator
             raise TypeError("%s being returned from non-creator method or property %s.%s" %
                             (err.typename,
                              self.descriptor.interface.identifier.name,
                              self.idlNode.identifier.name))
 
     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)
+        return CGGeneric('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() + "\n" + self.wrap_return_value())
 
 class CGSwitch(CGList):
     """
     A class to generate code for a switch statement.
 
@@ -3841,37 +3936,127 @@ class ClassMethod(ClassItem):
                   'decorators': self.getDecorators(False),
                   'returnType': self.returnType,
                   'className': cgClass.getNameString(),
                   'name': self.name,
                   'args': args,
                   'const': ' const' if self.const else '',
                   'body': body })
 
+class ClassConstructor(ClassItem):
+    """
+    Used for adding a constructor to a CGClass.
+    
+    args is a list of Argument objects that are the arguments taken by the
+    constructor.
+    
+    inline should be True if the constructor should be marked inline.
+
+    bodyInHeader should be True if the body should be placed in the class
+    declaration in the header.
+
+    visibility determines the visibility of the constructor (public,
+    protected, private), defaults to private.
+
+    baseConstructors is a list of strings containing calls to base constructors,
+    defaults to None.
+
+    body contains a string with the code for the constructor, defaults to None.
+    """
+    def __init__(self, args, inline=False, bodyInHeader=False,
+                 visibility="private", baseConstructors=None, body=None):
+        self.args = args
+        self.inline = inline or bodyInHeader
+        self.bodyInHeader = bodyInHeader
+        self.baseConstructors = baseConstructors
+        self.body = body
+        ClassItem.__init__(self, None, visibility)
+
+    def getDecorators(self, declaring):
+        decorators = []
+        if self.inline and declaring:
+            decorators.append('inline')
+        if decorators:
+            return ' '.join(decorators) + ' '
+        return ''
+
+    def getInitializationList(self, cgClass):
+        items = [str(c) for c in self.baseConstructors]
+        for m in cgClass.members:
+            if not m.static:
+                initialize = m.getBody()
+                if initialize:
+                    items.append(m.name + "(" + initialize + ")")
+            
+        if len(items) > 0:
+            return '\n  : ' + ',\n    '.join(items)
+        return ''
+
+    def getBody(self):
+        assert self.body is not None
+        return self.body
+
+    def declare(self, cgClass):
+        args = ', '.join([str(a) for a in self.args])
+        if self.bodyInHeader:
+            body = '  ' + self.getBody();
+            body = stripTrailingWhitespace(body.replace('\n', '\n  '))
+            if len(body) > 0:
+                body += '\n'
+            body = self.getInitializationList(cgClass) + '\n{\n' + body + '}'
+        else:
+            body = ';'
+
+        return string.Template("""${decorators}${className}(${args})${body}
+""").substitute({ 'decorators': self.getDecorators(True),
+                  'className': cgClass.getNameString(),
+                  'args': args,
+                  'body': body })
+
+    def define(self, cgClass):
+        if self.bodyInHeader:
+            return ''
+
+        args = ', '.join([str(a) for a in self.args])
+
+        body = '  ' + self.getBody()
+        body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n  '))
+        if len(body) > 0:
+            body += '\n'
+
+        return string.Template("""${decorators}
+${className}::${className}(${args})${initializationList}
+{${body}}\n
+""").substitute({ 'decorators': self.getDecorators(False),
+                  'className': cgClass.getNameString(),
+                  'args': args,
+                  'initializationList': self.getInitializationList(cgClass),
+                  '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())
+        if self.body:
+            body = " = " + self.body
+        else:
+            body = ""
+        return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(),
+                                      self.name, body)
 
 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)
@@ -3897,23 +4082,24 @@ class ClassEnum(ClassItem):
         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=''):
+    def __init__(self, name, bases=[], members=[], constructors=[], methods=[],
+                 typedefs = [], enums=[], templateArgs=[],
+                 templateSpecialization=[], isStruct=False, indent=''):
         CGThing.__init__(self)
         self.name = name
         self.bases = bases
         self.members = members
+        self.constructors = constructors
         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'
@@ -3980,43 +4166,44 @@ class CGClass(CGThing):
                         declaration = member.declare(cgClass)
                         declaration = CGIndenter(CGGeneric(declaration)).define()
                         result = result + declaration
                         itemCount = itemCount + 1
                     lastVisibility = visibility
             return (result, lastVisibility, itemCount)
 
         order = [(self.enums, ''), (self.typedefs, ''), (self.members, ''),
-                 (self.methods, '\n')]
+                 (self.constructors, '\n'), (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 = CGIndenter(CGGeneric(memberString),
                                           len(self.indent)).define()
             result = result + memberString
 
-        result = result + self.indent + '};\n\n'
+        result = result + self.indent + '};\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')]
+        order = [(self.members, '\n'), (self.constructors, '\n'),
+                 (self.methods, '\n')]
 
         result = ''
         itemCount = 0
         for (memberList, separator) in order:
             (memberString, itemCount) = defineMembers(self, memberList,
                                                       itemCount, separator)
             result = result + memberString
         return result
@@ -4112,99 +4299,632 @@ class CGClassForwardDeclare(CGThing):
         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 ''
 
+class CGProxySpecialOperation(CGPerSignatureCall):
+    """
+    Base class for classes for calling an indexed or named special operation
+    (don't use this directly, use the derived classes below).
+    """
+    def __init__(self, descriptor, operation):
+        nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation))
+        operation = descriptor.operations[operation]
+        assert len(operation.signatures()) == 1
+        signature = operation.signatures()[0]
+        extendedAttributes = descriptor.getExtendedAttributes(operation)
+
+        (returnType, arguments) = signature
+
+        # We pass len(arguments) as the final argument so that the
+        # CGPerSignatureCall won't do any argument conversion of its own.
+        CGPerSignatureCall.__init__(self, returnType, "", arguments, nativeName,
+                                    False, descriptor, operation,
+                                    len(arguments))
+
+        if operation.isSetter() or operation.isCreator():
+            # arguments[0] is the index or name of the item that we're setting.
+            argument = arguments[1]
+            template = getJSToNativeConversionTemplate(argument.type, descriptor)
+            templateValues = {
+                "declName": argument.identifier.name,
+                "holderName": argument.identifier.name + "_holder",
+                "val": "desc->value",
+                "valPtr": "&desc->value"
+            }
+            self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(template, templateValues))
+        elif operation.isGetter():
+            self.cgRoot.prepend(CGGeneric("bool found;"))
+
+    def getArguments(self):
+        args = [(a, a.identifier.name) for a in self.arguments]
+        if self.idlNode.isGetter():
+            args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean]), "found"))
+        return args
+
+    def wrap_return_value(self):
+        if not self.idlNode.isGetter() or self.templateValues is None:
+            return ""
+
+        wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues))
+        wrap = CGIfWrapper(wrap, "found")
+        return "\n" + wrap.define()
+
+class CGProxyIndexedGetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to an indexed getter. If templateValues is not None
+    the returned value will be wrapped with wrapForType using templateValues.
+    """
+    def __init__(self, descriptor, templateValues=None):
+        self.templateValues = templateValues
+        CGProxySpecialOperation.__init__(self, descriptor, 'IndexedGetter')
+
+class CGProxyIndexedSetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to an indexed setter.
+    """
+    def __init__(self, descriptor):
+        CGProxySpecialOperation.__init__(self, descriptor, 'IndexedSetter')
+
+class CGProxyNamedGetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to an named getter. If templateValues is not None
+    the returned value will be wrapped with wrapForType using templateValues.
+    """
+    def __init__(self, descriptor, templateValues=None):
+        self.templateValues = templateValues
+        CGProxySpecialOperation.__init__(self, descriptor, 'NamedGetter')
+
+class CGProxyNamedSetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to a named setter.
+    """
+    def __init__(self, descriptor):
+        CGProxySpecialOperation.__init__(self, descriptor, 'NamedSetter')
+
+class CGProxyIsProxy(CGAbstractMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSObject*', 'obj')]
+        CGAbstractMethod.__init__(self, descriptor, "IsProxy", "bool", args, alwaysInline=True)
+    def declare(self):
+        return ""
+    def definition_body(self):
+        return "  return js::IsProxy(obj) && js::GetProxyHandler(obj) == &DOMProxyHandler::instance;"
+
+class CGProxyUnwrap(CGAbstractMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSObject*', 'obj')]
+        CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", descriptor.nativeType + '*', args, alwaysInline=True)
+    def declare(self):
+        return ""
+    def definition_body(self):
+        return """  if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
+    obj = js::UnwrapObject(obj);
+  }
+  MOZ_ASSERT(IsProxy(obj));
+  return static_cast<%s*>(js::GetProxyPrivate(obj).toPrivate());""" % (self.descriptor.nativeType)
+
+class CGDOMJSProxyHandlerDOMClass(CGThing):
+    def __init__(self, descriptor):
+        CGThing.__init__(self)
+        self.descriptor = descriptor
+    def declare(self):
+        return "extern const DOMClass Class;\n"
+    def define(self):
+        return """
+const DOMClass Class = """ + DOMClass(self.descriptor) + """;
+
+"""
+
+class CGDOMJSProxyHandler_CGDOMJSProxyHandler(ClassConstructor):
+    def __init__(self):
+        ClassConstructor.__init__(self, [], inline=True, visibility="public",
+                                  baseConstructors=["mozilla::dom::DOMProxyHandler(Class)"],
+                                  body="")
+
+class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('jsid', 'id'), Argument('bool', 'set'),
+                Argument('JSPropertyDescriptor*', 'desc')]
+        ClassMethod.__init__(self, "getOwnPropertyDescriptor", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        indexedSetter = self.descriptor.operations['IndexedSetter']
+
+        setOrIndexedGet = ""
+        if indexedGetter or indexedSetter:
+            setOrIndexedGet += "int32_t index = GetArrayIndexFromId(cx, id);\n"
+
+        if indexedGetter:
+            readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None)
+            fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
+            templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value',
+                              'obj': 'proxy', 'successCode': fillDescriptor}
+            get = ("if (index >= 0) {\n" +
+                   "  %s* self = UnwrapProxy(proxy);\n" +
+                   CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
+                   "}\n") % (self.descriptor.nativeType)
+
+        if indexedSetter or self.descriptor.operations['NamedSetter']:
+            setOrIndexedGet += "if (set) {\n"
+            if indexedSetter:
+                setOrIndexedGet += ("  if (index >= 0) {\n")
+                if not 'IndexedCreator' in self.descriptor.operations:
+                    # FIXME need to check that this is a 'supported property index'
+                    assert False
+                setOrIndexedGet += ("    FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" +
+                                    "    return true;\n" +
+                                    "  }\n")
+            if self.descriptor.operations['NamedSetter']:
+                setOrIndexedGet += "  if (JSID_IS_STRING(id)) {\n"
+                if not 'NamedCreator' in self.descriptor.operations:
+                    # FIXME need to check that this is a 'supported property name'
+                    assert False
+                setOrIndexedGet += ("    FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" +
+                                    "    return true;\n" +
+                                    "  }\n")
+            setOrIndexedGet += "}"
+            if indexedGetter:
+                setOrIndexedGet += (" else {\n" +
+                                    CGIndenter(CGGeneric(get)).define() +
+                                    "}")
+            setOrIndexedGet += "\n\n"
+        elif indexedGetter:
+            setOrIndexedGet += ("if (!set) {\n" +
+                                CGIndenter(CGGeneric(get)).define() +
+                                "}\n\n")
+
+        namedGetter = self.descriptor.operations['NamedGetter']
+        if namedGetter:
+            readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
+            fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
+            templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value',
+                              'obj': 'proxy', 'successCode': fillDescriptor}
+            namedGet = ("\n" +
+                        "if (!set && JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
+                        "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                        "  FakeDependentString name;\n"
+                        "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                        "                              eStringify, eStringify, name)) {\n" +
+                        "    return false;\n" +
+                        "  }\n" +
+                        "\n" +
+                        "  %s* self = UnwrapProxy(proxy);\n" +
+                        CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" +
+                        "}\n") % (self.descriptor.nativeType)
+        else:
+            namedGet = ""
+
+        return setOrIndexedGet + """JSObject* expando;
+if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
+  unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED;
+  if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) {
+    return false;
+  }
+  if (desc->obj) {
+    // Pretend the property lives on the wrapper.
+    desc->obj = proxy;
+    return true;
+  }
+}
+""" + namedGet + """
+desc->obj = NULL;
+return true;"""
+
+class CGDOMJSProxyHandler_defineProperty(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('jsid', 'id'),
+                Argument('JSPropertyDescriptor*', 'desc')]
+        ClassMethod.__init__(self, "defineProperty", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        set = ""
+
+        indexedSetter = self.descriptor.operations['IndexedSetter']
+        if indexedSetter:
+            if not (self.descriptor.operations['IndexedCreator'] is indexedSetter):
+                raise TypeError("Can't handle creator that's different from the setter")
+            set += ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
+                    "if (index >= 0) {\n" +
+                    "  %s* self = UnwrapProxy(proxy);\n" +
+                    CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
+                    "  return true;\n" +
+                    "}\n") % (self.descriptor.nativeType)
+        elif self.descriptor.operations['IndexedGetter']:
+            set += ("if (GetArrayIndexFromId(cx, id)) {\n" +
+                    "  return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
+                    "}\n") % self.descriptor.name
+        namedSetter = self.descriptor.operations['NamedSetter']
+        if namedSetter:
+            if not self.descriptor.operations['NamedCreator'] is namedSetter:
+                raise TypeError("Can't handle creator that's different from the setter")
+            set += ("if (JSID_IS_STRING(id)) {\n" +
+                    "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                    "  FakeDependentString name;\n"
+                    "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                    "                              eStringify, eStringify, name)) {\n" +
+                    "    return false;\n" +
+                    "  }\n" +
+                    "\n" +
+                    "  %s* self = UnwrapProxy(proxy);\n" +
+                    CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + "\n" +
+                    "}\n") % (self.descriptor.nativeType)
+        elif self.descriptor.operations['NamedGetter']:
+            set += ("if (JSID_IS_STRING(id)) {\n" +
+                    "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                    "  FakeDependentString name;\n"
+                    "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                    "                              eStringify, eStringify, name)) {\n" +
+                    "    return false;\n" +
+                    "  }\n" +
+                    "  %s* self = UnwrapProxy(proxy);\n" +
+                    CGIndenter(CGProxyNamedGetter(self.descriptor)).define() +
+                    "  if (found) {\n"
+                    "    return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
+                    "  }\n" +
+                    "}\n") % (self.descriptor.nativeType, self.descriptor.name)
+        return set + """return mozilla::dom::DOMProxyHandler::defineProperty(%s);""" % ", ".join(a.name for a in self.args)
+
+class CGDOMJSProxyHandler_getOwnPropertyNames(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('JS::AutoIdVector&', 'props')]
+        ClassMethod.__init__(self, "getOwnPropertyNames", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            addIndices = """uint32_t length = UnwrapProxy(proxy)->GetLength();
+MOZ_ASSERT(int32_t(length) >= 0);
+for (int32_t i = 0; i < int32_t(length); ++i) {
+  if (!props.append(INT_TO_JSID(i))) {
+    return false;
+  }
+}
+
+"""
+        else:
+            addIndices = ""
+
+        return addIndices + """JSObject* expando;
+if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
+    !js::GetPropertyNames(cx, expando, JSITER_OWNONLY | JSITER_HIDDEN, &props)) {
+  return false;
+}
+
+// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=772869 Add named items
+return true;"""
+
+class CGDOMJSProxyHandler_hasOwn(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('jsid', 'id'), Argument('bool*', 'bp')]
+        ClassMethod.__init__(self, "hasOwn", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            indexed = ("int32_t index = GetArrayIndexFromId(cx, id);\n" + 
+                       "if (index >= 0) {\n" +
+                       "  %s* self = UnwrapProxy(proxy);\n" +
+                       CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" +
+                       "  *bp = found;\n" +
+                       "  return true;\n" +
+                       "}\n\n") % (self.descriptor.nativeType)
+        else:
+            indexed = ""
+
+        namedGetter = self.descriptor.operations['NamedGetter']
+        if namedGetter:
+            named = ("if (JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
+                     "  jsval nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                     "  FakeDependentString name;\n"
+                     "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                     "                              eStringify, eStringify, name)) {\n" +
+                     "    return false;\n" +
+                     "  }\n" +
+                     "\n" +
+                     "  %s* self = UnwrapProxy(proxy);\n" +
+                     CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" +
+                     "  *bp = found;\n"
+                     "  return true;\n"
+                     "}\n" +
+                     "\n") % (self.descriptor.nativeType)
+        else:
+            named = ""
+
+        return indexed + """JSObject* expando = GetExpandoObject(proxy);
+if (expando) {
+  JSBool b = true;
+  JSBool ok = JS_HasPropertyById(cx, expando, id, &b);
+  *bp = !!b;
+  if (!ok || *bp) {
+    return ok;
+  }
+}
+
+""" + named + """*bp = false;
+return true;"""
+
+class CGDOMJSProxyHandler_get(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('JSObject*', 'receiver'), Argument('jsid', 'id'),
+                Argument('JS::Value*', 'vp')]
+        ClassMethod.__init__(self, "get", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        getFromExpando = """JSObject* expando = DOMProxyHandler::GetExpandoObject(proxy);
+if (expando) {
+  JSBool hasProp;
+  if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
+    return false;
+  }
+
+  if (hasProp) {
+    return JS_GetPropertyById(cx, expando, id, vp);
+  }
+}"""
+
+        templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp', 'obj': 'proxy'}
+
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            getIndexedOrExpando = ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
+                                   "if (index >= 0) {\n" +
+                                   "  %s* self = UnwrapProxy(proxy);\n" +
+                                   CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define()) % (self.descriptor.nativeType)
+            getIndexedOrExpando += """
+  // Even if we don't have this index, we don't forward the
+  // get on to our expando object.
+} else {
+  %s
+}
+""" % (stripTrailingWhitespace(getFromExpando.replace('\n', '\n  ')))
+        else:
+            getIndexedOrExpando = getFromExpando + "\n"
+
+        namedGetter = self.descriptor.operations['NamedGetter']
+        if namedGetter:
+            getNamed = ("if (JSID_IS_STRING(id)) {\n" +
+                        "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                        "  FakeDependentString name;\n"
+                        "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                        "                              eStringify, eStringify, name)) {\n" +
+                        "    return false;\n" +
+                        "  }\n" +
+                        "\n" +
+                        "  %s* self = UnwrapProxy(proxy);\n" +
+                        CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
+                        "}\n") % (self.descriptor.nativeType)
+        else:
+            getNamed = ""
+
+        return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
+            "Should not have a XrayWrapper here");
+
+%s
+bool found;
+if (!GetPropertyOnPrototype(cx, proxy, id, &found, vp)) {
+  return false;
+}
+
+if (found) {
+  return true;
+}
+%s
+vp->setUndefined();
+return true;""" % (getIndexedOrExpando, getNamed)
+
+class CGDOMJSProxyHandler_obj_toString(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy')]
+        ClassMethod.__init__(self, "obj_toString", "JSString*", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        stringifier = self.descriptor.operations['Stringifier']
+        if stringifier:
+            name = stringifier.identifier.name
+            nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
+            signature = stringifier.signatures()[0]
+            returnType = signature[0]
+            extendedAttributes = self.descriptor.getExtendedAttributes(stringifier)
+            infallible = 'infallible' in extendedAttributes
+            if not infallible:
+                error = ('ThrowMethodFailedWithDetails(cx, rv, "%s", "toString")\n' +
+                         "return NULL;") % self.descriptor.interface.identifier.name
+            else:
+                error = None
+            call = CGCallGenerator(error, [], "", returnType, extendedAttributes, self.descriptor, nativeName, False, object="UnwrapProxy(proxy)")
+            return call.define() + """
+
+JSString* jsresult;
+return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;""" 
+
+        return "return mozilla::dom::DOMProxyHandler::obj_toString(cx, \"%s\");" % self.descriptor.name
+
+class CGDOMJSProxyHandler_finalize(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'proxy')]
+        ClassMethod.__init__(self, "finalize", "void", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        return ("%s self = UnwrapProxy(proxy);\n\n" % (self.descriptor.nativeType + "*") +
+                finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name))
+
+class CGDOMJSProxyHandler_getElementIfPresent(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('JSObject*', 'receiver'),
+                Argument('uint32_t', 'index'),
+                Argument('JS::Value*', 'vp'), Argument('bool*', 'present')]
+        ClassMethod.__init__(self, "getElementIfPresent", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            successCode = """*present = found;
+return true;"""
+            templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp',
+                              'obj': 'proxy', 'successCode': successCode}
+            get = ("%s* self = UnwrapProxy(proxy);\n" +
+                   CGProxyIndexedGetter(self.descriptor, templateValues).define() + "\n"
+                   "// We skip the expando object if there is an indexed getter.\n" +
+                   "\n") % (self.descriptor.nativeType)
+        else:
+            get = """
+
+JSObject* expando = GetExpandoObject(proxy);
+if (expando) {
+  JSBool isPresent;
+  if (!JS_GetElementIfPresent(cx, expando, index, expando, vp, &isPresent)) {
+    return false;
+  }
+  if (isPresent) {
+    *present = true;
+    return true;
+  }
+}
+"""
+
+        return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
+             "Should not have a XrayWrapper here");
+
+""" + get + """
+// No need to worry about name getters here, so just check the proto.
+
+JSObject *proto = js::GetObjectProto(proxy);
+if (proto) {
+  JSBool isPresent;
+  if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent)) {
+    return false;
+  }
+  *present = isPresent;
+  return true;
+}
+
+*present = false;
+// Can't Debug_SetValueRangeToCrashOnTouch because it's not public
+return true;"""
+
+class CGDOMJSProxyHandler(CGClass):
+    def __init__(self, descriptor):
+        constructors = [CGDOMJSProxyHandler_CGDOMJSProxyHandler()]
+        methods = [CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor)]
+        if descriptor.operations['IndexedSetter'] or descriptor.operations['NamedSetter']:
+            methods.append(CGDOMJSProxyHandler_defineProperty(descriptor))
+        methods.extend([CGDOMJSProxyHandler_getOwnPropertyNames(descriptor),
+                        CGDOMJSProxyHandler_hasOwn(descriptor),
+                        CGDOMJSProxyHandler_get(descriptor),
+                        CGDOMJSProxyHandler_obj_toString(descriptor),
+                        CGDOMJSProxyHandler_finalize(descriptor),
+                        CGDOMJSProxyHandler_getElementIfPresent(descriptor)])
+        CGClass.__init__(self, 'DOMProxyHandler',
+                         bases=[ClassBase('mozilla::dom::DOMProxyHandler')],
+                         members=[ClassMember('instance', 'DOMProxyHandler', visibility='public', static=True)],
+                         constructors=constructors,
+                         methods=methods)
+
 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():
             hasMethod, hasGetter, hasSetter = False, False, False
             for m in descriptor.interface.members:
-                if m.isMethod() and not m.isStatic():
+                if m.isMethod() and not m.isStatic() and not m.isIdentifierLess():
                     cgThings.append(CGSpecializedMethod(descriptor, m))
                     cgThings.append(CGMemberJITInfo(descriptor, m))
                     hasMethod = True
                 elif m.isAttr():
                     cgThings.append(CGSpecializedGetter(descriptor, m))
                     hasGetter = True
                     if not m.readonly:
                         cgThings.append(CGSpecializedSetter(descriptor, m))
                         hasSetter = True
                     cgThings.append(CGMemberJITInfo(descriptor, m))
             if hasMethod: cgThings.append(CGGenericMethod(descriptor))
             if hasGetter: cgThings.append(CGGenericGetter(descriptor))
             if hasSetter: cgThings.append(CGGenericSetter(descriptor))
 
-
-        if descriptor.concrete:
+        if descriptor.concrete and not descriptor.proxy:
             if not descriptor.workers and descriptor.wrapperCache:
                 cgThings.append(CGAddPropertyHook(descriptor))
 
             # Always have a finalize hook, regardless of whether the class wants a
             # custom hook.
             cgThings.append(CGClassFinalizeHook(descriptor))
 
             # Only generate a trace hook if the class wants a custom hook.
             if (descriptor.customTrace):
                 cgThings.append(CGClassTraceHook(descriptor))
 
-        if 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)))
+            cgThings.append(CGGetProtoObjectMethod(descriptor))
         else:
-            cgThings.append(CGIndenter(CGGetConstructorObjectMethod(descriptor)))
+            cgThings.append(CGGetConstructorObjectMethod(descriptor))
 
         # Set up our Xray callbacks as needed.  Note that we don't need to do
         # it in workers.
         if (descriptor.interface.hasInterfacePrototypeObject() and
             not descriptor.workers):
             cgThings.append(CGResolveProperty(descriptor, properties))
             cgThings.append(CGEnumerateProperties(descriptor, properties))
 
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
 
+        if descriptor.interface.hasInterfacePrototypeObject():
+            cgThings.append(CGNativePropertyHooks(descriptor))
+
         if descriptor.concrete:
+            if descriptor.proxy:
+                cgThings.append(CGProxyIsProxy(descriptor))
+                cgThings.append(CGProxyUnwrap(descriptor))
+                cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
+                cgThings.append(CGDOMJSProxyHandler(descriptor))
+                cgThings.append(CGIsMethod(descriptor))
+            else:
+                cgThings.append(CGDOMJSClass(descriptor))
+
             if descriptor.wrapperCache:
+                cgThings.append(CGWrapWithCacheMethod(descriptor))
                 cgThings.append(CGWrapMethod(descriptor))
             else:
                 cgThings.append(CGWrapNonWrapperCacheMethod(descriptor))
 
-        cgThings = CGList(cgThings)
-        cgThings = CGWrapper(cgThings, post='\n')
+        cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n")
+        cgThings = CGWrapper(cgThings, pre='\n', post='\n')
         self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
                                             cgThings),
                                 post='\n')
 
     def declare(self):
         return self.cgRoot.declare()
     def define(self):
         return self.cgRoot.define()
@@ -4607,17 +5327,18 @@ class CGBindingRoot(CGThing):
                                  defineOnly=True),
                        traitsClasses, curr],
                       "\n")
 
         # Add header includes.
         curr = CGHeaders(descriptors,
                          dictionaries,
                          ['mozilla/dom/BindingUtils.h',
-                          'mozilla/dom/DOMJSClass.h'],
+                          'mozilla/dom/DOMJSClass.h',
+                          'mozilla/dom/DOMJSProxyHandler.h'],
                          ['mozilla/dom/Nullable.h',
                           'PrimitiveConversions.h',
                           'XPCQuickStubs.h',
                           'nsDOMQS.h',
                           'AccessCheck.h',
                           'WorkerPrivate.h',
                           'nsContentUtils.h',
                           'mozilla/Preferences.h',
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -142,23 +142,73 @@ class Descriptor(DescriptorProvider):
         else:
             self.castable = desc.get('castable', True)
 
         self.notflattened = desc.get('notflattened', False)
         self.register = desc.get('register', True)
 
         # 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)
+        self.concrete = desc.get('concrete', not self.interface.isExternal())
         if self.concrete:
+            self.proxy = False
+            operations = {
+                'IndexedGetter': None,
+                'IndexedSetter': None,
+                'IndexedCreator': None,
+                'IndexedDeleter': None,
+                'NamedGetter': None,
+                'NamedSetter': None,
+                'NamedCreator': None,
+                'NamedDeleter': None,
+                'Stringifier': None
+            }
             iface = self.interface
             while iface:
+                for m in iface.members:
+                    if not m.isMethod():
+                        continue
+
+                    def addOperation(operation, m):
+                        if not operations[operation]:
+                            operations[operation] = m
+                    def addIndexedOrNamedOperation(operation, m):
+                        self.proxy = True
+                        if m.isIndexed():
+                            operation = 'Indexed' + operation
+                        else:
+                            assert m.isNamed()
+                            operation = 'Named' + operation
+                        addOperation(operation, m)
+                        
+                    if m.isStringifier():
+                        addOperation('Stringifier', m)
+                    else:
+                        if m.isGetter():
+                            addIndexedOrNamedOperation('Getter', m)
+                        if m.isSetter():
+                            addIndexedOrNamedOperation('Setter', m)
+                        if m.isCreator():
+                            addIndexedOrNamedOperation('Creator', m)
+                        if m.isDeleter():
+                            addIndexedOrNamedOperation('Deleter', m)
+                            raise TypeError("deleter specified on %s but we "
+                                            "don't support deleters yet" %
+                                            self.interface.identifier.name)
+
                 iface.setUserData('hasConcreteDescendant', True)
                 iface = iface.parent
 
+            if self.proxy:
+                self.operations = operations
+                iface = self.interface
+                while iface:
+                    iface.setUserData('hasProxyDescendant', True)
+                    iface = iface.parent
+
         if self.interface.isExternal() and 'prefable' in desc:
             raise TypeError("%s is external but has a prefable setting" %
                             self.interface.identifier.name)
         self.prefable = desc.get('prefable', False)
 
         self.nativeIsISupports = not self.workers
         self.customTrace = desc.get('customTrace', self.workers)
         self.customFinalize = desc.get('customFinalize', self.workers)
@@ -183,18 +233,24 @@ class Descriptor(DescriptorProvider):
                     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)
+                assert isinstance(config, str)
+                if config == '*':
+                    iface = self.interface
+                    while iface:
+                        add('all', map(lambda m: m.name, iface.members), attribute)
+                        iface = iface.parent
+                else:
+                    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 = []
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -40,41 +40,47 @@ typedef bool
 struct NativePropertyHooks
 {
   ResolveProperty mResolveProperty;
   EnumerateProperties mEnumerateProperties;
 
   const NativePropertyHooks *mProtoHooks;
 };
 
+struct DOMClass
+{
+  // A list of interfaces that this object implements, in order of decreasing
+  // derivedness.
+  const prototypes::ID mInterfaceChain[prototypes::id::_ID_Count];
+
+  // We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in
+  // the proxy private if we use a proxy object.
+  // Sometimes it's an nsISupports and sometimes it's not; this class tells
+  // us which it is.
+  const bool mDOMObjectIsISupports;
+
+  const NativePropertyHooks* mNativeHooks;
+};
+
 // 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];
+  DOMClass mClass;
 
   // 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;
-
-  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);
   }
new file mode 100644
--- /dev/null
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=2 sw=2 et tw=99 ft=cpp: */
+/* 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 "mozilla/Util.h"
+
+#include "DOMJSProxyHandler.h"
+#include "xpcpublic.h"
+#include "xpcprivate.h"
+#include "XPCQuickStubs.h"
+#include "XPCWrapper.h"
+#include "WrapperFactory.h"
+#include "nsDOMClassInfo.h"
+#include "nsGlobalWindow.h"
+#include "nsWrapperCacheInlines.h"
+#include "mozilla/dom/BindingUtils.h"
+
+#include "jsapi.h"
+#include "jsatom.h"
+
+using namespace JS;
+
+namespace mozilla {
+namespace dom {
+
+jsid s_length_id = JSID_VOID;
+
+bool
+DefineStaticJSVals(JSContext* cx)
+{
+  JSAutoRequest ar(cx);
+
+  return InternJSString(cx, s_length_id, "length");
+}
+
+
+int HandlerFamily;
+
+bool
+DefineConstructor(JSContext* cx, JSObject* obj, DefineInterface aDefine, nsresult* aResult)
+{
+  bool enabled;
+  bool defined = aDefine(cx, obj, &enabled);
+  MOZ_ASSERT(!defined || enabled,
+             "We defined a constructor but the new bindings are disabled?");
+  *aResult = defined ? NS_OK : NS_ERROR_FAILURE;
+  return enabled;
+}
+
+// static
+JSObject*
+DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JSObject* obj)
+{
+  NS_ASSERTION(IsDOMProxy(obj), "expected a DOM proxy object");
+  JSObject* expando = GetExpandoObject(obj);
+  if (!expando) {
+    expando = JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
+                                         js::GetObjectParent(obj));
+    if (!expando) {
+      return NULL;
+    }
+
+    xpc::CompartmentPrivate* priv = xpc::GetCompartmentPrivate(obj);
+    if (!priv->RegisterDOMExpandoObject(obj)) {
+      return NULL;
+    }
+
+    nsWrapperCache* cache;
+    CallQueryInterface(UnwrapDOMObject<nsISupports>(obj, eProxyDOMObject), &cache);
+    cache->SetPreservingWrapper(true);
+
+    js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando));
+  }
+  return expando;
+}
+
+bool
+DOMProxyHandler::getPropertyDescriptor(JSContext* cx, JSObject* proxy, jsid id, bool set,
+                                       JSPropertyDescriptor* desc)
+{
+  if (!getOwnPropertyDescriptor(cx, proxy, id, set, desc)) {
+    return false;
+  }
+  if (desc->obj) {
+    return true;
+  }
+
+  JSObject* proto = js::GetObjectProto(proxy);
+  if (!proto) {
+    desc->obj = NULL;
+    return true;
+  }
+
+  return JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, desc);
+}
+
+bool
+DOMProxyHandler::defineProperty(JSContext* cx, JSObject* proxy, jsid id,
+                                JSPropertyDescriptor* desc)
+{
+  if ((desc->attrs & JSPROP_GETTER) && desc->setter == JS_StrictPropertyStub) {
+    return JS_ReportErrorFlagsAndNumber(cx,
+                                        JSREPORT_WARNING | JSREPORT_STRICT |
+                                        JSREPORT_STRICT_MODE_ERROR,
+                                        js_GetErrorMessage, NULL,
+                                        JSMSG_GETTER_ONLY);
+  }
+
+  if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
+    return true;
+  }
+
+  JSObject* expando = EnsureExpandoObject(cx, proxy);
+  if (!expando) {
+    return false;
+  }
+
+  return JS_DefinePropertyById(cx, expando, id, desc->value, desc->getter, desc->setter,
+                               desc->attrs);
+}
+
+bool
+DOMProxyHandler::delete_(JSContext* cx, JSObject* proxy, jsid id, bool* bp)
+{
+  JSBool b = true;
+
+  JSObject* expando;
+  if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
+    Value v;
+    if (!JS_DeletePropertyById2(cx, expando, id, &v) || !JS_ValueToBoolean(cx, v, &b)) {
+      return false;
+    }
+  }
+
+  *bp = !!b;
+  return true;
+}
+
+bool
+DOMProxyHandler::enumerate(JSContext* cx, JSObject* proxy, AutoIdVector& props)
+{
+  JSObject* proto = JS_GetPrototype(proxy);
+  return getOwnPropertyNames(cx, proxy, props) &&
+         (!proto || js::GetPropertyNames(cx, proto, 0, &props));
+}
+
+bool
+DOMProxyHandler::fix(JSContext* cx, JSObject* proxy, Value* vp)
+{
+  vp->setUndefined();
+  return true;
+}
+
+bool
+DOMProxyHandler::has(JSContext* cx, JSObject* proxy, jsid id, bool* bp)
+{
+  if (!hasOwn(cx, proxy, id, bp)) {
+    return false;
+  }
+
+  if (*bp) {
+    // We have the property ourselves; no need to worry about our prototype
+    // chain.
+    return true;
+  }
+
+  // OK, now we have to look at the proto
+  JSObject *proto = js::GetObjectProto(proxy);
+  if (!proto) {
+    return true;
+  }
+  JSBool protoHasProp;
+  bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
+  if (ok) {
+    *bp = protoHasProp;
+  }
+  return ok;
+}
+
+// static
+JSString*
+DOMProxyHandler::obj_toString(JSContext* cx, const char* className)
+{
+  size_t nchars = sizeof("[object ]") - 1 + strlen(className);
+  jschar* chars = static_cast<jschar*>(JS_malloc(cx, (nchars + 1) * sizeof(jschar)));
+  if (!chars) {
+    return NULL;
+  }
+
+  const char* prefix = "[object ";
+  nchars = 0;
+  while ((chars[nchars] = (jschar)*prefix) != 0) {
+    nchars++, prefix++;
+  }
+  while ((chars[nchars] = (jschar)*className) != 0) {
+    nchars++, className++;
+  }
+  chars[nchars++] = ']';
+  chars[nchars] = 0;
+
+  JSString* str = JS_NewUCString(cx, chars, nchars);
+  if (!str) {
+    JS_free(cx, chars);
+  }
+  return str;
+}
+
+int32_t
+IdToInt32(JSContext* cx, jsid id)
+{
+  JSAutoRequest ar(cx);
+
+  jsval idval;
+  double array_index;
+  int32_t i;
+  if (!::JS_IdToValue(cx, id, &idval) ||
+      !::JS_ValueToNumber(cx, idval, &array_index) ||
+      !::JS_DoubleIsInt32(array_index, &i)) {
+    return -1;
+  }
+
+  return i;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -0,0 +1,109 @@
+/* -*- 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_DOMJSProxyHandler_h
+#define mozilla_dom_DOMJSProxyHandler_h
+
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jsproxy.h"
+#include "xpcpublic.h"
+#include "nsString.h"
+#include "mozilla/Likely.h"
+
+#define DOM_PROXY_OBJECT_SLOT js::JSSLOT_PROXY_PRIVATE
+
+namespace mozilla {
+namespace dom {
+
+enum {
+  JSPROXYSLOT_EXPANDO = 0
+};
+
+template<typename T> struct Prefable;
+
+class DOMProxyHandler : public js::BaseProxyHandler
+{
+public:
+  DOMProxyHandler(const DOMClass& aClass)
+    : js::BaseProxyHandler(ProxyFamily()),
+      mClass(aClass)
+  {
+  }
+
+  bool getPropertyDescriptor(JSContext* cx, JSObject* proxy, jsid id, bool set,
+                             JSPropertyDescriptor* desc);
+  bool defineProperty(JSContext* cx, JSObject* proxy, jsid id,
+                      JSPropertyDescriptor* desc);
+  bool delete_(JSContext* cx, JSObject* proxy, jsid id, bool* bp);
+  bool enumerate(JSContext* cx, JSObject* proxy, JS::AutoIdVector& props);
+  bool fix(JSContext* cx, JSObject* proxy, JS::Value* vp);
+  bool has(JSContext* cx, JSObject* proxy, jsid id, bool* bp);
+  using js::BaseProxyHandler::obj_toString;
+
+  static JSObject* GetExpandoObject(JSObject* obj)
+  {
+    MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
+    JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
+    return v.isUndefined() ? NULL : v.toObjectOrNull();
+  }
+  static JSObject* EnsureExpandoObject(JSContext* cx, JSObject* obj);
+
+  const DOMClass& mClass;
+
+protected:
+  static JSString* obj_toString(JSContext* cx, const char* className);
+};
+
+extern jsid s_length_id;
+
+int32_t IdToInt32(JSContext* cx, jsid id);
+
+inline int32_t
+GetArrayIndexFromId(JSContext* cx, jsid id)
+{
+  if (MOZ_LIKELY(JSID_IS_INT(id))) {
+    return JSID_TO_INT(id);
+  }
+  if (MOZ_LIKELY(id == s_length_id)) {
+    return -1;
+  }
+  if (MOZ_LIKELY(JSID_IS_ATOM(id))) {
+    JSAtom* atom = JSID_TO_ATOM(id);
+    jschar s = *js::GetAtomChars(atom);
+    if (MOZ_LIKELY((unsigned)s >= 'a' && (unsigned)s <= 'z'))
+      return -1;
+
+    uint32_t i;
+    JSLinearString* str = js::AtomToLinearString(JSID_TO_ATOM(id));
+    return js::StringIsArrayIndex(str, &i) ? i : -1;
+  }
+  return IdToInt32(cx, id);
+}
+
+inline void
+FillPropertyDescriptor(JSPropertyDescriptor* desc, JSObject* obj, bool readonly)
+{
+  desc->obj = obj;
+  desc->attrs = (readonly ? JSPROP_READONLY : 0) | JSPROP_ENUMERATE;
+  desc->getter = NULL;
+  desc->setter = NULL;
+  desc->shortid = 0;
+}
+
+inline void
+FillPropertyDescriptor(JSPropertyDescriptor* desc, JSObject* obj, jsval v, bool readonly)
+{
+  desc->value = v;
+  FillPropertyDescriptor(desc, obj, readonly);
+}
+
+JSObject* 
+EnsureExpandoObject(JSContext* cx, JSObject* obj);
+
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_DOMProxyHandler_h */
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -20,8 +20,9 @@
  */
 
 MSG_DEF(MSG_INVALID_ENUM_VALUE, 2, "Value '{0}' is not a valid value for enumeration {1}.")
 MSG_DEF(MSG_MISSING_ARGUMENTS, 1, "Not enough arguments to {0}.")
 MSG_DEF(MSG_NOT_OBJECT, 0, "Value not an object.")
 MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE, 1, "Value does not implement interface {0}.")
 MSG_DEF(MSG_NOT_IN_UNION, 1, "Value could not be converted to any of: {0}.")
 MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, "Illegal constructor.")
+MSG_DEF(MSG_NO_PROPERTY_SETTER, 1, "{0} doesn't have an indexed property setter.")
\ No newline at end of file
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -40,27 +40,29 @@ globalgen_targets := \
   UnionTypes.h \
   UnionConversions.h \
   $(NULL)
 
 CPPSRCS = \
   $(linked_binding_cpp_files) \
   $(filter %.cpp, $(globalgen_targets)) \
   BindingUtils.cpp \
+  DOMJSProxyHandler.cpp \
   $(NULL)
 
 EXPORTS_NAMESPACES = $(binding_include_path) mozilla
 
 EXPORTS_mozilla = \
   ErrorResult.h \
   $(NULL)
 
 EXPORTS_$(binding_include_path) = \
   BindingUtils.h \
   DOMJSClass.h \
+  DOMJSProxyHandler.h \
   Errors.msg \
   Nullable.h \
   PrimitiveConversions.h \
   PrototypeList.h \
   RegisterBindings.h \
   TypedArray.h \
   UnionConversions.h \
   UnionTypes.h \
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -2128,16 +2128,19 @@ class IDLMethod(IDLInterfaceMember, IDLS
         return self._legacycaller
 
     def isStringifier(self):
         return self._stringifier
 
     def hasOverloads(self):
         return self._hasOverloads
 
+    def isIdentifierLess(self):
+        return self.identifier.name[:2] == "__"
+
     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)
 
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -553,12 +553,108 @@ private:
   void PassNullableString(nsAString&, ErrorResult&) MOZ_DELETE;
   void PassOptionalString(Optional<nsAString>&, ErrorResult&) MOZ_DELETE;
   void PassOptionalStringWithDefaultValue(nsAString&, ErrorResult&) MOZ_DELETE;
   void PassOptionalNullableString(Optional<nsAString>&, ErrorResult&) MOZ_DELETE;
   void PassOptionalNullableStringWithDefaultValue(nsAString&, ErrorResult&) MOZ_DELETE;
 
 };
 
+class TestIndexedGetterInterface : public nsISupports,
+                                   public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
+  uint32_t IndexedGetter(uint32_t, ErrorResult&) MOZ_DELETE;
+  uint32_t Item(uint32_t, ErrorResult&);
+  uint32_t Item(uint32_t, bool&, ErrorResult&) MOZ_DELETE;
+  uint32_t GetLength();
+};
+
+class TestNamedGetterInterface : public nsISupports,
+                                 public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
+};
+
+class TestIndexedAndNamedGetterInterface : public nsISupports,
+                                           public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
+  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
+  void NamedItem(const nsAString&, nsAString&, ErrorResult&);
+  uint32_t GetLength();
+};
+
+class TestIndexedSetterInterface : public nsISupports,
+                                   public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void IndexedSetter(uint32_t, const nsAString&, ErrorResult&);
+  void SetItem(uint32_t, const nsAString&, ErrorResult&);
+};
+
+class TestNamedSetterInterface : public nsISupports,
+                                 public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void NamedSetter(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
+};
+
+class TestIndexedAndNamedSetterInterface : public nsISupports,
+                                           public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void IndexedSetter(uint32_t, TestIndexedSetterInterface&, ErrorResult&);
+  void NamedSetter(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
+  void SetNamedItem(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
+};
+
+class TestIndexedAndNamedGetterAndSetterInterface : public TestIndexedSetterInterface
+{
+public:
+  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
+  uint32_t Item(uint32_t, ErrorResult&);
+  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
+  void NamedItem(const nsAString&, nsAString&, ErrorResult&);
+  void IndexedSetter(uint32_t, int32_t&, ErrorResult&);
+  void IndexedSetter(uint32_t, const nsAString&, ErrorResult&) MOZ_DELETE;
+  void NamedSetter(const nsAString&, const nsAString&, ErrorResult&);
+  void Stringify(nsAString&);
+  uint32_t GetLength();
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* TestBindingHeader_h */
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -367,8 +367,45 @@ dictionary ParentDict : GrandparentDict 
   long c = 5;
   TestInterface someInterface;
   TestExternalInterface someExternalInterface;
 };
 
 dictionary DictContainingDict {
   Dict memberDict;
 };
+
+interface TestIndexedGetterInterface {
+  getter long item(unsigned long index);
+  readonly attribute unsigned long length;
+};
+
+interface TestNamedGetterInterface {
+  getter DOMString (DOMString name);
+};
+
+interface TestIndexedAndNamedGetterInterface {
+  getter long (unsigned long index);
+  getter DOMString namedItem(DOMString name);
+  readonly attribute unsigned long length;
+};
+
+interface TestIndexedSetterInterface {
+  setter creator void setItem(unsigned long index, DOMString item);
+};
+
+interface TestNamedSetterInterface {
+  setter creator void (DOMString name, TestIndexedSetterInterface item);
+};
+
+interface TestIndexedAndNamedSetterInterface {
+  setter creator void (unsigned long index, TestIndexedSetterInterface item);
+  setter creator void setNamedItem(DOMString name, TestIndexedSetterInterface item);
+};
+
+interface TestIndexedAndNamedGetterAndSetterInterface : TestIndexedSetterInterface {
+  getter long item(unsigned long index);
+  getter DOMString namedItem(DOMString name);
+  setter creator void (unsigned long index, long item);
+  setter creator void (DOMString name, DOMString item);
+  stringifier DOMString ();
+  readonly attribute unsigned long length;
+};
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -228,27 +228,29 @@ private:
   {
     return ConstructInternal(aCx, aArgc, aVp, false, Class());
   }
 
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_finalize(aFop);
     }
   }
 
   static void
   Trace(JSTracer* aTrc, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_trace(aTrc);
     }
   }
 
   static JSBool
   Terminate(JSContext* aCx, unsigned aArgc, jsval* aVp)
   {
@@ -298,19 +300,23 @@ DOMJSClass Worker::sClass = {
   {
     "Worker",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1) |
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
     NULL, NULL, NULL, NULL, Trace
   },
-  { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
-    prototypes::id::_ID_Count },
-  -1, false, &sNativePropertyHooks
+  {
+    { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
+      prototypes::id::_ID_Count },
+    false,
+    &sNativePropertyHooks
+  },
+  -1
 };
 
 JSPropertySpec Worker::sProperties[] = {
   { sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
   { sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
   { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }
@@ -371,44 +377,46 @@ private:
   ~ChromeWorker();
 
   static WorkerPrivate*
   GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
   {
     if (aObj) {
       JSClass* classPtr = JS_GetClass(aObj);
       if (classPtr == Class()) {
-        return UnwrapDOMObject<WorkerPrivate>(aObj);
+        return UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
       }
     }
 
     return Worker::GetInstancePrivate(aCx, aObj, aFunctionName);
   }
 
   static JSBool
   Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
   {
     return ConstructInternal(aCx, aArgc, aVp, true, Class());
   }
 
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_finalize(aFop);
     }
   }
 
   static void
   Trace(JSTracer* aTrc, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_trace(aTrc);
     }
   }
 };
 
 MOZ_STATIC_ASSERT(prototypes::MaxProtoChainLength == 3,
                   "The MaxProtoChainLength must match our manual DOMJSClasses");
@@ -418,28 +426,32 @@ MOZ_STATIC_ASSERT(prototypes::MaxProtoCh
 DOMJSClass ChromeWorker::sClass = {
   { "ChromeWorker",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1) |
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
     NULL, NULL, NULL, NULL, Trace,
   },
-  { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
-    prototypes::id::_ID_Count },
-  -1, false, &sNativePropertyHooks
+  {
+    { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
+      prototypes::id::_ID_Count },
+    false,
+    &sNativePropertyHooks
+  },
+  -1
 };
 
 WorkerPrivate*
 Worker::GetInstancePrivate(JSContext* aCx, JSObject* aObj,
                            const char* aFunctionName)
 {
   JSClass* classPtr = JS_GetClass(aObj);
   if (classPtr == Class() || classPtr == ChromeWorker::Class()) {
-    return UnwrapDOMObject<WorkerPrivate>(aObj);
+    return UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
   }
 
   JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
                        Class()->name, aFunctionName, classPtr->name);
   return NULL;
 }
 
 } // anonymous namespace
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -763,17 +763,18 @@ private:
     return true;
   }
 
   static DedicatedWorkerGlobalScope*
   GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
   {
     JSClass* classPtr = JS_GetClass(aObj);
     if (classPtr == Class()) {
-      return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+      return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj,
+                                                         eRegularDOMObject);
     }
 
     JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
                          JSMSG_INCOMPATIBLE_PROTO, Class()->name, aFunctionName,
                          classPtr->name);
     return NULL;
   }
 
@@ -798,29 +799,29 @@ private:
     return true;
   }
 
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
     DedicatedWorkerGlobalScope* scope =
-      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj, eRegularDOMObject);
     if (scope) {
       DestroyProtoOrIfaceCache(aObj);
       scope->_finalize(aFop);
     }
   }
 
   static void
   Trace(JSTracer* aTrc, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
     DedicatedWorkerGlobalScope* scope =
-      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj, eRegularDOMObject);
     if (scope) {
       mozilla::dom::TraceProtoOrIfaceCache(aTrc, aObj);
       scope->_trace(aTrc);
     }
   }
 
   static JSBool
   PostMessage(JSContext* aCx, unsigned aArgc, jsval* aVp)
@@ -854,19 +855,23 @@ DOMJSClass DedicatedWorkerGlobalScope::s
   {
     "DedicatedWorkerGlobalScope",
     JSCLASS_DOM_GLOBAL | JSCLASS_IS_DOMJSCLASS | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(3) | JSCLASS_NEW_RESOLVE,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, reinterpret_cast<JSResolveOp>(Resolve), JS_ConvertStub,
     Finalize, NULL, NULL, NULL, NULL, Trace
   },
-  { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
-    prototypes::id::_ID_Count },
-  -1, false, &sNativePropertyHooks
+  {
+    { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
+      prototypes::id::_ID_Count },
+    false,
+    &sNativePropertyHooks
+  },
+  -1
 };
 
 JSPropertySpec DedicatedWorkerGlobalScope::sProperties[] = {
   { sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
   { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }
 };
 
@@ -885,17 +890,17 @@ WorkerGlobalScope::GetInstancePrivate(JS
 {
   JSClass* classPtr = JS_GetClass(aObj);
 
   // We can only make DedicatedWorkerGlobalScope, not WorkerGlobalScope, so this
   // should never happen.
   JS_ASSERT(classPtr != Class());
 
   if (classPtr == DedicatedWorkerGlobalScope::Class()) {
-    return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+    return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj, eRegularDOMObject);
   }
 
   JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
                        sClass.name, aFunctionName, classPtr->name);
   return NULL;
 }
 
 } /* anonymous namespace */
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -70,22 +70,17 @@ XPCConvert::GetISupportsFromJSObject(JSO
     JSClass* jsclass = js::GetObjectJSClass(obj);
     NS_ASSERTION(jsclass, "obj has no class");
     if (jsclass &&
         (jsclass->flags & JSCLASS_HAS_PRIVATE) &&
         (jsclass->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS)) {
         *iface = (nsISupports*) xpc_GetJSPrivate(obj);
         return true;
     }
-    if (jsclass && IsDOMClass(jsclass) &&
-        DOMJSClass::FromJSClass(jsclass)->mDOMObjectIsISupports) {
-        *iface = UnwrapDOMObject<nsISupports>(obj);
-        return true;
-    }
-    return false;
+    return UnwrapDOMObjectToISupports(obj, *iface);
 }
 
 /***************************************************************************/
 
 static void
 FinalizeXPCOMUCString(const JSStringFinalizer *fin, jschar *chars)
 {
     nsMemory::Free(chars);
--- a/js/xpconnect/src/XPCJSID.cpp
+++ b/js/xpconnect/src/XPCJSID.cpp
@@ -477,25 +477,20 @@ nsJSIID::HasInstance(nsIXPConnectWrapped
             iid->ToProvidedString(foo);
             SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, foo);
 #endif
             if (!MorphSlimWrapper(cx, obj))
                 return NS_ERROR_FAILURE;
         }
 
         nsISupports *identity;
-        if (mozilla::dom::binding::instanceIsProxy(obj)) {
+        if (mozilla::dom::oldproxybindings::instanceIsProxy(obj)) {
             identity =
                 static_cast<nsISupports*>(js::GetProxyPrivate(obj).toPrivate());
-        } else if (mozilla::dom::IsDOMClass(js::GetObjectJSClass(obj)) &&
-                   mozilla::dom::DOMJSClass::FromJSClass(
-                        js::GetObjectJSClass(obj))->mDOMObjectIsISupports) {
-            identity =
-                mozilla::dom::UnwrapDOMObject<nsISupports>(obj);
-        } else {
+        } else if (!mozilla::dom::UnwrapDOMObjectToISupports(obj, identity)) {
             identity = nullptr;
         }
 
         if (identity) {
             nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(identity);
 
             XPCCallContext ccx(JS_CALLER, cx);
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -442,25 +442,24 @@ XPCJSRuntime::SuspectWrappedNative(XPCWr
 }
 
 static PLDHashOperator
 SuspectDOMExpandos(nsPtrHashKey<JSObject> *key, void *arg)
 {
     Closure *closure = static_cast<Closure*>(arg);
     JSObject* obj = key->GetKey();
     nsISupports* native = nullptr;
-    if (js::IsProxy(obj)) {
-        NS_ASSERTION(dom::binding::instanceIsProxy(obj),
-                     "Not a DOM proxy?");
+    if (dom::oldproxybindings::instanceIsProxy(obj)) {
         native = static_cast<nsISupports*>(js::GetProxyPrivate(obj).toPrivate());
     }
     else {
-        NS_ASSERTION(dom::DOMJSClass::FromJSClass(JS_GetClass(obj))->mDOMObjectIsISupports,
-                     "Someone added a wrapper for a non-nsISupports native to DOMExpandos!");
-        native = dom::UnwrapDOMObject<nsISupports>(obj);
+        const dom::DOMClass* clasp;
+        dom::DOMObjectSlot slot = GetDOMClass(obj, clasp);
+        MOZ_ASSERT(slot != dom::eNonDOMObject && clasp->mDOMObjectIsISupports);
+        native = dom::UnwrapDOMObject<nsISupports>(obj, slot);
     }
     closure->cb->NoteXPCOMRoot(native);
     return PL_DHASH_NEXT;
 }
 
 void
 XPCJSRuntime::AddXPConnectRoots(nsCycleCollectionTraversalCallback &cb)
 {
@@ -2289,17 +2288,18 @@ XPCJSRuntime::OnJSContextNew(JSContext *
                     mStrIDs[0] = JSID_VOID;
                     ok = false;
                     break;
                 }
                 mStrJSVals[i] = STRING_TO_JSVAL(str);
             }
         }
 
-        ok = mozilla::dom::binding::DefineStaticJSVals(cx);
+        ok = mozilla::dom::DefineStaticJSVals(cx) &&
+             mozilla::dom::oldproxybindings::DefineStaticJSVals(cx);
         if (!ok)
             return false;
 
         ok = InternStaticDictionaryJSVals(cx);
     }
     if (!ok)
         return false;
 
--- a/js/xpconnect/src/XPCQuickStubs.cpp
+++ b/js/xpconnect/src/XPCQuickStubs.cpp
@@ -692,30 +692,29 @@ getWrapper(JSContext *cx,
         MOZ_ASSERT(!js::IsWrapper(obj));
     }
 
     // Start with sane values.
     *wrapper = nullptr;
     *cur = nullptr;
     *tearoff = nullptr;
 
-    js::Class* clasp = js::GetObjectClass(obj);
-    if (dom::IsDOMClass(clasp) ||
-        dom::binding::instanceIsProxy(obj)) {
+    if (dom::IsDOMObject(obj)) {
         *cur = obj;
 
         return NS_OK;
     }
 
     // Handle tearoffs.
     //
     // If |obj| is of the tearoff class, that means we're dealing with a JS
     // object reflection of a particular interface (ie, |foo.nsIBar|). These
     // JS objects are parented to their wrapper, so we snag the tearoff object
     // along the way (if desired), and then set |obj| to its parent.
+    js::Class* clasp = js::GetObjectClass(obj);
     if (clasp == &XPC_WN_Tearoff_JSClass) {
         *tearoff = (XPCWrappedNativeTearOff*) js::GetObjectPrivate(obj);
         obj = js::GetObjectParent(obj);
     }
 
     // If we've got a WN or slim wrapper, store things the way callers expect.
     // Otherwise, leave things null and return.
     if (IS_WRAPPER_CLASS(clasp)) {
@@ -746,33 +745,24 @@ castNative(JSContext *cx,
         if (lccx && NS_SUCCEEDED(rv))
             lccx->SetWrapper(wrapper, tearoff);
 
         if (rv != NS_ERROR_NO_INTERFACE)
             return rv;
     } else if (cur) {
         nsISupports *native;
         QITableEntry *entries;
-        js::Class* clasp = js::GetObjectClass(cur);
-        if (dom::IsDOMClass(clasp)) {
-            dom::DOMJSClass* domClass = dom::DOMJSClass::FromJSClass(clasp);
-            if (!domClass->mDOMObjectIsISupports) {
-                *pThisRef = nullptr;
-                return NS_ERROR_ILLEGAL_VALUE;
-            }
-            native = dom::UnwrapDOMObject<nsISupports>(cur);
+        if (mozilla::dom::UnwrapDOMObjectToISupports(cur, native)) {
             entries = nullptr;
-        } else if (dom::binding::instanceIsProxy(cur)) {
-            native = static_cast<nsISupports*>(js::GetProxyPrivate(cur).toPrivate());
-            entries = nullptr;
-        } else if (IS_WRAPPER_CLASS(clasp) && IS_SLIM_WRAPPER_OBJECT(cur)) {
+        } else if (IS_SLIM_WRAPPER(cur)) {
             native = static_cast<nsISupports*>(xpc_GetJSPrivate(cur));
             entries = GetOffsetsFromSlimWrapper(cur);
         } else {
-            MOZ_NOT_REACHED("what kind of wrapper is this?");
+            *pThisRef = nullptr;
+            return NS_ERROR_ILLEGAL_VALUE;
         }
 
         if (NS_SUCCEEDED(getNative(native, entries, cur, iid, ppThis, pThisRef, vp))) {
             if (lccx) {
                 // This only matters for unwrapping of this objects, so we
                 // shouldn't end up here for the new DOM bindings.
                 NS_ABORT_IF_FALSE(IS_SLIM_WRAPPER(cur),
                                   "what kind of wrapper is this?");
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -26,20 +26,19 @@
 #include "mozilla/Util.h"
 
 using namespace xpc;
 
 bool
 xpc_OkToHandOutWrapper(nsWrapperCache *cache)
 {
     NS_ABORT_IF_FALSE(cache->GetWrapper(), "Must have wrapper");
-    NS_ABORT_IF_FALSE(cache->IsDOMBinding() || IS_WN_WRAPPER(cache->GetWrapper()),
-                      "Must have proxy or XPCWrappedNative wrapper");
-    return cache->IsDOMBinding() ?
-        mozilla::dom::binding::instanceIsProxy(cache->GetWrapper()) :
+    NS_ABORT_IF_FALSE(IS_WN_WRAPPER(cache->GetWrapper()),
+                      "Must have XPCWrappedNative wrapper");
+    return
         !static_cast<XPCWrappedNative*>(xpc_GetJSPrivate(cache->GetWrapper()))->
             NeedsSOW();
 }
 
 /***************************************************************************/
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
 
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -212,33 +212,30 @@ XPCWrappedNativeScope::SetGlobal(XPCCall
 
     // Try to find the native global object. If we didn't receive it explicitly,
     // we might be able to find it in the private slot.
     nsISupports *native;
     if (aNative) {
         native = aNative;
     } else {
         const JSClass *jsClass = js::GetObjectJSClass(aGlobal);
-        nsISupports *priv;
         if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
                                  JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
             // Our global has an nsISupports native pointer.  Let's
             // see whether it's what we want.
-            priv = static_cast<nsISupports*>(xpc_GetJSPrivate(aGlobal));
-        } else if (dom::IsDOMClass(jsClass) &&
-                   dom::DOMJSClass::FromJSClass(jsClass)->mDOMObjectIsISupports) {
-            priv = dom::UnwrapDOMObject<nsISupports>(aGlobal);
-        } else {
-            priv = nullptr;
+            nsISupports *priv =
+                static_cast<nsISupports*>(xpc_GetJSPrivate(aGlobal));
+            nsCOMPtr<nsIXPConnectWrappedNative> wn = do_QueryInterface(priv);
+            if (wn)
+                native = static_cast<XPCWrappedNative*>(wn.get())->GetIdentityObject();
+            else
+                native = nullptr;
+        } else if (!mozilla::dom::UnwrapDOMObjectToISupports(aGlobal, native)) {
+            native = nullptr;
         }
-        nsCOMPtr<nsIXPConnectWrappedNative> wn = do_QueryInterface(priv);
-        if (wn)
-            native = static_cast<XPCWrappedNative*>(wn.get())->GetIdentityObject();
-        else
-            native = priv;
     }
 
     // Now init our script object principal, if the new global has one.
     nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(native);
     mScriptObjectPrincipal = sop;
 
     // Lookup 'globalObject.Object.prototype' for our wrapper's proto
     JSObject *objectPrototype =
--- a/js/xpconnect/src/codegen.py
+++ b/js/xpconnect/src/codegen.py
@@ -288,16 +288,18 @@ def outParamForm(name, type):
     # possibly, and handle properly returning it too.  See bug 604198.
     assert type.kind != 'native' or type.specialtype != 'jsval'
     if type.kind == 'builtin':
         return '&' + name
     elif type.kind == 'native':
         if type.specialtype == 'jsval':
             return 'vp'
         elif type.modifier == 'ref':
+            if isStringType(type):
+                return '(nsAString&)' + name
             return name
         else:
             return '&' + name
     else:
         return 'getter_AddRefs(%s)' % name
 
 # From NativeData2JS.
 resultConvTemplates = {
--- a/js/xpconnect/src/dombindings.cpp
+++ b/js/xpconnect/src/dombindings.cpp
@@ -21,17 +21,17 @@
 #include "jsapi.h"
 #include "jsatom.h"
 
 using namespace JS;
 using namespace mozilla::dom;
 
 namespace mozilla {
 namespace dom {
-namespace binding {
+namespace oldproxybindings {
 
 enum {
     JSPROXYSLOT_EXPANDO = 0
 };
 
 static jsid s_prototype_id = JSID_VOID;
 
 static jsid s_length_id = JSID_VOID;
--- a/js/xpconnect/src/dombindings.h
+++ b/js/xpconnect/src/dombindings.h
@@ -10,17 +10,17 @@
 
 #include "jsapi.h"
 #include "jsproxy.h"
 #include "xpcpublic.h"
 #include "nsString.h"
 
 namespace mozilla {
 namespace dom {
-namespace binding {
+namespace oldproxybindings {
 
 class ProxyHandler : public js::BaseProxyHandler {
 protected:
     ProxyHandler() : js::BaseProxyHandler(ProxyFamily())
     {
     }
 
 public:
--- a/js/xpconnect/src/dombindingsgen.py
+++ b/js/xpconnect/src/dombindingsgen.py
@@ -370,17 +370,17 @@ def writeHeaderFile(filename, config):
                 namespaces.append(newNamespaces[i])
             f.write("class %s;\n" % type)
         for namespace in namespaces:
             f.write("}\n")
         f.write("\n")
 
         f.write("namespace mozilla {\n"
                 "namespace dom {\n"
-                "namespace binding {\n\n")
+                "namespace oldproxybindings {\n\n")
         f.write("bool\n"
                 "DefinePropertyStaticJSVals(JSContext *cx);\n\n")
 
         for clazz in config.list_classes.itervalues():
             f.write(string.Template(listDefinitionTemplate).substitute(clazz))
 
         f.write("\n"
                 "}\n"
@@ -633,17 +633,17 @@ def writeStubFile(filename, config, inte
                     for p in member.params:
                         addType(types, p.realtype, config.irregularFilenames)
 
         f.write("".join([("#include \"%s.h\"\n" % re.sub(r'(([^:]+::)*)', '', type)) for type in sorted(types)]))
         f.write("\n")
 
         f.write("namespace mozilla {\n"
                 "namespace dom {\n"
-                "namespace binding {\n\n")
+                "namespace oldproxybindings {\n\n")
 
         f.write("// Property name ids\n\n")
 
         ids = set()
         for clazz in config.list_classes.itervalues():
             assert clazz.indexGetter
             ids.add(clazz.indexGetter.name)
             if clazz.indexSetter:
@@ -707,17 +707,17 @@ def writeStubFile(filename, config, inte
             for member in sorted(clazz.members, key=lambda member: member.name):
                 if member.name == 'length':
                     if not member.readonly:
                         setterName = (clazz.name + '_' + header.attributeNativeName(member, False))
                         writeBindingStub(f, clazz.name, member, setterName, isSetter=True)
                     else:
                         setterName = "NULL"
 
-                    propertiesList.append("    { s_length_id, length_getter, %s }" % setterName)
+                    propertiesList.append("    { mozilla::dom::s_length_id, length_getter, %s }" % setterName)
                     continue
 
                 isAttr = (member.kind == 'attribute')
                 isMethod = (member.kind == 'method')
                 assert isAttr or isMethod
 
                 if isMethod:
                     methodsList.append(writeMethodStub(f, clazz.name, member))
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -831,26 +831,27 @@ NoteGCThingXPCOMChildren(js::Class *clas
         cb.NoteXPCOMChild(to->GetNative());
     }
     // XXX This test does seem fragile, we should probably whitelist classes
     //     that do hold a strong reference, but that might not be possible.
     else if (clasp->flags & JSCLASS_HAS_PRIVATE &&
              clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "xpc_GetJSPrivate(obj)");
         cb.NoteXPCOMChild(static_cast<nsISupports*>(xpc_GetJSPrivate(obj)));
-    } else if (binding::instanceIsProxy(obj)) {
+    } else if (oldproxybindings::instanceIsProxy(obj)) {
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "js::GetProxyPrivate(obj)");
         nsISupports *identity =
             static_cast<nsISupports*>(js::GetProxyPrivate(obj).toPrivate());
         cb.NoteXPCOMChild(identity);
-    } else if (IsDOMClass(clasp) &&
-               DOMJSClass::FromJSClass(clasp)->mDOMObjectIsISupports) {
-        NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "UnwrapDOMObject(obj)");
-        nsISupports *identity = UnwrapDOMObject<nsISupports>(obj);
-        cb.NoteXPCOMChild(identity);
+    } else {
+        nsISupports *identity;
+        if (UnwrapDOMObjectToISupports(obj, identity)) {
+            NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "UnwrapDOMObject(obj)");
+            cb.NoteXPCOMChild(identity);
+        }
     }
 }
 
 enum TraverseSelect {
     TRAVERSE_CPP,
     TRAVERSE_FULL
 };
 
@@ -1414,17 +1415,18 @@ nsXPConnect::GetNativeOfWrapper(JSContex
         XPCWrappedNative::GetWrappedNativeOfJSObject(aJSContext, aJSObj, nullptr,
                                                      &obj2);
     if (wrapper)
         return wrapper->Native();
 
     if (obj2)
         return (nsISupports*)xpc_GetJSPrivate(obj2);
 
-    if (mozilla::dom::binding::instanceIsProxy(aJSObj)) {
+    if (mozilla::dom::IsDOMProxy(aJSObj) ||
+        mozilla::dom::oldproxybindings::instanceIsProxy(aJSObj)) {
         // FIXME: Provide a fast non-refcounting way to get the canonical
         //        nsISupports from the proxy.
         nsISupports *supports =
             static_cast<nsISupports*>(js::GetProxyPrivate(aJSObj).toPrivate());
         nsCOMPtr<nsISupports> canonical = do_QueryInterface(supports);
         return canonical.get();
     }
 
@@ -1452,17 +1454,18 @@ nsXPConnect::GetJSObjectOfWrapper(JSCont
     if (wrapper) {
         wrapper->GetJSObject(_retval);
         return NS_OK;
     }
     if (obj2) {
         *_retval = obj2;
         return NS_OK;
     }
-    if (mozilla::dom::binding::instanceIsProxy(aJSObj)) {
+    if (mozilla::dom::IsDOMProxy(aJSObj) ||
+        mozilla::dom::oldproxybindings::instanceIsProxy(aJSObj)) {
         *_retval = aJSObj;
         return NS_OK;
     }
     // else...
     *_retval = nullptr;
     return NS_ERROR_FAILURE;
 }
 
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -126,17 +126,17 @@ xpc_FastGetCachedWrapper(nsWrapperCache 
     if (cache) {
         JSObject* wrapper = cache->GetWrapper();
         NS_ASSERTION(!wrapper ||
                      !cache->IsDOMBinding() ||
                      !IS_SLIM_WRAPPER(wrapper),
                      "Should never have a slim wrapper when IsDOMBinding()");
         if (wrapper &&
             js::GetObjectCompartment(wrapper) == js::GetObjectCompartment(scope) &&
-            (IS_SLIM_WRAPPER(wrapper) ||
+            (IS_SLIM_WRAPPER(wrapper) || cache->IsDOMBinding() ||
              xpc_OkToHandOutWrapper(cache))) {
             *vp = OBJECT_TO_JSVAL(wrapper);
             return wrapper;
         }
     }
 
     return nullptr;
 }
@@ -301,34 +301,48 @@ Throw(JSContext *cx, nsresult rv);
 
 } // namespace xpc
 
 nsCycleCollectionParticipant *
 xpc_JSCompartmentParticipant();
 
 namespace mozilla {
 namespace dom {
-namespace binding {
 
 extern int HandlerFamily;
 inline void* ProxyFamily() { return &HandlerFamily; }
-inline bool instanceIsProxy(JSObject *obj)
+inline bool IsDOMProxy(JSObject *obj)
 {
     return js::IsProxy(obj) &&
            js::GetProxyHandler(obj)->family() == ProxyFamily();
 }
 
 typedef bool
 (*DefineInterface)(JSContext *cx, JSObject *global, bool *enabled);
 
 extern bool
 DefineStaticJSVals(JSContext *cx);
 void
 Register(nsScriptNameSpaceManager* aNameSpaceManager);
 extern bool
 DefineConstructor(JSContext *cx, JSObject *obj, DefineInterface aDefine,
                   nsresult *aResult);
 
-} // namespace binding
+namespace oldproxybindings {
+
+extern int HandlerFamily;
+inline void* ProxyFamily() { return &HandlerFamily; }
+inline bool instanceIsProxy(JSObject *obj)
+{
+    return js::IsProxy(obj) &&
+           js::GetProxyHandler(obj)->family() == ProxyFamily();
+}
+extern bool
+DefineStaticJSVals(JSContext *cx);
+void
+Register(nsScriptNameSpaceManager* aNameSpaceManager);
+
+} // namespace oldproxybindings
+
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -294,17 +294,17 @@ enum XrayType {
 
 static XrayType
 GetXrayType(JSObject *obj)
 {
     js::Class* clasp = js::GetObjectClass(obj);
     if (mozilla::dom::IsDOMClass(Jsvalify(clasp))) {
         return XrayForDOMObject;
     }
-    if (mozilla::dom::binding::instanceIsProxy(obj)) {
+    if (mozilla::dom::oldproxybindings::instanceIsProxy(obj)) {
         return XrayForDOMProxyObject;
     }
     if (IS_WRAPPER_CLASS(clasp) || clasp->ext.innerObject) {
         NS_ASSERTION(clasp->ext.innerObject || IS_WN_WRAPPER_OBJECT(obj),
                      "We forgot to Morph a slim wrapper!");
         return XrayForWrappedNative;
     }
     return NotXray;
@@ -380,17 +380,17 @@ WrapperFactory::Rewrap(JSContext *cx, JS
             (wn = GetWrappedNative(cx, obj)) &&
             wn->HasProto() && wn->GetProto()->ClassIsDOMObject()) {
             typedef XrayWrapper<CrossCompartmentSecurityWrapper> Xray;
             usingXray = true;
             if (IsLocationObject(obj))
                 wrapper = &FilteringWrapper<Xray, LocationPolicy>::singleton;
             else
                 wrapper = &FilteringWrapper<Xray, CrossOriginAccessiblePropertiesOnly>::singleton;
-        } else if (mozilla::dom::binding::instanceIsProxy(obj)) {
+        } else if (mozilla::dom::oldproxybindings::instanceIsProxy(obj)) {
             wrapper = &FilteringWrapper<XrayProxy, CrossOriginAccessiblePropertiesOnly>::singleton;
         } else if (mozilla::dom::IsDOMClass(JS_GetClass(obj))) {
             wrapper = &FilteringWrapper<XrayDOM, CrossOriginAccessiblePropertiesOnly>::singleton;
         } else if (IsComponentsObject(obj)) {
             wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper,
                                         ComponentsObjectPolicy>::singleton;
         } else {
             wrapper = &ChromeObjectWrapper::singleton;
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1052,17 +1052,17 @@ ProxyXrayTraits::createHolderObject(JSCo
 }
 
 bool
 DOMXrayTraits::resolveNativeProperty(JSContext *cx, JSObject *wrapper, JSObject *holder, jsid id,
                                      bool set, JSPropertyDescriptor *desc)
 {
     JSObject *obj = getInnerObject(wrapper);
     const NativePropertyHooks *nativeHooks =
-        DOMJSClass::FromJSClass(JS_GetClass(obj))->mNativeHooks;
+        DOMJSClass::FromJSClass(JS_GetClass(obj))->mClass.mNativeHooks;
 
     do {
         if (nativeHooks->mResolveProperty(cx, wrapper, id, set, desc) &&
             desc->obj) {
             NS_ASSERTION(desc->obj == wrapper, "What did we resolve this on?");
             return true;
         }
     } while ((nativeHooks = nativeHooks->mProtoHooks));
@@ -1103,17 +1103,17 @@ DOMXrayTraits::enumerateNames(JSContext 
                               JS::AutoIdVector &props)
 {
     if (flags & (JSITER_OWNONLY | JSITER_HIDDEN))
         // Probably need to return expandos on the Xray here!
         return true;
 
     JSObject *obj = getInnerObject(wrapper);
     const NativePropertyHooks *nativeHooks =
-        DOMJSClass::FromJSClass(JS_GetClass(obj))->mNativeHooks;
+        DOMJSClass::FromJSClass(JS_GetClass(obj))->mClass.mNativeHooks;
 
     do {
         if (!nativeHooks->mEnumerateProperties(props)) {
             return false;
         }
     } while ((nativeHooks = nativeHooks->mProtoHooks));
 
     return true;
@@ -1179,17 +1179,17 @@ XrayToString(JSContext *cx, unsigned arg
         return false;
     if (!IsWrapper(wrapper) || !WrapperFactory::IsXrayWrapper(wrapper)) {
         JS_ReportError(cx, "XrayToString called on an incompatible object");
         return false;
     }
 
     nsAutoString result(NS_LITERAL_STRING("[object XrayWrapper "));
     JSObject *obj = &js::GetProxyPrivate(wrapper).toObject();
-    if (mozilla::dom::binding::instanceIsProxy(obj)) {
+    if (IsDOMProxy(obj) || oldproxybindings::instanceIsProxy(obj)) {
         JSString *wrapperStr = js::GetProxyHandler(wrapper)->obj_toString(cx, wrapper);
         size_t length;
         const jschar* chars = JS_GetStringCharsAndLength(cx, wrapperStr, &length);
         if (!chars) {
             JS_ReportOutOfMemory(cx);
             return false;
         }
         result.Append(chars, length);