Bug 1812499 [wpt PR 38184] - Simplify handling of name-to-subdir mapping in canvas...
[gecko.git] / ipc / mscom / Ptr.h
blobfd4bd9c91ffc1040d0061303c693727b678fe14d
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"
15 #include "nsError.h"
16 #include "nsThreadUtils.h"
17 #include "nsXULAppAPI.h"
19 #include <objidl.h>
21 /**
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
26 * handled correctly.
29 namespace mozilla {
30 namespace mscom {
32 namespace detail {
34 template <typename T>
35 struct MainThreadRelease {
36 void operator()(T* aPtr) {
37 if (!aPtr) {
38 return;
40 if (NS_IsMainThread()) {
41 aPtr->Release();
42 return;
44 DebugOnly<nsresult> rv = SchedulerGroup::Dispatch(
45 TaskCategory::Other,
46 NewNonOwningRunnableMethod("mscom::MainThreadRelease", aPtr,
47 &T::Release));
48 MOZ_ASSERT(NS_SUCCEEDED(rv));
52 template <typename T>
53 struct MTADelete {
54 void operator()(T* aPtr) {
55 if (!aPtr) {
56 return;
59 EnsureMTA::AsyncOperation([aPtr]() -> void { delete aPtr; });
63 template <typename T>
64 struct MTARelease {
65 void operator()(T* aPtr) {
66 if (!aPtr) {
67 return;
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.
72 void* ptr = aPtr;
73 EnsureMTA::AsyncOperation(
74 [ptr]() -> void { reinterpret_cast<T*>(ptr)->Release(); });
78 template <typename T>
79 struct MTAReleaseInChildProcess {
80 void operator()(T* aPtr) {
81 if (!aPtr) {
82 return;
85 if (XRE_IsParentProcess()) {
86 MOZ_ASSERT(NS_IsMainThread());
87 aPtr->Release();
88 return;
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.
93 void* ptr = aPtr;
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) {
107 if (!aPtr) {
108 return;
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.
113 void* ptr = aPtr;
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());
123 cleanup();
124 return;
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>;
153 namespace detail {
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 {
159 public:
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; }
171 private:
172 UniquePtr<T, Deleter>& mTargetSmartPtr;
173 T* mPtrStorage;
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());
192 if (aRawPtr) {
193 aRawPtr->AddRef();
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());
219 if (aRawPtr) {
220 aRawPtr->AddRef();
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()));
245 if (aRawPtr) {
246 aRawPtr->AddRef();
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);
272 } // namespace mscom
273 } // namespace mozilla
275 // This block makes it possible for these smart pointers to be correctly
276 // applied in NewRunnableMethod and friends
277 namespace detail {
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;
299 template <>
300 struct SmartPointerStorageClass<mozilla::mscom::PreservedStreamPtr> {
301 typedef StoreCopyPassByRRef<mozilla::mscom::PreservedStreamPtr> Type;
304 } // namespace detail
306 #endif // mozilla_mscom_Ptr_h