Bug 1116697 - Fix nsScriptError::InitWithWindowID to work better off the main thread, r=mrbkap.
authorBen Turner <bent.mozilla@gmail.com>
Mon, 05 Jan 2015 14:53:37 -0800
changeset 247971 7070c9621457ef4383b674c8c8569b3c8a9c2ed7
parent 247970 c963d611da18251d853d4befe8656ffa350a017a
child 247972 e89d431543ae151c041870c9cf0a728fa68fb1f0
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1116697
milestone37.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 1116697 - Fix nsScriptError::InitWithWindowID to work better off the main thread, r=mrbkap.
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
js/xpconnect/src/nsScriptError.cpp
js/xpconnect/src/xpcprivate.h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1113,16 +1113,18 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
     mNetworkDownloadObserverEnabled(false),
 #endif
     mCleanedUp(false),
     mDialogAbuseCount(0),
     mAreDialogsEnabled(true),
     mCanSkipCCGeneration(0),
     mVRDevicesInitialized(false)
 {
+  AssertIsOnMainThread();
+
   nsLayoutStatics::AddRef();
 
   // Initialize the PRCList (this).
   PR_INIT_CLIST(this);
 
   if (aOuterWindow) {
     // |this| is an inner window, add this inner window to the outer
     // window list of inners.
@@ -1213,20 +1215,33 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
 
   // Ensure that the current active state is initialized for child process windows.
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
     mIsActive = fm->IsParentActivated();
   }
 }
 
