Bug 785348. Part 1: Track when we've called into plugin code. While we're in plugin code, never run the refresh driver. r=mats
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 07 Dec 2012 12:58:14 +1300
changeset 124568 1869f4cbee0b8b9b04b935564041dcf4bd1dac21
parent 124567 bb0dbeb26f1d70f64940a07da8d9776fc28a6eab
child 124569 b30a1fff2d0758a6e69bbac0d87707444349b860
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs785348
milestone20.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 785348. Part 1: Track when we've called into plugin code. While we're in plugin code, never run the refresh driver. r=mats
dom/plugins/base/nsNPAPIPlugin.cpp
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/base/nsPluginSafety.h
layout/base/nsRefreshDriver.cpp
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -181,22 +181,30 @@ static PRCList sPendingAsyncCalls = PR_I
 // POST/GET stream type
 enum eNPPStreamTypeInternal {
   eNPPStreamTypeInternal_Get,
   eNPPStreamTypeInternal_Post
 };
 
 static NS_DEFINE_IID(kMemoryCID, NS_MEMORY_CID);
 
+PRIntervalTime NS_NotifyBeginPluginCall()
+{
+  nsNPAPIPluginInstance::BeginPluginCall();
+  return PR_IntervalNow();
+}
+
 // This function sends a notification using the observer service to any object
 // registered to listen to the "experimental-notify-plugin-call" subject.
 // Each "experimental-notify-plugin-call" notification carries with it the run
 // time value in milliseconds that the call took to execute.
 void NS_NotifyPluginCall(PRIntervalTime startTime) 
 {
+  nsNPAPIPluginInstance::EndPluginCall();
+
   PRIntervalTime endTime = PR_IntervalNow() - startTime;
   nsCOMPtr<nsIObserverService> notifyUIService =
     mozilla::services::GetObserverService();
   if (!notifyUIService)
     return;
 
   float runTimeInSeconds = float(endTime) / PR_TicksPerSecond();
   nsAutoString runTimeString;
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -195,16 +195,18 @@ nsNPAPIPluginInstance::~nsNPAPIPluginIns
   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance dtor: this=%p\n",this));
 
   if (mMIMEType) {
     PR_Free((void *)mMIMEType);
     mMIMEType = nullptr;
   }
 }
 
+uint32_t nsNPAPIPluginInstance::gInPluginCalls = 0;
+
 void
 nsNPAPIPluginInstance::Destroy()
 {
   Stop();
   mPlugin = nullptr;
 
 #if MOZ_WIDGET_ANDROID
   if (mContentSurface)
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -265,16 +265,24 @@ public:
 
   // Called when the instance fails to instantiate beceause the Carbon
   // event model is not supported.
   void CarbonNPAPIFailure();
 
   // Returns the contents scale factor of the screen the plugin is drawn on.
   double GetContentsScaleFactor();
 
+  static bool InPluginCall() { return gInPluginCalls > 0; }
+  static void BeginPluginCall() { ++gInPluginCalls; }
+  static void EndPluginCall()
+  {
+    NS_ASSERTION(InPluginCall(), "Must be in plugin call");
+    --gInPluginCalls;
+  }
+
 protected:
 
   nsresult GetTagType(nsPluginTagType *result);
   nsresult GetAttributes(uint16_t& n, const char*const*& names,
                          const char*const*& values);
   nsresult GetParameters(uint16_t& n, const char*const*& names,
                          const char*const*& values);
   nsresult GetMode(int32_t *result);
@@ -359,11 +367,13 @@ private:
   std::map<void*, VideoInfo*> mVideos;
   bool mOnScreen;
 
   nsIntSize mCurrentSize;
 #endif
 
   // is this instance Java and affected by bug 750480?
   bool mHaveJavaC2PJSObjectQuirk;
+
+  static uint32_t gInPluginCalls;
 };
 
 #endif // nsNPAPIPluginInstance_h_
--- a/dom/plugins/base/nsPluginSafety.h
+++ b/dom/plugins/base/nsPluginSafety.h
@@ -9,16 +9,17 @@
 #include "npapi.h"
 #include "nsPluginHost.h"
 #include <prinrval.h>
 
 #if defined(XP_WIN)
 #define CALL_SAFETY_ON
 #endif
 
+PRIntervalTime NS_NotifyBeginPluginCall();
 void NS_NotifyPluginCall(PRIntervalTime);
 
 #ifdef CALL_SAFETY_ON
 
 #include "mozilla/Preferences.h"
 
 extern bool gSkipPluginSafeCalls;
 
@@ -26,70 +27,70 @@ extern bool gSkipPluginSafeCalls;
 PR_BEGIN_MACRO                                                     \
   gSkipPluginSafeCalls =                                           \
     ::mozilla::Preferences::GetBool("plugin.dont_try_safe_calls",  \
                                     gSkipPluginSafeCalls);         \
 PR_END_MACRO
 
 #define NS_TRY_SAFE_CALL_RETURN(ret, fun, pluginInst) \
 PR_BEGIN_MACRO                                     \
