diff --git a/accessible/android/SessionAccessibility.cpp b/accessible/android/SessionAccessibility.cpp index 4f31f8f01dc9..0a190dd62fe9 100644 --- a/accessible/android/SessionAccessibility.cpp +++ b/accessible/android/SessionAccessibility.cpp @@ -30,6 +30,7 @@ #include "mozilla/a11y/DocAccessiblePlatformExtParent.h" #include "mozilla/a11y/DocManager.h" #include "mozilla/jni/GeckoBundleUtils.h" +#include "mozilla/jni/NativesInlines.h" #include "mozilla/widget/GeckoViewSupport.h" #include "mozilla/MouseEvents.h" #include "mozilla/dom/MouseEventBinding.h" diff --git a/widget/android/GeckoEditableSupport.cpp b/widget/android/GeckoEditableSupport.cpp index 8c21a0ff7311..a728a6253eac 100644 --- a/widget/android/GeckoEditableSupport.cpp +++ b/widget/android/GeckoEditableSupport.cpp @@ -17,6 +17,7 @@ #include "mozilla/IMEStateManager.h" #include "mozilla/java/GeckoEditableChildWrappers.h" #include "mozilla/java/GeckoServiceChildProcessWrappers.h" +#include "mozilla/jni/NativesInlines.h" #include "mozilla/Logging.h" #include "mozilla/MiscEvents.h" #include "mozilla/Preferences.h" diff --git a/widget/android/jni/Natives.h b/widget/android/jni/Natives.h index d99567d1dfa2..45b351ba215c 100644 --- a/widget/android/jni/Natives.h +++ b/widget/android/jni/Natives.h @@ -44,6 +44,10 @@ static NativeException NullWeakPtr() { } namespace mozilla { + +template +class MozPromise; + namespace jni { /** @@ -623,71 +627,6 @@ class MOZ_HEAP_CLASS NativeWeakPtrControlBlock final { StorageType mNativeImpl; }; -/** - * When a NativeWeakPtr is detached from its owning Java object, the calling - * thread invokes the implementation's OnWeakNonIntrusiveDetach to perform - * cleanup. We complete the remainder of the cleanup sequence on the Gecko - * main thread by expecting OnWeakNonIntrusiveDetach implementations to invoke - * this Runnable before exiting. It will move itself to the main thread if it - * is not already there. - */ -template -class NativeWeakPtrDetachRunnable final : public Runnable { - public: - NativeWeakPtrDetachRunnable( - already_AddRefed> aCtlBlock, - const Object::LocalRef& aOwner, - typename NativeWeakPtrControlBlockStorageTraits::Type - aNativeImpl) - : Runnable("mozilla::jni::detail::NativeWeakPtrDetachRunnable"), - mCtlBlock(aCtlBlock), - mOwner(aOwner), - mNativeImpl(std::move(aNativeImpl)), - mHasRun(false) { - MOZ_RELEASE_ASSERT(!!mCtlBlock); - MOZ_RELEASE_ASSERT(!!mNativeImpl); - } - - NS_INLINE_DECL_REFCOUNTING_INHERITED(NativeWeakPtrDetachRunnable, Runnable) - - NS_IMETHOD Run() override { - mHasRun = true; - - if (!NS_IsMainThread()) { - NS_DispatchToMainThread(this); - return NS_OK; - } - - // Get the owner object's native implementation - auto owner = ToLocalRef(mOwner); - auto attachedNativeImpl = NativePtrTraits::Get(owner); - MOZ_RELEASE_ASSERT(!!attachedNativeImpl); - - // NativePtrTraits::ClearFinish cleans out the JNIObject's handle, which - // obviously we don't want to attempt unless that handle still points to - // our native implementation. - if (attachedNativeImpl->IsSame(mCtlBlock)) { - NativePtrTraits::ClearFinish(owner); - } - - // Now we destroy that native object. - mNativeImpl = nullptr; - return NS_OK; - } - - private: - ~NativeWeakPtrDetachRunnable() { - // Guard against somebody forgetting to call this runnable. - MOZ_RELEASE_ASSERT(mHasRun, "You must run/dispatch this runnable!"); - } - - private: - RefPtr> mCtlBlock; - Object::GlobalRef mOwner; - typename NativeWeakPtrControlBlockStorageTraits::Type mNativeImpl; - bool mHasRun; -}; - /** * If you want to temporarily access the object held by a NativeWeakPtr, you * must obtain one of these Accessor objects from the pointer. Access must @@ -755,6 +694,8 @@ class MOZ_STACK_CLASS Accessor final { } // namespace detail +using DetachPromise = mozilla::MozPromise; + /** * This class implements support for thread-safe weak pointers to native objects * that are owned by Java objects deriving from JNIObject. @@ -791,31 +732,7 @@ class NativeWeakPtr { * Detach the underlying object's strong reference from its owning Java object * and clean it up. */ - void Detach() { - if (!IsAttached()) { - // Never attached to begin with; no-op - return; - } - - auto native = mCtlBlock->Clear(); - if (!native) { - // Detach already in progress - return; - } - - Object::LocalRef owner(mCtlBlock->GetJavaOwner()); - MOZ_RELEASE_ASSERT(!!owner); - - // Save the raw pointer before we move native into the runnable so that we - // may call OnWeakNonIntrusiveDetach on it even after moving native into - // the runnable. - NativeImpl* rawImpl = - detail::NativeWeakPtrControlBlock::StorageTraits::AsRaw( - native); - rawImpl->OnWeakNonIntrusiveDetach( - do_AddRef(new NativeWeakPtrDetachRunnable( - mCtlBlock.forget(), owner, std::move(native)))); - } + RefPtr Detach(); /** * This method does not indicate whether or not the weak pointer is still diff --git a/widget/android/jni/NativesInlines.h b/widget/android/jni/NativesInlines.h new file mode 100644 index 000000000000..858b67771557 --- /dev/null +++ b/widget/android/jni/NativesInlines.h @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Natives.h" + +#include "mozilla/MozPromise.h" + +namespace mozilla::jni { + +namespace details { + +/** + * When a NativeWeakPtr is detached from its owning Java object, the calling + * thread invokes the implementation's OnWeakNonIntrusiveDetach to perform + * cleanup. We complete the remainder of the cleanup sequence on the Gecko + * main thread by expecting OnWeakNonIntrusiveDetach implementations to invoke + * this Runnable before exiting. It will move itself to the main thread if it + * is not already there. + */ +template +class NativeWeakPtrDetachRunnable final : public Runnable { + public: + NativeWeakPtrDetachRunnable( + already_AddRefed> aCtlBlock, + const Object::LocalRef& aOwner, + typename NativeWeakPtrControlBlockStorageTraits::Type + aNativeImpl) + : Runnable("mozilla::jni::detail::NativeWeakPtrDetachRunnable"), + mCtlBlock(aCtlBlock), + mOwner(aOwner), + mNativeImpl(std::move(aNativeImpl)), + mHasRun(false) { + MOZ_RELEASE_ASSERT(!!mCtlBlock); + MOZ_RELEASE_ASSERT(!!mNativeImpl); + } + + NS_INLINE_DECL_REFCOUNTING_INHERITED(NativeWeakPtrDetachRunnable, Runnable) + + NS_IMETHOD Run() override { + mHasRun = true; + + if (!NS_IsMainThread()) { + NS_DispatchToMainThread(this); + return NS_OK; + } + + // Get the owner object's native implementation + auto owner = ToLocalRef(mOwner); + auto attachedNativeImpl = NativePtrTraits::Get(owner); + MOZ_RELEASE_ASSERT(!!attachedNativeImpl); + + // NativePtrTraits::ClearFinish cleans out the JNIObject's handle, which + // obviously we don't want to attempt unless that handle still points to + // our native implementation. + if (attachedNativeImpl->IsSame(mCtlBlock)) { + NativePtrTraits::ClearFinish(owner); + } + + // Now we destroy that native object. + mNativeImpl = nullptr; + mHolder.Resolve(true, __func__); + return NS_OK; + } + + RefPtr GetPromise() { return mHolder.Ensure(__func__); } + + private: + ~NativeWeakPtrDetachRunnable() { + // Guard against somebody forgetting to call this runnable. + MOZ_RELEASE_ASSERT(mHasRun, "You must run/dispatch this runnable!"); + } + + private: + RefPtr> mCtlBlock; + Object::GlobalRef mOwner; + MozPromiseHolder mHolder; + typename NativeWeakPtrControlBlockStorageTraits::Type mNativeImpl; + bool mHasRun; +}; + +} // namespace details + +template +RefPtr NativeWeakPtr::Detach() { + if (!IsAttached()) { + // Never attached to begin with; no-op + return DetachPromise::CreateAndResolve(true, __func__); + } + + auto native = mCtlBlock->Clear(); + if (!native) { + // Detach already in progress + return DetachPromise::CreateAndResolve(true, __func__); + } + + Object::LocalRef owner(mCtlBlock->GetJavaOwner()); + MOZ_RELEASE_ASSERT(!!owner); + + // Save the raw pointer before we move native into the runnable so that we + // may call OnWeakNonIntrusiveDetach on it even after moving native into + // the runnable. + NativeImpl* rawImpl = + detail::NativeWeakPtrControlBlock::StorageTraits::AsRaw( + native); + RefPtr> runnable = + new details::NativeWeakPtrDetachRunnable( + mCtlBlock.forget(), owner, std::move(native)); + RefPtr promise = runnable->GetPromise(); + rawImpl->OnWeakNonIntrusiveDetach(runnable.forget()); + return promise; +} + +} // namespace mozilla::jni diff --git a/widget/android/jni/moz.build b/widget/android/jni/moz.build index 373efb90e964..53bef6663fe3 100644 --- a/widget/android/jni/moz.build +++ b/widget/android/jni/moz.build @@ -13,6 +13,7 @@ EXPORTS.mozilla.jni += [ "GeckoBundleUtils.h", "GeckoResultUtils.h", "Natives.h", + "NativesInlines.h", "Refs.h", "TypeAdapter.h", "Types.h", diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 259ef0b6a978..b641221df273 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -90,6 +90,7 @@ #include "mozilla/java/PanZoomControllerNatives.h" #include "mozilla/java/SessionAccessibilityWrappers.h" #include "mozilla/java/SurfaceControlManagerWrappers.h" +#include "mozilla/jni/NativesInlines.h" #include "mozilla/layers/APZEventState.h" #include "mozilla/layers/APZInputBridge.h" #include "mozilla/layers/APZThreadUtils.h"