+#ifdef DEBUG
+
+/* static */
+void
+nsGlobalWindow::AssertIsOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+#endif // DEBUG
+
 /* static */
 void
 nsGlobalWindow::Init()
 {
+  AssertIsOnMainThread();
+
   CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
   NS_ASSERTION(gEntropyCollector,
                "gEntropyCollector should have been initialized!");
 
 #ifdef PR_LOGGING
   gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
   NS_ASSERTION(gDOMLeakPRLog, "gDOMLeakPRLog should have been initialized!");
 #endif
@@ -1240,16 +1255,18 @@ DisconnectEventTargetObjects(nsPtrHashKe
 {
   nsRefPtr<DOMEventTargetHelper> target = aKey->GetKey();
   target->DisconnectFromOwner();
   return PL_DHASH_NEXT;
 }
 
 nsGlobalWindow::~nsGlobalWindow()
 {
+  AssertIsOnMainThread();
+
   mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nullptr);
   mEventTargetObjects.Clear();
 
   // We have to check if sWindowsById isn't null because ::Shutdown might have
   // been called.
   if (sWindowsById) {
     NS_ASSERTION(sWindowsById->Get(mWindowID),
                  "This window should be in the hash table");
@@ -1358,16 +1375,18 @@ nsGlobalWindow::RemoveEventTargetObject(
   MOZ_ASSERT(IsInnerWindow());
   mEventTargetObjects.RemoveEntry(aObject);
 }
 
 // static
 void
 nsGlobalWindow::ShutDown()
 {
+  AssertIsOnMainThread();
+
   if (gDumpFile && gDumpFile != stdout) {
     fclose(gDumpFile);
   }
   gDumpFile = nullptr;
 
   NS_IF_RELEASE(gEntropyCollector);
 
   delete sWindowsById;
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -329,16 +329,24 @@ class nsGlobalWindow : public mozilla::d
                        public nsIInterfaceRequestor,
                        public PRCListStr
 {
 public:
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindow*> WindowByIdTable;
 
+  static void
+  AssertIsOnMainThread()
+#ifdef DEBUG
+  ;
+#else
+  { }
+#endif
+
   // public methods
   nsPIDOMWindow* GetPrivateParent();
 
   // callback for close event
   void ReallyCloseWindow();
 
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -665,34 +673,40 @@ public:
                         const nsAString& aPopupWindowName,
                         const nsAString& aPopupWindowFeatures) MOZ_OVERRIDE;
 
   virtual uint32_t GetSerial() {
     return mSerial;
   }
 
   static nsGlobalWindow* GetOuterWindowWithId(uint64_t aWindowID) {
+    AssertIsOnMainThread();
+
     if (!sWindowsById) {
       return nullptr;
     }
 
     nsGlobalWindow* outerWindow = sWindowsById->Get(aWindowID);
     return outerWindow && !outerWindow->IsInnerWindow() ? outerWindow : nullptr;
   }
 
   static nsGlobalWindow* GetInnerWindowWithId(uint64_t aInnerWindowID) {
+    AssertIsOnMainThread();
+
     if (!sWindowsById) {
       return nullptr;
     }
 
     nsGlobalWindow* innerWindow = sWindowsById->Get(aInnerWindowID);
     return innerWindow && innerWindow->IsInnerWindow() ? innerWindow : nullptr;
   }
 
   static WindowByIdTable* GetWindowsTable() {
+    AssertIsOnMainThread();
+
     return sWindowsById;
   }
 
   void AddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const;
 
   void UnmarkGrayTimers();
 
   // Inner windows only.
--- a/js/xpconnect/src/nsScriptError.cpp
+++ b/js/xpconnect/src/nsScriptError.cpp
@@ -6,16 +6,18 @@
 
 /*
  * nsIScriptError implementation.  Defined here, lacking a JS-specific
  * place to put XPCOM things.
  */
 
 #include "xpcprivate.h"
 #include "jsprf.h"
+#include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
 #include "nsGlobalWindow.h"
 #include "nsPIDOMWindow.h"
 #include "nsILoadContext.h"
 #include "nsIDocShell.h"
 
 NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError)
 
 nsScriptError::nsScriptError()
@@ -24,22 +26,53 @@ nsScriptError::nsScriptError()
        mLineNumber(0),
        mSourceLine(),
        mColumnNumber(0),
        mFlags(0),
        mCategory(),
        mOuterWindowID(0),
        mInnerWindowID(0),
        mTimeStamp(0),
+       mInitializedOnMainThread(false),
        mIsFromPrivateWindow(false)
 {
 }
 
 nsScriptError::~nsScriptError() {}
 
+void
+nsScriptError::InitializeOnMainThread()
+{
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(!mInitializedOnMainThread);
+
+    if (mInnerWindowID) {
+        nsGlobalWindow* window =
+          nsGlobalWindow::GetInnerWindowWithId(mInnerWindowID);
+        if (window) {
+            nsPIDOMWindow* outer = window->GetOuterWindow();
+            if (outer)
+                mOuterWindowID = outer->WindowID();
+
+            nsIDocShell* docShell = window->GetDocShell();
+            nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
+
+            if (loadContext) {
+                // Never mark exceptions from chrome windows as having come from
+                // private windows, since we always want them to be reported.
+                nsIPrincipal* winPrincipal = window->GetPrincipal();
+                mIsFromPrivateWindow = loadContext->UsePrivateBrowsing() &&
+                                       !nsContentUtils::IsSystemPrincipal(winPrincipal);
+            }
+        }
+    }
+
+    mInitializedOnMainThread = true;
+}
+
 // nsIConsoleMessage methods
 NS_IMETHODIMP
 nsScriptError::GetMessageMoz(char16_t **result) {
     nsresult rv;
 
     nsAutoCString message;
     rv = ToString(message);
     if (NS_FAILED(rv))
@@ -135,36 +168,18 @@ nsScriptError::InitWithWindowID(const ns
     mLineNumber = lineNumber;
     mSourceLine.Assign(sourceLine);
     mColumnNumber = columnNumber;
     mFlags = flags;
     mCategory = category;
     mTimeStamp = JS_Now() / 1000;
     mInnerWindowID = aInnerWindowID;
 
-    if (aInnerWindowID) {
-        nsGlobalWindow* window =
-          nsGlobalWindow::GetInnerWindowWithId(aInnerWindowID);
-        if (window) {
-            nsPIDOMWindow* outer = window->GetOuterWindow();
-            if (outer)
-                mOuterWindowID = outer->WindowID();
-
-            nsIDocShell* docShell = window->GetDocShell();
-            nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
-
-            if (loadContext) {
-                // Never mark exceptions from chrome windows as having come from
-                // private windows, since we always want them to be reported.
-                nsIPrincipal* winPrincipal = window->GetPrincipal();
-                mIsFromPrivateWindow = loadContext->UsePrivateBrowsing() &&
-                                       !nsContentUtils::IsSystemPrincipal(winPrincipal);
-            }
-
-        }
+    if (aInnerWindowID && NS_IsMainThread()) {
+        InitializeOnMainThread();
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptError::ToString(nsACString& /*UTF8*/ aResult)
 {
@@ -224,16 +239,24 @@ nsScriptError::ToString(nsACString& /*UT
     aResult.Assign(temp);
     JS_smprintf_free(temp);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptError::GetOuterWindowID(uint64_t *aOuterWindowID)
 {
+    NS_WARN_IF_FALSE(NS_IsMainThread() || mInitializedOnMainThread,
+                     "This can't be safely determined off the main thread, "
+                     "returning an inaccurate value!");
+
+    if (!mInitializedOnMainThread && NS_IsMainThread()) {
+        InitializeOnMainThread();
+    }
+
     *aOuterWindowID = mOuterWindowID;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptError::GetInnerWindowID(uint64_t *aInnerWindowID)
 {
     *aInnerWindowID = mInnerWindowID;
@@ -245,11 +268,19 @@ nsScriptError::GetTimeStamp(int64_t *aTi
 {
     *aTimeStamp = mTimeStamp;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptError::GetIsFromPrivateWindow(bool *aIsFromPrivateWindow)
 {
+    NS_WARN_IF_FALSE(NS_IsMainThread() || mInitializedOnMainThread,
+                     "This can't be safely determined off the main thread, "
+                     "returning an inaccurate value!");
+
+    if (!mInitializedOnMainThread && NS_IsMainThread()) {
+        InitializeOnMainThread();
+    }
+
     *aIsFromPrivateWindow = mIsFromPrivateWindow;
     return NS_OK;
 }
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -72,16 +72,17 @@
 /* All the XPConnect private declarations - only include locally. */
 
 #ifndef xpcprivate_h___
 #define xpcprivate_h___
 
 #include "mozilla/Alignment.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TimeStamp.h"
 
@@ -2966,26 +2967,33 @@ public:
 
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSICONSOLEMESSAGE
     NS_DECL_NSISCRIPTERROR
 
 private:
     virtual ~nsScriptError();
 
+    void
+    InitializeOnMainThread();
+
     nsString mMessage;
     nsString mSourceName;
     uint32_t mLineNumber;
     nsString mSourceLine;
     uint32_t mColumnNumber;
     uint32_t mFlags;
     nsCString mCategory;
+    // mOuterWindowID is set on the main thread from InitializeOnMainThread().
     uint64_t mOuterWindowID;
     uint64_t mInnerWindowID;
     int64_t mTimeStamp;
+    // mInitializedOnMainThread and mIsFromPrivateWindow are set on the main
+    // thread from InitializeOnMainThread().
+    mozilla::Atomic<bool> mInitializedOnMainThread;
     bool mIsFromPrivateWindow;
 };
 
 /******************************************************************************
  * Handles pre/post script processing.
  */
 class MOZ_STACK_CLASS AutoScriptEvaluate
 {