-  PRIntervalTime startTime = PR_IntervalNow();     \
+  PRIntervalTime startTime = NS_NotifyBeginPluginCall(); \
   if(gSkipPluginSafeCalls)                         \
     ret = fun;                                     \
   else                                             \
   {                                                \
     MOZ_SEH_TRY                                    \
     {                                              \
       ret = fun;                                   \
     }                                              \
-    MOZ_SEH_EXCEPT(true)                        \
+    MOZ_SEH_EXCEPT(true)                           \
     {                                              \
       nsresult res;                                \
       nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &res));\
       if(NS_SUCCEEDED(res) && (host != nullptr))    \
         static_cast<nsPluginHost*>(host.get())->HandleBadPlugin(nullptr, pluginInst); \
       ret = (NPError)NS_ERROR_FAILURE;             \
     }                                              \
   }                                                \
   NS_NotifyPluginCall(startTime);		   \
 PR_END_MACRO
 
 #define NS_TRY_SAFE_CALL_VOID(fun, pluginInst) \
 PR_BEGIN_MACRO                              \
-  PRIntervalTime startTime = PR_IntervalNow();     \
+  PRIntervalTime startTime = NS_NotifyBeginPluginCall(); \
   if(gSkipPluginSafeCalls)                  \
     fun;                                    \
   else                                      \
   {                                         \
     MOZ_SEH_TRY                             \
     {                                       \
       fun;                                  \
     }                                       \
-    MOZ_SEH_EXCEPT(true)                 \
+    MOZ_SEH_EXCEPT(true)                    \
     {                                       \
       nsresult res;                         \
       nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &res));\
       if(NS_SUCCEEDED(res) && (host != nullptr))\
         static_cast<nsPluginHost*>(host.get())->HandleBadPlugin(nullptr, pluginInst);\
     }                                       \
   }                                         \
   NS_NotifyPluginCall(startTime);		   \
 PR_END_MACRO
 
 #else // vanilla calls
 
 #define NS_TRY_SAFE_CALL_RETURN(ret, fun, pluginInst) \
 PR_BEGIN_MACRO                                     \
-  PRIntervalTime startTime = PR_IntervalNow();     \
+  PRIntervalTime startTime = NS_NotifyBeginPluginCall(); \
   ret = fun;                                       \
-  NS_NotifyPluginCall(startTime);		   \
+  NS_NotifyPluginCall(startTime);		               \
 PR_END_MACRO
 
-#define NS_TRY_SAFE_CALL_VOID(fun, pluginInst) \
-PR_BEGIN_MACRO                              \
-  PRIntervalTime startTime = PR_IntervalNow();     \
-  fun;                                      \
-  NS_NotifyPluginCall(startTime);		   \
+#define NS_TRY_SAFE_CALL_VOID(fun, pluginInst)     \
+PR_BEGIN_MACRO                                     \
+  PRIntervalTime startTime = NS_NotifyBeginPluginCall(); \
+  fun;                                             \
+  NS_NotifyPluginCall(startTime);		               \
 PR_END_MACRO
 
 #endif // CALL_SAFETY_ON
 
 #endif //nsPluginSafety_h_
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -20,19 +20,17 @@
 #include "nsIDocument.h"
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "jsapi.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsIViewManager.h"
 #include "sampler.h"
-
-using mozilla::TimeStamp;
-using mozilla::TimeDuration;
+#include "nsNPAPIPluginInstance.h"
 
 using namespace mozilla;
 
 #define DEFAULT_FRAME_RATE 60
 #define DEFAULT_THROTTLED_FRAME_RATE 1
 
 static bool sPrecisePref;
 
@@ -305,16 +303,21 @@ NS_IMETHODIMP
 nsRefreshDriver::Notify(nsITimer *aTimer)
 {
   SAMPLE_LABEL("nsRefreshDriver", "Notify");
 
   NS_PRECONDITION(!mFrozen, "Why are we notified while frozen?");
   NS_PRECONDITION(mPresContext, "Why are we notified after disconnection?");
   NS_PRECONDITION(!nsContentUtils::GetCurrentJSContext(),
                   "Shouldn't have a JSContext on the stack");
+  if (nsNPAPIPluginInstance::InPluginCall()) {
+    NS_ERROR("Refresh driver should not run during plugin call!");
+    // Try to survive this by just ignoring the refresh tick.
+    return NS_OK;
+  }
 
   if (mTestControllingRefreshes && aTimer) {
     // Ignore real refreshes from our timer (but honor the others).
     return NS_OK;
   }
 
   UpdateMostRecentRefresh();