1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/base/nsAgg.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,331 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef nsAgg_h___ 1.10 +#define nsAgg_h___ 1.11 + 1.12 +#include "nsISupports.h" 1.13 +#include "nsCycleCollectionParticipant.h" 1.14 + 1.15 + 1.16 +//////////////////////////////////////////////////////////////////////////////// 1.17 + 1.18 +// Put NS_DECL_AGGREGATED or NS_DECL_CYCLE_COLLECTING_AGGREGATED in your class's 1.19 +// declaration. 1.20 +#define NS_DECL_AGGREGATED \ 1.21 + NS_DECL_ISUPPORTS \ 1.22 + NS_DECL_AGGREGATED_HELPER 1.23 + 1.24 +#define NS_DECL_CYCLE_COLLECTING_AGGREGATED \ 1.25 + NS_DECL_CYCLE_COLLECTING_ISUPPORTS \ 1.26 + NS_DECL_AGGREGATED_HELPER 1.27 + 1.28 +#define NS_DECL_AGGREGATED_HELPER \ 1.29 +public: \ 1.30 + \ 1.31 + /** \ 1.32 + * Returns the nsISupports pointer of the inner object (aka the \ 1.33 + * aggregatee). This pointer is really only useful to the outer object \ 1.34 + * (aka the aggregator), which can use it to hold on to the inner \ 1.35 + * object. Anything else wants the nsISupports pointer of the outer \ 1.36 + * object (gotten by QI'ing inner or outer to nsISupports). This method \ 1.37 + * returns a non-addrefed pointer. \ 1.38 + * @return the nsISupports pointer of the inner object \ 1.39 + */ \ 1.40 + nsISupports* InnerObject(void) { return &fAggregated; } \ 1.41 + \ 1.42 + /** \ 1.43 + * Returns true if this object is part of an aggregated object. \ 1.44 + */ \ 1.45 + bool IsPartOfAggregated(void) { return fOuter != InnerObject(); } \ 1.46 + \ 1.47 +private: \ 1.48 + \ 1.49 + /* You must implement this operation instead of the nsISupports */ \ 1.50 + /* methods. */ \ 1.51 + nsresult \ 1.52 + AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr); \ 1.53 + \ 1.54 + class Internal : public nsISupports { \ 1.55 + public: \ 1.56 + \ 1.57 + Internal() {} \ 1.58 + \ 1.59 + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); \ 1.60 + NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ 1.61 + NS_IMETHOD_(MozExternalRefCountType) Release(void); \ 1.62 + \ 1.63 + NS_DECL_OWNINGTHREAD \ 1.64 + }; \ 1.65 + \ 1.66 + friend class Internal; \ 1.67 + \ 1.68 + nsISupports* fOuter; \ 1.69 + Internal fAggregated; \ 1.70 + \ 1.71 +public: \ 1.72 + 1.73 +#define NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(_class) \ 1.74 +class NS_CYCLE_COLLECTION_INNERCLASS \ 1.75 + : public nsXPCOMCycleCollectionParticipant \ 1.76 +{ \ 1.77 +public: \ 1.78 + NS_IMETHOD_(void) Unlink(void *p); \ 1.79 + NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb); \ 1.80 + NS_IMETHOD_(void) DeleteCycleCollectable(void* p) \ 1.81 + { \ 1.82 + NS_CYCLE_COLLECTION_CLASSNAME(_class):: \ 1.83 + Downcast(static_cast<nsISupports*>(p))->DeleteCycleCollectable(); \ 1.84 + } \ 1.85 + static _class* Downcast(nsISupports* s) \ 1.86 + { \ 1.87 + return (_class*)((char*)(s) - offsetof(_class, fAggregated)); \ 1.88 + } \ 1.89 + static nsISupports* Upcast(_class *p) \ 1.90 + { \ 1.91 + return p->InnerObject(); \ 1.92 + } \ 1.93 + static nsXPCOMCycleCollectionParticipant* GetParticipant() \ 1.94 + { \ 1.95 + return &_class::NS_CYCLE_COLLECTION_INNERNAME; \ 1.96 + } \ 1.97 +}; \ 1.98 +NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class); \ 1.99 +static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; 1.100 + 1.101 +// Put this in your class's constructor: 1.102 +#define NS_INIT_AGGREGATED(outer) \ 1.103 + PR_BEGIN_MACRO \ 1.104 + fOuter = outer ? outer : &fAggregated; \ 1.105 + PR_END_MACRO 1.106 + 1.107 + 1.108 +// Put this in your class's implementation file: 1.109 +#define NS_IMPL_AGGREGATED(_class) \ 1.110 + \ 1.111 +NS_IMPL_AGGREGATED_HELPER(_class) \ 1.112 + \ 1.113 +NS_IMETHODIMP_(MozExternalRefCountType) \ 1.114 +_class::Internal::AddRef(void) \ 1.115 +{ \ 1.116 + _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ 1.117 + MOZ_ASSERT(int32_t(agg->mRefCnt) >= 0, "illegal refcnt"); \ 1.118 + NS_ASSERT_OWNINGTHREAD(_class); \ 1.119 + ++agg->mRefCnt; \ 1.120 + NS_LOG_ADDREF(this, agg->mRefCnt, #_class, sizeof(*this)); \ 1.121 + return agg->mRefCnt; \ 1.122 +} \ 1.123 + \ 1.124 +NS_IMETHODIMP_(MozExternalRefCountType) \ 1.125 +_class::Internal::Release(void) \ 1.126 +{ \ 1.127 + _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ 1.128 + MOZ_ASSERT(int32_t(agg->mRefCnt) > 0, "dup release"); \ 1.129 + NS_ASSERT_OWNINGTHREAD(_class); \ 1.130 + --agg->mRefCnt; \ 1.131 + NS_LOG_RELEASE(this, agg->mRefCnt, #_class); \ 1.132 + if (agg->mRefCnt == 0) { \ 1.133 + agg->mRefCnt = 1; /* stabilize */ \ 1.134 + delete agg; \ 1.135 + return 0; \ 1.136 + } \ 1.137 + return agg->mRefCnt; \ 1.138 +} \ 1.139 + 1.140 +#define NS_IMPL_CYCLE_COLLECTING_AGGREGATED(_class) \ 1.141 + \ 1.142 +NS_IMPL_AGGREGATED_HELPER(_class) \ 1.143 + \ 1.144 +NS_IMETHODIMP_(MozExternalRefCountType) \ 1.145 +_class::Internal::AddRef(void) \ 1.146 +{ \ 1.147 + _class* agg = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Downcast(this); \ 1.148 + MOZ_ASSERT(int32_t(agg->mRefCnt) >= 0, "illegal refcnt"); \ 1.149 + NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class); \ 1.150 + nsrefcnt count = agg->mRefCnt.incr(this); \ 1.151 + NS_LOG_ADDREF(this, count, #_class, sizeof(*agg)); \ 1.152 + return count; \ 1.153 +} \ 1.154 +NS_IMETHODIMP_(MozExternalRefCountType) \ 1.155 +_class::Internal::Release(void) \ 1.156 +{ \ 1.157 + _class* agg = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Downcast(this); \ 1.158 + MOZ_ASSERT(int32_t(agg->mRefCnt) > 0, "dup release"); \ 1.159 + NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class); \ 1.160 + nsrefcnt count = agg->mRefCnt.decr(this); \ 1.161 + NS_LOG_RELEASE(this, count, #_class); \ 1.162 + return count; \ 1.163 +} \ 1.164 +NS_IMETHODIMP_(void) \ 1.165 +_class::DeleteCycleCollectable(void) \ 1.166 +{ \ 1.167 + delete this; \ 1.168 +} 1.169 + 1.170 +#define NS_IMPL_AGGREGATED_HELPER(_class) \ 1.171 +NS_IMETHODIMP \ 1.172 +_class::QueryInterface(const nsIID& aIID, void** aInstancePtr) \ 1.173 +{ \ 1.174 + return fOuter->QueryInterface(aIID, aInstancePtr); \ 1.175 +} \ 1.176 + \ 1.177 +NS_IMETHODIMP_(MozExternalRefCountType) \ 1.178 +_class::AddRef(void) \ 1.179 +{ \ 1.180 + return fOuter->AddRef(); \ 1.181 +} \ 1.182 + \ 1.183 +NS_IMETHODIMP_(MozExternalRefCountType) \ 1.184 +_class::Release(void) \ 1.185 +{ \ 1.186 + return fOuter->Release(); \ 1.187 +} \ 1.188 + \ 1.189 +NS_IMETHODIMP \ 1.190 +_class::Internal::QueryInterface(const nsIID& aIID, void** aInstancePtr) \ 1.191 +{ \ 1.192 + _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ 1.193 + return agg->AggregatedQueryInterface(aIID, aInstancePtr); \ 1.194 +} \ 1.195 + 1.196 +/** 1.197 + * To make aggregated objects participate in cycle collection we need to enable 1.198 + * the outer object (aggregator) to traverse/unlink the objects held by the 1.199 + * inner object (the aggregatee). We can't just make the inner object QI'able to 1.200 + * NS_CYCLECOLLECTIONPARTICIPANT_IID, we don't want to return the inner object's 1.201 + * nsCycleCollectionParticipant for the outer object (which will happen if the 1.202 + * outer object doesn't participate in cycle collection itself). 1.203 + * NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID enables the outer object to get 1.204 + * the inner objects nsCycleCollectionParticipant. 1.205 + * 1.206 + * There are three cases: 1.207 + * - No aggregation 1.208 + * QI'ing to NS_CYCLECOLLECTIONPARTICIPANT_IID will return the inner 1.209 + * object's nsCycleCollectionParticipant. 1.210 + * 1.211 + * - Aggregation and outer object does not participate in cycle collection 1.212 + * QI'ing to NS_CYCLECOLLECTIONPARTICIPANT_IID will not return anything. 1.213 + * 1.214 + * - Aggregation and outer object does participate in cycle collection 1.215 + * QI'ing to NS_CYCLECOLLECTIONPARTICIPANT_IID will return the outer 1.216 + * object's nsCycleCollectionParticipant. The outer object's 1.217 + * nsCycleCollectionParticipant can then QI the inner object to 1.218 + * NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID to get the inner object's 1.219 + * nsCycleCollectionParticipant, which it can use to traverse/unlink the 1.220 + * objects reachable from the inner object. 1.221 + */ 1.222 +#define NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID \ 1.223 +{ \ 1.224 + 0x32889b7e, \ 1.225 + 0xe4fe, \ 1.226 + 0x43f4, \ 1.227 + { 0x85, 0x31, 0xb5, 0x28, 0x23, 0xa2, 0xe9, 0xfc } \ 1.228 +} 1.229 + 1.230 +/** 1.231 + * Just holds the IID so NS_GET_IID works. 1.232 + */ 1.233 +class nsAggregatedCycleCollectionParticipant 1.234 +{ 1.235 +public: 1.236 + NS_DECLARE_STATIC_IID_ACCESSOR(NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID) 1.237 +}; 1.238 + 1.239 +NS_DEFINE_STATIC_IID_ACCESSOR(nsAggregatedCycleCollectionParticipant, 1.240 + NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID) 1.241 + 1.242 +// for use with QI macros in nsISupportsUtils.h: 1.243 + 1.244 +#define NS_INTERFACE_MAP_BEGIN_AGGREGATED(_class) \ 1.245 + NS_IMPL_AGGREGATED_QUERY_HEAD(_class) 1.246 + 1.247 +#define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_AGGREGATED(_class) \ 1.248 + NS_IMPL_QUERY_CYCLE_COLLECTION(_class) 1.249 + 1.250 +#define NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(_class) \ 1.251 + NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_AGGREGATED(_class) \ 1.252 + NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class) 1.253 + 1.254 +#define NS_IMPL_AGGREGATED_QUERY_HEAD(_class) \ 1.255 +nsresult \ 1.256 +_class::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr) \ 1.257 +{ \ 1.258 + NS_ASSERTION(aInstancePtr, \ 1.259 + "AggregatedQueryInterface requires a non-NULL result ptr!"); \ 1.260 + if ( !aInstancePtr ) \ 1.261 + return NS_ERROR_NULL_POINTER; \ 1.262 + nsISupports* foundInterface; \ 1.263 + if ( aIID.Equals(NS_GET_IID(nsISupports)) ) \ 1.264 + foundInterface = InnerObject(); \ 1.265 + else 1.266 + 1.267 +#define NS_IMPL_AGGREGATED_QUERY_CYCLE_COLLECTION(_class) \ 1.268 + if (aIID.Equals(IsPartOfAggregated() ? \ 1.269 + NS_GET_IID(nsCycleCollectionParticipant) : \ 1.270 + NS_GET_IID(nsAggregatedCycleCollectionParticipant))) \ 1.271 + foundInterface = NS_CYCLE_COLLECTION_PARTICIPANT(_class); \ 1.272 + else 1.273 + 1.274 +#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(_class) \ 1.275 + NS_IMETHODIMP \ 1.276 + NS_CYCLE_COLLECTION_CLASSNAME(_class)::Traverse \ 1.277 + (void *p, nsCycleCollectionTraversalCallback &cb) \ 1.278 + { \ 1.279 + nsISupports *s = static_cast<nsISupports*>(p); \ 1.280 + MOZ_ASSERT(CheckForRightISupports(s), \ 1.281 + "not the nsISupports pointer we expect"); \ 1.282 + _class *tmp = static_cast<_class*>(Downcast(s)); \ 1.283 + if (!tmp->IsPartOfAggregated()) \ 1.284 + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, tmp->mRefCnt.get()) 1.285 + 1.286 +#define NS_GENERIC_AGGREGATED_CONSTRUCTOR(_InstanceClass) \ 1.287 +static nsresult \ 1.288 +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ 1.289 + void **aResult) \ 1.290 +{ \ 1.291 + *aResult = nullptr; \ 1.292 + if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports)))) \ 1.293 + return NS_ERROR_INVALID_ARG; \ 1.294 + \ 1.295 + _InstanceClass* inst = new _InstanceClass(aOuter); \ 1.296 + if (!inst) { \ 1.297 + return NS_ERROR_OUT_OF_MEMORY; \ 1.298 + } \ 1.299 + \ 1.300 + nsISupports* inner = inst->InnerObject(); \ 1.301 + nsresult rv = inner->QueryInterface(aIID, aResult); \ 1.302 + if (NS_FAILED(rv)) { \ 1.303 + delete inst; \ 1.304 + } \ 1.305 + \ 1.306 + return rv; \ 1.307 +} \ 1.308 + 1.309 +#define NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT(_InstanceClass, _InitMethod) \ 1.310 +static nsresult \ 1.311 +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ 1.312 + void **aResult) \ 1.313 +{ \ 1.314 + *aResult = nullptr; \ 1.315 + if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports)))) \ 1.316 + return NS_ERROR_INVALID_ARG; \ 1.317 + \ 1.318 + _InstanceClass* inst = new _InstanceClass(aOuter); \ 1.319 + if (!inst) { \ 1.320 + return NS_ERROR_OUT_OF_MEMORY; \ 1.321 + } \ 1.322 + \ 1.323 + nsISupports* inner = inst->InnerObject(); \ 1.324 + NS_ADDREF(inner); \ 1.325 + nsresult rv = inst->_InitMethod(); \ 1.326 + if (NS_SUCCEEDED(rv)) { \ 1.327 + rv = inner->QueryInterface(aIID, aResult); \ 1.328 + } \ 1.329 + NS_RELEASE(inner); \ 1.330 + \ 1.331 + return rv; \ 1.332 +} \ 1.333 + 1.334 +#endif /* nsAgg_h___ */