Bug 1215139 - Discard stale native calls after nsWindow destruction; r=snorp
authorJim Chen <nchen@mozilla.com>
Thu, 22 Oct 2015 17:45:46 -0400
changeset 304284 cc90b297f32f640bbf00d8849810fa13ad70f837
parent 304283 3fde465d5226c8f91e167fad8ac36c2bd59aa564
child 304285 8b395733b46e7dc3043ef62351a5eea5c1ebf473
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1215139
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1215139 - Discard stale native calls after nsWindow destruction; r=snorp In the period after nsWindow is destroyed, but before disposeNative is called, we should discard any pending native calls. These calls would result in exceptions anyways because the nsWindow weak pointer is now null. After disposeNative is called, any native calls will still result in exceptions because in that case, it's Java code's responsibility to ensure that calls are not made after disposeNative is called.
widget/android/nsWindow.cpp
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -8,16 +8,17 @@
 #include <unistd.h>
 
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
+#include "mozilla/TypeTraits.h"
 #include "mozilla/WeakPtr.h"
 
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/unused.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/layers/RenderTrace.h"
 #include <algorithm>
@@ -157,32 +158,72 @@ static const double SWIPE_MIN_DISTANCE_I
 class nsWindow::Natives final
     : public GeckoView::Window::Natives<Natives>
     , public GeckoEditable::Natives<Natives>
     , public SupportsWeakPtr<Natives>
     , public UsesGeckoThreadProxy
 {
     nsWindow& window;
 
+    template<typename T>
+    class WindowEvent : public nsAppShell::LambdaEvent<T>
+    {
+        typedef nsAppShell::LambdaEvent<T> Base;
+
+        // Static calls are never stale since they don't need native instances.
+        template<bool Static>
+        typename mozilla::EnableIf<Static, bool>::Type IsStaleCall()
+        { return false; }
+
+        template<bool Static>
+        typename mozilla::EnableIf<!Static, bool>::Type IsStaleCall()
+        {
+            JNIEnv* const env = mozilla::jni::GetEnvForThread();
+            const auto& thisArg = Base::lambda.GetThisArg();
+
+            const auto natives = reinterpret_cast<mozilla::WeakPtr<Natives>*>(
+                    jni::GetNativeHandle(env, thisArg.Get()));
+            jni::HandleUncaughtException(env);
+
+            // The call is stale if the nsWindow has been destroyed on the
+            // Gecko side, but the Java object is still attached to it through
+            // a weak pointer. Stale calls should be discarded. Note that it's
+            // an error if natives is nullptr here; we return false but the
+            // native call will throw an error.
+            return natives && !natives->get();
+        }
+
+    public:
+        WindowEvent(T&& l) : Base(mozilla::Move(l)) {}
+
+        void Run() override
+        {
+            if (!IsStaleCall<T::isStatic>()) {
+                return Base::Run();
+            }
+        }
+    };
+
 public:
     typedef GeckoView::Window::Natives<Natives> Base;
     typedef GeckoEditable::Natives<Natives> EditableBase;
 
     MOZ_DECLARE_WEAKREFERENCE_TYPENAME(Natives);
 
     template<typename Functor>
     static void OnNativeCall(Functor&& aCall)
     {
         if (aCall.IsTarget(&Open) && NS_IsMainThread()) {
             // Gecko state probably just switched to PROFILE_READY, and the
             // event loop is not running yet. Skip the event loop here so we
             // can get a head start on opening our window.
             return aCall();
         }
-        return UsesGeckoThreadProxy::OnNativeCall(mozilla::Move(aCall));
+        return nsAppShell::gAppShell->PostEvent(mozilla::MakeUnique<
+                WindowEvent<Functor>>(mozilla::Move(aCall)));
     }
 
     Natives(nsWindow* aWindow) : window(*aWindow) {}
     ~Natives();
 
     /**
      * GeckoView methods
      */