Bug 894448 part 2 - Remove nativeOwnership = 'nsisupports'. r=bzbarsky
authorPeter Van der Beken <peterv@propagandism.org>
Thu, 04 Jul 2013 17:24:59 +0200
changeset 140101 9308a970daee28e4431da34b1d3e258524db4337
parent 140100 bb2a64270e6a96a9fce4ff5fda95147f258d0420
child 140102 bbf37166d07cc117d5e6304706e7f0d00b5415d5
push id31593
push userbzbarsky@mozilla.com
push dateFri, 26 Jul 2013 02:42:05 +0000
treeherdermozilla-inbound@9308a970daee [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs894448
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 894448 part 2 - Remove nativeOwnership = 'nsisupports'. r=bzbarsky
dom/bindings/BindingUtils.h
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/bindings/Configuration.py
js/xpconnect/tests/chrome/test_paris_weakmap_keys.xul
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2,27 +2,30 @@
 /* vim: set ts=2 sw=2 et tw=79: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_BindingUtils_h__
 #define mozilla_dom_BindingUtils_h__
 
+#include <algorithm>
+
 #include "jsfriendapi.h"
 #include "jswrapper.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/CallbackObject.h"
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/DOMJSProxyHandler.h"
 #include "mozilla/dom/NonRefcountedDOMObject.h"
 #include "mozilla/dom/Nullable.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Likely.h"
+#include "nsCycleCollector.h"
 #include "nsIXPConnect.h"
 #include "nsTraceRefcnt.h"
 #include "qsObjectHelper.h"
 #include "xpcpublic.h"
 
 #include "nsWrapperCacheInlines.h"
 
 class nsPIDOMWindow;
@@ -406,34 +409,16 @@ class Has##_name##Member {              
   typedef char no[2];                                                     \
   HAS_MEMBER_CHECK(_name);                                                \
   template<typename V> static no& Check(...);                             \
                                                                           \
 public:                                                                   \
   static bool const Value = sizeof(Check<T>(nullptr)) == sizeof(yes);     \
 };
 
-HAS_MEMBER(AddRef)
-HAS_MEMBER(Release)
-HAS_MEMBER(QueryInterface)
-
-template<typename T>
-struct IsRefCounted
-{
-  static bool const Value = HasAddRefMember<T>::Value &&
-                            HasReleaseMember<T>::Value;
-};
-
-template<typename T>
-struct IsISupports
-{
-  static bool const Value = IsRefCounted<T>::Value &&
-                            HasQueryInterfaceMember<T>::Value;
-};
-
 HAS_MEMBER(WrapObject)
 
 // HasWrapObject<T>::Value will be true if T has a WrapObject member but it's
 // not nsWrapperCache::WrapObject.
 template<typename T>
 struct HasWrapObject
 {
 private:
@@ -446,17 +431,17 @@ private:
   template <typename V> static yes& Check(...);
 
 public:
   static bool const Value = HasWrapObjectMember<T>::Value &&
                             sizeof(Check<T>(nullptr)) == sizeof(yes);
 };
 
 #ifdef DEBUG
-template <class T, bool isISupports=IsISupports<T>::Value>
+template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
 struct
 CheckWrapperCacheCast
 {
   static bool Check()
   {
     return reinterpret_cast<uintptr_t>(
       static_cast<nsWrapperCache*>(
         reinterpret_cast<T*>(1))) == 1;
@@ -682,17 +667,17 @@ WrapNewBindingObject(JSContext* cx, JS::
   if (clasp) {
     // Some sanity asserts about our object.  Specifically:
     // 1)  If our class claims we're nsISupports, we better be nsISupports
     //     XXXbz ideally, we could assert that reinterpret_cast to nsISupports
     //     does the right thing, but I don't see a way to do it.  :(
     // 2)  If our class doesn't claim we're nsISupports we better be
     //     reinterpret_castable to nsWrapperCache.
     MOZ_ASSERT(clasp, "What happened here?");
-    MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, IsISupports<T>::Value);
+    MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, (IsBaseOf<nsISupports, T>::value));
     MOZ_ASSERT(CheckWrapperCacheCast<T>::Check());
   }
 
   // When called via XrayWrapper, we end up here while running in the
   // chrome compartment.  But the obj we have would be created in
   // whatever the content compartment is.  So at this point we need to
   // make sure it's correctly wrapped for the compartment of |scope|.
   // cx should already be in the compartment of |scope| here.
@@ -1127,17 +1112,17 @@ WrapNativeISupportsParent(JSContext* cx,
   JS::Rooted<JS::Value> v(cx);
   return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, v.address()) ?
          JSVAL_TO_OBJECT(v) :
          nullptr;
 }
 
 
 // Fallback for when our parent is not a WebIDL binding object.
-template<typename T, bool isISupports=IsISupports<T>::Value >
+template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
 struct WrapNativeParentFallback
 {
   static inline JSObject* Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
                                T* parent, nsWrapperCache* cache)
   {
     return nullptr;
   }
 };
@@ -1398,16 +1383,36 @@ InitIds(JSContext* cx, const Prefable<Sp
     ++ids;
   } while ((++prefableSpecs)->specs);
 
   return true;
 }
 
 JSBool
 QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
+
+template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
+struct
+WantsQueryInterface
+{
+  static bool Enabled(JSContext* aCx, JSObject* aGlobal)
+  {
+    return false;
+  }
+};
+template <class T>
+struct
+WantsQueryInterface<T, true>
+{
+  static bool Enabled(JSContext* aCx, JSObject* aGlobal)
+  {
+    return IsChromeOrXBL(aCx, aGlobal);
+  }
+};
+
 JSBool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
 
 bool
 GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id, bool* found,
                        JS::Value* vp);
 
@@ -2110,12 +2115,185 @@ inline bool ByteStringToJsval(JSContext 
 {
     if (str.IsVoid()) {
         rval.setNull();
         return true;
     }
     return NonVoidByteStringToJsval(cx, str, rval);
 }
 
+template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
+struct PreserveWrapperHelper
+{
+  static void PreserveWrapper(T* aObject)
+  {
+    aObject->PreserveWrapper(aObject, NS_CYCLE_COLLECTION_PARTICIPANT(T));
+  }
+};
+
+template<class T>
+struct PreserveWrapperHelper<T, true>
+{
+  static void PreserveWrapper(T* aObject)
+  {
+    aObject->PreserveWrapper(reinterpret_cast<nsISupports*>(aObject));
+  }
+};
+
+template<class T>
+void PreserveWrapper(T* aObject)
+{
+  PreserveWrapperHelper<T>::PreserveWrapper(aObject);
+}
+
+template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
+struct CastingAssertions
+{
+  static bool ToSupportsIsCorrect(T*)
+  {
+    return true;
+  }
+  static bool ToSupportsIsOnPrimaryInheritanceChain(T*, nsWrapperCache*)
+  {
+    return true;
+  }
+};
+
+template<class T>
+struct CastingAssertions<T, true>
+{
+  static bool ToSupportsIsCorrect(T* aObject)
+  {
+    return ToSupports(aObject) ==  reinterpret_cast<nsISupports*>(aObject);
+  }
+  static bool ToSupportsIsOnPrimaryInheritanceChain(T* aObject,
+                                                    nsWrapperCache* aCache)
+  {
+    return reinterpret_cast<void*>(aObject) != aCache;
+  }
+};
+
+template<class T>
+bool
+ToSupportsIsCorrect(T* aObject)
+{
+  return CastingAssertions<T>::ToSupportsIsCorrect(aObject);
+}
+
+template<class T>
+bool
+ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
+{
+  return CastingAssertions<T>::ToSupportsIsOnPrimaryInheritanceChain(aObject,
+                                                                     aCache);
+}
+
+template<class T, template <typename> class SmartPtr,
+         bool isISupports=IsBaseOf<nsISupports, T>::value>
+class DeferredFinalizer
+{
+  typedef nsTArray<SmartPtr<T> > SmartPtrArray;
+
+  static void*
+  AppendDeferredFinalizePointer(void* aData, void* aObject)
+  {
+    SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
+    if (!pointers) {
+      pointers = new SmartPtrArray();
+    }
+
+    T* self = static_cast<T*>(aObject);
+
+    SmartPtr<T>* defer = pointers->AppendElement();
+    Take(*defer, self);
+    return pointers;
+  }
+  static bool
+  DeferredFinalize(uint32_t aSlice, void* aData)
+  {
+    MOZ_ASSERT(aSlice > 0, "nonsensical/useless call with aSlice == 0");
+    SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
+    uint32_t oldLen = pointers->Length();
+    aSlice = std::min(oldLen, aSlice);
+    uint32_t newLen = oldLen - aSlice;
+    pointers->RemoveElementsAt(newLen, aSlice);
+    if (newLen == 0) {
+      delete pointers;
+      return true;
+    }
+    return false;
+  }
+
+public:
+  static void
+  AddForDeferredFinalization(T* aObject)
+  {
+    cyclecollector::DeferredFinalize(AppendDeferredFinalizePointer,
+                                     DeferredFinalize, aObject);
+  }
+};
+
+template<class T, template <typename> class SmartPtr>
+class DeferredFinalizer<T, SmartPtr, true>
+{
+public:
+  static void
+  AddForDeferredFinalization(T* aObject)
+  {
+    cyclecollector::DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
+  }
+};
+
+template<class T, template <typename> class SmartPtr>
+static void
+AddForDeferredFinalization(T* aObject)
+{
+  DeferredFinalizer<T, SmartPtr>::AddForDeferredFinalization(aObject);
+}
+
+// This returns T's CC participant if it participates in CC or null if it
+// doesn't. This also returns null for classes that don't inherit from
+// nsISupports (QI should be used to get the participant for those).
+template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
+class GetCCParticipant
+{
+  // Helper for GetCCParticipant for classes that participate in CC.
+  template<class U>
+  static nsCycleCollectionParticipant*
+  GetHelper(int, typename U::NS_CYCLE_COLLECTION_INNERCLASS* dummy=nullptr)
+  {
+    return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
+  }
+  // Helper for GetCCParticipant for classes that don't participate in CC.
+  template<class U>
+  static nsCycleCollectionParticipant*
+  GetHelper(double)
+  {
+    return nullptr;
+  }
+
+public:
+  static nsCycleCollectionParticipant*
+  Get()
+  {
+    // Passing int() here will try to call the GetHelper that takes an int as
+    // its firt argument. If T doesn't participate in CC then substitution for
+    // the second argument (with a default value) will fail and because of
+    // SFINAE the next best match (the variant taking a double) will be called.
+    return GetHelper<T>(int());
+  }
+};
+
+template<class T>
+class GetCCParticipant<T, true>
+{
+public:
+  static nsCycleCollectionParticipant*
+  Get()
+  {
+    return nullptr;
+  }
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -39,33 +39,32 @@
 #                   in the WebIDL.
 #   * wrapperCache: True if this object is a wrapper cache.  Objects that are
 #                   not can only be returned from a limited set of methods,
 #                   cannot be prefable, and must ensure that they disallow
 #                   XPConnect wrapping.  Always false for callback interfaces.
 #                   Always true for worker descriptors for non-callback
 #                   interfaces.  Defaults to true for non-worker non-callback
 #                   descriptors.
-#   * nativeOwnership: Describes how the native object is held. 4 possible
+#   * nativeOwnership: Describes how the native object is held. 3 possible
 #                      types: worker object ('worker'), non-refcounted object
-#                      ('owned'), refcounted non-nsISupports object
-#                      ('refcounted') or nsISupports ('nsisupports').
+#                      ('owned'), refcounted object ('refcounted').
 #                      Non-refcounted objects need to inherit from
 #                      mozilla::dom::NonRefcountedDOMObject and preferably use
 #                      MOZ_COUNT_CTOR/MOZ_COUNT_DTOR in their
 #                      constructor/destructor so they participate in leak
 #                      logging.
 #                      This mostly determines how the finalizer releases the
 #                      binding's hold on the native object. For a worker object
 #                      it'll call Release, for a non-refcounted object it'll
 #                      call delete through XPConnect's deferred finalization
 #                      mechanism, for a refcounted object it'll call Release
 #                      through XPConnect's deferred finalization mechanism.
 #                      Always 'worker' for worker descriptors. Defaults to
-#                      'nsisupports'.
+#                      'refcounted'.
 #
 #   The following fields are either a string, an array (defaults to an empty
 #   array) or a dictionary with three possible keys (all, getterOnly and
 #   setterOnly) each having such an array as the value
 #
 #   * implicitJSContext - attributes and methods specified in the .webidl file
 #                         that require a JSContext as the first argument
 #   * resultNotAddRefed - attributes and methods specified in the .webidl file
@@ -100,41 +99,32 @@ DOMInterfaces = {
 
 'AudioChannelManager': {
     'nativeType': 'mozilla::dom::system::AudioChannelManager',
     'headerFile': 'AudioChannelManager.h'
 },
 
 'AudioContext': {
     'implicitJSContext': [ 'createBuffer' ],
-    'nativeOwnership': 'refcounted',
     'resultNotAddRefed': [ 'destination', 'listener' ],
 },
 
 'AudioBufferSourceNode': {
     'implicitJSContext': [ 'buffer' ],
     'resultNotAddRefed': [ 'playbackRate' ],
 },
 
-'AudioListener' : {
-    'nativeOwnership': 'refcounted'
-},
-
 'AudioNode' : {
     'concrete': False,
     'binaryNames': {
         'channelCountMode': 'channelCountModeValue',
         'channelInterpretation': 'channelInterpretationValue',
     },
 },
 
-'AudioParam' : {
-    'nativeOwnership': 'refcounted'
-},
-
 'AudioProcessingEvent' : {
     'resultNotAddRefed': [ 'inputBuffer', 'outputBuffer' ],
 },
 
 'BeforeUnloadEvent': {
     'nativeType': 'nsDOMBeforeUnloadEvent',
 },
 
@@ -741,17 +731,16 @@ DOMInterfaces = {
 
 'OfflineAudioCompletionEvent': {
     'resultNotAddRefed': [ 'renderedBuffer' ],
 },
 
 'OfflineAudioContext': {
     'nativeType': 'mozilla::dom::AudioContext',
     'implicitJSContext': [ 'createBuffer' ],
-    'nativeOwnership': 'refcounted',
     'resultNotAddRefed': [ 'destination', 'listener' ],
 },
 
 'OfflineResourceList': {
     'nativeType': 'nsDOMOfflineResourceList',
 },
 
 'PaintRequest': {
@@ -771,24 +760,22 @@ DOMInterfaces = {
 
 'Performance': {
     'nativeType': 'nsPerformance',
     'resultNotAddRefed': [ 'timing', 'navigation' ]
 },
 
 'PerformanceTiming': {
     'nativeType': 'nsPerformanceTiming',
-    'headerFile': 'nsPerformance.h',
-    'nativeOwnership': 'refcounted'
+    'headerFile': 'nsPerformance.h'
 },
 
 'PerformanceNavigation': {
     'nativeType': 'nsPerformanceNavigation',
-    'headerFile': 'nsPerformance.h',
-    'nativeOwnership': 'refcounted'
+    'headerFile': 'nsPerformance.h'
 },
 
 'PeriodicWave' : {
     'nativeOwnership': 'refcounted'
 },
 
 'Plugin': {
     'headerFile' : 'nsPluginArray.h',
@@ -827,17 +814,16 @@ DOMInterfaces = {
 },
 
 'Rect': {
     'nativeType': 'nsDOMCSSRect',
     'resultNotAddRefed': [ 'top', 'right', 'bottom', 'left' ]
 },
 
 'RGBColor': {
-    'nativeOwnership': 'refcounted',
     'nativeType': 'nsDOMCSSRGBColor',
     'resultNotAddRefed': [ 'alpha', 'blue', 'green', 'red' ]
 },
 
 'Screen': {
     'nativeType': 'nsScreen',
 },
 
@@ -884,24 +870,16 @@ DOMInterfaces = {
     'headerFile': 'DOMSVGAnimatedNumberList.h'
 },
 
 'SVGAnimatedPreserveAspectRatio': {
     'nativeType': 'mozilla::dom::DOMSVGAnimatedPreserveAspectRatio',
     'headerFile': 'SVGAnimatedPreserveAspectRatio.h'
 },
 
-'SVGAnimatedRect' : {
-    'nativeOwnership': 'refcounted'
-},
-
-'SVGAnimatedTransformList': {
-    'nativeOwnership': 'refcounted',
-},
-
 'SVGAnimationElement': {
     'resultNotAddRefed': ['targetElement'],
     'concrete': False
 },
 
 'SVGComponentTransferFunctionElement': {
     'concrete': False,
 },
@@ -940,20 +918,16 @@ DOMInterfaces = {
     'nativeType': 'mozilla::DOMSVGLengthList',
     'headerFile': 'DOMSVGLengthList.h'
 },
 
 'SVGLinearGradientElement': {
     'headerFile': 'mozilla/dom/SVGGradientElement.h',
 },
 
-'SVGMatrix' : {
-    'nativeOwnership': 'refcounted'
-},
-
 'SVGNumberList': {
     'nativeType': 'mozilla::DOMSVGNumberList',
     'headerFile': 'DOMSVGNumberList.h'
 },
 
 'SVGPathSeg': {
     'nativeType': 'mozilla::DOMSVGPathSeg',
     'headerFile': 'DOMSVGPathSeg.h',
@@ -1087,17 +1061,16 @@ DOMInterfaces = {
     'concrete': False
 },
 
 'SVGTextPositioningElement': {
     'concrete': False
 },
 
 'SVGTransform': {
-    'nativeOwnership': 'refcounted',
     'resultNotAddRefed': [ 'matrix' ]
 },
 
 'SVGTransformList': {
     'nativeType': 'mozilla::DOMSVGTransformList',
     'headerFile': 'DOMSVGTransformList.h'
 },
 
@@ -1121,25 +1094,21 @@ DOMInterfaces = {
 'Text': {
     # Total hack to allow binding code to realize that nsTextNode can
     # in fact be cast to Text.
     'headerFile': 'nsTextNode.h',
 },
 
 'TextDecoder': [
 {
-    'nativeOwnership': 'refcounted',
-},
-{
     'workers': True,
 }],
 
 'TextEncoder': [
 {
-    'nativeOwnership': 'refcounted',
     'implicitJSContext': [ 'encode' ],
 },
 {
     'workers': True,
     'implicitJSContext': [ 'encode' ],
 }],
 
 'TextMetrics': {
@@ -1188,23 +1157,16 @@ DOMInterfaces = {
 'URL' : [{
     'concrete': False,
 },
 {
     'implicitJSContext': [ 'createObjectURL', 'revokeObjectURL' ],
     'workers': True,
 }],
 
-'VideoPlaybackQuality': {
-   'nativeOwnership': 'refcounted',
-},
-
-'VideoStreamTrack': {
-},
-
 'WebGLActiveInfo': {
    'nativeType': 'mozilla::WebGLActiveInfo',
    'headerFile': 'WebGLContext.h',
    'wrapperCache': False
 },
 
 'WebGLBuffer': {
    'nativeType': 'mozilla::WebGLBuffer',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -132,29 +132,29 @@ def NativePropertyHooks(descriptor):
 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)
-        if descriptor.workers or descriptor.nativeOwnership != 'refcounted':
+        if descriptor.workers:
             participant = "nullptr"
         else:
-            participant = "NS_CYCLE_COLLECTION_PARTICIPANT(%s)" % descriptor.nativeType
+            participant = "GetCCParticipant<%s>::Get()" % descriptor.nativeType
         getParentObject = "GetParentObject<%s>::Get" % descriptor.nativeType
         return """{
   { %s },
-  %s,
+  IsBaseOf<nsISupports, %s >::value,
   %s,
   %s,
   GetProtoObject,
   %s
-}""" % (prototypeChainString, toStringBool(descriptor.nativeOwnership == 'nsisupports'),
+}""" % (prototypeChainString, descriptor.nativeType,
         NativePropertyHooks(descriptor),
         getParentObject,
         participant)
 
 class CGDOMJSClass(CGThing):
     """
     Generate a DOMJSClass for a given descriptor
     """
@@ -916,24 +916,19 @@ class CGAbstractClassHook(CGAbstractStat
     Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
     'this' unwrapping as it assumes that the unwrapped type is always known.
     """
     def __init__(self, descriptor, name, returnType, args):
         CGAbstractStaticMethod.__init__(self, descriptor, name, returnType,
                                         args)
 
     def definition_body_prologue(self):
-        if self.descriptor.nativeOwnership == 'nsisupports':
-            assertion = ('  MOZ_STATIC_ASSERT((IsBaseOf<nsISupports, %s>::value), '
-                         '"Must be an nsISupports class");') % self.descriptor.nativeType
-        else:
-            assertion = ''
-        return """%s
+        return """
   %s* self = UnwrapDOMObject<%s>(obj);
-""" % (assertion, self.descriptor.nativeType, self.descriptor.nativeType)
+""" % (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)
 
@@ -944,87 +939,43 @@ class CGAddPropertyHook(CGAbstractClassH
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('JS::Handle<jsid>', 'id'), Argument('JS::MutableHandle<JS::Value>', 'vp')]
         CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME,
                                      'JSBool', args)
 
     def generate_code(self):
         assert not self.descriptor.workers and self.descriptor.wrapperCache
-        if self.descriptor.nativeOwnership == 'nsisupports':
-            preserveArgs = "reinterpret_cast<nsISupports*>(self)"
-        else:
-            preserveArgs = "self, NS_CYCLE_COLLECTION_PARTICIPANT(%s)" % self.descriptor.nativeType
         return ("  // We don't want to preserve if we don't have a wrapper.\n"
                 "  if (self->GetWrapperPreserveColor()) {\n"
-                "    self->PreserveWrapper(%s);\n"
+                "    PreserveWrapper(self);\n"
                 "  }\n"
-                "  return true;" % preserveArgs)
+                "  return true;")
 
 def DeferredFinalizeSmartPtr(descriptor):
     if descriptor.nativeOwnership == 'owned':
-        smartPtr = 'nsAutoPtr<%s>'
+        smartPtr = 'nsAutoPtr'
     else:
-        assert descriptor.nativeOwnership == 'refcounted'
-        smartPtr = 'nsRefPtr<%s>'
-    return smartPtr % descriptor.nativeType
-
-class CGAppendDeferredFinalizePointer(CGAbstractStaticMethod):
-    def __init__(self, descriptor):
-        CGAbstractStaticMethod.__init__(self, descriptor, "AppendDeferredFinalizePointer", "void*", [Argument('void*', 'data'), Argument('void*', 'thing')])
-
-    def definition_body(self):
-        smartPtr = DeferredFinalizeSmartPtr(self.descriptor)
-        return """  nsTArray<%(smartPtr)s >* pointers = static_cast<nsTArray<%(smartPtr)s >*>(data);
-  if (!pointers) {
-    pointers = new nsTArray<%(smartPtr)s >();
-  }
-
-  %(nativeType)s* self = static_cast<%(nativeType)s*>(thing);
-
-  %(smartPtr)s* defer = pointers->AppendElement();
-  Take(*defer, self);
-  return pointers;""" % { 'smartPtr': smartPtr, 'nativeType': self.descriptor.nativeType }
-
-class CGDeferredFinalize(CGAbstractStaticMethod):
-    def __init__(self, descriptor):
-        CGAbstractStaticMethod.__init__(self, descriptor, "DeferredFinalize", "bool", [Argument('uint32_t', 'slice'), Argument('void*', 'data')])
-
-    def definition_body(self):
-        smartPtr = DeferredFinalizeSmartPtr(self.descriptor)
-        return """  MOZ_ASSERT(slice > 0, "nonsensical/useless call with slice == 0");
-  nsTArray<%(smartPtr)s >* pointers = static_cast<nsTArray<%(smartPtr)s >*>(data);
-  uint32_t oldLen = pointers->Length();
-  slice = std::min(oldLen, slice);
-  uint32_t newLen = oldLen - slice;
-  pointers->RemoveElementsAt(newLen, slice);
-  if (newLen == 0) {
-    delete pointers;
-    return true;
-  }
-  return false;""" % { 'smartPtr': smartPtr }
+        smartPtr = 'nsRefPtr'
+    return smartPtr
 
 def finalizeHook(descriptor, hookName, context):
     if descriptor.customFinalize:
         finalize = "self->%s(%s);" % (hookName, context)
     else:
         finalize = "JSBindingFinalized<%s>::Finalized(self);\n" % descriptor.nativeType
         if descriptor.wrapperCache:
             finalize += "ClearWrapper(self, self);\n"
         if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
             finalize += "self->mExpandoAndGeneration.expando = JS::UndefinedValue();\n"
         if descriptor.workers:
             finalize += "self->Release();"
-        elif descriptor.nativeOwnership == 'nsisupports':
-            finalize += "nsContentUtils::DeferredFinalize(reinterpret_cast<nsISupports*>(self));"
-        else:
-            finalize += """nsContentUtils::DeferredFinalize(AppendDeferredFinalizePointer,
-                                 DeferredFinalize,
-                                 self);
-"""
+        else:
+            finalize += ("AddForDeferredFinalization<%s, %s >(self);" %
+                (descriptor.nativeType, DeferredFinalizeSmartPtr(descriptor)))
     return CGIfWrapper(CGGeneric(finalize), "self")
 
 class CGClassFinalizeHook(CGAbstractClassHook):
     """
     A hook for finalize, used to release our native object.
     """
     def __init__(self, descriptor):
         args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'obj')]
@@ -1187,40 +1138,43 @@ class CGClassHasInstanceHook(CGAbstractS
         if not NeedsGeneratedHasInstance(self.descriptor):
             return ""
         return CGAbstractStaticMethod.define(self)
 
     def definition_body(self):
         return self.generate_code()
 
     def generate_code(self):
-        assert self.descriptor.nativeOwnership == 'nsisupports'
         header = """
   if (!vp.isObject()) {
     *bp = false;
     return true;
   }
 
   JS::Rooted<JSObject*> instance(cx, &vp.toObject());
   """
         if self.descriptor.interface.hasInterfacePrototypeObject():
             return header + """
+  MOZ_STATIC_ASSERT((IsBaseOf<nsISupports, %s>::value),
+                    "HasInstance only works for nsISupports-based classes.");
+
   bool ok = InterfaceHasInstance(cx, obj, instance, bp);
   if (!ok || *bp) {
     return ok;
   }
 
   // FIXME Limit this to chrome by checking xpc::AccessCheck::isChrome(obj).
   nsISupports* native =
     nsContentUtils::XPConnect()->GetNativeOfWrapper(cx,
                                                     js::UncheckedUnwrap(instance));
   nsCOMPtr<nsIDOM%s> qiResult = do_QueryInterface(native);
   *bp = !!qiResult;
   return true;
-         """ % self.descriptor.interface.identifier.name
+         """ % (self.descriptor.nativeType,
+                self.descriptor.interface.identifier.name)
 
         hasInstanceCode = """
   const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
   *bp = false;
   if (!domClass) {
     // Not a DOM object, so certainly not an instance of this interface
     return true;
   }
@@ -1414,17 +1368,17 @@ def requiresQueryInterfaceMethod(descrip
     # interfaces that are concrete and all of whose ancestors are abstract.
     def allAncestorsAbstract(iface):
         if not iface.parent:
             return True
         desc = descriptor.getDescriptor(iface.parent.identifier.name)
         if desc.concrete:
             return False
         return allAncestorsAbstract(iface.parent)
-    return (descriptor.nativeOwnership == 'nsisupports' and
+    return (not descriptor.workers and
             descriptor.interface.hasInterfacePrototypeObject() and
             descriptor.concrete and
             allAncestorsAbstract(descriptor.interface))
 
 class MethodDefiner(PropertyDefiner):
     """
     A class for defining methods on a prototype object.
     """
@@ -1460,22 +1414,22 @@ class MethodDefiner(PropertyDefiner):
             self.regular.append({"name": 'iterator',
                                  "methodInfo": False,
                                  "nativeName": "JS_ArrayIterator",
                                  "length": 0,
                                  "flags": "JSPROP_ENUMERATE",
                                  "condition": MemberCondition(None, None) })
 
         if not static and requiresQueryInterfaceMethod(descriptor):
+            condition = "WantsQueryInterface<%s>::Enabled" % descriptor.nativeType
             self.regular.append({"name": 'QueryInterface',
                                  "methodInfo": False,
                                  "length": 1,
                                  "flags": "0",
-                                 "condition":
-                                     MemberCondition(None, "IsChromeOrXBL") })
+                                 "condition": MemberCondition(None, condition) })
 
         if not static:
             stringifier = descriptor.operations['Stringifier']
             if stringifier:
                 toStringDesc = { "name": "toString",
                                  "nativeName": stringifier.identifier.name,
                                  "length": 0,
                                  "flags": "JSPROP_ENUMERATE",
@@ -2066,21 +2020,20 @@ def CreateBindingJSObject(descriptor, pr
   if (!obj) {
     return nullptr;
   }
 
   js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
 """
     create = objDecl + create
 
-    if descriptor.nativeOwnership in ['refcounted', 'nsisupports']:
+    if descriptor.nativeOwnership == 'refcounted':
         create += """  NS_ADDREF(aObject);
 """
     else:
-        assert descriptor.nativeOwnership == 'owned'
         create += """  // Make sure the native objects inherit from NonRefcountedDOMObject so that we
   // log their ctor and dtor.
   MustInheritFromNonRefcountedDOMObject(aObject);
   *aTookOwnership = true;
 """
     return create % parent
 
 def GetAccessCheck(descriptor, object):
@@ -2149,20 +2102,18 @@ def AssertInheritanceChain(descriptor):
     iface = descriptor.interface
     while iface:
         desc = descriptor.getDescriptor(iface.identifier.name)
         asserts += (
             "  MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
             "             reinterpret_cast<%s*>(aObject));\n" %
             (desc.nativeType, desc.nativeType))
         iface = iface.parent
-    if descriptor.nativeOwnership == 'nsisupports':
-        asserts += (
-            "  MOZ_ASSERT(ToSupports(aObject) == \n"
-            "             reinterpret_cast<nsISupports*>(aObject));\n")
+    asserts += (
+        "  MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n")
     return asserts
 
 class CGWrapWithCacheMethod(CGAbstractMethod):
     """
     Create a wrapper JSObject for a given native that implements nsWrapperCache.
 
     properties should be a PropertyArrays instance.
     """
@@ -2174,22 +2125,19 @@ class CGWrapWithCacheMethod(CGAbstractMe
                 Argument('nsWrapperCache*', 'aCache')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
         self.properties = properties
 
     def definition_body(self):
         if self.descriptor.workers:
             return """  return aObject->GetJSObject();"""
 
-        if self.descriptor.nativeOwnership == 'nsisupports':
-            assertISupportsInheritance = (
-                '  MOZ_ASSERT(reinterpret_cast<void*>(aObject) != aCache,\n'
-                '             "nsISupports must be on our primary inheritance chain");\n')
-        else:
-            assertISupportsInheritance = ""
+        assertISupportsInheritance = (
+            '  MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),\n'
+            '             "nsISupports must be on our primary inheritance chain");\n')
         return """%s
 %s
   JS::Rooted<JSObject*> parent(aCx,
     GetRealParentObject(aObject,
                         WrapNativeParent(aCx, aScope, aObject->GetParentObject())));
   if (!parent) {
     return nullptr;
   }
@@ -7645,32 +7593,27 @@ class CGDescriptor(CGThing):
         if hasSetter: cgThings.append(CGGenericSetter(descriptor))
         if hasLenientSetter: cgThings.append(CGGenericSetter(descriptor,
                                                              lenientThis=True))
 
         if descriptor.interface.getNavigatorProperty():
             cgThings.append(CGConstructNavigatorObjectHelper(descriptor))
             cgThings.append(CGConstructNavigatorObject(descriptor))
 
-        if descriptor.concrete:
-            if descriptor.nativeOwnership == 'owned' or descriptor.nativeOwnership == 'refcounted':
-                cgThings.append(CGAppendDeferredFinalizePointer(descriptor))
-                cgThings.append(CGDeferredFinalize(descriptor))
-
-            if 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.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))
 
         properties = PropertyArrays(descriptor)
         cgThings.append(CGGeneric(define=str(properties)))
         cgThings.append(CGNativeProperties(descriptor, properties))
 
         # Set up our Xray callbacks as needed.  Note that we don't need to do
         # it in workers.
         if not descriptor.workers and descriptor.concrete and descriptor.proxy:
@@ -7723,19 +7666,21 @@ class CGDescriptor(CGThing):
                 cgThings.append(CGPrefEnabledNative(descriptor))
             elif havePref is not None:
                 cgThings.append(CGPrefEnabled(descriptor))
             elif haveChromeOnly is not None:
                 cgThings.append(CGConstructorEnabledChromeOnly(descriptor))
 
         if descriptor.concrete:
             if descriptor.proxy:
-                if descriptor.nativeOwnership != 'nsisupports':
-                    raise TypeError("We don't support non-nsISupports native classes for "
-                                    "proxy-based bindings yet (" + descriptor.name + ")")
+                cgThings.append(CGGeneric("""MOZ_STATIC_ASSERT((IsBaseOf<nsISupports, %s >::value),
+                  "We don't support non-nsISupports native classes for "
+                  "proxy-based bindings yet");
+
+""" % descriptor.nativeType))
                 if not descriptor.wrapperCache:
                     raise TypeError("We need a wrappercache to support expandos for proxy-based "
                                     "bindings (" + descriptor.name + ")")
                 cgThings.append(CGProxyIsProxy(descriptor))
                 cgThings.append(CGProxyUnwrap(descriptor))
                 cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
                 cgThings.append(CGDOMJSProxyHandler(descriptor))
                 cgThings.append(CGIsMethod(descriptor))
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -357,18 +357,18 @@ class Descriptor(DescriptorProvider):
 
         if self.workers:
             if desc.get('nativeOwnership', 'worker') != 'worker':
                 raise TypeError("Worker descriptor for %s should have 'worker' "
                                 "as value for nativeOwnership" %
                                 self.interface.identifier.name)
             self.nativeOwnership = "worker"
         else:
-            self.nativeOwnership = desc.get('nativeOwnership', 'nsisupports')
-            if not self.nativeOwnership in ['owned', 'refcounted', 'nsisupports']:
+            self.nativeOwnership = desc.get('nativeOwnership', 'refcounted')
+            if not self.nativeOwnership in ['owned', 'refcounted']:
                 raise TypeError("Descriptor for %s has unrecognized value (%s) "
                                 "for nativeOwnership" %
                                 (self.interface.identifier.name, self.nativeOwnership))
         self.customTrace = desc.get('customTrace', self.workers)
         self.customFinalize = desc.get('customFinalize', self.workers)
         self.wrapperCache = (not self.interface.isCallback() and
                              (self.workers or
                               (self.nativeOwnership != 'owned' and
--- a/js/xpconnect/tests/chrome/test_paris_weakmap_keys.xul
+++ b/js/xpconnect/tests/chrome/test_paris_weakmap_keys.xul
@@ -41,20 +41,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 
     is(live_map.get(get_div_style()), 12345, "Live map should have live style with right value before GC.");
 
   }
 
   make_live_map();
 
 
-  // AudioContext is the only Paris bindings non-nsISupports refCounted class.
+  // TextDecoder is a non-nsISupports refCounted class using WebIDL bindings.
 
   // non-nsISupports cycle-collected classes should fail as weak map keys.
-  let context = new AudioContext();
+  let context = new TextDecoder();
   let contextFail = false;
   try {
     live_map.set(context, 2);
   } catch (e) {
     contextFail = true;
   }
 
   ok(contextFail, "Cycle collected non-nsISupports classes aren't allowed as weak map keys.");