Bug 1283616 - part 2 - micro-optimize inserting microtask runnables into the queue; r=khuey
authorNathan Froyd <froydnj@gmail.com>
Tue, 05 Jul 2016 18:49:06 -0400
changeset 303701 92f2f41c5f7e8893be52a9ee7aa939df40db1b37
parent 303700 72e450d5e17bf090ba786bf330c46d5baf20339c
child 303702 2e94e4eb877c523d790f64cb23c662249a1bf500
push id79144
push usernfroyd@mozilla.com
push dateTue, 05 Jul 2016 14:50:44 +0000
treeherdermozilla-inbound@92f2f41c5f7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1283616
milestone50.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 1283616 - part 2 - micro-optimize inserting microtask runnables into the queue; r=khuey We can save an AddRef/Release pair by passing in the reference to the queue.
dom/animation/Animation.cpp
dom/promise/Promise.cpp
dom/workers/RuntimeService.cpp
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/CycleCollectedJSRuntime.h
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -1247,18 +1247,18 @@ Animation::DoFinishNotification(SyncNoti
 {
   CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get();
 
   if (aSyncNotifyFlag == SyncNotifyFlag::Sync) {
     DoFinishNotificationImmediately();
   } else if (!mFinishNotificationTask.IsPending()) {
     RefPtr<nsRunnableMethod<Animation>> runnable =
       NewRunnableMethod(this, &Animation::DoFinishNotificationImmediately);
-    runtime->DispatchToMicroTask(runnable);
-    mFinishNotificationTask = runnable;
+    runtime->DispatchToMicroTask(do_AddRef(runnable));
+    mFinishNotificationTask = runnable.forget();
   }
 }
 
 void
 Animation::ResetFinishedPromise()
 {
   mFinishedIsResolved = false;
   mFinished = nullptr;
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -2692,17 +2692,17 @@ Promise::ResolveInternal(JSContext* aCx,
       //
       // Ensuring that stuff while not inside SpiderMonkey is painful, so let's
       // drop the fast path for now.
 
       RefPtr<PromiseInit> thenCallback =
         new PromiseInit(nullptr, thenObj, mozilla::dom::GetIncumbentGlobal());
       RefPtr<PromiseResolveThenableJob> task =
         new PromiseResolveThenableJob(this, valueObj, thenCallback);
-      runtime->DispatchToMicroTask(task);
+      runtime->DispatchToMicroTask(task.forget());
       return;
     }
   }
 
   MaybeSettle(aValue, Resolved);
 }
 
 void
