Bug 657917 - Update nsIClassInfoImpl docs. r=peterv
authorJustin Lebar <justin.lebar@gmail.com>
Fri, 20 May 2011 12:37:32 -0400
changeset 73289 ff3401bfbf5907b99765b534260915cfeedf9f27
parent 73288 87645ab8ab276d153a36564e3990f52ef0dedb05
child 73290 4a2758e01ea1605dd0cbe484df48d132f1ecfe19
push id752
push userjlebar@mozilla.com
push dateMon, 25 Jul 2011 12:53:25 +0000
treeherdermozilla-inbound@ff3401bfbf59 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs657917
milestone8.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 657917 - Update nsIClassInfoImpl docs. r=peterv
xpcom/components/nsIClassInfo.idl
xpcom/glue/nsIClassInfoImpl.h
--- a/xpcom/components/nsIClassInfo.idl
+++ b/xpcom/components/nsIClassInfo.idl
@@ -48,17 +48,19 @@
  * nsISupports).
  */
 #define NS_THISPTROFFSETS_SID \
     { 0x23e017cc, 0x5d6f, 0x430c, \
       { 0xb3, 0xe6, 0x9d, 0x32, 0x65, 0x70, 0xd6, 0xb8 } }
 %}
 
 /**
- * Provides information about a specific implementation class
+ * Provides information about a specific implementation class.  If you want
+ * your class to implement nsIClassInfo, see nsIClassInfo.h for instructions --
+ * you most likely do not want to inherit from nsIClassInfo.
  */
 
 [scriptable, uuid(986c11d0-f340-11d4-9075-0010a4e73d9a)]
 interface nsIClassInfo : nsISupports
 {
     /**
      * Get an ordered list of the interface ids that instances of the class 
      * promise to implement. Note that nsISupports is an implicit member 
--- a/xpcom/glue/nsIClassInfoImpl.h
+++ b/xpcom/glue/nsIClassInfoImpl.h
@@ -36,16 +36,84 @@
 #ifndef nsIClassInfoImpl_h__
 #define nsIClassInfoImpl_h__
 
 #include "nsIClassInfo.h"
 #include "nsISupportsImpl.h"
 
 #include NEW_H
 
+/**
+ * This header file provides macros which help you make your class implement
+ * nsIClassInfo.  Implementing nsIClassInfo is particularly helpful if you have
+ * a C++ class which implements multiple interfaces and which you access from
+ * JavaScript.  If that class implements nsIClassInfo, the JavaScript code
+ * won't have to call QueryInterface on instances of the class; all methods
+ * from all interfaces returned by GetInterfaces() will be available
+ * automagically.
+ *
+ * Here's all you need to do.  Given a class
+ *
+ *   class nsFooBar : public nsIFoo, public nsIBar { };
+ *
+ * you should already have the following nsISupports implementation in its cpp
+ * file:
+ *
+ *   NS_IMPL_ISUPPORTS2(nsFooBar, nsIFoo, nsIBar).
+ *
+ * Change this to
+ *
+ *   NS_IMPL_CLASSINFO(nsFooBar, NULL, 0, NS_FOOBAR_CID)
+ *   NS_IMPL_ISUPPORTS2_CI(nsFooBar, nsIFoo, nsIBar)
+ *
+ * If nsFooBar is threadsafe, change the 0 above to nsIClassInfo::THREADSAFE.
+ * If it's a singleton, use nsIClassInfo::SINGLETON.  The full list of flags is
+ * in nsIClassInfo.idl.
+ *
+ * The NULL parameter is there so you can pass a function for converting from
+ * an XPCOM object to a scriptable helper.  Unless you're doing specialized JS
+ * work, you can probably leave this as NULL.
+ *
+ * This file also defines the NS_IMPL_QUERY_INTERFACE2_CI macro, which you can
+ * use to replace NS_IMPL_QUERY_INTERFACE2, if you use that instead of
+ * NS_IMPL_ISUPPORTS2.
+ *
+ * That's it!  The rest is gory details.
+ *
+ *
+ * Notice that nsFooBar didn't need to inherit from nsIClassInfo in order to
+ * "implement" it.  However, after adding these macros to nsFooBar, you you can
+ * QueryInterface an instance of nsFooBar to nsIClassInfo.  How can this be?
+ *
+ * The answer lies in the NS_IMPL_ISUPPORTS2_CI macro.  It modifies nsFooBar's
+ * QueryInterface implementation such that, if we ask to QI to nsIClassInfo, it
+ * returns a singleton object associated with the class.  (That singleton is
+ * defined by NS_IMPL_CLASSINFO.)  So all nsFooBar instances will return the
+ * same object when QI'ed to nsIClassInfo.  (You can see this in
+ * NS_IMPL_QUERY_CLASSINFO below.)
+ *
+ * This hack breaks XPCOM's rules, since if you take an instance of nsFooBar,
+ * QI it to nsIClassInfo, and then try to QI to nsIFoo, that will fail.  On the
+ * upside, implementing nsIClassInfo doesn't add a vtable pointer to instances
+ * of your class.
+ *
+ * In principal, you can also implement nsIClassInfo by inheriting from the
+ * interface.  But some code expects that when it QI's an object to
+ * nsIClassInfo, it gets back a singleton which isn't attached to any
+ * particular object.  If a class were to implement nsIClassInfo through
+ * inheritance, that code might QI to nsIClassInfo and keep the resulting
+ * object alive, thinking it was only keeping alive the classinfo singleton,
+ * but in fact keeping a whole instance of the class alive.  See, e.g., bug
+ * 658632.
+ *
+ * Unless you specifically need to have a different nsIClassInfo instance for
+ * each instance of your class, you should probably just implement nsIClassInfo
+ * as a singleton.
+ */
+
 class NS_COM_GLUE GenericClassInfo : public nsIClassInfo
 {
 public:
   struct ClassInfoData
   {
     typedef NS_CALLBACK(GetInterfacesProc)(PRUint32* NS_OUTPARAM countp,
                                            nsIID*** NS_OUTPARAM array);
     typedef NS_CALLBACK(GetLanguageHelperProc)(PRUint32 language,