xpcom/glue/nsIClassInfoImpl.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #ifndef nsIClassInfoImpl_h__
michael@0 6 #define nsIClassInfoImpl_h__
michael@0 7
michael@0 8 #include "mozilla/Alignment.h"
michael@0 9 #include "mozilla/Assertions.h"
michael@0 10 #include "mozilla/MacroArgs.h"
michael@0 11 #include "mozilla/MacroForEach.h"
michael@0 12 #include "nsIClassInfo.h"
michael@0 13 #include "nsISupportsImpl.h"
michael@0 14
michael@0 15 #include <new>
michael@0 16
michael@0 17 /**
michael@0 18 * This header file provides macros which help you make your class implement
michael@0 19 * nsIClassInfo. Implementing nsIClassInfo is particularly helpful if you have
michael@0 20 * a C++ class which implements multiple interfaces and which you access from
michael@0 21 * JavaScript. If that class implements nsIClassInfo, the JavaScript code
michael@0 22 * won't have to call QueryInterface on instances of the class; all methods
michael@0 23 * from all interfaces returned by GetInterfaces() will be available
michael@0 24 * automagically.
michael@0 25 *
michael@0 26 * Here's all you need to do. Given a class
michael@0 27 *
michael@0 28 * class nsFooBar : public nsIFoo, public nsIBar { };
michael@0 29 *
michael@0 30 * you should already have the following nsISupports implementation in its cpp
michael@0 31 * file:
michael@0 32 *
michael@0 33 * NS_IMPL_ISUPPORTS(nsFooBar, nsIFoo, nsIBar).
michael@0 34 *
michael@0 35 * Change this to
michael@0 36 *
michael@0 37 * NS_IMPL_CLASSINFO(nsFooBar, nullptr, 0, NS_FOOBAR_CID)
michael@0 38 * NS_IMPL_ISUPPORTS_CI(nsFooBar, nsIFoo, nsIBar)
michael@0 39 *
michael@0 40 * If nsFooBar is threadsafe, change the 0 above to nsIClassInfo::THREADSAFE.
michael@0 41 * If it's a singleton, use nsIClassInfo::SINGLETON. The full list of flags is
michael@0 42 * in nsIClassInfo.idl.
michael@0 43 *
michael@0 44 * The nullptr parameter is there so you can pass a function for converting
michael@0 45 * from an XPCOM object to a scriptable helper. Unless you're doing
michael@0 46 * specialized JS work, you can probably leave this as nullptr.
michael@0 47 *
michael@0 48 * This file also defines the NS_IMPL_QUERY_INTERFACE_CI macro, which you can
michael@0 49 * use to replace NS_IMPL_QUERY_INTERFACE, if you use that instead of
michael@0 50 * NS_IMPL_ISUPPORTS.
michael@0 51 *
michael@0 52 * That's it! The rest is gory details.
michael@0 53 *
michael@0 54 *
michael@0 55 * Notice that nsFooBar didn't need to inherit from nsIClassInfo in order to
michael@0 56 * "implement" it. However, after adding these macros to nsFooBar, you you can
michael@0 57 * QueryInterface an instance of nsFooBar to nsIClassInfo. How can this be?
michael@0 58 *
michael@0 59 * The answer lies in the NS_IMPL_ISUPPORTS_CI macro. It modifies nsFooBar's
michael@0 60 * QueryInterface implementation such that, if we ask to QI to nsIClassInfo, it
michael@0 61 * returns a singleton object associated with the class. (That singleton is
michael@0 62 * defined by NS_IMPL_CLASSINFO.) So all nsFooBar instances will return the
michael@0 63 * same object when QI'ed to nsIClassInfo. (You can see this in
michael@0 64 * NS_IMPL_QUERY_CLASSINFO below.)
michael@0 65 *
michael@0 66 * This hack breaks XPCOM's rules, since if you take an instance of nsFooBar,
michael@0 67 * QI it to nsIClassInfo, and then try to QI to nsIFoo, that will fail. On the
michael@0 68 * upside, implementing nsIClassInfo doesn't add a vtable pointer to instances
michael@0 69 * of your class.
michael@0 70 *
michael@0 71 * In principal, you can also implement nsIClassInfo by inheriting from the
michael@0 72 * interface. But some code expects that when it QI's an object to
michael@0 73 * nsIClassInfo, it gets back a singleton which isn't attached to any
michael@0 74 * particular object. If a class were to implement nsIClassInfo through
michael@0 75 * inheritance, that code might QI to nsIClassInfo and keep the resulting
michael@0 76 * object alive, thinking it was only keeping alive the classinfo singleton,
michael@0 77 * but in fact keeping a whole instance of the class alive. See, e.g., bug
michael@0 78 * 658632.
michael@0 79 *
michael@0 80 * Unless you specifically need to have a different nsIClassInfo instance for
michael@0 81 * each instance of your class, you should probably just implement nsIClassInfo
michael@0 82 * as a singleton.
michael@0 83 */
michael@0 84
michael@0 85 class NS_COM_GLUE GenericClassInfo : public nsIClassInfo
michael@0 86 {
michael@0 87 public:
michael@0 88 struct ClassInfoData
michael@0 89 {
michael@0 90 typedef NS_CALLBACK(GetInterfacesProc)(uint32_t* countp,
michael@0 91 nsIID*** array);
michael@0 92 typedef NS_CALLBACK(GetLanguageHelperProc)(uint32_t language,
michael@0 93 nsISupports** helper);
michael@0 94
michael@0 95 GetInterfacesProc getinterfaces;
michael@0 96 GetLanguageHelperProc getlanguagehelper;
michael@0 97 uint32_t flags;
michael@0 98 nsCID cid;
michael@0 99 };
michael@0 100
michael@0 101 NS_DECL_ISUPPORTS_INHERITED
michael@0 102 NS_DECL_NSICLASSINFO
michael@0 103
michael@0 104 GenericClassInfo(const ClassInfoData* data)
michael@0 105 : mData(data)
michael@0 106 { }
michael@0 107
michael@0 108 private:
michael@0 109 const ClassInfoData* mData;
michael@0 110 };
michael@0 111
michael@0 112 #define NS_CLASSINFO_NAME(_class) g##_class##_classInfoGlobal
michael@0 113 #define NS_CI_INTERFACE_GETTER_NAME(_class) _class##_GetInterfacesHelper
michael@0 114 #define NS_DECL_CI_INTERFACE_GETTER(_class) \
michael@0 115 extern NS_IMETHODIMP NS_CI_INTERFACE_GETTER_NAME(_class) \
michael@0 116 (uint32_t *, nsIID ***);
michael@0 117
michael@0 118 #define NS_IMPL_CLASSINFO(_class, _getlanguagehelper, _flags, _cid) \
michael@0 119 NS_DECL_CI_INTERFACE_GETTER(_class) \
michael@0 120 static const GenericClassInfo::ClassInfoData k##_class##ClassInfoData = { \
michael@0 121 NS_CI_INTERFACE_GETTER_NAME(_class), \
michael@0 122 _getlanguagehelper, \
michael@0 123 _flags | nsIClassInfo::SINGLETON_CLASSINFO, \
michael@0 124 _cid, \
michael@0 125 }; \
michael@0 126 mozilla::AlignedStorage2<GenericClassInfo> k##_class##ClassInfoDataPlace; \
michael@0 127 nsIClassInfo* NS_CLASSINFO_NAME(_class) = nullptr;
michael@0 128
michael@0 129 #define NS_IMPL_QUERY_CLASSINFO(_class) \
michael@0 130 if ( aIID.Equals(NS_GET_IID(nsIClassInfo)) ) { \
michael@0 131 if (!NS_CLASSINFO_NAME(_class)) \
michael@0 132 NS_CLASSINFO_NAME(_class) = new (k##_class##ClassInfoDataPlace.addr()) \
michael@0 133 GenericClassInfo(&k##_class##ClassInfoData); \
michael@0 134 foundInterface = NS_CLASSINFO_NAME(_class); \
michael@0 135 } else
michael@0 136
michael@0 137 #define NS_CLASSINFO_HELPER_BEGIN(_class, _c) \
michael@0 138 NS_IMETHODIMP \
michael@0 139 NS_CI_INTERFACE_GETTER_NAME(_class)(uint32_t *count, nsIID ***array) \
michael@0 140 { \
michael@0 141 *count = _c; \
michael@0 142 *array = (nsIID **)nsMemory::Alloc(sizeof (nsIID *) * _c); \
michael@0 143 uint32_t i = 0;
michael@0 144
michael@0 145 #define NS_CLASSINFO_HELPER_ENTRY(_interface) \
michael@0 146 (*array)[i++] = (nsIID*)nsMemory::Clone(&NS_GET_IID(_interface), \
michael@0 147 sizeof(nsIID));
michael@0 148
michael@0 149 #define NS_CLASSINFO_HELPER_END \
michael@0 150 MOZ_ASSERT(i == *count, "Incorrent number of entries"); \
michael@0 151 return NS_OK; \
michael@0 152 }
michael@0 153
michael@0 154 #define NS_IMPL_CI_INTERFACE_GETTER(aClass, ...) \
michael@0 155 MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \
michael@0 156 NS_CLASSINFO_HELPER_BEGIN(aClass, \
michael@0 157 MOZ_PASTE_PREFIX_AND_ARG_COUNT(/* No prefix */, \
michael@0 158 __VA_ARGS__)) \
michael@0 159 MOZ_FOR_EACH(NS_CLASSINFO_HELPER_ENTRY, (), (__VA_ARGS__)) \
michael@0 160 NS_CLASSINFO_HELPER_END
michael@0 161
michael@0 162 #define NS_IMPL_QUERY_INTERFACE_CI(aClass, ...) \
michael@0 163 MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \
michael@0 164 NS_INTERFACE_MAP_BEGIN(aClass) \
michael@0 165 MOZ_FOR_EACH(NS_INTERFACE_MAP_ENTRY, (), (__VA_ARGS__)) \
michael@0 166 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, MOZ_ARG_1(__VA_ARGS__)) \
michael@0 167 NS_IMPL_QUERY_CLASSINFO(aClass) \
michael@0 168 NS_INTERFACE_MAP_END
michael@0 169
michael@0 170 #define NS_IMPL_ISUPPORTS_CI(aClass, ...) \
michael@0 171 NS_IMPL_ADDREF(aClass) \
michael@0 172 NS_IMPL_RELEASE(aClass) \
michael@0 173 NS_IMPL_QUERY_INTERFACE_CI(aClass, __VA_ARGS__) \
michael@0 174 NS_IMPL_CI_INTERFACE_GETTER(aClass, __VA_ARGS__)
michael@0 175
michael@0 176 #endif // nsIClassInfoImpl_h__

mercurial