LCOV - code coverage report
Current view: top level - js/xpconnect/src - XPCJSContext.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 249 383 65.0 %
Date: 2017-07-14 16:53:18 Functions: 40 55 72.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* Per JSContext object */
       8             : 
       9             : #include "mozilla/MemoryReporting.h"
      10             : #include "mozilla/UniquePtr.h"
      11             : 
      12             : #include "xpcprivate.h"
      13             : #include "xpcpublic.h"
      14             : #include "XPCWrapper.h"
      15             : #include "XPCJSMemoryReporter.h"
      16             : #include "WrapperFactory.h"
      17             : #include "mozJSComponentLoader.h"
      18             : #include "nsAutoPtr.h"
      19             : #include "nsNetUtil.h"
      20             : #include "nsThreadUtils.h"
      21             : 
      22             : #include "nsIMemoryInfoDumper.h"
      23             : #include "nsIMemoryReporter.h"
      24             : #include "nsIObserverService.h"
      25             : #include "nsIDebug2.h"
      26             : #include "nsIDocShell.h"
      27             : #include "nsIRunnable.h"
      28             : #include "amIAddonManager.h"
      29             : #include "nsPIDOMWindow.h"
      30             : #include "nsPrintfCString.h"
      31             : #include "mozilla/Preferences.h"
      32             : #include "mozilla/Telemetry.h"
      33             : #include "mozilla/Services.h"
      34             : #include "mozilla/dom/ScriptSettings.h"
      35             : 
      36             : #include "nsContentUtils.h"
      37             : #include "nsCCUncollectableMarker.h"
      38             : #include "nsCycleCollectionNoteRootCallback.h"
      39             : #include "nsCycleCollector.h"
      40             : #include "jsapi.h"
      41             : #include "jsprf.h"
      42             : #include "js/MemoryMetrics.h"
      43             : #include "mozilla/dom/GeneratedAtomList.h"
      44             : #include "mozilla/dom/BindingUtils.h"
      45             : #include "mozilla/dom/Element.h"
      46             : #include "mozilla/dom/ScriptLoader.h"
      47             : #include "mozilla/dom/WindowBinding.h"
      48             : #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
      49             : #include "mozilla/Atomics.h"
      50             : #include "mozilla/Attributes.h"
      51             : #include "mozilla/ProcessHangMonitor.h"
      52             : #include "mozilla/Sprintf.h"
      53             : #include "mozilla/ThreadLocal.h"
      54             : #include "mozilla/UniquePtrExtensions.h"
      55             : #include "mozilla/Unused.h"
      56             : #include "AccessCheck.h"
      57             : #include "nsGlobalWindow.h"
      58             : #include "nsAboutProtocolUtils.h"
      59             : 
      60             : #include "GeckoProfiler.h"
      61             : #include "nsIInputStream.h"
      62             : #include "nsIXULRuntime.h"
      63             : #include "nsJSPrincipals.h"
      64             : 
      65             : #ifdef MOZ_CRASHREPORTER
      66             : #include "nsExceptionHandler.h"
      67             : #endif
      68             : 
      69             : #ifdef XP_WIN
      70             : #include <windows.h>
      71             : #endif
      72             : 
      73             : static MOZ_THREAD_LOCAL(XPCJSContext*) gTlsContext;
      74             : 
      75             : using namespace mozilla;
      76             : using namespace xpc;
      77             : using namespace JS;
      78             : using mozilla::dom::PerThreadAtomCache;
      79             : using mozilla::dom::AutoEntryScript;
      80             : 
      81             : static void WatchdogMain(void* arg);
      82             : class Watchdog;
      83             : class WatchdogManager;
      84             : class AutoLockWatchdog {
      85             :     Watchdog* const mWatchdog;
      86             :   public:
      87             :     explicit AutoLockWatchdog(Watchdog* aWatchdog);
      88             :     ~AutoLockWatchdog();
      89             : };
      90             : 
      91             : class Watchdog
      92             : {
      93             :   public:
      94           3 :     explicit Watchdog(WatchdogManager* aManager)
      95           3 :       : mManager(aManager)
      96             :       , mLock(nullptr)
      97             :       , mWakeup(nullptr)
      98             :       , mThread(nullptr)
      99             :       , mHibernating(false)
     100             :       , mInitialized(false)
     101             :       , mShuttingDown(false)
     102           3 :       , mMinScriptRunTimeSeconds(1)
     103           3 :     {}
     104           0 :     ~Watchdog() { MOZ_ASSERT(!Initialized()); }
     105             : 
     106           3 :     WatchdogManager* Manager() { return mManager; }
     107           3 :     bool Initialized() { return mInitialized; }
     108          35 :     bool ShuttingDown() { return mShuttingDown; }
     109        6859 :     PRLock* GetLock() { return mLock; }
     110        1713 :     bool Hibernating() { return mHibernating; }
     111           0 :     void WakeUp()
     112             :     {
     113           0 :         MOZ_ASSERT(Initialized());
     114           0 :         MOZ_ASSERT(Hibernating());
     115           0 :         mHibernating = false;
     116           0 :         PR_NotifyCondVar(mWakeup);
     117           0 :     }
     118             : 
     119             :     //
     120             :     // Invoked by the main thread only.
     121             :     //
     122             : 
     123           3 :     void Init()
     124             :     {
     125           3 :         MOZ_ASSERT(NS_IsMainThread());
     126           3 :         mLock = PR_NewLock();
     127           3 :         if (!mLock)
     128           0 :             NS_RUNTIMEABORT("PR_NewLock failed.");
     129           3 :         mWakeup = PR_NewCondVar(mLock);
     130           3 :         if (!mWakeup)
     131           0 :             NS_RUNTIMEABORT("PR_NewCondVar failed.");
     132             : 
     133             :         {
     134           6 :             AutoLockWatchdog lock(this);
     135             : 
     136             :             // Gecko uses thread private for accounting and has to clean up at thread exit.
     137             :             // Therefore, even though we don't have a return value from the watchdog, we need to
     138             :             // join it on shutdown.
     139           3 :             mThread = PR_CreateThread(PR_USER_THREAD, WatchdogMain, this,
     140             :                                       PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
     141             :                                       PR_JOINABLE_THREAD, 0);
     142           3 :             if (!mThread)
     143           0 :                 NS_RUNTIMEABORT("PR_CreateThread failed!");
     144             : 
     145             :             // WatchdogMain acquires the lock and then asserts mInitialized. So
     146             :             // make sure to set mInitialized before releasing the lock here so
     147             :             // that it's atomic with the creation of the thread.
     148           3 :             mInitialized = true;
     149             :         }
     150           3 :     }
     151             : 
     152           0 :     void Shutdown()
     153             :     {
     154           0 :         MOZ_ASSERT(NS_IsMainThread());
     155           0 :         MOZ_ASSERT(Initialized());
     156             :         {   // Scoped lock.
     157           0 :             AutoLockWatchdog lock(this);
     158             : 
     159             :             // Signal to the watchdog thread that it's time to shut down.
     160           0 :             mShuttingDown = true;
     161             : 
     162             :             // Wake up the watchdog, and wait for it to call us back.
     163           0 :             PR_NotifyCondVar(mWakeup);
     164             :         }
     165             : 
     166           0 :         PR_JoinThread(mThread);
     167             : 
     168             :         // The thread sets mShuttingDown to false as it exits.
     169           0 :         MOZ_ASSERT(!mShuttingDown);
     170             : 
     171             :         // Destroy state.
     172           0 :         mThread = nullptr;
     173           0 :         PR_DestroyCondVar(mWakeup);
     174           0 :         mWakeup = nullptr;
     175           0 :         PR_DestroyLock(mLock);
     176           0 :         mLock = nullptr;
     177             : 
     178             :         // All done.
     179           0 :         mInitialized = false;
     180           0 :     }
     181             : 
     182          13 :     void SetMinScriptRunTimeSeconds(int32_t seconds)
     183             :     {
     184             :         // This variable is atomic, and is set from the main thread without
     185             :         // locking.
     186          13 :         MOZ_ASSERT(seconds > 0);
     187          13 :         mMinScriptRunTimeSeconds = seconds;
     188          13 :     }
     189             : 
     190             :     //
     191             :     // Invoked by the watchdog thread only.
     192             :     //
     193             : 
     194           0 :     void Hibernate()
     195             :     {
     196           0 :         MOZ_ASSERT(!NS_IsMainThread());
     197           0 :         mHibernating = true;
     198           0 :         Sleep(PR_INTERVAL_NO_TIMEOUT);
     199           0 :     }
     200          32 :     void Sleep(PRIntervalTime timeout)
     201             :     {
     202          32 :         MOZ_ASSERT(!NS_IsMainThread());
     203          32 :         MOZ_ALWAYS_TRUE(PR_WaitCondVar(mWakeup, timeout) == PR_SUCCESS);
     204          29 :     }
     205           0 :     void Finished()
     206             :     {
     207           0 :         MOZ_ASSERT(!NS_IsMainThread());
     208           0 :         mShuttingDown = false;
     209           0 :     }
     210             : 
     211          29 :     int32_t MinScriptRunTimeSeconds()
     212             :     {
     213          29 :         return mMinScriptRunTimeSeconds;
     214             :     }
     215             : 
     216             :   private:
     217             :     WatchdogManager* mManager;
     218             : 
     219             :     PRLock* mLock;
     220             :     PRCondVar* mWakeup;
     221             :     PRThread* mThread;
     222             :     bool mHibernating;
     223             :     bool mInitialized;
     224             :     bool mShuttingDown;
     225             :     mozilla::Atomic<int32_t> mMinScriptRunTimeSeconds;
     226             : };
     227             : 
     228             : #define PREF_MAX_SCRIPT_RUN_TIME_CONTENT "dom.max_script_run_time"
     229             : #define PREF_MAX_SCRIPT_RUN_TIME_CHROME "dom.max_chrome_script_run_time"
     230             : 
     231             : class WatchdogManager : public nsIObserver
     232             : {
     233             :   public:
     234             : 
     235             :     NS_DECL_ISUPPORTS
     236           3 :     explicit WatchdogManager(XPCJSContext* aContext) : mContext(aContext)
     237           3 :                                                      , mContextState(CONTEXT_INACTIVE)
     238             :     {
     239             :         // All the timestamps start at zero except for context state change.
     240           3 :         PodArrayZero(mTimestamps);
     241           3 :         mTimestamps[TimestampContextStateChange] = PR_Now();
     242             : 
     243             :         // Enable the watchdog, if appropriate.
     244           3 :         RefreshWatchdog();
     245             : 
     246             :         // Register ourselves as an observer to get updates on the pref.
     247           3 :         mozilla::Preferences::AddStrongObserver(this, "dom.use_watchdog");
     248           3 :         mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
     249           3 :         mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
     250           3 :     }
     251             : 
     252             :   protected:
     253             : 
     254           0 :     virtual ~WatchdogManager()
     255           0 :     {
     256             :         // Shutting down the watchdog requires context-switching to the watchdog
     257             :         // thread, which isn't great to do in a destructor. So we require
     258             :         // consumers to shut it down manually before releasing it.
     259           0 :         MOZ_ASSERT(!mWatchdog);
     260           0 :     }
     261             : 
     262             :   public:
     263             : 
     264           0 :     void Shutdown()
     265             :     {
     266           0 :         mozilla::Preferences::RemoveObserver(this, "dom.use_watchdog");
     267           0 :         mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
     268           0 :         mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
     269           0 :     }
     270             : 
     271          10 :     NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
     272             :                        const char16_t* aData) override
     273             :     {
     274          10 :         RefreshWatchdog();
     275          10 :         return NS_OK;
     276             :     }
     277             : 
     278             :     // Context statistics. These live on the watchdog manager, are written
     279             :     // from the main thread, and are read from the watchdog thread (holding
     280             :     // the lock in each case).
     281             :     void
     282        3425 :     RecordContextActivity(bool active)
     283             :     {
     284             :         // The watchdog reads this state, so acquire the lock before writing it.
     285        3425 :         MOZ_ASSERT(NS_IsMainThread());
     286        6850 :         Maybe<AutoLockWatchdog> lock;
     287        3425 :         if (mWatchdog)
     288        3425 :             lock.emplace(mWatchdog);
     289             : 
     290             :         // Write state.
     291        3425 :         mTimestamps[TimestampContextStateChange] = PR_Now();
     292        3425 :         mContextState = active ? CONTEXT_ACTIVE : CONTEXT_INACTIVE;
     293             : 
     294             :         // The watchdog may be hibernating, waiting for the context to go
     295             :         // active. Wake it up if necessary.
     296        3425 :         if (active && mWatchdog && mWatchdog->Hibernating())
     297           0 :             mWatchdog->WakeUp();
     298        3425 :     }
     299          61 :     bool IsContextActive() { return mContextState == CONTEXT_ACTIVE; }
     300          32 :     PRTime TimeSinceLastContextStateChange()
     301             :     {
     302          32 :         return PR_Now() - GetTimestamp(TimestampContextStateChange);
     303             :     }
     304             : 
     305             :     // Note - Because of the context activity timestamp, these are read and
     306             :     // written from both threads.
     307          29 :     void RecordTimestamp(WatchdogTimestampCategory aCategory)
     308             :     {
     309             :         // The watchdog thread always holds the lock when it runs.
     310          58 :         Maybe<AutoLockWatchdog> maybeLock;
     311          29 :         if (NS_IsMainThread() && mWatchdog)
     312           0 :             maybeLock.emplace(mWatchdog);
     313          29 :         mTimestamps[aCategory] = PR_Now();
     314          29 :     }
     315          32 :     PRTime GetTimestamp(WatchdogTimestampCategory aCategory)
     316             :     {
     317             :         // The watchdog thread always holds the lock when it runs.
     318          64 :         Maybe<AutoLockWatchdog> maybeLock;
     319          32 :         if (NS_IsMainThread() && mWatchdog)
     320           0 :             maybeLock.emplace(mWatchdog);
     321          64 :         return mTimestamps[aCategory];
     322             :     }
     323             : 
     324           0 :     XPCJSContext* Context() { return mContext; }
     325           0 :     Watchdog* GetWatchdog() { return mWatchdog; }
     326             : 
     327          13 :     void RefreshWatchdog()
     328             :     {
     329          13 :         bool wantWatchdog = Preferences::GetBool("dom.use_watchdog", true);
     330          13 :         if (wantWatchdog != !!mWatchdog) {
     331           3 :             if (wantWatchdog)
     332           3 :                 StartWatchdog();
     333             :             else
     334           0 :                 StopWatchdog();
     335             :         }
     336             : 
     337          13 :         if (mWatchdog) {
     338          13 :             int32_t contentTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CONTENT, 10);
     339          13 :             if (contentTime <= 0)
     340           9 :                 contentTime = INT32_MAX;
     341          13 :             int32_t chromeTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CHROME, 20);
     342          13 :             if (chromeTime <= 0)
     343          10 :                 chromeTime = INT32_MAX;
     344          13 :             mWatchdog->SetMinScriptRunTimeSeconds(std::min(contentTime, chromeTime));
     345             :         }
     346          13 :     }
     347             : 
     348           3 :     void StartWatchdog()
     349             :     {
     350           3 :         MOZ_ASSERT(!mWatchdog);
     351           3 :         mWatchdog = new Watchdog(this);
     352           3 :         mWatchdog->Init();
     353           3 :     }
     354             : 
     355           0 :     void StopWatchdog()
     356             :     {
     357           0 :         MOZ_ASSERT(mWatchdog);
     358           0 :         mWatchdog->Shutdown();
     359           0 :         mWatchdog = nullptr;
     360           0 :     }
     361             : 
     362             :   private:
     363             :     XPCJSContext* mContext;
     364             :     nsAutoPtr<Watchdog> mWatchdog;
     365             : 
     366             :     enum { CONTEXT_ACTIVE, CONTEXT_INACTIVE } mContextState;
     367             :     PRTime mTimestamps[TimestampCount];
     368             : };
     369             : 
     370         125 : NS_IMPL_ISUPPORTS(WatchdogManager, nsIObserver)
     371             : 
     372        3431 : AutoLockWatchdog::AutoLockWatchdog(Watchdog* aWatchdog) : mWatchdog(aWatchdog)
     373             : {
     374        3431 :     PR_Lock(mWatchdog->GetLock());
     375        3431 : }
     376             : 
     377        6856 : AutoLockWatchdog::~AutoLockWatchdog()
     378             : {
     379        3428 :     PR_Unlock(mWatchdog->GetLock());
     380        3428 : }
     381             : 
     382             : static void
     383           3 : WatchdogMain(void* arg)
     384             : {
     385           3 :     mozilla::AutoProfilerRegisterThread registerThread("JS Watchdog");
     386           3 :     NS_SetCurrentThreadName("JS Watchdog");
     387             : 
     388           3 :     Watchdog* self = static_cast<Watchdog*>(arg);
     389           3 :     WatchdogManager* manager = self->Manager();
     390             : 
     391             :     // Lock lasts until we return
     392           3 :     AutoLockWatchdog lock(self);
     393             : 
     394           3 :     MOZ_ASSERT(self->Initialized());
     395           3 :     MOZ_ASSERT(!self->ShuttingDown());
     396          61 :     while (!self->ShuttingDown()) {
     397             :         // Sleep only 1 second if recently (or currently) active; otherwise, hibernate
     398          43 :         if (manager->IsContextActive() ||
     399          11 :             manager->TimeSinceLastContextStateChange() <= PRTime(2*PR_USEC_PER_SEC))
     400             :         {
     401          32 :             self->Sleep(PR_TicksPerSecond());
     402             :         } else {
     403           0 :             manager->RecordTimestamp(TimestampWatchdogHibernateStart);
     404           0 :             self->Hibernate();
     405           0 :             manager->RecordTimestamp(TimestampWatchdogHibernateStop);
     406             :         }
     407             : 
     408             :         // Rise and shine.
     409          29 :         manager->RecordTimestamp(TimestampWatchdogWakeup);
     410             : 
     411             :         // Don't request an interrupt callback unless the current script has
     412             :         // been running long enough that we might show the slow script dialog.
     413             :         // Triggering the callback from off the main thread can be expensive.
     414             : 
     415             :         // We want to avoid showing the slow script dialog if the user's laptop
     416             :         // goes to sleep in the middle of running a script. To ensure this, we
     417             :         // invoke the interrupt callback after only half the timeout has
     418             :         // elapsed. The callback simply records the fact that it was called in
     419             :         // the mSlowScriptSecondHalf flag. Then we wait another (timeout/2)
     420             :         // seconds and invoke the callback again. This time around it sees
     421             :         // mSlowScriptSecondHalf is set and so it shows the slow script
     422             :         // dialog. If the computer is put to sleep during one of the (timeout/2)
     423             :         // periods, the script still has the other (timeout/2) seconds to
     424             :         // finish.
     425          29 :         PRTime usecs = self->MinScriptRunTimeSeconds() * PR_USEC_PER_SEC / 2;
     426          50 :         if (manager->IsContextActive() &&
     427          21 :             manager->TimeSinceLastContextStateChange() >= usecs)
     428             :         {
     429           0 :             bool debuggerAttached = false;
     430           0 :             nsCOMPtr<nsIDebug2> dbg = do_GetService("@mozilla.org/xpcom/debug;1");
     431           0 :             if (dbg)
     432           0 :                 dbg->GetIsDebuggerAttached(&debuggerAttached);
     433           0 :             if (!debuggerAttached)
     434           0 :                 JS_RequestInterruptCallback(manager->Context()->Context());
     435             :         }
     436             :     }
     437             : 
     438             :     // Tell the manager that we've shut down.
     439           0 :     self->Finished();
     440           0 : }
     441             : 
     442             : PRTime
     443           0 : XPCJSContext::GetWatchdogTimestamp(WatchdogTimestampCategory aCategory)
     444             : {
     445           0 :     return mWatchdogManager->GetTimestamp(aCategory);
     446             : }
     447             : 
     448             : void
     449           0 : xpc::SimulateActivityCallback(bool aActive)
     450             : {
     451           0 :     XPCJSContext::ActivityCallback(XPCJSContext::Get(), aActive);
     452           0 : }
     453             : 
     454             : // static
     455             : void
     456        3425 : XPCJSContext::ActivityCallback(void* arg, bool active)
     457             : {
     458        3425 :     if (!active) {
     459        1712 :         ProcessHangMonitor::ClearHang();
     460             :     }
     461             : 
     462        3425 :     XPCJSContext* self = static_cast<XPCJSContext*>(arg);
     463        3425 :     self->mWatchdogManager->RecordContextActivity(active);
     464        3425 : }
     465             : 
     466             : // static
     467             : bool
     468          27 : XPCJSContext::InterruptCallback(JSContext* cx)
     469             : {
     470          27 :     XPCJSContext* self = XPCJSContext::Get();
     471             : 
     472             :     // Now is a good time to turn on profiling if it's pending.
     473          27 :     profiler_js_interrupt_callback();
     474             : 
     475             :     // Normally we record mSlowScriptCheckpoint when we start to process an
     476             :     // event. However, we can run JS outside of event handlers. This code takes
     477             :     // care of that case.
     478          27 :     if (self->mSlowScriptCheckpoint.IsNull()) {
     479           4 :         self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
     480           4 :         self->mSlowScriptSecondHalf = false;
     481           4 :         self->mSlowScriptActualWait = mozilla::TimeDuration();
     482           4 :         self->mTimeoutAccumulated = false;
     483           4 :         return true;
     484             :     }
     485             : 
     486             :     // Sometimes we get called back during XPConnect initialization, before Gecko
     487             :     // has finished bootstrapping. Avoid crashing in nsContentUtils below.
     488          23 :     if (!nsContentUtils::IsInitialized())
     489           0 :         return true;
     490             : 
     491             :     // This is at least the second interrupt callback we've received since
     492             :     // returning to the event loop. See how long it's been, and what the limit
     493             :     // is.
     494          23 :     TimeDuration duration = TimeStamp::NowLoRes() - self->mSlowScriptCheckpoint;
     495          23 :     bool chrome = nsContentUtils::IsSystemCaller(cx);
     496          23 :     const char* prefName = chrome ? PREF_MAX_SCRIPT_RUN_TIME_CHROME
     497          23 :                                   : PREF_MAX_SCRIPT_RUN_TIME_CONTENT;
     498          23 :     int32_t limit = Preferences::GetInt(prefName, chrome ? 20 : 10);
     499             : 
     500             :     // If there's no limit, or we're within the limit, let it go.
     501          23 :     if (limit == 0 || duration.ToSeconds() < limit / 2.0)
     502          23 :         return true;
     503             : 
     504           0 :     self->mSlowScriptActualWait += duration;
     505             : 
     506             :     // In order to guard against time changes or laptops going to sleep, we
     507             :     // don't trigger the slow script warning until (limit/2) seconds have
     508             :     // elapsed twice.
     509           0 :     if (!self->mSlowScriptSecondHalf) {
     510           0 :         self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
     511           0 :         self->mSlowScriptSecondHalf = true;
     512           0 :         return true;
     513             :     }
     514             : 
     515             :     //
     516             :     // This has gone on long enough! Time to take action. ;-)
     517             :     //
     518             : 
     519             :     // Get the DOM window associated with the running script. If the script is
     520             :     // running in a non-DOM scope, we have to just let it keep running.
     521           0 :     RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
     522           0 :     RefPtr<nsGlobalWindow> win = WindowOrNull(global);
     523           0 :     if (!win && IsSandbox(global)) {
     524             :         // If this is a sandbox associated with a DOMWindow via a
     525             :         // sandboxPrototype, use that DOMWindow. This supports GreaseMonkey
     526             :         // and JetPack content scripts.
     527           0 :         JS::Rooted<JSObject*> proto(cx);
     528           0 :         if (!JS_GetPrototype(cx, global, &proto))
     529           0 :             return false;
     530           0 :         if (proto && IsSandboxPrototypeProxy(proto) &&
     531           0 :             (proto = js::CheckedUnwrap(proto, /* stopAtWindowProxy = */ false)))
     532             :         {
     533           0 :             win = WindowGlobalOrNull(proto);
     534             :         }
     535             :     }
     536             : 
     537           0 :     if (!win) {
     538           0 :         NS_WARNING("No active window");
     539           0 :         return true;
     540             :     }
     541             : 
     542           0 :     if (win->IsDying()) {
     543             :         // The window is being torn down. When that happens we try to prevent
     544             :         // the dispatch of new runnables, so it also makes sense to kill any
     545             :         // long-running script. The user is primarily interested in this page
     546             :         // going away.
     547           0 :         return false;
     548             :     }
     549             : 
     550           0 :     if (win->GetIsPrerendered()) {
     551             :         // We cannot display a dialog if the page is being prerendered, so
     552             :         // just kill the page.
     553           0 :         mozilla::dom::HandlePrerenderingViolation(win->AsInner());
     554           0 :         return false;
     555             :     }
     556             : 
     557             :     // Accumulate slow script invokation delay.
     558           0 :     if (!chrome && !self->mTimeoutAccumulated) {
     559           0 :       uint32_t delay = uint32_t(self->mSlowScriptActualWait.ToMilliseconds() - (limit * 1000.0));
     560           0 :       Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_NOTIFY_DELAY, delay);
     561           0 :       self->mTimeoutAccumulated = true;
     562             :     }
     563             : 
     564             :     // Show the prompt to the user, and kill if requested.
     565           0 :     nsGlobalWindow::SlowScriptResponse response = win->ShowSlowScriptDialog();
     566           0 :     if (response == nsGlobalWindow::KillSlowScript) {
     567           0 :         if (Preferences::GetBool("dom.global_stop_script", true))
     568           0 :             xpc::Scriptability::Get(global).Block();
     569           0 :         return false;
     570             :     }
     571             : 
     572             :     // The user chose to continue the script. Reset the timer, and disable this
     573             :     // machinery with a pref of the user opted out of future slow-script dialogs.
     574           0 :     if (response != nsGlobalWindow::ContinueSlowScriptAndKeepNotifying)
     575           0 :         self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
     576             : 
     577           0 :     if (response == nsGlobalWindow::AlwaysContinueSlowScript)
     578           0 :         Preferences::SetInt(prefName, 0);
     579             : 
     580           0 :     return true;
     581             : }
     582             : 
     583             : #define JS_OPTIONS_DOT_STR "javascript.options."
     584             : 
     585             : static mozilla::Atomic<bool> sDiscardSystemSource(false);
     586             : 
     587             : bool
     588         271 : xpc::ShouldDiscardSystemSource() { return sDiscardSystemSource; }
     589             : 
     590             : #ifdef DEBUG
     591             : static mozilla::Atomic<bool> sExtraWarningsForSystemJS(false);
     592         268 : bool xpc::ExtraWarningsForSystemJS() { return sExtraWarningsForSystemJS; }
     593             : #else
     594             : bool xpc::ExtraWarningsForSystemJS() { return false; }
     595             : #endif
     596             : 
     597             : static mozilla::Atomic<bool> sSharedMemoryEnabled(false);
     598             : 
     599             : bool
     600         554 : xpc::SharedMemoryEnabled() { return sSharedMemoryEnabled; }
     601             : 
     602             : static void
     603           3 : ReloadPrefsCallback(const char* pref, void* data)
     604             : {
     605           3 :     XPCJSContext* xpccx = static_cast<XPCJSContext*>(data);
     606           3 :     JSContext* cx = xpccx->Context();
     607             : 
     608           3 :     bool safeMode = false;
     609           6 :     nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
     610           3 :     if (xr) {
     611           3 :         xr->GetInSafeMode(&safeMode);
     612             :     }
     613             : 
     614           3 :     bool useBaseline = Preferences::GetBool(JS_OPTIONS_DOT_STR "baselinejit") && !safeMode;
     615           3 :     bool useIon = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion") && !safeMode;
     616           3 :     bool useAsmJS = Preferences::GetBool(JS_OPTIONS_DOT_STR "asmjs") && !safeMode;
     617           3 :     bool useWasm = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm") && !safeMode;
     618           3 :     bool useWasmBaseline = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm_baselinejit") && !safeMode;
     619             :     bool throwOnAsmJSValidationFailure = Preferences::GetBool(JS_OPTIONS_DOT_STR
     620           3 :                                                               "throw_on_asmjs_validation_failure");
     621           3 :     bool useNativeRegExp = Preferences::GetBool(JS_OPTIONS_DOT_STR "native_regexp") && !safeMode;
     622             : 
     623           3 :     bool parallelParsing = Preferences::GetBool(JS_OPTIONS_DOT_STR "parallel_parsing");
     624             :     bool offthreadIonCompilation = Preferences::GetBool(JS_OPTIONS_DOT_STR
     625           3 :                                                        "ion.offthread_compilation");
     626             :     bool useBaselineEager = Preferences::GetBool(JS_OPTIONS_DOT_STR
     627           3 :                                                  "baselinejit.unsafe_eager_compilation");
     628           3 :     bool useIonEager = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion.unsafe_eager_compilation");
     629             : #ifdef DEBUG
     630           3 :     bool fullJitDebugChecks = Preferences::GetBool(JS_OPTIONS_DOT_STR "jit.full_debug_checks");
     631             : #endif
     632             : 
     633           3 :     int32_t baselineThreshold = Preferences::GetInt(JS_OPTIONS_DOT_STR "baselinejit.threshold", -1);
     634           3 :     int32_t ionThreshold = Preferences::GetInt(JS_OPTIONS_DOT_STR "ion.threshold", -1);
     635             : 
     636           3 :     sDiscardSystemSource = Preferences::GetBool(JS_OPTIONS_DOT_STR "discardSystemSource");
     637             : 
     638           3 :     bool useAsyncStack = Preferences::GetBool(JS_OPTIONS_DOT_STR "asyncstack");
     639             : 
     640             :     bool throwOnDebuggeeWouldRun = Preferences::GetBool(JS_OPTIONS_DOT_STR
     641           3 :                                                         "throw_on_debuggee_would_run");
     642             : 
     643             :     bool dumpStackOnDebuggeeWouldRun = Preferences::GetBool(JS_OPTIONS_DOT_STR
     644           3 :                                                             "dump_stack_on_debuggee_would_run");
     645             : 
     646           3 :     bool werror = Preferences::GetBool(JS_OPTIONS_DOT_STR "werror");
     647             : 
     648           3 :     bool extraWarnings = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict");
     649             : 
     650           3 :     sSharedMemoryEnabled = Preferences::GetBool(JS_OPTIONS_DOT_STR "shared_memory");
     651             : 
     652             : #ifdef DEBUG
     653           3 :     sExtraWarningsForSystemJS = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict.debug");
     654             : #endif
     655             : 
     656             : #ifdef JS_GC_ZEAL
     657           3 :     int32_t zeal = Preferences::GetInt(JS_OPTIONS_DOT_STR "gczeal", -1);
     658             :     int32_t zeal_frequency =
     659             :         Preferences::GetInt(JS_OPTIONS_DOT_STR "gczeal.frequency",
     660           3 :                             JS_DEFAULT_ZEAL_FREQ);
     661           3 :     if (zeal >= 0) {
     662           0 :         JS_SetGCZeal(cx, (uint8_t)zeal, zeal_frequency);
     663             :     }
     664             : #endif // JS_GC_ZEAL
     665             : 
     666             : #ifdef FUZZING
     667             :     bool fuzzingEnabled = Preferences::GetBool("fuzzing.enabled");
     668             : #endif
     669             : 
     670           3 :     JS::ContextOptionsRef(cx).setBaseline(useBaseline)
     671           6 :                              .setIon(useIon)
     672           6 :                              .setAsmJS(useAsmJS)
     673           6 :                              .setWasm(useWasm)
     674           6 :                              .setWasmAlwaysBaseline(useWasmBaseline)
     675           6 :                              .setThrowOnAsmJSValidationFailure(throwOnAsmJSValidationFailure)
     676           6 :                              .setNativeRegExp(useNativeRegExp)
     677           6 :                              .setAsyncStack(useAsyncStack)
     678           6 :                              .setThrowOnDebuggeeWouldRun(throwOnDebuggeeWouldRun)
     679           6 :                              .setDumpStackOnDebuggeeWouldRun(dumpStackOnDebuggeeWouldRun)
     680           6 :                              .setWerror(werror)
     681             : #ifdef FUZZING
     682             :                              .setFuzzing(fuzzingEnabled)
     683             : #endif
     684           6 :                              .setExtraWarnings(extraWarnings);
     685             : 
     686           3 :     JS_SetParallelParsingEnabled(cx, parallelParsing);
     687           3 :     JS_SetOffthreadIonCompilationEnabled(cx, offthreadIonCompilation);
     688           3 :     JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_BASELINE_WARMUP_TRIGGER,
     689           3 :                                   useBaselineEager ? 0 : baselineThreshold);
     690           3 :     JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_WARMUP_TRIGGER,
     691           3 :                                   useIonEager ? 0 : ionThreshold);
     692             : #ifdef DEBUG
     693           3 :     JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_FULL_DEBUG_CHECKS, fullJitDebugChecks);
     694             : #endif
     695           3 : }
     696             : 
     697           0 : XPCJSContext::~XPCJSContext()
     698             : {
     699           0 :     MOZ_COUNT_DTOR_INHERITED(XPCJSContext, CycleCollectedJSContext);
     700             :     // Elsewhere we abort immediately if XPCJSContext initialization fails.
     701             :     // Therefore the context must be non-null.
     702           0 :     MOZ_ASSERT(MaybeContext());
     703             : 
     704             :     Preferences::UnregisterPrefixCallback(ReloadPrefsCallback,
     705             :                                           JS_OPTIONS_DOT_STR,
     706           0 :                                           this);
     707             : 
     708             : #ifdef FUZZING
     709             :     Preferences::UnregisterCallback(ReloadPrefsCallback, "fuzzing.enabled", this);
     710             : #endif
     711             : 
     712           0 :     js::SetActivityCallback(Context(), nullptr, nullptr);
     713             : 
     714             :     // Clear any pending exception.  It might be an XPCWrappedJS, and if we try
     715             :     // to destroy it later we will crash.
     716           0 :     SetPendingException(nullptr);
     717             : 
     718           0 :     xpc_DelocalizeContext(Context());
     719             : 
     720           0 :     if (mWatchdogManager->GetWatchdog())
     721           0 :         mWatchdogManager->StopWatchdog();
     722           0 :     mWatchdogManager->Shutdown();
     723             : 
     724           0 :     if (mCallContext)
     725           0 :         mCallContext->SystemIsBeingShutDown();
     726             : 
     727           0 :     auto rtPrivate = static_cast<PerThreadAtomCache*>(JS_GetContextPrivate(Context()));
     728             :     delete rtPrivate;
     729           0 :     JS_SetContextPrivate(Context(), nullptr);
     730             : 
     731           0 :     profiler_clear_js_context();
     732             : 
     733           0 :     gTlsContext.set(nullptr);
     734           0 : }
     735             : 
     736           3 : XPCJSContext::XPCJSContext()
     737             :  : mCallContext(nullptr),
     738             :    mAutoRoots(nullptr),
     739             :    mResolveName(JSID_VOID),
     740             :    mResolvingWrapper(nullptr),
     741           3 :    mWatchdogManager(new WatchdogManager(this)),
     742             :    mSlowScriptSecondHalf(false),
     743             :    mTimeoutAccumulated(false),
     744           6 :    mPendingResult(NS_OK)
     745             : {
     746           3 :     MOZ_COUNT_CTOR_INHERITED(XPCJSContext, CycleCollectedJSContext);
     747           3 :     MOZ_RELEASE_ASSERT(!gTlsContext.get());
     748           3 :     gTlsContext.set(this);
     749           3 : }
     750             : 
     751             : /* static */ XPCJSContext*
     752       75163 : XPCJSContext::Get()
     753             : {
     754       75163 :     return gTlsContext.get();
     755             : }
     756             : 
     757             : #ifdef XP_WIN
     758             : static size_t
     759             : GetWindowsStackSize()
     760             : {
     761             :     // First, get the stack base. Because the stack grows down, this is the top
     762             :     // of the stack.
     763             :     const uint8_t* stackTop;
     764             : #ifdef _WIN64
     765             :     PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
     766             :     stackTop = reinterpret_cast<const uint8_t*>(pTib->StackBase);
     767             : #else
     768             :     PNT_TIB pTib = reinterpret_cast<PNT_TIB>(NtCurrentTeb());
     769             :     stackTop = reinterpret_cast<const uint8_t*>(pTib->StackBase);
     770             : #endif
     771             : 
     772             :     // Now determine the stack bottom. Note that we can't use tib->StackLimit,
     773             :     // because that's the size of the committed area and we're also interested
     774             :     // in the reserved pages below that.
     775             :     MEMORY_BASIC_INFORMATION mbi;
     776             :     if (!VirtualQuery(&mbi, &mbi, sizeof(mbi)))
     777             :         MOZ_CRASH("VirtualQuery failed");
     778             : 
     779             :     const uint8_t* stackBottom = reinterpret_cast<const uint8_t*>(mbi.AllocationBase);
     780             : 
     781             :     // Do some sanity checks.
     782             :     size_t stackSize = size_t(stackTop - stackBottom);
     783             :     MOZ_RELEASE_ASSERT(stackSize >= 1 * 1024 * 1024);
     784             :     MOZ_RELEASE_ASSERT(stackSize <= 32 * 1024 * 1024);
     785             : 
     786             :     // Subtract 40 KB (Win32) or 80 KB (Win64) to account for things like
     787             :     // the guard page and large PGO stack frames.
     788             :     return stackSize - 10 * sizeof(uintptr_t) * 1024;
     789             : }
     790             : #endif
     791             : 
     792             : XPCJSRuntime*
     793       24262 : XPCJSContext::Runtime() const
     794             : {
     795       24262 :     return static_cast<XPCJSRuntime*>(CycleCollectedJSContext::Runtime());
     796             : }
     797             : 
     798             : CycleCollectedJSRuntime*
     799           3 : XPCJSContext::CreateRuntime(JSContext* aCx)
     800             : {
     801           3 :     return new XPCJSRuntime(aCx);
     802             : }
     803             : 
     804             : nsresult
     805           3 : XPCJSContext::Initialize(XPCJSContext* aPrimaryContext)
     806             : {
     807             :     nsresult rv;
     808           3 :     if (aPrimaryContext) {
     809           0 :         rv = CycleCollectedJSContext::InitializeNonPrimary(aPrimaryContext);
     810             :     } else {
     811           3 :         rv = CycleCollectedJSContext::Initialize(nullptr,
     812             :                                                  JS::DefaultHeapMaxBytes,
     813           3 :                                                  JS::DefaultNurseryBytes);
     814             :     }
     815           3 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     816           0 :       return rv;
     817             :     }
     818             : 
     819           3 :     MOZ_ASSERT(Context());
     820           3 :     JSContext* cx = Context();
     821             : 
     822           3 :     auto cxPrivate = new PerThreadAtomCache();
     823           3 :     memset(cxPrivate, 0, sizeof(PerThreadAtomCache));
     824           3 :     JS_SetContextPrivate(cx, cxPrivate);
     825             : 
     826             :     // The JS engine permits us to set different stack limits for system code,
     827             :     // trusted script, and untrusted script. We have tests that ensure that
     828             :     // we can always execute 10 "heavy" (eval+with) stack frames deeper in
     829             :     // privileged code. Our stack sizes vary greatly in different configurations,
     830             :     // so satisfying those tests requires some care. Manual measurements of the
     831             :     // number of heavy stack frames achievable gives us the following rough data,
     832             :     // ordered by the effective categories in which they are grouped in the
     833             :     // JS_SetNativeStackQuota call (which predates this analysis).
     834             :     //
     835             :     // (NB: These numbers may have drifted recently - see bug 938429)
     836             :     // OSX 64-bit Debug: 7MB stack, 636 stack frames => ~11.3k per stack frame
     837             :     // OSX64 Opt: 7MB stack, 2440 stack frames => ~3k per stack frame
     838             :     //
     839             :     // Linux 32-bit Debug: 2MB stack, 426 stack frames => ~4.8k per stack frame
     840             :     // Linux 64-bit Debug: 4MB stack, 455 stack frames => ~9.0k per stack frame
     841             :     //
     842             :     // Windows (Opt+Debug): 900K stack, 235 stack frames => ~3.4k per stack frame
     843             :     //
     844             :     // Linux 32-bit Opt: 1MB stack, 272 stack frames => ~3.8k per stack frame
     845             :     // Linux 64-bit Opt: 2MB stack, 316 stack frames => ~6.5k per stack frame
     846             :     //
     847             :     // We tune the trusted/untrusted quotas for each configuration to achieve our
     848             :     // invariants while attempting to minimize overhead. In contrast, our buffer
     849             :     // between system code and trusted script is a very unscientific 10k.
     850           3 :     const size_t kSystemCodeBuffer = 10 * 1024;
     851             : 
     852             :     // Our "default" stack is what we use in configurations where we don't have
     853             :     // a compelling reason to do things differently. This is effectively 512KB
     854             :     // on 32-bit platforms and 1MB on 64-bit platforms.
     855           3 :     const size_t kDefaultStackQuota = 128 * sizeof(size_t) * 1024;
     856             : 
     857             :     // Set stack sizes for different configurations. It's probably not great for
     858             :     // the web to base this decision primarily on the default stack size that the
     859             :     // underlying platform makes available, but that seems to be what we do. :-(
     860             : 
     861             : #if defined(XP_MACOSX) || defined(DARWIN)
     862             :     // MacOS has a gargantuan default stack size of 8MB. Go wild with 7MB,
     863             :     // and give trusted script 180k extra. The stack is huge on mac anyway.
     864             :     const size_t kStackQuota = 7 * 1024 * 1024;
     865             :     const size_t kTrustedScriptBuffer = 180 * 1024;
     866             : #elif defined(MOZ_ASAN)
     867             :     // ASan requires more stack space due to red-zones, so give it double the
     868             :     // default (1MB on 32-bit, 2MB on 64-bit). ASAN stack frame measurements
     869             :     // were not taken at the time of this writing, so we hazard a guess that
     870             :     // ASAN builds have roughly thrice the stack overhead as normal builds.
     871             :     // On normal builds, the largest stack frame size we might encounter is
     872             :     // 9.0k (see above), so let's use a buffer of 9.0 * 5 * 10 = 450k.
     873             :     const size_t kStackQuota =  2 * kDefaultStackQuota;
     874             :     const size_t kTrustedScriptBuffer = 450 * 1024;
     875             : #elif defined(XP_WIN)
     876             :     // 1MB is the default stack size on Windows. We use the /STACK linker flag
     877             :     // to request a larger stack, so we determine the stack size at runtime.
     878             :     const size_t kStackQuota = GetWindowsStackSize();
     879             :     const size_t kTrustedScriptBuffer = (sizeof(size_t) == 8) ? 180 * 1024   //win64
     880             :                                                               : 120 * 1024;  //win32
     881             :     // The following two configurations are linux-only. Given the numbers above,
     882             :     // we use 50k and 100k trusted buffers on 32-bit and 64-bit respectively.
     883             : #elif defined(ANDROID)
     884             :     // Android appears to have 1MB stacks. Allow the use of 3/4 of that size
     885             :     // (768KB on 32-bit), since otherwise we can crash with a stack overflow
     886             :     // when nearing the 1MB limit.
     887             :     const size_t kStackQuota = kDefaultStackQuota + kDefaultStackQuota / 2;
     888             :     const size_t kTrustedScriptBuffer = sizeof(size_t) * 12800;
     889             : #elif defined(DEBUG)
     890             :     // Bug 803182: account for the 4x difference in the size of js::Interpret
     891             :     // between optimized and debug builds.
     892             :     // XXXbholley - Then why do we only account for 2x of difference?
     893           3 :     const size_t kStackQuota = 2 * kDefaultStackQuota;
     894           3 :     const size_t kTrustedScriptBuffer = sizeof(size_t) * 12800;
     895             : #else
     896             :     const size_t kStackQuota = kDefaultStackQuota;
     897             :     const size_t kTrustedScriptBuffer = sizeof(size_t) * 12800;
     898             : #endif
     899             : 
     900             :     // Avoid an unused variable warning on platforms where we don't use the
     901             :     // default.
     902             :     (void) kDefaultStackQuota;
     903             : 
     904             :     JS_SetNativeStackQuota(cx,
     905             :                            kStackQuota,
     906             :                            kStackQuota - kSystemCodeBuffer,
     907           3 :                            kStackQuota - kSystemCodeBuffer - kTrustedScriptBuffer);
     908             : 
     909           3 :     profiler_set_js_context(cx);
     910             : 
     911           3 :     js::SetActivityCallback(cx, ActivityCallback, this);
     912           3 :     JS_AddInterruptCallback(cx, InterruptCallback);
     913             : 
     914             :     // Set up locale information and callbacks for the newly-created context so
     915             :     // that the various toLocaleString() methods, localeCompare(), and other
     916             :     // internationalization APIs work as desired.
     917           3 :     if (!xpc_LocalizeContext(cx))
     918           0 :         NS_RUNTIMEABORT("xpc_LocalizeContext failed.");
     919             : 
     920           3 :     if (!aPrimaryContext) {
     921           3 :         Runtime()->Initialize(cx);
     922             :     }
     923             : 
     924             :     // Watch for the JS boolean options.
     925           3 :     ReloadPrefsCallback(nullptr, this);
     926             :     Preferences::RegisterPrefixCallback(ReloadPrefsCallback,
     927             :                                         JS_OPTIONS_DOT_STR,
     928           3 :                                         this);
     929             : 
     930             : #ifdef FUZZING
     931             :     Preferences::RegisterCallback(ReloadPrefsCallback, "fuzzing.enabled", this);
     932             : #endif
     933             : 
     934           3 :     return NS_OK;
     935             : }
     936             : 
     937             : // static
     938             : void
     939           3 : XPCJSContext::InitTLS()
     940             : {
     941           3 :     MOZ_RELEASE_ASSERT(gTlsContext.init());
     942           3 : }
     943             : 
     944             : // static
     945             : XPCJSContext*
     946           3 : XPCJSContext::NewXPCJSContext(XPCJSContext* aPrimaryContext)
     947             : {
     948           3 :     XPCJSContext* self = new XPCJSContext();
     949           3 :     nsresult rv = self->Initialize(aPrimaryContext);
     950           3 :     if (NS_FAILED(rv)) {
     951           0 :         NS_RUNTIMEABORT("new XPCJSContext failed to initialize.");
     952           0 :         delete self;
     953           0 :         return nullptr;
     954             :     }
     955             : 
     956           3 :     if (self->Context())
     957           3 :         return self;
     958             : 
     959           0 :     NS_RUNTIMEABORT("new XPCJSContext failed to initialize.");
     960           0 :     return nullptr;
     961             : }
     962             : 
     963             : void
     964        1230 : XPCJSContext::BeforeProcessTask(bool aMightBlock)
     965             : {
     966        1230 :     MOZ_ASSERT(NS_IsMainThread());
     967             : 
     968             :     // If ProcessNextEvent was called during a Promise "then" callback, we
     969             :     // must process any pending microtasks before blocking in the event loop,
     970             :     // otherwise we may deadlock until an event enters the queue later.
     971        1230 :     if (aMightBlock) {
     972          89 :         if (Promise::PerformMicroTaskCheckpoint()) {
     973             :             // If any microtask was processed, we post a dummy event in order to
     974             :             // force the ProcessNextEvent call not to block.  This is required
     975             :             // to support nested event loops implemented using a pattern like
     976             :             // "while (condition) thread.processNextEvent(true)", in case the
     977             :             // condition is triggered here by a Promise "then" callback.
     978             : 
     979           0 :             NS_DispatchToMainThread(new Runnable("Empty_microtask_runnable"));
     980             :         }
     981             :     }
     982             : 
     983             :     // Start the slow script timer.
     984        1230 :     mSlowScriptCheckpoint = mozilla::TimeStamp::NowLoRes();
     985        1230 :     mSlowScriptSecondHalf = false;
     986        1230 :     mSlowScriptActualWait = mozilla::TimeDuration();
     987        1230 :     mTimeoutAccumulated = false;
     988             : 
     989             :     // As we may be entering a nested event loop, we need to
     990             :     // cancel any ongoing performance measurement.
     991        1230 :     js::ResetPerformanceMonitoring(Context());
     992             : 
     993        1230 :     CycleCollectedJSContext::BeforeProcessTask(aMightBlock);
     994        1230 : }
     995             : 
     996             : void
     997        1227 : XPCJSContext::AfterProcessTask(uint32_t aNewRecursionDepth)
     998             : {
     999             :     // Now that we're back to the event loop, reset the slow script checkpoint.
    1000        1227 :     mSlowScriptCheckpoint = mozilla::TimeStamp();
    1001        1227 :     mSlowScriptSecondHalf = false;
    1002             : 
    1003             :     // Call cycle collector occasionally.
    1004        1227 :     MOZ_ASSERT(NS_IsMainThread());
    1005        1227 :     nsJSContext::MaybePokeCC();
    1006             : 
    1007        1227 :     CycleCollectedJSContext::AfterProcessTask(aNewRecursionDepth);
    1008             : 
    1009             :     // Now that we are certain that the event is complete,
    1010             :     // we can flush any ongoing performance measurement.
    1011        1227 :     js::FlushPerformanceMonitoring(Context());
    1012             : 
    1013        1227 :     mozilla::jsipc::AfterProcessTask();
    1014        1227 : }

Generated by: LCOV version 1.13