@@ -2807,17 +2807,17 @@ Promise::TriggerPromiseReactions()
   callbacks.SwapElements(mState == Resolved ? mResolveCallbacks
                                             : mRejectCallbacks);
   mResolveCallbacks.Clear();
   mRejectCallbacks.Clear();
 
   for (uint32_t i = 0; i < callbacks.Length(); ++i) {
     RefPtr<PromiseReactionJob> task =
       new PromiseReactionJob(this, callbacks[i], mResult);
-    runtime->DispatchToMicroTask(task);
+    runtime->DispatchToMicroTask(task.forget());
   }
 }
 
 #if defined(DOM_PROMISE_DEPRECATED_REPORTING)
 void
 Promise::RemoveWorkerHolder()
 {
   NS_ASSERT_OWNINGTHREAD(Promise);
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -943,20 +943,22 @@ public:
   {
     // Only perform the Promise microtask checkpoint on the outermost event
     // loop.  Don't run it, for example, during sync XHR or importScripts.
     if (aRecursionDepth == 2) {
       CycleCollectedJSRuntime::AfterProcessTask(aRecursionDepth);
     }
   }
 
-  virtual void DispatchToMicroTask(nsIRunnable* aRunnable) override
+  virtual void DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable) override
   {
+    RefPtr<nsIRunnable> runnable(aRunnable);
+
     MOZ_ASSERT(!NS_IsMainThread());
-    MOZ_ASSERT(aRunnable);
+    MOZ_ASSERT(runnable);
 
     std::queue<nsCOMPtr<nsIRunnable>>* microTaskQueue = nullptr;
 
     JSContext* cx = GetCurrentThreadJSContext();
     NS_ASSERTION(cx, "This should never be null!");
 
     JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
     NS_ASSERTION(global, "This should never be null!");
@@ -968,17 +970,17 @@ public:
     if (IsWorkerGlobal(global)) {
       microTaskQueue = &mPromiseMicroTaskQueue;
     } else {
       MOZ_ASSERT(IsDebuggerGlobal(global) || IsDebuggerSandbox(global));
 
       microTaskQueue = &mDebuggerPromiseMicroTaskQueue;
     }
 
-    microTaskQueue->push(aRunnable);
+    microTaskQueue->push(runnable.forget());
   }
 
 private:
   WorkerPrivate* mWorkerPrivate;
 };
 
 class WorkerThreadPrimaryRunnable final : public Runnable
 {
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -970,17 +970,17 @@ CycleCollectedJSRuntime::EnqueuePromiseJ
   MOZ_ASSERT(JS_GetRuntime(aCx) == self->Runtime());
   MOZ_ASSERT(Get() == self);
 
   nsIGlobalObject* global = nullptr;
   if (aIncumbentGlobal) {
     global = xpc::NativeGlobal(aIncumbentGlobal);
   }
   nsCOMPtr<nsIRunnable> runnable = new PromiseJobRunnable(aJob, aAllocationSite, global);
-  self->DispatchToMicroTask(runnable);
+  self->DispatchToMicroTask(runnable.forget());
   return true;
 }
 
 #ifdef SPIDERMONKEY_PROMISE
 /* static */
 void
 CycleCollectedJSRuntime::PromiseRejectionTrackerCallback(JSContext* aCx,
                                                          JS::HandleObject aPromise,
@@ -1675,22 +1675,24 @@ CycleCollectedJSRuntime::PrepareWaitingZ
     for (auto iter = mZonesWaitingForGC.Iter(); !iter.Done(); iter.Next()) {
       JS::PrepareZoneForGC(iter.Get()->GetKey());
     }
     mZonesWaitingForGC.Clear();
   }
 }
 
 void
-CycleCollectedJSRuntime::DispatchToMicroTask(nsIRunnable* aRunnable)
+CycleCollectedJSRuntime::DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable)
 {
+  RefPtr<nsIRunnable> runnable(aRunnable);
+
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aRunnable);
+  MOZ_ASSERT(runnable);
 
-  mPromiseMicroTaskQueue.push(aRunnable);
+  mPromiseMicroTaskQueue.push(runnable.forget());
 }
 
 void
 CycleCollectedJSRuntime::EnvironmentPreparer::invoke(JS::HandleObject scope,
                                                      js::ScriptEnvironmentPreparer::Closure& closure)
 {
   nsIGlobalObject* global = xpc::NativeGlobal(scope);
 
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -367,17 +367,17 @@ public:
 
   // Prepare any zones for GC that have been passed to AddZoneWaitingForGC()
   // since the last GC or since the last call to PrepareWaitingZonesForGC(),
   // whichever was most recent. If there were no such zones, prepare for a
   // full GC.
   void PrepareWaitingZonesForGC();
 
   // Queue an async microtask to the current main or worker thread.
-  virtual void DispatchToMicroTask(nsIRunnable* aRunnable);
+  virtual void DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable);
 
   // Storage for watching rejected promises waiting for some client to
   // consume their rejection.
 #ifdef SPIDERMONKEY_PROMISE
   // Promises in this list have been rejected in the last turn of the
   // event loop without the rejection being handled.
   // Note that this can contain nullptrs in place of promises removed because
   // they're consumed before it'd be reported.