Bug 1298661, let meta-stable state runnables run during sync loops, r=baku
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Mon, 05 Sep 2016 18:54:04 +0300
changeset 341243 45d53e85bd0d0e820186c70c92603aa15003a8b0
parent 341242 9c52e335a78355041ad09f68732cd58704ff825d
child 341244 354f2bd63b9ec4a6507dc7da011dbea0ba37e8e5
push idunknown
push userunknown
push dateunknown
reviewersbaku
bugs1298661
milestone51.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 1298661, let meta-stable state runnables run during sync loops, r=baku
dom/workers/RuntimeService.cpp
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/CycleCollectedJSRuntime.h
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -1138,16 +1138,19 @@ public:
   }
 
   virtual void AfterProcessTask(uint32_t aRecursionDepth) override
   {
     // 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);
+    } else if (aRecursionDepth > 2) {
+      AutoDisableMicroTaskCheckpoint disableMicroTaskCheckpoint;
+      CycleCollectedJSRuntime::AfterProcessTask(aRecursionDepth);
     }
   }
 
   virtual void DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable) override
   {
     RefPtr<nsIRunnable> runnable(aRunnable);
 
     MOZ_ASSERT(!NS_IsMainThread());
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -437,16 +437,17 @@ mozilla::GetBuildId(JS::BuildIdCharVecto
 CycleCollectedJSRuntime::CycleCollectedJSRuntime()
   : mGCThingCycleCollectorGlobal(sGCThingCycleCollectorGlobal)
   , mJSZoneCycleCollectorGlobal(sJSZoneCycleCollectorGlobal)
   , mJSContext(nullptr)
   , mPrevGCSliceCallback(nullptr)
   , mPrevGCNurseryCollectionCallback(nullptr)
   , mJSHolders(256)
   , mDoingStableStates(false)
+  , mDisableMicroTaskCheckpoint(false)
   , mOutOfMemoryState(OOMState::OK)
   , mLargeAllocationFailureState(OOMState::OK)
 {
   nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
   mOwningThread = thread.forget().downcast<nsThread>().take();
   MOZ_RELEASE_ASSERT(mOwningThread);
 }
 
@@ -1379,21 +1380,23 @@ CycleCollectedJSRuntime::AfterProcessTas
 
   // See HTML 6.1.4.2 Processing model
 
   // Execute any events that were waiting for a microtask to complete.
   // This is not (yet) in the spec.
   ProcessMetastableStateQueue(aRecursionDepth);
 
   // Step 4.1: Execute microtasks.
-  if (NS_IsMainThread()) {
-    nsContentUtils::PerformMainThreadMicroTaskCheckpoint();
-    Promise::PerformMicroTaskCheckpoint();
-  } else {
-    Promise::PerformWorkerMicroTaskCheckpoint();
+  if (!mDisableMicroTaskCheckpoint) {
+    if (NS_IsMainThread()) {
+      nsContentUtils::PerformMainThreadMicroTaskCheckpoint();
+      Promise::PerformMicroTaskCheckpoint();
+    } else {
+      Promise::PerformWorkerMicroTaskCheckpoint();
+    }
   }
 
   // Step 4.2 Execute any events that were waiting for a stable state.
   ProcessStableStateQueue();
 }
 
 void
 CycleCollectedJSRuntime::AfterProcessMicrotask()
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -331,16 +331,45 @@ public:
   }
 
   JS::RootingContext* RootingCx() const
   {
     MOZ_ASSERT(mJSContext);
     return JS::RootingContext::get(mJSContext);
   }
 
+  bool MicroTaskCheckpointDisabled() const
+  {
+    return mDisableMicroTaskCheckpoint;
+  }
+
+  void DisableMicroTaskCheckpoint(bool aDisable)
+  {
+    mDisableMicroTaskCheckpoint = aDisable;
+  }
+
+  class MOZ_RAII AutoDisableMicroTaskCheckpoint
+  {
+    public:
+    AutoDisableMicroTaskCheckpoint()
+    : mCCRT(CycleCollectedJSRuntime::Get())
+    {
+      mOldValue = mCCRT->MicroTaskCheckpointDisabled();
+      mCCRT->DisableMicroTaskCheckpoint(true);
+    }
+
+    ~AutoDisableMicroTaskCheckpoint()
+    {
+      mCCRT->DisableMicroTaskCheckpoint(mOldValue);
+    }
+
+    CycleCollectedJSRuntime* mCCRT;
+    bool mOldValue;
+  };
+
 protected:
   JSContext* MaybeContext() const { return mJSContext; }
 
 public:
   // nsThread entrypoints
   virtual void BeforeProcessTask(bool aMightBlock) { };
   virtual void AfterProcessTask(uint32_t aRecursionDepth);
 
@@ -423,16 +452,18 @@ private:
     uint32_t mRecursionDepth;
   };
 
   nsTArray<nsCOMPtr<nsIRunnable>> mStableStateEvents;
   nsTArray<RunInMetastableStateData> mMetastableStateEvents;
   uint32_t mBaseRecursionDepth;
   bool mDoingStableStates;
 
+  bool mDisableMicroTaskCheckpoint;
+
   OOMState mOutOfMemoryState;
   OOMState mLargeAllocationFailureState;
 
   static const size_t kSegmentSize = 512;
   SegmentedVector<nsWrapperCache*, kSegmentSize, InfallibleAllocPolicy>
     mNurseryObjects;
   SegmentedVector<JS::PersistentRooted<JSObject*>, kSegmentSize,
                   InfallibleAllocPolicy>