1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_mscom_Ptr_h
8 #define mozilla_mscom_Ptr_h
10 #include "mozilla/Assertions.h"
11 #include "mozilla/DebugOnly.h"
12 #include "mozilla/mscom/EnsureMTA.h"
13 #include "mozilla/SchedulerGroup.h"
14 #include "mozilla/UniquePtr.h"
16 #include "nsThreadUtils.h"
17 #include "nsXULAppAPI.h"
22 * The glue code in mozilla::mscom often needs to pass around interface pointers
23 * belonging to a different apartment from the current one. We must not touch
24 * the reference counts of those objects on the wrong apartment. By using these
25 * UniquePtr specializations, we may ensure that the reference counts are always
35 struct MainThreadRelease
{
36 void operator()(T
* aPtr
) {
40 if (NS_IsMainThread()) {
44 DebugOnly
<nsresult
> rv
= SchedulerGroup::Dispatch(
46 NewNonOwningRunnableMethod("mscom::MainThreadRelease", aPtr
,
48 MOZ_ASSERT(NS_SUCCEEDED(rv
));
54 void operator()(T
* aPtr
) {
59 EnsureMTA::AsyncOperation([aPtr
]() -> void { delete aPtr
; });
65 void operator()(T
* aPtr
) {
70 // Static analysis doesn't recognize that, even though aPtr escapes the
71 // current scope, we are in effect moving our strong ref into the lambda.
73 EnsureMTA::AsyncOperation(
74 [ptr
]() -> void { reinterpret_cast<T
*>(ptr
)->Release(); });
79 struct MTAReleaseInChildProcess
{
80 void operator()(T
* aPtr
) {
85 if (XRE_IsParentProcess()) {
86 MOZ_ASSERT(NS_IsMainThread());
91 // Static analysis doesn't recognize that, even though aPtr escapes the
92 // current scope, we are in effect moving our strong ref into the lambda.
94 EnsureMTA::AsyncOperation(
95 [ptr
]() -> void { reinterpret_cast<T
*>(ptr
)->Release(); });
99 struct InterceptorTargetDeleter
{
100 void operator()(IUnknown
* aPtr
) {
101 // We intentionally do not touch the refcounts of interceptor targets!
105 struct PreservedStreamDeleter
{
106 void operator()(IStream
* aPtr
) {
111 // Static analysis doesn't recognize that, even though aPtr escapes the
112 // current scope, we are in effect moving our strong ref into the lambda.
114 auto cleanup
= [ptr
]() -> void {
115 DebugOnly
<HRESULT
> hr
=
116 ::CoReleaseMarshalData(reinterpret_cast<LPSTREAM
>(ptr
));
117 MOZ_ASSERT(SUCCEEDED(hr
));
118 reinterpret_cast<LPSTREAM
>(ptr
)->Release();
121 if (XRE_IsParentProcess()) {
122 MOZ_ASSERT(NS_IsMainThread());
127 EnsureMTA::AsyncOperation(cleanup
);
131 } // namespace detail
133 template <typename T
>
134 using STAUniquePtr
= mozilla::UniquePtr
<T
, detail::MainThreadRelease
<T
>>;
136 template <typename T
>
137 using MTAUniquePtr
= mozilla::UniquePtr
<T
, detail::MTARelease
<T
>>;
139 template <typename T
>
140 using MTADeletePtr
= mozilla::UniquePtr
<T
, detail::MTADelete
<T
>>;
142 template <typename T
>
143 using ProxyUniquePtr
=
144 mozilla::UniquePtr
<T
, detail::MTAReleaseInChildProcess
<T
>>;
146 template <typename T
>
147 using InterceptorTargetPtr
=
148 mozilla::UniquePtr
<T
, detail::InterceptorTargetDeleter
>;
150 using PreservedStreamPtr
=
151 mozilla::UniquePtr
<IStream
, detail::PreservedStreamDeleter
>;
155 // We don't have direct access to UniquePtr's storage, so we use mPtrStorage
156 // to receive the pointer and then set the target inside the destructor.
157 template <typename T
, typename Deleter
>
158 class UniquePtrGetterAddRefs
{
160 explicit UniquePtrGetterAddRefs(UniquePtr
<T
, Deleter
>& aSmartPtr
)
161 : mTargetSmartPtr(aSmartPtr
), mPtrStorage(nullptr) {}
163 ~UniquePtrGetterAddRefs() { mTargetSmartPtr
.reset(mPtrStorage
); }
165 operator void**() { return reinterpret_cast<void**>(&mPtrStorage
); }
167 operator T
**() { return &mPtrStorage
; }
169 T
*& operator*() { return mPtrStorage
; }
172 UniquePtr
<T
, Deleter
>& mTargetSmartPtr
;
176 } // namespace detail
178 template <typename T
>
179 inline STAUniquePtr
<T
> ToSTAUniquePtr(RefPtr
<T
>&& aRefPtr
) {
180 return STAUniquePtr
<T
>(aRefPtr
.forget().take());
183 template <typename T
>
184 inline STAUniquePtr
<T
> ToSTAUniquePtr(const RefPtr
<T
>& aRefPtr
) {
185 MOZ_ASSERT(NS_IsMainThread());
186 return STAUniquePtr
<T
>(do_AddRef(aRefPtr
).take());
189 template <typename T
>
190 inline STAUniquePtr
<T
> ToSTAUniquePtr(T
* aRawPtr
) {
191 MOZ_ASSERT(NS_IsMainThread());
195 return STAUniquePtr
<T
>(aRawPtr
);
198 template <typename T
, typename U
>
199 inline STAUniquePtr
<T
> ToSTAUniquePtr(const InterceptorTargetPtr
<U
>& aTarget
) {
200 MOZ_ASSERT(NS_IsMainThread());
201 RefPtr
<T
> newRef(static_cast<T
*>(aTarget
.get()));
202 return ToSTAUniquePtr(std::move(newRef
));
205 template <typename T
>
206 inline MTAUniquePtr
<T
> ToMTAUniquePtr(RefPtr
<T
>&& aRefPtr
) {
207 return MTAUniquePtr
<T
>(aRefPtr
.forget().take());
210 template <typename T
>
211 inline MTAUniquePtr
<T
> ToMTAUniquePtr(const RefPtr
<T
>& aRefPtr
) {
212 MOZ_ASSERT(IsCurrentThreadMTA());
213 return MTAUniquePtr
<T
>(do_AddRef(aRefPtr
).take());
216 template <typename T
>
217 inline MTAUniquePtr
<T
> ToMTAUniquePtr(T
* aRawPtr
) {
218 MOZ_ASSERT(IsCurrentThreadMTA());
222 return MTAUniquePtr
<T
>(aRawPtr
);
225 template <typename T
>
226 inline ProxyUniquePtr
<T
> ToProxyUniquePtr(RefPtr
<T
>&& aRefPtr
) {
227 return ProxyUniquePtr
<T
>(aRefPtr
.forget().take());
230 template <typename T
>
231 inline ProxyUniquePtr
<T
> ToProxyUniquePtr(const RefPtr
<T
>& aRefPtr
) {
232 MOZ_ASSERT(IsProxy(aRefPtr
));
233 MOZ_ASSERT((XRE_IsParentProcess() && NS_IsMainThread()) ||
234 (XRE_IsContentProcess() && IsCurrentThreadMTA()));
236 return ProxyUniquePtr
<T
>(do_AddRef(aRefPtr
).take());
239 template <typename T
>
240 inline ProxyUniquePtr
<T
> ToProxyUniquePtr(T
* aRawPtr
) {
241 MOZ_ASSERT(IsProxy(aRawPtr
));
242 MOZ_ASSERT((XRE_IsParentProcess() && NS_IsMainThread()) ||
243 (XRE_IsContentProcess() && IsCurrentThreadMTA()));
248 return ProxyUniquePtr
<T
>(aRawPtr
);
251 template <typename T
, typename Deleter
>
252 inline InterceptorTargetPtr
<T
> ToInterceptorTargetPtr(
253 const UniquePtr
<T
, Deleter
>& aTargetPtr
) {
254 return InterceptorTargetPtr
<T
>(aTargetPtr
.get());
257 inline PreservedStreamPtr
ToPreservedStreamPtr(RefPtr
<IStream
>&& aStream
) {
258 return PreservedStreamPtr(aStream
.forget().take());
261 inline PreservedStreamPtr
ToPreservedStreamPtr(
262 already_AddRefed
<IStream
>& aStream
) {
263 return PreservedStreamPtr(aStream
.take());
266 template <typename T
, typename Deleter
>
267 inline detail::UniquePtrGetterAddRefs
<T
, Deleter
> getter_AddRefs(
268 UniquePtr
<T
, Deleter
>& aSmartPtr
) {
269 return detail::UniquePtrGetterAddRefs
<T
, Deleter
>(aSmartPtr
);
273 } // namespace mozilla
275 // This block makes it possible for these smart pointers to be correctly
276 // applied in NewRunnableMethod and friends
279 template <typename T
>
280 struct SmartPointerStorageClass
<mozilla::mscom::STAUniquePtr
<T
>> {
281 typedef StoreCopyPassByRRef
<mozilla::mscom::STAUniquePtr
<T
>> Type
;
284 template <typename T
>
285 struct SmartPointerStorageClass
<mozilla::mscom::MTAUniquePtr
<T
>> {
286 typedef StoreCopyPassByRRef
<mozilla::mscom::MTAUniquePtr
<T
>> Type
;
289 template <typename T
>
290 struct SmartPointerStorageClass
<mozilla::mscom::ProxyUniquePtr
<T
>> {
291 typedef StoreCopyPassByRRef
<mozilla::mscom::ProxyUniquePtr
<T
>> Type
;
294 template <typename T
>
295 struct SmartPointerStorageClass
<mozilla::mscom::InterceptorTargetPtr
<T
>> {
296 typedef StoreCopyPassByRRef
<mozilla::mscom::InterceptorTargetPtr
<T
>> Type
;
300 struct SmartPointerStorageClass
<mozilla::mscom::PreservedStreamPtr
> {
301 typedef StoreCopyPassByRRef
<mozilla::mscom::PreservedStreamPtr
> Type
;
304 } // namespace detail
306 #endif // mozilla_mscom_Ptr_h