Bug 975695. r=khuey, a=sledru
authorBen Turner <bent.mozilla@gmail.com>
Tue, 04 Mar 2014 15:09:23 -0800
changeset 183175 84fc324bc2f2d0eb4931ac712f4118fcdba97ce1
parent 183174 2d93d4f0acb8dd81c5b5baf6ce468affabc1506d
child 183176 3ed75dc281999967ebb6a067a7e6cff6bcd46f65
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey, sledru
bugs975695
milestone29.0a2
Bug 975695. r=khuey, a=sledru
dom/workers/RuntimeService.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -2576,17 +2576,17 @@ WorkerThreadPrimaryRunnable::Run()
     // Now WorkerJSRuntime goes out of scope and its destructor will shut
     // down the cycle collector and destroy the final JSContext.  This
     // breaks any remaining cycles and collects the C++ and JS objects
     // participating.
   }
 
   mThread->SetWorker(nullptr);
 
-  mWorkerPrivate->ScheduleDeletion();
+  mWorkerPrivate->ScheduleDeletion(WorkerPrivate::WorkerRan);
 
   // It is no longer safe to touch mWorkerPrivate.
   mWorkerPrivate = nullptr;
 
   // Now recycle this thread.
   nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
   MOZ_ASSERT(mainThread);
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2353,17 +2353,17 @@ WorkerPrivateParent<Derived>::NotifyPriv
 
       MOZ_ASSERT(!self->mPRThread);
       self->mPRThread = PRThreadFromThread(currentThread);
       MOZ_ASSERT(self->mPRThread);
     }
 #endif
 
     // Worker never got a chance to run, go ahead and delete it.
-    self->ScheduleDeletion();
+    self->ScheduleDeletion(WorkerPrivate::WorkerNeverRan);
     return true;
   }
 
   // Only top-level workers should have a synchronize runnable.
   MOZ_ASSERT_IF(mSynchronizeRunnable.get(), !GetParent());
   mSynchronizeRunnable.Revoke();
 
   NS_ASSERTION(aStatus != Terminating || mQueuedRunnables.IsEmpty(),
@@ -4246,23 +4246,23 @@ WorkerPrivate::IsOnCurrentThread(bool* a
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 void
-WorkerPrivate::ScheduleDeletion()
+WorkerPrivate::ScheduleDeletion(WorkerRanOrNot aRanOrNot)
 {
   AssertIsOnWorkerThread();
   MOZ_ASSERT(mChildWorkers.IsEmpty());
   MOZ_ASSERT(mSyncLoopStack.IsEmpty());
 
-  ClearMainEventQueue();
+  ClearMainEventQueue(aRanOrNot);
 
   if (WorkerPrivate* parent = GetParent()) {
     nsRefPtr<WorkerFinishedRunnable> runnable =
       new WorkerFinishedRunnable(parent, this);
     if (!runnable->Dispatch(nullptr)) {
       NS_WARNING("Failed to dispatch runnable!");
     }
   }
@@ -4469,28 +4469,37 @@ WorkerPrivate::ProcessAllControlRunnable
 
     event->Release();
   }
 
   return result;
 }
 
 void
-WorkerPrivate::ClearMainEventQueue()
+WorkerPrivate::ClearMainEventQueue(WorkerRanOrNot aRanOrNot)
 {
   AssertIsOnWorkerThread();
 
-  nsIThread* currentThread = NS_GetCurrentThread();
-  MOZ_ASSERT(currentThread);
-
   MOZ_ASSERT(!mCancelAllPendingRunnables);
   mCancelAllPendingRunnables = true;
 
-  NS_ProcessPendingEvents(currentThread);
-  MOZ_ASSERT(!NS_HasPendingEvents(currentThread));
+  if (WorkerNeverRan == aRanOrNot) {
+    for (uint32_t count = mPreStartRunnables.Length(), index = 0;
+         index < count;
+         index++) {
+      nsRefPtr<WorkerRunnable> runnable = mPreStartRunnables[index].forget();
+      static_cast<nsIRunnable*>(runnable.get())->Run();
+    }
+  } else {
+    nsIThread* currentThread = NS_GetCurrentThread();
+    MOZ_ASSERT(currentThread);
+
+    NS_ProcessPendingEvents(currentThread);
+    MOZ_ASSERT(!NS_HasPendingEvents(currentThread));
+  }
 
   MOZ_ASSERT(mCancelAllPendingRunnables);
   mCancelAllPendingRunnables = false;
 }
 
 uint32_t
 WorkerPrivate::RemainingRunTimeMS() const
 {
@@ -5021,17 +5030,17 @@ WorkerPrivate::NotifyInternal(JSContext*
   MOZ_ASSERT(previousStatus >= Canceling || mKillTime.IsNull());
 
   // Let all our features know the new status.
   NotifyFeatures(aCx, aStatus);
 
   // If this is the first time our status has changed then we need to clear the
   // main event queue.
   if (previousStatus == Running) {
-    ClearMainEventQueue();
+    ClearMainEventQueue(WorkerRan);
   }
 
   // If we've run the close handler, we don't need to do anything else.
   if (mCloseHandlerFinished) {
     return true;
   }
 
   // If the worker script never ran, or failed to compile, we don't need to do
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -893,18 +893,23 @@ public:
                                  const JS::ContextOptions& aChromeOptions);
 
   void
   UpdatePreferenceInternal(JSContext* aCx, WorkerPreference aPref, bool aValue);
 
   void
   UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, uint32_t aValue);
 
+  enum WorkerRanOrNot {
+    WorkerNeverRan = 0,
+    WorkerRan
+  };
+
   void
-  ScheduleDeletion();
+  ScheduleDeletion(WorkerRanOrNot aRanOrNot);
 
   bool
   BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats);
 
 #ifdef JS_GC_ZEAL
   void
   UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal, uint32_t aFrequency);
 #endif
@@ -1025,17 +1030,17 @@ public:
 
 private:
   WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
                 const nsAString& aScriptURL, bool aIsChromeWorker,
                 WorkerType aWorkerType, const nsACString& aSharedWorkerName,
                 LoadInfo& aLoadInfo);
 
   void
-  ClearMainEventQueue();
+  ClearMainEventQueue(WorkerRanOrNot aRanOrNot);
 
   bool
   MayContinueRunning()
   {
     AssertIsOnWorkerThread();
 
     Status status;
     {