LCOV - code coverage report
Current view: top level - dom/base - nsJSEnvironment.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 458 1291 35.5 %
Date: 2017-07-14 16:53:18 Functions: 63 151 41.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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             : #include "nsError.h"
       8             : #include "nsJSEnvironment.h"
       9             : #include "nsIScriptGlobalObject.h"
      10             : #include "nsIScriptObjectPrincipal.h"
      11             : #include "nsIDOMChromeWindow.h"
      12             : #include "nsPIDOMWindow.h"
      13             : #include "nsIScriptSecurityManager.h"
      14             : #include "nsDOMCID.h"
      15             : #include "nsIServiceManager.h"
      16             : #include "nsIXPConnect.h"
      17             : #include "nsCOMPtr.h"
      18             : #include "nsISupportsPrimitives.h"
      19             : #include "nsReadableUtils.h"
      20             : #include "nsDOMJSUtils.h"
      21             : #include "nsJSUtils.h"
      22             : #include "nsIDocShell.h"
      23             : #include "nsIDocShellTreeItem.h"
      24             : #include "nsPresContext.h"
      25             : #include "nsIConsoleService.h"
      26             : #include "nsIScriptError.h"
      27             : #include "nsIInterfaceRequestor.h"
      28             : #include "nsIInterfaceRequestorUtils.h"
      29             : #include "nsIPrompt.h"
      30             : #include "nsIObserverService.h"
      31             : #include "nsITimer.h"
      32             : #include "nsIAtom.h"
      33             : #include "nsContentUtils.h"
      34             : #include "mozilla/EventDispatcher.h"
      35             : #include "nsIContent.h"
      36             : #include "nsCycleCollector.h"
      37             : #include "nsXPCOMCIDInternal.h"
      38             : #include "nsIXULRuntime.h"
      39             : #include "nsTextFormatter.h"
      40             : #ifdef XP_WIN
      41             : #include <process.h>
      42             : #define getpid _getpid
      43             : #else
      44             : #include <unistd.h> // for getpid()
      45             : #endif
      46             : #include "xpcpublic.h"
      47             : 
      48             : #include "jsapi.h"
      49             : #include "jswrapper.h"
      50             : #include "js/SliceBudget.h"
      51             : #include "nsIArray.h"
      52             : #include "nsIObjectInputStream.h"
      53             : #include "nsIObjectOutputStream.h"
      54             : #include "WrapperFactory.h"
      55             : #include "nsGlobalWindow.h"
      56             : #include "nsScriptNameSpaceManager.h"
      57             : #include "mozilla/AutoRestore.h"
      58             : #include "mozilla/MainThreadIdlePeriod.h"
      59             : #include "mozilla/StaticPtr.h"
      60             : #include "mozilla/dom/DOMException.h"
      61             : #include "mozilla/dom/DOMExceptionBinding.h"
      62             : #include "mozilla/dom/Element.h"
      63             : #include "mozilla/dom/ErrorEvent.h"
      64             : #include "mozilla/dom/ScriptSettings.h"
      65             : #include "nsAXPCNativeCallContext.h"
      66             : #include "mozilla/CycleCollectedJSRuntime.h"
      67             : #include "mozilla/SystemGroup.h"
      68             : #include "nsRefreshDriver.h"
      69             : #include "nsJSPrincipals.h"
      70             : 
      71             : #ifdef XP_MACOSX
      72             : // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
      73             : #undef check
      74             : #endif
      75             : #include "AccessCheck.h"
      76             : 
      77             : #include "mozilla/Logging.h"
      78             : #include "prthread.h"
      79             : 
      80             : #include "mozilla/Preferences.h"
      81             : #include "mozilla/Telemetry.h"
      82             : #include "mozilla/dom/BindingUtils.h"
      83             : #include "mozilla/Attributes.h"
      84             : #include "mozilla/dom/asmjscache/AsmJSCache.h"
      85             : #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
      86             : #include "mozilla/ContentEvents.h"
      87             : 
      88             : #include "nsCycleCollectionNoteRootCallback.h"
      89             : #include "GeckoProfiler.h"
      90             : 
      91             : using namespace mozilla;
      92             : using namespace mozilla::dom;
      93             : 
      94             : const size_t gStackSize = 8192;
      95             : 
      96             : // Thank you Microsoft!
      97             : #ifdef CompareString
      98             : #undef CompareString
      99             : #endif
     100             : 
     101             : #define NS_SHRINK_GC_BUFFERS_DELAY  4000 // ms
     102             : 
     103             : // The amount of time we wait from the first request to GC to actually
     104             : // doing the first GC.
     105             : #define NS_FIRST_GC_DELAY           10000 // ms
     106             : 
     107             : #define NS_FULL_GC_DELAY            60000 // ms
     108             : 
     109             : // The default amount of time to wait from the user being idle to starting a
     110             : // shrinking GC.
     111             : #define NS_DEAULT_INACTIVE_GC_DELAY 300000 // ms
     112             : 
     113             : // Maximum amount of time that should elapse between incremental GC slices
     114             : #define NS_INTERSLICE_GC_DELAY      100 // ms
     115             : 
     116             : // The amount of time we wait between a request to CC (after GC ran)
     117             : // and doing the actual CC.
     118             : #define NS_CC_DELAY                 6000 // ms
     119             : 
     120             : #define NS_CC_SKIPPABLE_DELAY       250 // ms
     121             : 
     122             : // ForgetSkippable is usually fast, so we can use small budgets.
     123             : // This isn't a real budget but a hint to CollectorRunner whether there
     124             : // is enough time to call ForgetSkippable.
     125             : static const int64_t kForgetSkippableSliceDuration = 2;
     126             : 
     127             : // Maximum amount of time that should elapse between incremental CC slices
     128             : static const int64_t kICCIntersliceDelay = 64; // ms
     129             : 
     130             : // Time budget for an incremental CC slice when using timer to run it.
     131             : static const int64_t kICCSliceBudget = 3; // ms
     132             : // Minimum budget for an incremental CC slice when using idle time to run it.
     133             : static const int64_t kIdleICCSliceBudget = 2; // ms
     134             : 
     135             : // Maximum total duration for an ICC
     136             : static const uint32_t kMaxICCDuration = 2000; // ms
     137             : 
     138             : // Force a CC after this long if there's more than NS_CC_FORCED_PURPLE_LIMIT
     139             : // objects in the purple buffer.
     140             : #define NS_CC_FORCED                (2 * 60 * PR_USEC_PER_SEC) // 2 min
     141             : #define NS_CC_FORCED_PURPLE_LIMIT   10
     142             : 
     143             : // Don't allow an incremental GC to lock out the CC for too long.
     144             : #define NS_MAX_CC_LOCKEDOUT_TIME    (30 * PR_USEC_PER_SEC) // 30 seconds
     145             : 
     146             : // Trigger a CC if the purple buffer exceeds this size when we check it.
     147             : #define NS_CC_PURPLE_LIMIT          200
     148             : 
     149             : // Large value used to specify that a script should run essentially forever
     150             : #define NS_UNLIMITED_SCRIPT_RUNTIME (0x40000000LL << 32)
     151             : 
     152             : class CollectorRunner;
     153             : 
     154             : // if you add statics here, add them to the list in StartupJSEnvironment
     155             : 
     156             : static nsITimer *sGCTimer;
     157             : static nsITimer *sShrinkingGCTimer;
     158           3 : static StaticRefPtr<CollectorRunner> sCCRunner;
     159           3 : static StaticRefPtr<CollectorRunner> sICCRunner;
     160             : static nsITimer *sFullGCTimer;
     161           3 : static StaticRefPtr<CollectorRunner> sInterSliceGCRunner;
     162             : 
     163             : static TimeStamp sLastCCEndTime;
     164             : 
     165             : static bool sCCLockedOut;
     166             : static PRTime sCCLockedOutTime;
     167             : 
     168             : static JS::GCSliceCallback sPrevGCSliceCallback;
     169             : 
     170             : static bool sHasRunGC;
     171             : 
     172             : // The number of currently pending document loads. This count isn't
     173             : // guaranteed to always reflect reality and can't easily as we don't
     174             : // have an easy place to know when a load ends or is interrupted in
     175             : // all cases. This counter also gets reset if we end up GC'ing while
     176             : // we're waiting for a slow page to load. IOW, this count may be 0
     177             : // even when there are pending loads.
     178             : static uint32_t sPendingLoadCount;
     179             : static bool sLoadingInProgress;
     180             : 
     181             : static uint32_t sCCollectedWaitingForGC;
     182             : static uint32_t sCCollectedZonesWaitingForGC;
     183             : static uint32_t sLikelyShortLivingObjectsNeedingGC;
     184             : static bool sPostGCEventsToConsole;
     185             : static bool sPostGCEventsToObserver;
     186             : static int32_t sCCRunnerFireCount = 0;
     187             : static uint32_t sMinForgetSkippableTime = UINT32_MAX;
     188             : static uint32_t sMaxForgetSkippableTime = 0;
     189             : static uint32_t sTotalForgetSkippableTime = 0;
     190             : static uint32_t sRemovedPurples = 0;
     191             : static uint32_t sForgetSkippableBeforeCC = 0;
     192             : static uint32_t sPreviousSuspectedCount = 0;
     193             : static uint32_t sCleanupsSinceLastGC = UINT32_MAX;
     194             : static bool sNeedsFullCC = false;
     195             : static bool sNeedsFullGC = false;
     196             : static bool sNeedsGCAfterCC = false;
     197             : static bool sIncrementalCC = false;
     198             : static int32_t sActiveIntersliceGCBudget = 5; // ms;
     199             : static nsScriptNameSpaceManager *gNameSpaceManager;
     200             : 
     201             : static PRTime sFirstCollectionTime;
     202             : 
     203             : static bool sIsInitialized;
     204             : static bool sDidShutdown;
     205             : static bool sShuttingDown;
     206             : static int32_t sContextCount;
     207             : 
     208             : static nsIScriptSecurityManager *sSecurityManager;
     209             : 
     210             : // nsJSEnvironmentObserver observes the memory-pressure notifications
     211             : // and forces a garbage collection and cycle collection when it happens, if
     212             : // the appropriate pref is set.
     213             : 
     214             : static bool sGCOnMemoryPressure;
     215             : 
     216             : // nsJSEnvironmentObserver observes the user-interaction-inactive notifications
     217             : // and triggers a shrinking a garbage collection if the user is still inactive
     218             : // after NS_SHRINKING_GC_DELAY ms later, if the appropriate pref is set.
     219             : 
     220             : static bool sCompactOnUserInactive;
     221             : static uint32_t sCompactOnUserInactiveDelay = NS_DEAULT_INACTIVE_GC_DELAY;
     222             : static bool sIsCompactingOnUserInactive = false;
     223             : 
     224             : // In testing, we call RunNextCollectorTimer() to ensure that the collectors are run more
     225             : // aggressively than they would be in regular browsing. sExpensiveCollectorPokes keeps
     226             : // us from triggering expensive full collections too frequently.
     227             : static int32_t sExpensiveCollectorPokes = 0;
     228             : static const int32_t kPokesBetweenExpensiveCollectorTriggers = 5;
     229             : 
     230             : static TimeDuration sGCUnnotifiedTotalTime;
     231             : 
     232             : // Return true if some meaningful work was done.
     233             : typedef bool (*CollectorRunnerCallback) (TimeStamp aDeadline, void* aData);
     234             : 
     235             : // Repeating callback runner for CC and GC.
     236             : class CollectorRunner final : public IdleRunnable
     237             : {
     238             : public:
     239             :   static already_AddRefed<CollectorRunner>
     240           4 :   Create(CollectorRunnerCallback aCallback, uint32_t aDelay,
     241             :          int64_t aBudget, bool aRepeating, void* aData = nullptr)
     242             :   {
     243           4 :     if (sShuttingDown) {
     244           0 :       return nullptr;
     245             :     }
     246             : 
     247             :     RefPtr<CollectorRunner> runner =
     248           8 :       new CollectorRunner(aCallback, aDelay, aBudget, aRepeating, aData);
     249           4 :     runner->Schedule(false); // Initial scheduling shouldn't use idle dispatch.
     250           4 :     return runner.forget();
     251             :   }
     252             : 
     253           3 :   NS_IMETHOD Run() override
     254             :   {
     255           3 :     if (!mCallback) {
     256           0 :       return NS_OK;
     257             :     }
     258             : 
     259             :     // Deadline is null when called from timer.
     260           3 :     bool deadLineWasNull = mDeadline.IsNull();
     261           3 :     bool didRun = false;
     262           3 :     if (deadLineWasNull || ((TimeStamp::Now() + mBudget) < mDeadline)) {
     263           3 :       CancelTimer();
     264           3 :       didRun = mCallback(mDeadline, mData);
     265             :     }
     266             : 
     267           3 :     if (mCallback && (mRepeating || !didRun)) {
     268             :       // If we didn't do meaningful work, don't schedule using immediate
     269             :       // idle dispatch, since that could lead to a loop until the idle
     270             :       // period ends.
     271           0 :       Schedule(didRun);
     272             :     }
     273             : 
     274           3 :     return NS_OK;
     275             :   }
     276             : 
     277             :   static void
     278           3 :   TimedOut(nsITimer* aTimer, void* aClosure)
     279             :   {
     280           6 :     RefPtr<CollectorRunner> runnable = static_cast<CollectorRunner*>(aClosure);
     281           3 :     runnable->Run();
     282           3 :   }
     283             : 
     284           0 :   void SetDeadline(mozilla::TimeStamp aDeadline) override
     285             :   {
     286           0 :     mDeadline = aDeadline;
     287           0 :   };
     288             : 
     289           7 :   void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override
     290             :   {
     291           7 :     if (mTimerActive) {
     292           3 :       return;
     293             :     }
     294             : 
     295           4 :     mTarget = aTarget;
     296           4 :     if (!mTimer) {
     297           4 :       mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
     298             :     } else {
     299           0 :       mTimer->Cancel();
     300             :     }
     301             : 
     302           4 :     if (mTimer) {
     303           4 :       mTimer->SetTarget(mTarget);
     304           4 :       mTimer->InitWithNamedFuncCallback(TimedOut, this, aDelay,
     305             :                                         nsITimer::TYPE_ONE_SHOT,
     306           4 :                                         "CollectorRunner");
     307           4 :       mTimerActive = true;
     308             :     }
     309             :   }
     310             : 
     311           3 :   nsresult Cancel() override
     312             :   {
     313           3 :     CancelTimer();
     314           3 :     mTimer = nullptr;
     315           3 :     mScheduleTimer = nullptr;
     316           3 :     mCallback = nullptr;
     317           3 :     return NS_OK;
     318             :   }
     319             : 
     320             :   static void
     321           2 :   ScheduleTimedOut(nsITimer* aTimer, void* aClosure)
     322             :   {
     323           4 :     RefPtr<CollectorRunner> runnable = static_cast<CollectorRunner*>(aClosure);
     324           2 :     runnable->Schedule(true);
     325           2 :   }
     326             : 
     327           6 :   void Schedule(bool aAllowIdleDispatch)
     328             :   {
     329           6 :     if (!mCallback) {
     330           0 :       return;
     331             :     }
     332             : 
     333           6 :     if (sShuttingDown) {
     334           0 :       Cancel();
     335           0 :       return;
     336             :     }
     337             : 
     338           6 :     mDeadline = TimeStamp();
     339           6 :     TimeStamp now = TimeStamp::Now();
     340           6 :     TimeStamp hint = nsRefreshDriver::GetIdleDeadlineHint(now);
     341           6 :     if (hint != now) {
     342             :       // RefreshDriver is ticking, let it schedule the idle dispatch.
     343           3 :       nsRefreshDriver::DispatchIdleRunnableAfterTick(this, mDelay);
     344             :       // Ensure we get called at some point, even if RefreshDriver is stopped.
     345           3 :       SetTimer(mDelay, mTarget);
     346             :     } else {
     347             :       // RefreshDriver doesn't seem to be running.
     348           3 :       if (aAllowIdleDispatch) {
     349           2 :         nsCOMPtr<nsIRunnable> runnable = this;
     350           1 :         NS_IdleDispatchToCurrentThread(runnable.forget(), mDelay);
     351           1 :         SetTimer(mDelay, mTarget);
     352             :       } else {
     353           2 :         if (!mScheduleTimer) {
     354           2 :           mScheduleTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
     355           2 :           if (!mScheduleTimer) {
     356           0 :             return;
     357             :           }
     358             :         } else {
     359           0 :           mScheduleTimer->Cancel();
     360             :         }
     361             : 
     362             :         // We weren't allowed to do idle dispatch immediately, do it after a
     363             :         // short timeout.
     364           2 :         mScheduleTimer->InitWithNamedFuncCallback(ScheduleTimedOut, this, 16,
     365             :                                                   nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
     366           2 :                                                   "CollectorRunner");
     367             :       }
     368             :     }
     369             :   }
     370             : 
     371             : private:
     372           4 :   explicit CollectorRunner(CollectorRunnerCallback aCallback,
     373             :                            uint32_t aDelay, int64_t aBudget,
     374             :                            bool aRepeating, void* aData)
     375           4 :     : mCallback(aCallback), mDelay(aDelay)
     376           4 :     , mBudget(TimeDuration::FromMilliseconds(aBudget))
     377           8 :     , mRepeating(aRepeating), mTimerActive(false), mData(aData)
     378             :   {
     379           4 :   }
     380             : 
     381           0 :   ~CollectorRunner()
     382           0 :   {
     383           0 :     CancelTimer();
     384           0 :   }
     385             : 
     386           6 :   void CancelTimer()
     387             :   {
     388           6 :     nsRefreshDriver::CancelIdleRunnable(this);
     389           6 :     if (mTimer) {
     390           6 :       mTimer->Cancel();
     391             :     }
     392           6 :     if (mScheduleTimer) {
     393           4 :       mScheduleTimer->Cancel();
     394             :     }
     395           6 :     mTimerActive = false;
     396           6 :   }
     397             : 
     398             :   nsCOMPtr<nsITimer> mTimer;
     399             :   nsCOMPtr<nsITimer> mScheduleTimer;
     400             :   nsCOMPtr<nsIEventTarget> mTarget;
     401             :   CollectorRunnerCallback mCallback;
     402             :   uint32_t mDelay;
     403             :   TimeStamp mDeadline;
     404             :   TimeDuration mBudget;
     405             :   bool mRepeating;
     406             :   bool mTimerActive;
     407             :   void* mData;
     408             : };
     409             : 
     410             : static const char*
     411           0 : ProcessNameForCollectorLog()
     412             : {
     413           0 :   return XRE_GetProcessType() == GeckoProcessType_Default ?
     414           0 :     "default" : "content";
     415             : }
     416             : 
     417             : namespace xpc {
     418             : 
     419             : // This handles JS Exceptions (via ExceptionStackOrNull), as well as DOM and XPC
     420             : // Exceptions.
     421             : //
     422             : // Note that the returned object is _not_ wrapped into the compartment of
     423             : // exceptionValue.
     424             : JSObject*
     425           0 : FindExceptionStackForConsoleReport(nsPIDOMWindowInner* win,
     426             :                                    JS::HandleValue exceptionValue)
     427             : {
     428           0 :   if (!exceptionValue.isObject()) {
     429           0 :     return nullptr;
     430             :   }
     431             : 
     432           0 :   if (win && win->InnerObjectsFreed()) {
     433             :     // Pretend like we have no stack, so we don't end up keeping the global
     434             :     // alive via the stack.
     435           0 :     return nullptr;
     436             :   }
     437             : 
     438           0 :   JS::RootingContext* rcx = RootingCx();
     439           0 :   JS::RootedObject exceptionObject(rcx, &exceptionValue.toObject());
     440           0 :   JSObject* stackObject = ExceptionStackOrNull(exceptionObject);
     441           0 :   if (stackObject) {
     442           0 :     return stackObject;
     443             :   }
     444             : 
     445             :   // It is not a JS Exception, try DOM Exception.
     446           0 :   RefPtr<Exception> exception;
     447           0 :   UNWRAP_OBJECT(DOMException, exceptionObject, exception);
     448           0 :   if (!exception) {
     449             :     // Not a DOM Exception, try XPC Exception.
     450           0 :     UNWRAP_OBJECT(Exception, exceptionObject, exception);
     451           0 :     if (!exception) {
     452           0 :       return nullptr;
     453             :     }
     454             :   }
     455             : 
     456           0 :   nsCOMPtr<nsIStackFrame> stack = exception->GetLocation();
     457           0 :   if (!stack) {
     458           0 :     return nullptr;
     459             :   }
     460           0 :   JS::RootedValue value(rcx);
     461           0 :   stack->GetNativeSavedFrame(&value);
     462           0 :   if (value.isObject()) {
     463           0 :     return &value.toObject();
     464             :   }
     465           0 :   return nullptr;
     466             : }
     467             : 
     468             : } /* namespace xpc */
     469             : 
     470             : static PRTime
     471           0 : GetCollectionTimeDelta()
     472             : {
     473           0 :   PRTime now = PR_Now();
     474           0 :   if (sFirstCollectionTime) {
     475           0 :     return now - sFirstCollectionTime;
     476             :   }
     477           0 :   sFirstCollectionTime = now;
     478           0 :   return 0;
     479             : }
     480             : 
     481             : static void
     482           0 : KillTimers()
     483             : {
     484           0 :   nsJSContext::KillGCTimer();
     485           0 :   nsJSContext::KillShrinkingGCTimer();
     486           0 :   nsJSContext::KillCCRunner();
     487           0 :   nsJSContext::KillICCRunner();
     488           0 :   nsJSContext::KillFullGCTimer();
     489           0 :   nsJSContext::KillInterSliceGCRunner();
     490           0 : }
     491             : 
     492             : // If we collected a substantial amount of cycles, poke the GC since more objects
     493             : // might be unreachable now.
     494             : static bool
     495           0 : NeedsGCAfterCC()
     496             : {
     497           0 :   return sCCollectedWaitingForGC > 250 ||
     498           0 :     sCCollectedZonesWaitingForGC > 0 ||
     499           0 :     sLikelyShortLivingObjectsNeedingGC > 2500 ||
     500           0 :     sNeedsGCAfterCC;
     501             : }
     502             : 
     503           2 : class nsJSEnvironmentObserver final : public nsIObserver
     504             : {
     505           0 :   ~nsJSEnvironmentObserver() {}
     506             : public:
     507             :   NS_DECL_ISUPPORTS
     508             :   NS_DECL_NSIOBSERVER
     509             : };
     510             : 
     511          22 : NS_IMPL_ISUPPORTS(nsJSEnvironmentObserver, nsIObserver)
     512             : 
     513             : NS_IMETHODIMP
     514           3 : nsJSEnvironmentObserver::Observe(nsISupports* aSubject, const char* aTopic,
     515             :                                  const char16_t* aData)
     516             : {
     517           3 :   if (!nsCRT::strcmp(aTopic, "memory-pressure")) {
     518           0 :     if (sGCOnMemoryPressure) {
     519           0 :       if(StringBeginsWith(nsDependentString(aData),
     520           0 :                           NS_LITERAL_STRING("low-memory-ongoing"))) {
     521             :         // Don't GC/CC if we are in an ongoing low-memory state since its very
     522             :         // slow and it likely won't help us anyway.
     523           0 :         return NS_OK;
     524             :       }
     525             :       nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
     526             :                                      nsJSContext::NonIncrementalGC,
     527           0 :                                      nsJSContext::ShrinkingGC);
     528           0 :       nsJSContext::CycleCollectNow();
     529           0 :       if (NeedsGCAfterCC()) {
     530             :         nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
     531             :                                        nsJSContext::NonIncrementalGC,
     532           0 :                                        nsJSContext::ShrinkingGC);
     533             :       }
     534             :     }
     535           3 :   } else if (!nsCRT::strcmp(aTopic, "user-interaction-inactive")) {
     536           2 :     if (sCompactOnUserInactive) {
     537           2 :       nsJSContext::PokeShrinkingGC();
     538             :     }
     539           1 :   } else if (!nsCRT::strcmp(aTopic, "user-interaction-active")) {
     540           1 :     nsJSContext::KillShrinkingGCTimer();
     541           1 :     if (sIsCompactingOnUserInactive) {
     542           0 :       AutoJSAPI jsapi;
     543           0 :       jsapi.Init();
     544           0 :       JS::AbortIncrementalGC(jsapi.cx());
     545             :     }
     546           1 :     MOZ_ASSERT(!sIsCompactingOnUserInactive);
     547           0 :   } else if (!nsCRT::strcmp(aTopic, "quit-application") ||
     548           0 :              !nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     549           0 :     sShuttingDown = true;
     550           0 :     KillTimers();
     551             :   }
     552             : 
     553           3 :   return NS_OK;
     554             : }
     555             : 
     556             : /****************************************************************
     557             :  ************************** AutoFree ****************************
     558             :  ****************************************************************/
     559             : 
     560             : class AutoFree {
     561             : public:
     562           0 :   explicit AutoFree(void* aPtr) : mPtr(aPtr) {
     563           0 :   }
     564           0 :   ~AutoFree() {
     565           0 :     if (mPtr)
     566           0 :       free(mPtr);
     567           0 :   }
     568             :   void Invalidate() {
     569             :     mPtr = 0;
     570             :   }
     571             : private:
     572             :   void *mPtr;
     573             : };
     574             : 
     575             : // A utility function for script languages to call.  Although it looks small,
     576             : // the use of nsIDocShell and nsPresContext triggers a huge number of
     577             : // dependencies that most languages would not otherwise need.
     578             : // XXXmarkh - This function is mis-placed!
     579             : bool
     580           0 : NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
     581             :                      const ErrorEventInit &aErrorEventInit,
     582             :                      nsEventStatus *aStatus)
     583             : {
     584           0 :   bool called = false;
     585           0 :   nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aScriptGlobal));
     586           0 :   nsIDocShell *docShell = win ? win->GetDocShell() : nullptr;
     587           0 :   if (docShell) {
     588           0 :     RefPtr<nsPresContext> presContext;
     589           0 :     docShell->GetPresContext(getter_AddRefs(presContext));
     590             : 
     591             :     static int32_t errorDepth; // Recursion prevention
     592           0 :     ++errorDepth;
     593             : 
     594           0 :     if (errorDepth < 2) {
     595             :       // Dispatch() must be synchronous for the recursion block
     596             :       // (errorDepth) to work.
     597             :       RefPtr<ErrorEvent> event =
     598           0 :         ErrorEvent::Constructor(nsGlobalWindow::Cast(win),
     599           0 :                                 NS_LITERAL_STRING("error"),
     600           0 :                                 aErrorEventInit);
     601           0 :       event->SetTrusted(true);
     602             : 
     603           0 :       EventDispatcher::DispatchDOMEvent(win, nullptr, event, presContext,
     604           0 :                                         aStatus);
     605           0 :       called = true;
     606             :     }
     607           0 :     --errorDepth;
     608             :   }
     609           0 :   return called;
     610             : }
     611             : 
     612           0 : class ScriptErrorEvent : public Runnable
     613             : {
     614             : public:
     615           0 :   ScriptErrorEvent(nsPIDOMWindowInner* aWindow,
     616             :                    JS::RootingContext* aRootingCx,
     617             :                    xpc::ErrorReport* aReport,
     618             :                    JS::Handle<JS::Value> aError)
     619           0 :     : mozilla::Runnable("ScriptErrorEvent")
     620             :     , mWindow(aWindow)
     621             :     , mReport(aReport)
     622           0 :     , mError(aRootingCx, aError)
     623           0 :   {}
     624             : 
     625           0 :   NS_IMETHOD Run() override
     626             :   {
     627           0 :     nsEventStatus status = nsEventStatus_eIgnore;
     628           0 :     nsPIDOMWindowInner* win = mWindow;
     629           0 :     MOZ_ASSERT(win);
     630           0 :     MOZ_ASSERT(NS_IsMainThread());
     631             :     // First, notify the DOM that we have a script error, but only if
     632             :     // our window is still the current inner.
     633           0 :     JS::RootingContext* rootingCx = RootingCx();
     634           0 :     if (win->IsCurrentInnerWindow() && win->GetDocShell() && !sHandlingScriptError) {
     635           0 :       AutoRestore<bool> recursionGuard(sHandlingScriptError);
     636           0 :       sHandlingScriptError = true;
     637             : 
     638           0 :       RefPtr<nsPresContext> presContext;
     639           0 :       win->GetDocShell()->GetPresContext(getter_AddRefs(presContext));
     640             : 
     641           0 :       RootedDictionary<ErrorEventInit> init(rootingCx);
     642           0 :       init.mCancelable = true;
     643           0 :       init.mFilename = mReport->mFileName;
     644           0 :       init.mBubbles = true;
     645             : 
     646           0 :       NS_NAMED_LITERAL_STRING(xoriginMsg, "Script error.");
     647           0 :       if (!mReport->mIsMuted) {
     648           0 :         init.mMessage = mReport->mErrorMsg;
     649           0 :         init.mLineno = mReport->mLineNumber;
     650           0 :         init.mColno = mReport->mColumn;
     651           0 :         init.mError = mError;
     652             :       } else {
     653           0 :         NS_WARNING("Not same origin error!");
     654           0 :         init.mMessage = xoriginMsg;
     655           0 :         init.mLineno = 0;
     656             :       }
     657             : 
     658             :       RefPtr<ErrorEvent> event =
     659           0 :         ErrorEvent::Constructor(nsGlobalWindow::Cast(win),
     660           0 :                                 NS_LITERAL_STRING("error"), init);
     661           0 :       event->SetTrusted(true);
     662             : 
     663           0 :       EventDispatcher::DispatchDOMEvent(win, nullptr, event, presContext,
     664           0 :                                         &status);
     665             :     }
     666             : 
     667           0 :     if (status != nsEventStatus_eConsumeNoDefault) {
     668             :       JS::Rooted<JSObject*> stack(rootingCx,
     669           0 :         xpc::FindExceptionStackForConsoleReport(win, mError));
     670           0 :       mReport->LogToConsoleWithStack(stack);
     671             :     }
     672             : 
     673           0 :     return NS_OK;
     674             :   }
     675             : 
     676             : private:
     677             :   nsCOMPtr<nsPIDOMWindowInner>  mWindow;
     678             :   RefPtr<xpc::ErrorReport>      mReport;
     679             :   JS::PersistentRootedValue       mError;
     680             : 
     681             :   static bool sHandlingScriptError;
     682             : };
     683             : 
     684             : bool ScriptErrorEvent::sHandlingScriptError = false;
     685             : 
     686             : // This temporarily lives here to avoid code churn. It will go away entirely
     687             : // soon.
     688             : namespace xpc {
     689             : 
     690             : void
     691           0 : DispatchScriptErrorEvent(nsPIDOMWindowInner *win, JS::RootingContext* rootingCx,
     692             :                          xpc::ErrorReport *xpcReport, JS::Handle<JS::Value> exception)
     693             : {
     694           0 :   nsContentUtils::AddScriptRunner(new ScriptErrorEvent(win, rootingCx, xpcReport, exception));
     695           0 : }
     696             : 
     697             : } /* namespace xpc */
     698             : 
     699             : #ifdef DEBUG
     700             : // A couple of useful functions to call when you're debugging.
     701             : nsGlobalWindow *
     702           0 : JSObject2Win(JSObject *obj)
     703             : {
     704           0 :   return xpc::WindowOrNull(obj);
     705             : }
     706             : 
     707             : void
     708           0 : PrintWinURI(nsGlobalWindow *win)
     709             : {
     710           0 :   if (!win) {
     711           0 :     printf("No window passed in.\n");
     712           0 :     return;
     713             :   }
     714             : 
     715           0 :   nsCOMPtr<nsIDocument> doc = win->GetExtantDoc();
     716           0 :   if (!doc) {
     717           0 :     printf("No document in the window.\n");
     718           0 :     return;
     719             :   }
     720             : 
     721           0 :   nsIURI *uri = doc->GetDocumentURI();
     722           0 :   if (!uri) {
     723           0 :     printf("Document doesn't have a URI.\n");
     724           0 :     return;
     725             :   }
     726             : 
     727           0 :   printf("%s\n", uri->GetSpecOrDefault().get());
     728             : }
     729             : 
     730             : void
     731           0 : PrintWinCodebase(nsGlobalWindow *win)
     732             : {
     733           0 :   if (!win) {
     734           0 :     printf("No window passed in.\n");
     735           0 :     return;
     736             :   }
     737             : 
     738           0 :   nsIPrincipal *prin = win->GetPrincipal();
     739           0 :   if (!prin) {
     740           0 :     printf("Window doesn't have principals.\n");
     741           0 :     return;
     742             :   }
     743             : 
     744           0 :   nsCOMPtr<nsIURI> uri;
     745           0 :   prin->GetURI(getter_AddRefs(uri));
     746           0 :   if (!uri) {
     747           0 :     printf("No URI, maybe the system principal.\n");
     748           0 :     return;
     749             :   }
     750             : 
     751           0 :   printf("%s\n", uri->GetSpecOrDefault().get());
     752             : }
     753             : 
     754             : void
     755           0 : DumpString(const nsAString &str)
     756             : {
     757           0 :   printf("%s\n", NS_ConvertUTF16toUTF8(str).get());
     758           0 : }
     759             : #endif
     760             : 
     761             : #define JS_OPTIONS_DOT_STR "javascript.options."
     762             : 
     763             : static const char js_options_dot_str[]   = JS_OPTIONS_DOT_STR;
     764             : 
     765           5 : nsJSContext::nsJSContext(bool aGCOnDestruction,
     766           5 :                          nsIScriptGlobalObject* aGlobalObject)
     767             :   : mWindowProxy(nullptr)
     768             :   , mGCOnDestruction(aGCOnDestruction)
     769           5 :   , mGlobalObjectRef(aGlobalObject)
     770             : {
     771           5 :   EnsureStatics();
     772             : 
     773           5 :   ++sContextCount;
     774             : 
     775           5 :   mIsInitialized = false;
     776           5 :   mProcessingScriptTag = false;
     777           5 :   HoldJSObjects(this);
     778           5 : }
     779             : 
     780           3 : nsJSContext::~nsJSContext()
     781             : {
     782           1 :   mGlobalObjectRef = nullptr;
     783             : 
     784           1 :   Destroy();
     785             : 
     786           1 :   --sContextCount;
     787             : 
     788           1 :   if (!sContextCount && sDidShutdown) {
     789             :     // The last context is being deleted, and we're already in the
     790             :     // process of shutting down, release the security manager.
     791             : 
     792           0 :     NS_IF_RELEASE(sSecurityManager);
     793             :   }
     794           3 : }
     795             : 
     796             : void
     797           1 : nsJSContext::Destroy()
     798             : {
     799           1 :   if (mGCOnDestruction) {
     800           1 :     PokeGC(JS::gcreason::NSJSCONTEXT_DESTROY, mWindowProxy);
     801             :   }
     802             : 
     803           1 :   DropJSObjects(this);
     804           1 : }
     805             : 
     806             : // QueryInterface implementation for nsJSContext
     807             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSContext)
     808             : 
     809           6 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSContext)
     810           6 :   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mWindowProxy)
     811           6 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     812             : 
     813           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSContext)
     814           0 :   tmp->mIsInitialized = false;
     815           0 :   tmp->mGCOnDestruction = false;
     816           0 :   tmp->mWindowProxy = nullptr;
     817           0 :   tmp->Destroy();
     818           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobalObjectRef)
     819           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     820           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSContext)
     821           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobalObjectRef)
     822           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     823             : 
     824          61 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext)
     825          28 :   NS_INTERFACE_MAP_ENTRY(nsIScriptContext)
     826           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     827           0 : NS_INTERFACE_MAP_END
     828             : 
     829             : 
     830          69 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSContext)
     831          66 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSContext)
     832             : 
     833             : #ifdef DEBUG
     834             : bool
     835           0 : AtomIsEventHandlerName(nsIAtom *aName)
     836             : {
     837           0 :   const char16_t *name = aName->GetUTF16String();
     838             : 
     839             :   const char16_t *cp;
     840             :   char16_t c;
     841           0 :   for (cp = name; *cp != '\0'; ++cp)
     842             :   {
     843           0 :     c = *cp;
     844           0 :     if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z'))
     845           0 :       return false;
     846             :   }
     847             : 
     848           0 :   return true;
     849             : }
     850             : #endif
     851             : 
     852             : nsIScriptGlobalObject *
     853           2 : nsJSContext::GetGlobalObject()
     854             : {
     855             :   // Note: this could probably be simplified somewhat more; see bug 974327
     856             :   // comments 1 and 3.
     857           2 :   if (!mWindowProxy) {
     858           0 :     return nullptr;
     859             :   }
     860             : 
     861           2 :   MOZ_ASSERT(mGlobalObjectRef);
     862           2 :   return mGlobalObjectRef;
     863             : }
     864             : 
     865             : nsresult
     866           5 : nsJSContext::InitContext()
     867             : {
     868             :   // Make sure callers of this use
     869             :   // WillInitializeContext/DidInitializeContext around this call.
     870           5 :   NS_ENSURE_TRUE(!mIsInitialized, NS_ERROR_ALREADY_INITIALIZED);
     871             : 
     872             :   // XXXbz Is there still a point to this function?
     873           5 :   return NS_OK;
     874             : }
     875             : 
     876             : nsresult
     877           2 : nsJSContext::SetProperty(JS::Handle<JSObject*> aTarget, const char* aPropName, nsISupports* aArgs)
     878             : {
     879           4 :   AutoJSAPI jsapi;
     880           2 :   if (NS_WARN_IF(!jsapi.Init(GetGlobalObject()))) {
     881           0 :     return NS_ERROR_FAILURE;
     882             :   }
     883           2 :   JSContext* cx = jsapi.cx();
     884             : 
     885           4 :   JS::AutoValueVector args(cx);
     886             : 
     887           4 :   JS::Rooted<JSObject*> global(cx, GetWindowProxy());
     888             :   nsresult rv =
     889           2 :     ConvertSupportsTojsvals(aArgs, global, args);
     890           2 :   NS_ENSURE_SUCCESS(rv, rv);
     891             : 
     892             :   // got the arguments, now attach them.
     893             : 
     894          12 :   for (uint32_t i = 0; i < args.length(); ++i) {
     895          10 :     if (!JS_WrapValue(cx, args[i])) {
     896           0 :       return NS_ERROR_FAILURE;
     897             :     }
     898             :   }
     899             : 
     900           4 :   JS::Rooted<JSObject*> array(cx, ::JS_NewArrayObject(cx, args));
     901           2 :   if (!array) {
     902           0 :     return NS_ERROR_FAILURE;
     903             :   }
     904             : 
     905           2 :   return JS_DefineProperty(cx, aTarget, aPropName, array, 0) ? NS_OK : NS_ERROR_FAILURE;
     906             : }
     907             : 
     908             : nsresult
     909           2 : nsJSContext::ConvertSupportsTojsvals(nsISupports* aArgs,
     910             :                                      JS::Handle<JSObject*> aScope,
     911             :                                      JS::AutoValueVector& aArgsOut)
     912             : {
     913           2 :   nsresult rv = NS_OK;
     914             : 
     915             :   // If the array implements nsIJSArgArray, copy the contents and return.
     916           4 :   nsCOMPtr<nsIJSArgArray> fastArray = do_QueryInterface(aArgs);
     917           2 :   if (fastArray) {
     918             :     uint32_t argc;
     919             :     JS::Value* argv;
     920           0 :     rv = fastArray->GetArgs(&argc, reinterpret_cast<void **>(&argv));
     921           0 :     if (NS_SUCCEEDED(rv) && !aArgsOut.append(argv, argc)) {
     922           0 :       rv = NS_ERROR_OUT_OF_MEMORY;
     923             :     }
     924           0 :     return rv;
     925             :   }
     926             : 
     927             :   // Take the slower path converting each item.
     928             :   // Handle only nsIArray and nsIVariant.  nsIArray is only needed for
     929             :   // SetProperty('arguments', ...);
     930             : 
     931           2 :   nsIXPConnect *xpc = nsContentUtils::XPConnect();
     932           2 :   NS_ENSURE_TRUE(xpc, NS_ERROR_UNEXPECTED);
     933           4 :   AutoJSContext cx;
     934             : 
     935           2 :   if (!aArgs)
     936           0 :     return NS_OK;
     937             :   uint32_t argCount;
     938             :   // This general purpose function may need to convert an arg array
     939             :   // (window.arguments, event-handler args) and a generic property.
     940           4 :   nsCOMPtr<nsIArray> argsArray(do_QueryInterface(aArgs));
     941             : 
     942           2 :   if (argsArray) {
     943           2 :     rv = argsArray->GetLength(&argCount);
     944           2 :     NS_ENSURE_SUCCESS(rv, rv);
     945           2 :     if (argCount == 0)
     946           0 :       return NS_OK;
     947             :   } else {
     948           0 :     argCount = 1; // the nsISupports which is not an array
     949             :   }
     950             : 
     951             :   // Use the caller's auto guards to release and unroot.
     952           2 :   if (!aArgsOut.resize(argCount)) {
     953           0 :     return NS_ERROR_OUT_OF_MEMORY;
     954             :   }
     955             : 
     956           2 :   if (argsArray) {
     957          12 :     for (uint32_t argCtr = 0; argCtr < argCount && NS_SUCCEEDED(rv); argCtr++) {
     958          12 :       nsCOMPtr<nsISupports> arg;
     959          10 :       JS::MutableHandle<JS::Value> thisVal = aArgsOut[argCtr];
     960          20 :       argsArray->QueryElementAt(argCtr, NS_GET_IID(nsISupports),
     961          20 :                                 getter_AddRefs(arg));
     962          10 :       if (!arg) {
     963           8 :         thisVal.setNull();
     964           8 :         continue;
     965             :       }
     966           4 :       nsCOMPtr<nsIVariant> variant(do_QueryInterface(arg));
     967           2 :       if (variant != nullptr) {
     968           0 :         rv = xpc->VariantToJS(cx, aScope, variant, thisVal);
     969             :       } else {
     970             :         // And finally, support the nsISupportsPrimitives supplied
     971             :         // by the AppShell.  It generally will pass only strings, but
     972             :         // as we have code for handling all, we may as well use it.
     973           2 :         rv = AddSupportsPrimitiveTojsvals(arg, thisVal.address());
     974           2 :         if (rv == NS_ERROR_NO_INTERFACE) {
     975             :           // something else - probably an event object or similar -
     976             :           // just wrap it.
     977             : #ifdef DEBUG
     978             :           // but first, check its not another nsISupportsPrimitive, as
     979             :           // these are now deprecated for use with script contexts.
     980           4 :           nsCOMPtr<nsISupportsPrimitive> prim(do_QueryInterface(arg));
     981           2 :           NS_ASSERTION(prim == nullptr,
     982             :                        "Don't pass nsISupportsPrimitives - use nsIVariant!");
     983             : #endif
     984           4 :           JSAutoCompartment ac(cx, aScope);
     985           2 :           rv = nsContentUtils::WrapNative(cx, arg, thisVal);
     986             :         }
     987             :       }
     988             :     }
     989             :   } else {
     990           0 :     nsCOMPtr<nsIVariant> variant = do_QueryInterface(aArgs);
     991           0 :     if (variant) {
     992           0 :       rv = xpc->VariantToJS(cx, aScope, variant, aArgsOut[0]);
     993             :     } else {
     994           0 :       NS_ERROR("Not an array, not an interface?");
     995           0 :       rv = NS_ERROR_UNEXPECTED;
     996             :     }
     997             :   }
     998           2 :   return rv;
     999             : }
    1000             : 
    1001             : // This really should go into xpconnect somewhere...
    1002             : nsresult
    1003           2 : nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
    1004             : {
    1005           2 :   NS_PRECONDITION(aArg, "Empty arg");
    1006             : 
    1007           4 :   nsCOMPtr<nsISupportsPrimitive> argPrimitive(do_QueryInterface(aArg));
    1008           2 :   if (!argPrimitive)
    1009           2 :     return NS_ERROR_NO_INTERFACE;
    1010             : 
    1011           0 :   AutoJSContext cx;
    1012             :   uint16_t type;
    1013           0 :   argPrimitive->GetType(&type);
    1014             : 
    1015           0 :   switch(type) {
    1016             :     case nsISupportsPrimitive::TYPE_CSTRING : {
    1017           0 :       nsCOMPtr<nsISupportsCString> p(do_QueryInterface(argPrimitive));
    1018           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1019             : 
    1020           0 :       nsAutoCString data;
    1021             : 
    1022           0 :       p->GetData(data);
    1023             : 
    1024             : 
    1025           0 :       JSString *str = ::JS_NewStringCopyN(cx, data.get(), data.Length());
    1026           0 :       NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
    1027             : 
    1028           0 :       aArgv->setString(str);
    1029             : 
    1030           0 :       break;
    1031             :     }
    1032             :     case nsISupportsPrimitive::TYPE_STRING : {
    1033           0 :       nsCOMPtr<nsISupportsString> p(do_QueryInterface(argPrimitive));
    1034           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1035             : 
    1036           0 :       nsAutoString data;
    1037             : 
    1038           0 :       p->GetData(data);
    1039             : 
    1040             :       // cast is probably safe since wchar_t and char16_t are expected
    1041             :       // to be equivalent; both unsigned 16-bit entities
    1042             :       JSString *str =
    1043           0 :         ::JS_NewUCStringCopyN(cx, data.get(), data.Length());
    1044           0 :       NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
    1045             : 
    1046           0 :       aArgv->setString(str);
    1047           0 :       break;
    1048             :     }
    1049             :     case nsISupportsPrimitive::TYPE_PRBOOL : {
    1050           0 :       nsCOMPtr<nsISupportsPRBool> p(do_QueryInterface(argPrimitive));
    1051           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1052             : 
    1053             :       bool data;
    1054             : 
    1055           0 :       p->GetData(&data);
    1056             : 
    1057           0 :       aArgv->setBoolean(data);
    1058             : 
    1059           0 :       break;
    1060             :     }
    1061             :     case nsISupportsPrimitive::TYPE_PRUINT8 : {
    1062           0 :       nsCOMPtr<nsISupportsPRUint8> p(do_QueryInterface(argPrimitive));
    1063           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1064             : 
    1065             :       uint8_t data;
    1066             : 
    1067           0 :       p->GetData(&data);
    1068             : 
    1069           0 :       aArgv->setInt32(data);
    1070             : 
    1071           0 :       break;
    1072             :     }
    1073             :     case nsISupportsPrimitive::TYPE_PRUINT16 : {
    1074           0 :       nsCOMPtr<nsISupportsPRUint16> p(do_QueryInterface(argPrimitive));
    1075           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1076             : 
    1077             :       uint16_t data;
    1078             : 
    1079           0 :       p->GetData(&data);
    1080             : 
    1081           0 :       aArgv->setInt32(data);
    1082             : 
    1083           0 :       break;
    1084             :     }
    1085             :     case nsISupportsPrimitive::TYPE_PRUINT32 : {
    1086           0 :       nsCOMPtr<nsISupportsPRUint32> p(do_QueryInterface(argPrimitive));
    1087           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1088             : 
    1089             :       uint32_t data;
    1090             : 
    1091           0 :       p->GetData(&data);
    1092             : 
    1093           0 :       aArgv->setInt32(data);
    1094             : 
    1095           0 :       break;
    1096             :     }
    1097             :     case nsISupportsPrimitive::TYPE_CHAR : {
    1098           0 :       nsCOMPtr<nsISupportsChar> p(do_QueryInterface(argPrimitive));
    1099           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1100             : 
    1101             :       char data;
    1102             : 
    1103           0 :       p->GetData(&data);
    1104             : 
    1105           0 :       JSString *str = ::JS_NewStringCopyN(cx, &data, 1);
    1106           0 :       NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
    1107             : 
    1108           0 :       aArgv->setString(str);
    1109             : 
    1110           0 :       break;
    1111             :     }
    1112             :     case nsISupportsPrimitive::TYPE_PRINT16 : {
    1113           0 :       nsCOMPtr<nsISupportsPRInt16> p(do_QueryInterface(argPrimitive));
    1114           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1115             : 
    1116             :       int16_t data;
    1117             : 
    1118           0 :       p->GetData(&data);
    1119             : 
    1120           0 :       aArgv->setInt32(data);
    1121             : 
    1122           0 :       break;
    1123             :     }
    1124             :     case nsISupportsPrimitive::TYPE_PRINT32 : {
    1125           0 :       nsCOMPtr<nsISupportsPRInt32> p(do_QueryInterface(argPrimitive));
    1126           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1127             : 
    1128             :       int32_t data;
    1129             : 
    1130           0 :       p->GetData(&data);
    1131             : 
    1132           0 :       aArgv->setInt32(data);
    1133             : 
    1134           0 :       break;
    1135             :     }
    1136             :     case nsISupportsPrimitive::TYPE_FLOAT : {
    1137           0 :       nsCOMPtr<nsISupportsFloat> p(do_QueryInterface(argPrimitive));
    1138           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1139             : 
    1140             :       float data;
    1141             : 
    1142           0 :       p->GetData(&data);
    1143             : 
    1144           0 :       *aArgv = ::JS_NumberValue(data);
    1145             : 
    1146           0 :       break;
    1147             :     }
    1148             :     case nsISupportsPrimitive::TYPE_DOUBLE : {
    1149           0 :       nsCOMPtr<nsISupportsDouble> p(do_QueryInterface(argPrimitive));
    1150           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1151             : 
    1152             :       double data;
    1153             : 
    1154           0 :       p->GetData(&data);
    1155             : 
    1156           0 :       *aArgv = ::JS_NumberValue(data);
    1157             : 
    1158           0 :       break;
    1159             :     }
    1160             :     case nsISupportsPrimitive::TYPE_INTERFACE_POINTER : {
    1161           0 :       nsCOMPtr<nsISupportsInterfacePointer> p(do_QueryInterface(argPrimitive));
    1162           0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    1163             : 
    1164           0 :       nsCOMPtr<nsISupports> data;
    1165           0 :       nsIID *iid = nullptr;
    1166             : 
    1167           0 :       p->GetData(getter_AddRefs(data));
    1168           0 :       p->GetDataIID(&iid);
    1169           0 :       NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
    1170             : 
    1171           0 :       AutoFree iidGuard(iid); // Free iid upon destruction.
    1172             : 
    1173           0 :       JS::Rooted<JSObject*> scope(cx, GetWindowProxy());
    1174           0 :       JS::Rooted<JS::Value> v(cx);
    1175           0 :       JSAutoCompartment ac(cx, scope);
    1176           0 :       nsresult rv = nsContentUtils::WrapNative(cx, data, iid, &v);
    1177           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1178             : 
    1179           0 :       *aArgv = v;
    1180             : 
    1181           0 :       break;
    1182             :     }
    1183             :     case nsISupportsPrimitive::TYPE_ID :
    1184             :     case nsISupportsPrimitive::TYPE_PRUINT64 :
    1185             :     case nsISupportsPrimitive::TYPE_PRINT64 :
    1186             :     case nsISupportsPrimitive::TYPE_PRTIME : {
    1187           0 :       NS_WARNING("Unsupported primitive type used");
    1188           0 :       aArgv->setNull();
    1189           0 :       break;
    1190             :     }
    1191             :     default : {
    1192           0 :       NS_WARNING("Unknown primitive type used");
    1193           0 :       aArgv->setNull();
    1194           0 :       break;
    1195             :     }
    1196             :   }
    1197           0 :   return NS_OK;
    1198             : }
    1199             : 
    1200             : #ifdef MOZ_JPROF
    1201             : 
    1202             : #include <signal.h>
    1203             : 
    1204             : inline bool
    1205             : IsJProfAction(struct sigaction *action)
    1206             : {
    1207             :     return (action->sa_sigaction &&
    1208             :             (action->sa_flags & (SA_RESTART | SA_SIGINFO)) == (SA_RESTART | SA_SIGINFO));
    1209             : }
    1210             : 
    1211             : void NS_JProfStartProfiling();
    1212             : void NS_JProfStopProfiling();
    1213             : void NS_JProfClearCircular();
    1214             : 
    1215             : static bool
    1216             : JProfStartProfilingJS(JSContext *cx, unsigned argc, JS::Value *vp)
    1217             : {
    1218             :   NS_JProfStartProfiling();
    1219             :   return true;
    1220             : }
    1221             : 
    1222             : void NS_JProfStartProfiling()
    1223             : {
    1224             :     // Figure out whether we're dealing with SIGPROF, SIGALRM, or
    1225             :     // SIGPOLL profiling (SIGALRM for JP_REALTIME, SIGPOLL for
    1226             :     // JP_RTC_HZ)
    1227             :     struct sigaction action;
    1228             : 
    1229             :     // Must check ALRM before PROF since both are enabled for real-time
    1230             :     sigaction(SIGALRM, nullptr, &action);
    1231             :     //printf("SIGALRM: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
    1232             :     if (IsJProfAction(&action)) {
    1233             :         //printf("Beginning real-time jprof profiling.\n");
    1234             :         raise(SIGALRM);
    1235             :         return;
    1236             :     }
    1237             : 
    1238             :     sigaction(SIGPROF, nullptr, &action);
    1239             :     //printf("SIGPROF: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
    1240             :     if (IsJProfAction(&action)) {
    1241             :         //printf("Beginning process-time jprof profiling.\n");
    1242             :         raise(SIGPROF);
    1243             :         return;
    1244             :     }
    1245             : 
    1246             :     sigaction(SIGPOLL, nullptr, &action);
    1247             :     //printf("SIGPOLL: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
    1248             :     if (IsJProfAction(&action)) {
    1249             :         //printf("Beginning rtc-based jprof profiling.\n");
    1250             :         raise(SIGPOLL);
    1251             :         return;
    1252             :     }
    1253             : 
    1254             :     printf("Could not start jprof-profiling since JPROF_FLAGS was not set.\n");
    1255             : }
    1256             : 
    1257             : static bool
    1258             : JProfStopProfilingJS(JSContext *cx, unsigned argc, JS::Value *vp)
    1259             : {
    1260             :   NS_JProfStopProfiling();
    1261             :   return true;
    1262             : }
    1263             : 
    1264             : void
    1265             : NS_JProfStopProfiling()
    1266             : {
    1267             :     raise(SIGUSR1);
    1268             :     //printf("Stopped jprof profiling.\n");
    1269             : }
    1270             : 
    1271             : static bool
    1272             : JProfClearCircularJS(JSContext *cx, unsigned argc, JS::Value *vp)
    1273             : {
    1274             :   NS_JProfClearCircular();
    1275             :   return true;
    1276             : }
    1277             : 
    1278             : void
    1279             : NS_JProfClearCircular()
    1280             : {
    1281             :     raise(SIGUSR2);
    1282             :     //printf("cleared jprof buffer\n");
    1283             : }
    1284             : 
    1285             : static bool
    1286             : JProfSaveCircularJS(JSContext *cx, unsigned argc, JS::Value *vp)
    1287             : {
    1288             :   // Not ideal...
    1289             :   NS_JProfStopProfiling();
    1290             :   NS_JProfStartProfiling();
    1291             :   return true;
    1292             : }
    1293             : 
    1294             : static const JSFunctionSpec JProfFunctions[] = {
    1295             :     JS_FS("JProfStartProfiling",        JProfStartProfilingJS,      0, 0),
    1296             :     JS_FS("JProfStopProfiling",         JProfStopProfilingJS,       0, 0),
    1297             :     JS_FS("JProfClearCircular",         JProfClearCircularJS,       0, 0),
    1298             :     JS_FS("JProfSaveCircular",          JProfSaveCircularJS,        0, 0),
    1299             :     JS_FS_END
    1300             : };
    1301             : 
    1302             : #endif /* defined(MOZ_JPROF) */
    1303             : 
    1304             : nsresult
    1305           7 : nsJSContext::InitClasses(JS::Handle<JSObject*> aGlobalObj)
    1306             : {
    1307          14 :   AutoJSAPI jsapi;
    1308           7 :   jsapi.Init();
    1309           7 :   JSContext* cx = jsapi.cx();
    1310          14 :   JSAutoCompartment ac(cx, aGlobalObj);
    1311             : 
    1312             :   // Attempt to initialize profiling functions
    1313           7 :   ::JS_DefineProfilingFunctions(cx, aGlobalObj);
    1314             : 
    1315             : #ifdef MOZ_JPROF
    1316             :   // Attempt to initialize JProf functions
    1317             :   ::JS_DefineFunctions(cx, aGlobalObj, JProfFunctions);
    1318             : #endif
    1319             : 
    1320          14 :   return NS_OK;
    1321             : }
    1322             : 
    1323             : void
    1324          13 : nsJSContext::WillInitializeContext()
    1325             : {
    1326          13 :   mIsInitialized = false;
    1327          13 : }
    1328             : 
    1329             : void
    1330          13 : nsJSContext::DidInitializeContext()
    1331             : {
    1332          13 :   mIsInitialized = true;
    1333          13 : }
    1334             : 
    1335             : bool
    1336           0 : nsJSContext::IsContextInitialized()
    1337             : {
    1338           0 :   return mIsInitialized;
    1339             : }
    1340             : 
    1341             : bool
    1342           5 : nsJSContext::GetProcessingScriptTag()
    1343             : {
    1344           5 :   return mProcessingScriptTag;
    1345             : }
    1346             : 
    1347             : void
    1348          10 : nsJSContext::SetProcessingScriptTag(bool aFlag)
    1349             : {
    1350          10 :   mProcessingScriptTag = aFlag;
    1351          10 : }
    1352             : 
    1353             : void
    1354           0 : FullGCTimerFired(nsITimer* aTimer, void* aClosure)
    1355             : {
    1356           0 :   nsJSContext::KillFullGCTimer();
    1357           0 :   MOZ_ASSERT(!aClosure, "Don't pass a closure to FullGCTimerFired");
    1358             :   nsJSContext::GarbageCollectNow(JS::gcreason::FULL_GC_TIMER,
    1359           0 :                                  nsJSContext::IncrementalGC);
    1360           0 : }
    1361             : 
    1362             : //static
    1363             : void
    1364           3 : nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
    1365             :                                IsIncremental aIncremental,
    1366             :                                IsShrinking aShrinking,
    1367             :                                int64_t aSliceMillis)
    1368             : {
    1369           4 :   AUTO_PROFILER_LABEL_DYNAMIC("nsJSContext::GarbageCollectNow", GC,
    1370             :                               JS::gcreason::ExplainReason(aReason));
    1371             : 
    1372           3 :   MOZ_ASSERT_IF(aSliceMillis, aIncremental == IncrementalGC);
    1373             : 
    1374           3 :   KillGCTimer();
    1375             : 
    1376             :   // Reset sPendingLoadCount in case the timer that fired was a
    1377             :   // timer we scheduled due to a normal GC timer firing while
    1378             :   // documents were loading. If this happens we're waiting for a
    1379             :   // document that is taking a long time to load, and we effectively
    1380             :   // ignore the fact that the currently loading documents are still
    1381             :   // loading and move on as if they weren't.
    1382           3 :   sPendingLoadCount = 0;
    1383           3 :   sLoadingInProgress = false;
    1384             : 
    1385             :   // We use danger::GetJSContext() since AutoJSAPI will assert if the current
    1386             :   // thread's context is null (such as during shutdown).
    1387           3 :   JSContext* cx = danger::GetJSContext();
    1388             : 
    1389           3 :   if (!nsContentUtils::XPConnect() || !cx) {
    1390           0 :     return;
    1391             :   }
    1392             : 
    1393           3 :   if (sCCLockedOut && aIncremental == IncrementalGC) {
    1394             :     // We're in the middle of incremental GC. Do another slice.
    1395           2 :     JS::PrepareForIncrementalGC(cx);
    1396           2 :     JS::IncrementalGCSlice(cx, aReason, aSliceMillis);
    1397           2 :     return;
    1398             :   }
    1399             : 
    1400           1 :   JSGCInvocationKind gckind = aShrinking == ShrinkingGC ? GC_SHRINK : GC_NORMAL;
    1401             : 
    1402           1 :   if (aIncremental == NonIncrementalGC || aReason == JS::gcreason::FULL_GC_TIMER) {
    1403           0 :     sNeedsFullGC = true;
    1404             :   }
    1405             : 
    1406           1 :   if (sNeedsFullGC) {
    1407           1 :     JS::PrepareForFullGC(cx);
    1408             :   } else {
    1409           0 :     CycleCollectedJSRuntime::Get()->PrepareWaitingZonesForGC();
    1410             :   }
    1411             : 
    1412           1 :   if (aIncremental == IncrementalGC) {
    1413           1 :     JS::StartIncrementalGC(cx, gckind, aReason, aSliceMillis);
    1414             :   } else {
    1415           0 :     JS::GCForReason(cx, gckind, aReason);
    1416             :   }
    1417             : }
    1418             : 
    1419             : static void
    1420           0 : FinishAnyIncrementalGC()
    1421             : {
    1422           0 :   AUTO_PROFILER_LABEL("FinishAnyIncrementalGC", GC);
    1423             : 
    1424           0 :   if (sCCLockedOut) {
    1425           0 :     AutoJSAPI jsapi;
    1426           0 :     jsapi.Init();
    1427             : 
    1428             :     // We're in the middle of an incremental GC, so finish it.
    1429           0 :     JS::PrepareForIncrementalGC(jsapi.cx());
    1430           0 :     JS::FinishIncrementalGC(jsapi.cx(), JS::gcreason::CC_FORCED);
    1431             :   }
    1432           0 : }
    1433             : 
    1434             : static void
    1435           0 : FireForgetSkippable(uint32_t aSuspected, bool aRemoveChildless,
    1436             :                     TimeStamp aDeadline)
    1437             : {
    1438             :   AutoProfilerTracing
    1439           0 :     tracing("CC", aDeadline.IsNull() ? "ForgetSkippable" : "IdleForgetSkippable");
    1440           0 :   PRTime startTime = PR_Now();
    1441           0 :   TimeStamp startTimeStamp = TimeStamp::Now();
    1442           0 :   FinishAnyIncrementalGC();
    1443             :   bool earlyForgetSkippable =
    1444           0 :     sCleanupsSinceLastGC < NS_MAJOR_FORGET_SKIPPABLE_CALLS;
    1445             : 
    1446           0 :   int64_t budgetMs = aDeadline.IsNull() ?
    1447             :     kForgetSkippableSliceDuration :
    1448           0 :     int64_t((aDeadline - TimeStamp::Now()).ToMilliseconds());
    1449           0 :   js::SliceBudget budget = js::SliceBudget(js::TimeBudget(budgetMs));
    1450           0 :   nsCycleCollector_forgetSkippable(budget, aRemoveChildless, earlyForgetSkippable);
    1451             : 
    1452           0 :   sPreviousSuspectedCount = nsCycleCollector_suspectedCount();
    1453           0 :   ++sCleanupsSinceLastGC;
    1454           0 :   PRTime delta = PR_Now() - startTime;
    1455           0 :   if (sMinForgetSkippableTime > delta) {
    1456           0 :     sMinForgetSkippableTime = delta;
    1457             :   }
    1458           0 :   if (sMaxForgetSkippableTime < delta) {
    1459           0 :     sMaxForgetSkippableTime = delta;
    1460             :   }
    1461           0 :   sTotalForgetSkippableTime += delta;
    1462           0 :   sRemovedPurples += (aSuspected - sPreviousSuspectedCount);
    1463           0 :   ++sForgetSkippableBeforeCC;
    1464             : 
    1465           0 :   TimeStamp now = TimeStamp::Now();
    1466           0 :   TimeDuration duration = now - startTimeStamp;
    1467           0 :   if (duration.ToSeconds()) {
    1468           0 :     TimeDuration idleDuration;
    1469           0 :     if (!aDeadline.IsNull()) {
    1470           0 :       if (aDeadline < now) {
    1471             :         // This slice overflowed the idle period.
    1472           0 :         idleDuration = aDeadline - startTimeStamp;
    1473             :       } else {
    1474           0 :         idleDuration = duration;
    1475             :       }
    1476             :     }
    1477             : 
    1478             :     uint32_t percent =
    1479           0 :       uint32_t(idleDuration.ToSeconds() / duration.ToSeconds() * 100);
    1480           0 :     Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_DURING_IDLE, percent);
    1481             :   }
    1482           0 : }
    1483             : 
    1484             : MOZ_ALWAYS_INLINE
    1485             : static uint32_t
    1486           0 : TimeBetween(TimeStamp start, TimeStamp end)
    1487             : {
    1488           0 :   MOZ_ASSERT(end >= start);
    1489           0 :   return (uint32_t) ((end - start).ToMilliseconds());
    1490             : }
    1491             : 
    1492             : static uint32_t
    1493           0 : TimeUntilNow(TimeStamp start)
    1494             : {
    1495           0 :   if (start.IsNull()) {
    1496           0 :     return 0;
    1497             :   }
    1498           0 :   return TimeBetween(start, TimeStamp::Now());
    1499             : }
    1500             : 
    1501             : struct CycleCollectorStats
    1502             : {
    1503             :   constexpr CycleCollectorStats() :
    1504             :     mMaxGCDuration(0), mRanSyncForgetSkippable(false), mSuspected(0),
    1505             :     mMaxSkippableDuration(0), mMaxSliceTime(0), mMaxSliceTimeSinceClear(0),
    1506             :     mTotalSliceTime(0), mAnyLockedOut(false), mFile(nullptr)
    1507             :   {}
    1508             : 
    1509           3 :   void Init()
    1510             :   {
    1511           3 :     Clear();
    1512           3 :     mMaxSliceTimeSinceClear = 0;
    1513             : 
    1514           3 :     char* env = getenv("MOZ_CCTIMER");
    1515           3 :     if (!env) {
    1516           3 :       return;
    1517             :     }
    1518           0 :     if (strcmp(env, "none") == 0) {
    1519           0 :       mFile = nullptr;
    1520           0 :     } else if (strcmp(env, "stdout") == 0) {
    1521           0 :       mFile = stdout;
    1522           0 :     } else if (strcmp(env, "stderr") == 0) {
    1523           0 :       mFile = stderr;
    1524             :     } else {
    1525           0 :       mFile = fopen(env, "a");
    1526           0 :       if (!mFile) {
    1527           0 :         MOZ_CRASH("Failed to open MOZ_CCTIMER log file.");
    1528             :       }
    1529             :     }
    1530             :   }
    1531             : 
    1532           3 :   void Clear()
    1533             :   {
    1534           3 :     if (mFile && mFile != stdout && mFile != stderr) {
    1535           0 :       fclose(mFile);
    1536             :     }
    1537           3 :     mBeginSliceTime = TimeStamp();
    1538           3 :     mEndSliceTime = TimeStamp();
    1539           3 :     mBeginTime = TimeStamp();
    1540           3 :     mMaxGCDuration = 0;
    1541           3 :     mRanSyncForgetSkippable = false;
    1542           3 :     mSuspected = 0;
    1543           3 :     mMaxSkippableDuration = 0;
    1544           3 :     mMaxSliceTime = 0;
    1545           3 :     mTotalSliceTime = 0;
    1546           3 :     mAnyLockedOut = false;
    1547           3 :   }
    1548             : 
    1549             :   void PrepareForCycleCollectionSlice(TimeStamp aDeadline = TimeStamp());
    1550             : 
    1551           0 :   void FinishCycleCollectionSlice()
    1552             :   {
    1553           0 :     if (mBeginSliceTime.IsNull()) {
    1554             :       // We already called this method from EndCycleCollectionCallback for this slice.
    1555           0 :       return;
    1556             :     }
    1557             : 
    1558           0 :     mEndSliceTime = TimeStamp::Now();
    1559           0 :     TimeDuration duration = mEndSliceTime - mBeginSliceTime;
    1560             : 
    1561           0 :     if (duration.ToSeconds()) {
    1562           0 :       TimeDuration idleDuration;
    1563           0 :       if (!mIdleDeadline.IsNull()) {
    1564           0 :         if (mIdleDeadline < mEndSliceTime) {
    1565             :           // This slice overflowed the idle period.
    1566           0 :           idleDuration = mIdleDeadline - mBeginSliceTime;
    1567             :         } else {
    1568           0 :           idleDuration = duration;
    1569             :         }
    1570             :       }
    1571             : 
    1572             :       uint32_t percent =
    1573           0 :         uint32_t(idleDuration.ToSeconds() / duration.ToSeconds() * 100);
    1574             :       Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SLICE_DURING_IDLE,
    1575           0 :                             percent);
    1576             :     }
    1577             : 
    1578           0 :     uint32_t sliceTime = TimeBetween(mBeginSliceTime, mEndSliceTime);
    1579           0 :     mMaxSliceTime = std::max(mMaxSliceTime, sliceTime);
    1580           0 :     mMaxSliceTimeSinceClear = std::max(mMaxSliceTimeSinceClear, sliceTime);
    1581           0 :     mTotalSliceTime += sliceTime;
    1582           0 :     mBeginSliceTime = TimeStamp();
    1583             :   }
    1584             : 
    1585             :   void RunForgetSkippable();
    1586             : 
    1587             :   // Time the current slice began, including any GC finishing.
    1588             :   TimeStamp mBeginSliceTime;
    1589             : 
    1590             :   // Time the previous slice of the current CC ended.
    1591             :   TimeStamp mEndSliceTime;
    1592             : 
    1593             :   // Time the current cycle collection began.
    1594             :   TimeStamp mBeginTime;
    1595             : 
    1596             :   // The longest GC finishing duration for any slice of the current CC.
    1597             :   uint32_t mMaxGCDuration;
    1598             : 
    1599             :   // True if we ran sync forget skippable in any slice of the current CC.
    1600             :   bool mRanSyncForgetSkippable;
    1601             : 
    1602             :   // Number of suspected objects at the start of the current CC.
    1603             :   uint32_t mSuspected;
    1604             : 
    1605             :   // The longest duration spent on sync forget skippable in any slice of the
    1606             :   // current CC.
    1607             :   uint32_t mMaxSkippableDuration;
    1608             : 
    1609             :   // The longest pause of any slice in the current CC.
    1610             :   uint32_t mMaxSliceTime;
    1611             : 
    1612             :   // The longest slice time since ClearMaxCCSliceTime() was called.
    1613             :   uint32_t mMaxSliceTimeSinceClear;
    1614             : 
    1615             :   // The total amount of time spent actually running the current CC.
    1616             :   uint32_t mTotalSliceTime;
    1617             : 
    1618             :   // True if we were locked out by the GC in any slice of the current CC.
    1619             :   bool mAnyLockedOut;
    1620             : 
    1621             :   // A file to dump CC activity to; set by MOZ_CCTIMER environment variable.
    1622             :   FILE* mFile;
    1623             : 
    1624             :   // In case CC slice was triggered during idle time, set to the end of the idle
    1625             :   // period.
    1626             :   TimeStamp mIdleDeadline;
    1627             : };
    1628             : 
    1629             : CycleCollectorStats gCCStats;
    1630             : 
    1631             : void
    1632           0 : CycleCollectorStats::PrepareForCycleCollectionSlice(TimeStamp aDeadline)
    1633             : {
    1634           0 :   mBeginSliceTime = TimeStamp::Now();
    1635           0 :   mIdleDeadline = aDeadline;
    1636             : 
    1637             :   // Before we begin the cycle collection, make sure there is no active GC.
    1638           0 :   if (sCCLockedOut) {
    1639           0 :     mAnyLockedOut = true;
    1640           0 :     FinishAnyIncrementalGC();
    1641           0 :     uint32_t gcTime = TimeBetween(mBeginSliceTime, TimeStamp::Now());
    1642           0 :     mMaxGCDuration = std::max(mMaxGCDuration, gcTime);
    1643             :   }
    1644           0 : }
    1645             : 
    1646             : void
    1647           0 : CycleCollectorStats::RunForgetSkippable()
    1648             : {
    1649             :   // Run forgetSkippable synchronously to reduce the size of the CC graph. This
    1650             :   // is particularly useful if we recently finished a GC.
    1651           0 :   TimeStamp beginForgetSkippable = TimeStamp::Now();
    1652           0 :   bool ranSyncForgetSkippable = false;
    1653           0 :   while (sCleanupsSinceLastGC < NS_MAJOR_FORGET_SKIPPABLE_CALLS) {
    1654           0 :     FireForgetSkippable(nsCycleCollector_suspectedCount(), false, TimeStamp());
    1655           0 :     ranSyncForgetSkippable = true;
    1656             :   }
    1657             : 
    1658           0 :   if (ranSyncForgetSkippable) {
    1659           0 :     mMaxSkippableDuration =
    1660           0 :       std::max(mMaxSkippableDuration, TimeUntilNow(beginForgetSkippable));
    1661           0 :     mRanSyncForgetSkippable = true;
    1662             :   }
    1663           0 : }
    1664             : 
    1665             : //static
    1666             : void
    1667           0 : nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener)
    1668             : {
    1669           0 :   if (!NS_IsMainThread()) {
    1670           0 :     return;
    1671             :   }
    1672             : 
    1673           0 :   AUTO_PROFILER_LABEL("nsJSContext::CycleCollectNow", CC);
    1674             : 
    1675           0 :   gCCStats.PrepareForCycleCollectionSlice(TimeStamp());
    1676           0 :   nsCycleCollector_collect(aListener);
    1677           0 :   gCCStats.FinishCycleCollectionSlice();
    1678             : }
    1679             : 
    1680             : //static
    1681             : void
    1682           0 : nsJSContext::RunCycleCollectorSlice(TimeStamp aDeadline)
    1683             : {
    1684           0 :   if (!NS_IsMainThread()) {
    1685           0 :     return;
    1686             :   }
    1687             : 
    1688             :   AutoProfilerTracing
    1689           0 :     tracing("CC", aDeadline.IsNull() ? "CCSlice" : "IdleCCSlice");
    1690             : 
    1691           0 :   AUTO_PROFILER_LABEL("nsJSContext::RunCycleCollectorSlice", CC);
    1692             : 
    1693           0 :   gCCStats.PrepareForCycleCollectionSlice(aDeadline);
    1694             : 
    1695             :   // Decide how long we want to budget for this slice. By default,
    1696             :   // use an unlimited budget.
    1697           0 :   js::SliceBudget budget = js::SliceBudget::unlimited();
    1698             : 
    1699           0 :   if (sIncrementalCC) {
    1700           0 :     int64_t baseBudget = kICCSliceBudget;
    1701           0 :     if (!aDeadline.IsNull()) {
    1702           0 :       baseBudget = int64_t((aDeadline - TimeStamp::Now()).ToMilliseconds());
    1703             :     }
    1704             : 
    1705           0 :     if (gCCStats.mBeginTime.IsNull()) {
    1706             :       // If no CC is in progress, use the standard slice time.
    1707           0 :       budget = js::SliceBudget(js::TimeBudget(baseBudget));
    1708             :     } else {
    1709           0 :       TimeStamp now = TimeStamp::Now();
    1710             : 
    1711             :       // Only run a limited slice if we're within the max running time.
    1712           0 :       uint32_t runningTime = TimeBetween(gCCStats.mBeginTime, now);
    1713           0 :       if (runningTime < kMaxICCDuration) {
    1714           0 :         const float maxSlice = MainThreadIdlePeriod::GetLongIdlePeriod();
    1715             : 
    1716             :         // Try to make up for a delay in running this slice.
    1717             :         float sliceDelayMultiplier =
    1718           0 :           TimeBetween(gCCStats.mEndSliceTime, now) / (float)kICCIntersliceDelay;
    1719             :         float delaySliceBudget =
    1720           0 :           std::min(baseBudget * sliceDelayMultiplier, maxSlice);
    1721             : 
    1722             :         // Increase slice budgets up to |maxSlice| as we approach
    1723             :         // half way through the ICC, to avoid large sync CCs.
    1724           0 :         float percentToHalfDone = std::min(2.0f * runningTime / kMaxICCDuration, 1.0f);
    1725           0 :         float laterSliceBudget = maxSlice * percentToHalfDone;
    1726             : 
    1727           0 :         budget = js::SliceBudget(js::TimeBudget(std::max({delaySliceBudget,
    1728           0 :                   laterSliceBudget, (float)baseBudget})));
    1729             :       }
    1730             :     }
    1731             :   }
    1732             : 
    1733           0 :   nsCycleCollector_collectSlice(budget,
    1734           0 :                                 aDeadline.IsNull() ||
    1735           0 :                                 (aDeadline - TimeStamp::Now()).ToMilliseconds() <
    1736           0 :                                   kICCSliceBudget);
    1737             : 
    1738           0 :   gCCStats.FinishCycleCollectionSlice();
    1739             : }
    1740             : 
    1741             : //static
    1742             : void
    1743           0 : nsJSContext::RunCycleCollectorWorkSlice(int64_t aWorkBudget)
    1744             : {
    1745           0 :   if (!NS_IsMainThread()) {
    1746           0 :     return;
    1747             :   }
    1748             : 
    1749           0 :   AUTO_PROFILER_LABEL("nsJSContext::RunCycleCollectorWorkSlice", CC);
    1750             : 
    1751           0 :   gCCStats.PrepareForCycleCollectionSlice();
    1752             : 
    1753           0 :   js::SliceBudget budget = js::SliceBudget(js::WorkBudget(aWorkBudget));
    1754           0 :   nsCycleCollector_collectSlice(budget);
    1755             : 
    1756           0 :   gCCStats.FinishCycleCollectionSlice();
    1757             : }
    1758             : 
    1759             : void
    1760           0 : nsJSContext::ClearMaxCCSliceTime()
    1761             : {
    1762           0 :   gCCStats.mMaxSliceTimeSinceClear = 0;
    1763           0 : }
    1764             : 
    1765             : uint32_t
    1766           0 : nsJSContext::GetMaxCCSliceTimeSinceClear()
    1767             : {
    1768           0 :   return gCCStats.mMaxSliceTimeSinceClear;
    1769             : }
    1770             : 
    1771             : static bool
    1772           0 : ICCRunnerFired(TimeStamp aDeadline, void* aData)
    1773             : {
    1774           0 :   if (sDidShutdown) {
    1775           0 :     return false;
    1776             :   }
    1777             : 
    1778             :   // Ignore ICC timer fires during IGC. Running ICC during an IGC will cause us
    1779             :   // to synchronously finish the GC, which is bad.
    1780             : 
    1781           0 :   if (sCCLockedOut) {
    1782           0 :     PRTime now = PR_Now();
    1783           0 :     if (sCCLockedOutTime == 0) {
    1784           0 :       sCCLockedOutTime = now;
    1785           0 :       return false;
    1786             :     }
    1787           0 :     if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) {
    1788           0 :       return false;
    1789             :     }
    1790             :   }
    1791             : 
    1792           0 :   nsJSContext::RunCycleCollectorSlice(aDeadline);
    1793           0 :   return true;
    1794             : }
    1795             : 
    1796             : //static
    1797             : void
    1798           0 : nsJSContext::BeginCycleCollectionCallback()
    1799             : {
    1800           0 :   MOZ_ASSERT(NS_IsMainThread());
    1801             : 
    1802           0 :   gCCStats.mBeginTime = gCCStats.mBeginSliceTime.IsNull() ? TimeStamp::Now() : gCCStats.mBeginSliceTime;
    1803           0 :   gCCStats.mSuspected = nsCycleCollector_suspectedCount();
    1804             : 
    1805           0 :   KillCCRunner();
    1806             : 
    1807           0 :   gCCStats.RunForgetSkippable();
    1808             : 
    1809           0 :   MOZ_ASSERT(!sICCRunner, "Tried to create a new ICC timer when one already existed.");
    1810             : 
    1811             :   // Create an ICC timer even if ICC is globally disabled, because we could be manually triggering
    1812             :   // an incremental collection, and we want to be sure to finish it.
    1813           0 :   sICCRunner = CollectorRunner::Create(ICCRunnerFired, kICCIntersliceDelay,
    1814           0 :                                        kIdleICCSliceBudget, true);
    1815           0 : }
    1816             : 
    1817             : static_assert(NS_GC_DELAY > kMaxICCDuration, "A max duration ICC shouldn't reduce GC delay to 0");
    1818             : 
    1819             : //static
    1820             : void
    1821           0 : nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults)
    1822             : {
    1823           0 :   MOZ_ASSERT(NS_IsMainThread());
    1824             : 
    1825           0 :   nsJSContext::KillICCRunner();
    1826             : 
    1827             :   // Update timing information for the current slice before we log it, if
    1828             :   // we previously called PrepareForCycleCollectionSlice(). During shutdown
    1829             :   // CCs, this won't happen.
    1830           0 :   gCCStats.FinishCycleCollectionSlice();
    1831             : 
    1832           0 :   sCCollectedWaitingForGC += aResults.mFreedGCed;
    1833           0 :   sCCollectedZonesWaitingForGC += aResults.mFreedJSZones;
    1834             : 
    1835           0 :   TimeStamp endCCTimeStamp = TimeStamp::Now();
    1836           0 :   uint32_t ccNowDuration = TimeBetween(gCCStats.mBeginTime, endCCTimeStamp);
    1837             : 
    1838           0 :   if (NeedsGCAfterCC()) {
    1839           0 :     PokeGC(JS::gcreason::CC_WAITING, nullptr,
    1840           0 :            NS_GC_DELAY - std::min(ccNowDuration, kMaxICCDuration));
    1841             :   }
    1842             : 
    1843             :   // Log information about the CC via telemetry, JSON and the console.
    1844           0 :   Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC, gCCStats.mAnyLockedOut);
    1845           0 :   Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE, gCCStats.mRanSyncForgetSkippable);
    1846           0 :   Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FULL, ccNowDuration);
    1847           0 :   Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_MAX_PAUSE, gCCStats.mMaxSliceTime);
    1848             : 
    1849           0 :   if (!sLastCCEndTime.IsNull()) {
    1850             :     // TimeBetween returns milliseconds, but we want to report seconds.
    1851           0 :     uint32_t timeBetween = TimeBetween(sLastCCEndTime, gCCStats.mBeginTime) / 1000;
    1852           0 :     Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN, timeBetween);
    1853             :   }
    1854           0 :   sLastCCEndTime = endCCTimeStamp;
    1855             : 
    1856           0 :   Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX,
    1857           0 :                         sMaxForgetSkippableTime / PR_USEC_PER_MSEC);
    1858             : 
    1859           0 :   PRTime delta = GetCollectionTimeDelta();
    1860             : 
    1861           0 :   uint32_t cleanups = sForgetSkippableBeforeCC ? sForgetSkippableBeforeCC : 1;
    1862           0 :   uint32_t minForgetSkippableTime = (sMinForgetSkippableTime == UINT32_MAX)
    1863           0 :     ? 0 : sMinForgetSkippableTime;
    1864             : 
    1865           0 :   if (sPostGCEventsToConsole || gCCStats.mFile) {
    1866           0 :     nsCString mergeMsg;
    1867           0 :     if (aResults.mMergedZones) {
    1868           0 :       mergeMsg.AssignLiteral(" merged");
    1869             :     }
    1870             : 
    1871           0 :     nsCString gcMsg;
    1872           0 :     if (aResults.mForcedGC) {
    1873           0 :       gcMsg.AssignLiteral(", forced a GC");
    1874             :     }
    1875             : 
    1876             :     const char16_t *kFmt =
    1877             :       u"CC(T+%.1f)[%s-%i] max pause: %lums, total time: %lums, slices: %lu, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu|%lu|%lu waiting for GC)%s\n"
    1878           0 :       u"ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, max sync: %lu ms, removed: %lu";
    1879           0 :     nsString msg;
    1880           0 :     msg.Adopt(nsTextFormatter::smprintf(kFmt, double(delta) / PR_USEC_PER_SEC,
    1881             :                                         ProcessNameForCollectorLog(), getpid(),
    1882             :                                         gCCStats.mMaxSliceTime, gCCStats.mTotalSliceTime,
    1883             :                                         aResults.mNumSlices, gCCStats.mSuspected,
    1884             :                                         aResults.mVisitedRefCounted, aResults.mVisitedGCed, mergeMsg.get(),
    1885             :                                         aResults.mFreedRefCounted, aResults.mFreedGCed,
    1886             :                                         sCCollectedWaitingForGC, sCCollectedZonesWaitingForGC, sLikelyShortLivingObjectsNeedingGC,
    1887             :                                         gcMsg.get(),
    1888             :                                         sForgetSkippableBeforeCC,
    1889           0 :                                         minForgetSkippableTime / PR_USEC_PER_MSEC,
    1890           0 :                                         sMaxForgetSkippableTime / PR_USEC_PER_MSEC,
    1891           0 :                                         (sTotalForgetSkippableTime / cleanups) /
    1892             :                                           PR_USEC_PER_MSEC,
    1893           0 :                                         sTotalForgetSkippableTime / PR_USEC_PER_MSEC,
    1894           0 :                                         gCCStats.mMaxSkippableDuration, sRemovedPurples));
    1895           0 :     if (sPostGCEventsToConsole) {
    1896             :       nsCOMPtr<nsIConsoleService> cs =
    1897           0 :         do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    1898           0 :       if (cs) {
    1899           0 :         cs->LogStringMessage(msg.get());
    1900             :       }
    1901             :     }
    1902           0 :     if (gCCStats.mFile) {
    1903           0 :       fprintf(gCCStats.mFile, "%s\n", NS_ConvertUTF16toUTF8(msg).get());
    1904             :     }
    1905             :   }
    1906             : 
    1907           0 :   if (sPostGCEventsToObserver) {
    1908             :     const char16_t* kJSONFmt =
    1909             :        u"{ \"timestamp\": %llu, "
    1910             :          u"\"duration\": %lu, "
    1911             :          u"\"max_slice_pause\": %lu, "
    1912             :          u"\"total_slice_pause\": %lu, "
    1913             :          u"\"max_finish_gc_duration\": %lu, "
    1914             :          u"\"max_sync_skippable_duration\": %lu, "
    1915             :          u"\"suspected\": %lu, "
    1916             :          u"\"visited\": { "
    1917             :              u"\"RCed\": %lu, "
    1918             :              u"\"GCed\": %lu }, "
    1919             :          u"\"collected\": { "
    1920             :              u"\"RCed\": %lu, "
    1921             :              u"\"GCed\": %lu }, "
    1922             :          u"\"waiting_for_gc\": %lu, "
    1923             :          u"\"zones_waiting_for_gc\": %lu, "
    1924             :          u"\"short_living_objects_waiting_for_gc\": %lu, "
    1925             :          u"\"forced_gc\": %d, "
    1926             :          u"\"forget_skippable\": { "
    1927             :              u"\"times_before_cc\": %lu, "
    1928             :              u"\"min\": %lu, "
    1929             :              u"\"max\": %lu, "
    1930             :              u"\"avg\": %lu, "
    1931             :              u"\"total\": %lu, "
    1932             :              u"\"removed\": %lu } "
    1933           0 :        u"}";
    1934           0 :     nsString json;
    1935             : 
    1936           0 :     json.Adopt(nsTextFormatter::smprintf(kJSONFmt, PR_Now(), ccNowDuration,
    1937             :                                          gCCStats.mMaxSliceTime,
    1938             :                                          gCCStats.mTotalSliceTime,
    1939             :                                          gCCStats.mMaxGCDuration,
    1940             :                                          gCCStats.mMaxSkippableDuration,
    1941             :                                          gCCStats.mSuspected,
    1942             :                                          aResults.mVisitedRefCounted, aResults.mVisitedGCed,
    1943             :                                          aResults.mFreedRefCounted, aResults.mFreedGCed,
    1944             :                                          sCCollectedWaitingForGC,
    1945             :                                          sCCollectedZonesWaitingForGC,
    1946             :                                          sLikelyShortLivingObjectsNeedingGC,
    1947           0 :                                          aResults.mForcedGC,
    1948             :                                          sForgetSkippableBeforeCC,
    1949           0 :                                          minForgetSkippableTime / PR_USEC_PER_MSEC,
    1950           0 :                                          sMaxForgetSkippableTime / PR_USEC_PER_MSEC,
    1951           0 :                                          (sTotalForgetSkippableTime / cleanups) /
    1952             :                                            PR_USEC_PER_MSEC,
    1953           0 :                                          sTotalForgetSkippableTime / PR_USEC_PER_MSEC,
    1954           0 :                                          sRemovedPurples));
    1955           0 :     nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
    1956           0 :     if (observerService) {
    1957           0 :       observerService->NotifyObservers(nullptr, "cycle-collection-statistics", json.get());
    1958             :     }
    1959             :   }
    1960             : 
    1961             :   // Update global state to indicate we have just run a cycle collection.
    1962           0 :   sMinForgetSkippableTime = UINT32_MAX;
    1963           0 :   sMaxForgetSkippableTime = 0;
    1964           0 :   sTotalForgetSkippableTime = 0;
    1965           0 :   sRemovedPurples = 0;
    1966           0 :   sForgetSkippableBeforeCC = 0;
    1967           0 :   sNeedsFullCC = false;
    1968           0 :   sNeedsGCAfterCC = false;
    1969           0 :   gCCStats.Clear();
    1970           0 : }
    1971             : 
    1972             : // static
    1973             : bool
    1974           3 : InterSliceGCRunnerFired(TimeStamp aDeadline, void* aData)
    1975             : {
    1976           3 :   nsJSContext::KillInterSliceGCRunner();
    1977           3 :   MOZ_ASSERT(sActiveIntersliceGCBudget > 0);
    1978             :   // We use longer budgets when timer runs since that means
    1979             :   // there hasn't been idle time recently and we may have significant amount
    1980             :   // garbage to collect.
    1981           3 :   int64_t budget = sActiveIntersliceGCBudget * 2;
    1982           3 :   if (!aDeadline.IsNull()) {
    1983           0 :     budget = int64_t((aDeadline - TimeStamp::Now()).ToMilliseconds());
    1984             :   }
    1985             : 
    1986           3 :   TimeStamp startTimeStamp = TimeStamp::Now();
    1987           3 :   TimeDuration duration = sGCUnnotifiedTotalTime;
    1988           3 :   uintptr_t reason = reinterpret_cast<uintptr_t>(aData);
    1989           3 :   nsJSContext::GarbageCollectNow(aData ?
    1990             :                                    static_cast<JS::gcreason::Reason>(reason) :
    1991             :                                    JS::gcreason::INTER_SLICE_GC,
    1992             :                                  nsJSContext::IncrementalGC,
    1993             :                                  nsJSContext::NonShrinkingGC,
    1994           3 :                                  budget);
    1995             : 
    1996           3 :   sGCUnnotifiedTotalTime = TimeDuration();
    1997           3 :   TimeStamp now = TimeStamp::Now();
    1998           3 :   TimeDuration sliceDuration = now - startTimeStamp;
    1999           3 :   duration += sliceDuration;
    2000           3 :   if (duration.ToSeconds()) {
    2001           3 :     TimeDuration idleDuration;
    2002           3 :     if (!aDeadline.IsNull()) {
    2003           0 :       if (aDeadline < now) {
    2004             :         // This slice overflowed the idle period.
    2005           0 :         idleDuration = aDeadline - startTimeStamp;
    2006             :       } else {
    2007             :         // Note, we don't want to use duration here, since it may contain
    2008             :         // data also from JS engine triggered GC slices.
    2009           0 :         idleDuration = sliceDuration;
    2010             :       }
    2011             :     }
    2012             : 
    2013             :     uint32_t percent =
    2014           3 :       uint32_t(idleDuration.ToSeconds() / duration.ToSeconds() * 100);
    2015           3 :     Telemetry::Accumulate(Telemetry::GC_SLICE_DURING_IDLE, percent);
    2016             :   }
    2017           3 :   return true;
    2018             : }
    2019             : 
    2020             : // static
    2021             : void
    2022           1 : GCTimerFired(nsITimer *aTimer, void *aClosure)
    2023             : {
    2024           1 :   nsJSContext::KillGCTimer();
    2025             :   // Now start the actual GC after initial timer has fired.
    2026           2 :   sInterSliceGCRunner = CollectorRunner::Create(InterSliceGCRunnerFired,
    2027             :                                                 NS_INTERSLICE_GC_DELAY,
    2028             :                                                 sActiveIntersliceGCBudget,
    2029             :                                                 false,
    2030           1 :                                                 aClosure);
    2031           1 : }
    2032             : 
    2033             : // static
    2034             : void
    2035           0 : ShrinkingGCTimerFired(nsITimer* aTimer, void* aClosure)
    2036             : {
    2037           0 :   nsJSContext::KillShrinkingGCTimer();
    2038           0 :   sIsCompactingOnUserInactive = true;
    2039             :   nsJSContext::GarbageCollectNow(JS::gcreason::USER_INACTIVE,
    2040             :                                  nsJSContext::IncrementalGC,
    2041           0 :                                  nsJSContext::ShrinkingGC);
    2042           0 : }
    2043             : 
    2044             : static bool
    2045           3 : ShouldTriggerCC(uint32_t aSuspected)
    2046             : {
    2047           3 :   return sNeedsFullCC ||
    2048           6 :          aSuspected > NS_CC_PURPLE_LIMIT ||
    2049           0 :          (aSuspected > NS_CC_FORCED_PURPLE_LIMIT &&
    2050           3 :           TimeUntilNow(sLastCCEndTime) > NS_CC_FORCED);
    2051             : }
    2052             : 
    2053             : static bool
    2054           0 : CCRunnerFired(TimeStamp aDeadline, void* aData)
    2055             : {
    2056           0 :   if (sDidShutdown) {
    2057           0 :     return false;
    2058             :   }
    2059             : 
    2060             :   static uint32_t ccDelay = NS_CC_DELAY;
    2061           0 :   if (sCCLockedOut) {
    2062           0 :     ccDelay = NS_CC_DELAY / 3;
    2063             : 
    2064           0 :     PRTime now = PR_Now();
    2065           0 :     if (sCCLockedOutTime == 0) {
    2066             :       // Reset sCCRunnerFireCount so that we run forgetSkippable
    2067             :       // often enough before CC. Because of reduced ccDelay
    2068             :       // forgetSkippable will be called just a few times.
    2069             :       // NS_MAX_CC_LOCKEDOUT_TIME limit guarantees that we end up calling
    2070             :       // forgetSkippable and CycleCollectNow eventually.
    2071           0 :       sCCRunnerFireCount = 0;
    2072           0 :       sCCLockedOutTime = now;
    2073           0 :       return false;
    2074             :     }
    2075           0 :     if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) {
    2076           0 :       return false;
    2077             :     }
    2078             :   }
    2079             : 
    2080           0 :   ++sCCRunnerFireCount;
    2081             : 
    2082           0 :   bool didDoWork = false;
    2083             : 
    2084             :   // During early timer fires, we only run forgetSkippable. During the first
    2085             :   // late timer fire, we decide if we are going to have a second and final
    2086             :   // late timer fire, where we may begin to run the CC. Should run at least one
    2087             :   // early timer fire to allow cleanup before the CC.
    2088           0 :   int32_t numEarlyTimerFires = std::max((int32_t)ccDelay / NS_CC_SKIPPABLE_DELAY - 2, 1);
    2089           0 :   bool isLateTimerFire = sCCRunnerFireCount > numEarlyTimerFires;
    2090           0 :   uint32_t suspected = nsCycleCollector_suspectedCount();
    2091           0 :   if (isLateTimerFire && ShouldTriggerCC(suspected)) {
    2092           0 :     if (sCCRunnerFireCount == numEarlyTimerFires + 1) {
    2093           0 :       FireForgetSkippable(suspected, true, aDeadline);
    2094           0 :       didDoWork = true;
    2095           0 :       if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
    2096             :         // Our efforts to avoid a CC have failed, so we return to let the
    2097             :         // timer fire once more to trigger a CC.
    2098             : 
    2099             :         // Clear content unbinder before the first CC slice.
    2100           0 :         Element::ClearContentUnbinder();
    2101             :         // And trigger deferred deletion too.
    2102           0 :         nsCycleCollector_doDeferredDeletion();
    2103           0 :         return didDoWork;
    2104             :       }
    2105             :     } else {
    2106             :       // We are in the final timer fire and still meet the conditions for
    2107             :       // triggering a CC. Let RunCycleCollectorSlice finish the current IGC, if
    2108             :       // any because that will allow us to include the GC time in the CC pause.
    2109           0 :       nsJSContext::RunCycleCollectorSlice(aDeadline);
    2110           0 :       didDoWork = true;
    2111             :     }
    2112           0 :   } else if (((sPreviousSuspectedCount + 100) <= suspected) ||
    2113           0 :              (sCleanupsSinceLastGC < NS_MAJOR_FORGET_SKIPPABLE_CALLS)) {
    2114             :       // Only do a forget skippable if there are more than a few new objects
    2115             :       // or we're doing the initial forget skippables.
    2116           0 :       FireForgetSkippable(suspected, false, aDeadline);
    2117           0 :       didDoWork = true;
    2118             :   }
    2119             : 
    2120           0 :   if (isLateTimerFire) {
    2121           0 :     ccDelay = NS_CC_DELAY;
    2122             : 
    2123             :     // We have either just run the CC or decided we don't want to run the CC
    2124             :     // next time, so kill the timer.
    2125           0 :     sPreviousSuspectedCount = 0;
    2126           0 :     nsJSContext::KillCCRunner();
    2127             :   }
    2128             : 
    2129           0 :   return didDoWork;
    2130             : }
    2131             : 
    2132             : // static
    2133             : uint32_t
    2134           0 : nsJSContext::CleanupsSinceLastGC()
    2135             : {
    2136           0 :   return sCleanupsSinceLastGC;
    2137             : }
    2138             : 
    2139             : // static
    2140             : void
    2141           8 : nsJSContext::LoadStart()
    2142             : {
    2143           8 :   sLoadingInProgress = true;
    2144           8 :   ++sPendingLoadCount;
    2145           8 : }
    2146             : 
    2147             : // static
    2148             : void
    2149           6 : nsJSContext::LoadEnd()
    2150             : {
    2151           6 :   if (!sLoadingInProgress)
    2152           0 :     return;
    2153             : 
    2154             :   // sPendingLoadCount is not a well managed load counter (and doesn't
    2155             :   // need to be), so make sure we don't make it wrap backwards here.
    2156           6 :   if (sPendingLoadCount > 0) {
    2157           6 :     --sPendingLoadCount;
    2158           6 :     return;
    2159             :   }
    2160             : 
    2161           0 :   sLoadingInProgress = false;
    2162             : }
    2163             : 
    2164             : // Only trigger expensive timers when they have been checked a number of times.
    2165             : static bool
    2166           0 : ReadyToTriggerExpensiveCollectorTimer()
    2167             : {
    2168           0 :   bool ready = kPokesBetweenExpensiveCollectorTriggers < ++sExpensiveCollectorPokes;
    2169           0 :   if (ready) {
    2170           0 :     sExpensiveCollectorPokes = 0;
    2171             :   }
    2172           0 :   return ready;
    2173             : }
    2174             : 
    2175             : 
    2176             : // Check all of the various collector timers/runners and see if they are waiting to fire.
    2177             : // For the synchronous collector timers/runners, sGCTimer and sCCRunner, we only want to
    2178             : // trigger the collection occasionally, because they are expensive.  The incremental collector
    2179             : // timers, sInterSliceGCRunner and sICCRunner, are fast and need to be run many times, so
    2180             : // always run their corresponding timer.
    2181             : 
    2182             : // This does not check sFullGCTimer, as that's a more expensive collection we run
    2183             : // on a long timer.
    2184             : 
    2185             : // static
    2186             : void
    2187           0 : nsJSContext::RunNextCollectorTimer()
    2188             : {
    2189           0 :   if (sShuttingDown) {
    2190           0 :     return;
    2191             :   }
    2192             : 
    2193           0 :   if (sGCTimer) {
    2194           0 :     if (ReadyToTriggerExpensiveCollectorTimer()) {
    2195           0 :       GCTimerFired(nullptr, reinterpret_cast<void *>(JS::gcreason::DOM_WINDOW_UTILS));
    2196             :     }
    2197           0 :     return;
    2198             :   }
    2199             : 
    2200           0 :   if (sInterSliceGCRunner) {
    2201           0 :     InterSliceGCRunnerFired(TimeStamp(), nullptr);
    2202           0 :     return;
    2203             :   }
    2204             : 
    2205             :   // Check the CC timers after the GC timers, because the CC timers won't do
    2206             :   // anything if a GC is in progress.
    2207           0 :   MOZ_ASSERT(!sCCLockedOut, "Don't check the CC timers if the CC is locked out.");
    2208             : 
    2209           0 :   if (sCCRunner) {
    2210           0 :     if (ReadyToTriggerExpensiveCollectorTimer()) {
    2211           0 :       CCRunnerFired(TimeStamp(), nullptr);
    2212             :     }
    2213           0 :     return;
    2214             :   }
    2215             : 
    2216           0 :   if (sICCRunner) {
    2217           0 :     ICCRunnerFired(TimeStamp(), nullptr);
    2218           0 :     return;
    2219             :   }
    2220             : }
    2221             : 
    2222             : // static
    2223             : void
    2224          12 : nsJSContext::PokeGC(JS::gcreason::Reason aReason,
    2225             :                     JSObject* aObj,
    2226             :                     int aDelay)
    2227             : {
    2228          12 :   if (sShuttingDown) {
    2229           0 :     return;
    2230             :   }
    2231             : 
    2232          12 :   if (aObj) {
    2233          11 :     JS::Zone* zone = JS::GetObjectZone(aObj);
    2234          11 :     CycleCollectedJSRuntime::Get()->AddZoneWaitingForGC(zone);
    2235           1 :   } else if (aReason != JS::gcreason::CC_WAITING) {
    2236           1 :     sNeedsFullGC = true;
    2237             :   }
    2238             : 
    2239          12 :   if (sGCTimer || sInterSliceGCRunner) {
    2240             :     // There's already a timer for GC'ing, just return
    2241          10 :     return;
    2242             :   }
    2243             : 
    2244           2 :   if (sCCRunner) {
    2245             :     // Make sure CC is called...
    2246           0 :     sNeedsFullCC = true;
    2247             :     // and GC after it.
    2248           0 :     sNeedsGCAfterCC = true;
    2249           0 :     return;
    2250             :   }
    2251             : 
    2252           2 :   if (sICCRunner) {
    2253             :     // Make sure GC is called after the current CC completes.
    2254             :     // No need to set sNeedsFullCC because we are currently running a CC.
    2255           0 :     sNeedsGCAfterCC = true;
    2256           0 :     return;
    2257             :   }
    2258             : 
    2259           2 :   CallCreateInstance("@mozilla.org/timer;1", &sGCTimer);
    2260             : 
    2261           2 :   if (!sGCTimer) {
    2262             :     // Failed to create timer (probably because we're in XPCOM shutdown)
    2263           0 :     return;
    2264             :   }
    2265             : 
    2266             :   static bool first = true;
    2267             : 
    2268           2 :   sGCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
    2269           3 :   sGCTimer->InitWithNamedFuncCallback(GCTimerFired,
    2270             :                                       reinterpret_cast<void *>(aReason),
    2271             :                                       aDelay
    2272           1 :                                       ? aDelay
    2273             :                                       : (first
    2274             :                                          ? NS_FIRST_GC_DELAY
    2275             :                                          : NS_GC_DELAY),
    2276             :                                       nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
    2277           4 :                                       "GCTimerFired");
    2278             : 
    2279           2 :   first = false;
    2280             : }
    2281             : 
    2282             : // static
    2283             : void
    2284           2 : nsJSContext::PokeShrinkingGC()
    2285             : {
    2286           2 :   if (sShrinkingGCTimer || sShuttingDown) {
    2287           0 :     return;
    2288             :   }
    2289             : 
    2290           2 :   CallCreateInstance("@mozilla.org/timer;1", &sShrinkingGCTimer);
    2291             : 
    2292           2 :   if (!sShrinkingGCTimer) {
    2293             :     // Failed to create timer (probably because we're in XPCOM shutdown)
    2294           0 :     return;
    2295             :   }
    2296             : 
    2297           2 :   sShrinkingGCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
    2298           2 :   sShrinkingGCTimer->InitWithNamedFuncCallback(ShrinkingGCTimerFired, nullptr,
    2299             :                                                sCompactOnUserInactiveDelay,
    2300             :                                                nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
    2301           4 :                                                "ShrinkingGCTimerFired");
    2302             : }
    2303             : 
    2304             : // static
    2305             : void
    2306        1227 : nsJSContext::MaybePokeCC()
    2307             : {
    2308        1227 :   if (sCCRunner || sICCRunner || sShuttingDown || !sHasRunGC) {
    2309        1227 :     return;
    2310             :   }
    2311             : 
    2312           0 :   uint32_t sinceLastCCEnd = TimeUntilNow(sLastCCEndTime);
    2313           0 :   if (sinceLastCCEnd && sinceLastCCEnd < NS_CC_DELAY) {
    2314           0 :     return;
    2315             :   }
    2316             : 
    2317           0 :   if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
    2318           0 :     sCCRunnerFireCount = 0;
    2319             : 
    2320             :     // We can kill some objects before running forgetSkippable.
    2321           0 :     nsCycleCollector_dispatchDeferredDeletion();
    2322             : 
    2323             :     sCCRunner =
    2324           0 :       CollectorRunner::Create(CCRunnerFired, NS_CC_SKIPPABLE_DELAY,
    2325           0 :                               kForgetSkippableSliceDuration, true);
    2326             :   }
    2327             : }
    2328             : 
    2329             : //static
    2330             : void
    2331           4 : nsJSContext::KillGCTimer()
    2332             : {
    2333           4 :   if (sGCTimer) {
    2334           1 :     sGCTimer->Cancel();
    2335           1 :     NS_RELEASE(sGCTimer);
    2336             :   }
    2337           4 : }
    2338             : 
    2339             : void
    2340           0 : nsJSContext::KillFullGCTimer()
    2341             : {
    2342           0 :   if (sFullGCTimer) {
    2343           0 :     sFullGCTimer->Cancel();
    2344           0 :     NS_RELEASE(sFullGCTimer);
    2345             :   }
    2346           0 : }
    2347             : 
    2348             : void
    2349           6 : nsJSContext::KillInterSliceGCRunner()
    2350             : {
    2351           6 :   if (sInterSliceGCRunner) {
    2352           3 :     sInterSliceGCRunner->Cancel();
    2353           3 :     sInterSliceGCRunner = nullptr;
    2354             :   }
    2355           6 : }
    2356             : 
    2357             : //static
    2358             : void
    2359           1 : nsJSContext::KillShrinkingGCTimer()
    2360             : {
    2361           1 :   if (sShrinkingGCTimer) {
    2362           1 :     sShrinkingGCTimer->Cancel();
    2363           1 :     NS_RELEASE(sShrinkingGCTimer);
    2364             :   }
    2365           1 : }
    2366             : 
    2367             : //static
    2368             : void
    2369           0 : nsJSContext::KillCCRunner()
    2370             : {
    2371           0 :   sCCLockedOutTime = 0;
    2372           0 :   if (sCCRunner) {
    2373           0 :     sCCRunner->Cancel();
    2374           0 :     sCCRunner = nullptr;
    2375             :   }
    2376           0 : }
    2377             : 
    2378             : //static
    2379             : void
    2380           0 : nsJSContext::KillICCRunner()
    2381             : {
    2382           0 :   sCCLockedOutTime = 0;
    2383             : 
    2384           0 :   if (sICCRunner) {
    2385           0 :     sICCRunner->Cancel();
    2386           0 :     sICCRunner = nullptr;
    2387             :   }
    2388           0 : }
    2389             : 
    2390           0 : class NotifyGCEndRunnable : public Runnable
    2391             : {
    2392             :   nsString mMessage;
    2393             : 
    2394             : public:
    2395           0 :   explicit NotifyGCEndRunnable(const nsString& aMessage)
    2396           0 :     : mozilla::Runnable("NotifyGCEndRunnable")
    2397           0 :     , mMessage(aMessage)
    2398             :   {
    2399           0 :   }
    2400             : 
    2401             :   NS_DECL_NSIRUNNABLE
    2402             : };
    2403             : 
    2404             : NS_IMETHODIMP
    2405           0 : NotifyGCEndRunnable::Run()
    2406             : {
    2407           0 :   MOZ_ASSERT(NS_IsMainThread());
    2408             : 
    2409           0 :   nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
    2410           0 :   if (!observerService) {
    2411           0 :     return NS_OK;
    2412             :   }
    2413             : 
    2414           0 :   const char16_t oomMsg[3] = { '{', '}', 0 };
    2415           0 :   const char16_t *toSend = mMessage.get() ? mMessage.get() : oomMsg;
    2416           0 :   observerService->NotifyObservers(nullptr, "garbage-collection-statistics", toSend);
    2417             : 
    2418           0 :   return NS_OK;
    2419             : }
    2420             : 
    2421             : static void
    2422           7 : DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, const JS::GCDescription &aDesc)
    2423             : {
    2424           7 :   NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
    2425             : 
    2426           7 :   switch (aProgress) {
    2427             :     case JS::GC_CYCLE_BEGIN: {
    2428             :       // Prevent cycle collections and shrinking during incremental GC.
    2429           1 :       sCCLockedOut = true;
    2430           1 :       break;
    2431             :     }
    2432             : 
    2433             :     case JS::GC_CYCLE_END: {
    2434           0 :       PRTime delta = GetCollectionTimeDelta();
    2435             : 
    2436           0 :       if (sPostGCEventsToConsole) {
    2437           0 :         nsString prefix, gcstats;
    2438           0 :         gcstats.Adopt(aDesc.formatSummaryMessage(aCx));
    2439           0 :         prefix.Adopt(nsTextFormatter::smprintf(u"GC(T+%.1f)[%s-%i] ",
    2440           0 :                                                double(delta) / PR_USEC_PER_SEC,
    2441             :                                                ProcessNameForCollectorLog(),
    2442           0 :                                                getpid()));
    2443           0 :         nsString msg = prefix + gcstats;
    2444           0 :         nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    2445           0 :         if (cs) {
    2446           0 :           cs->LogStringMessage(msg.get());
    2447             :         }
    2448             :       }
    2449             : 
    2450           0 :       if (!sShuttingDown) {
    2451           0 :         if (sPostGCEventsToObserver || Telemetry::CanRecordExtended()) {
    2452           0 :           nsString json;
    2453           0 :           json.Adopt(aDesc.formatJSON(aCx, PR_Now()));
    2454           0 :           RefPtr<NotifyGCEndRunnable> notify = new NotifyGCEndRunnable(json);
    2455           0 :           NS_DispatchToMainThread(notify);
    2456             :         }
    2457             :       }
    2458             : 
    2459           0 :       sCCLockedOut = false;
    2460           0 :       sIsCompactingOnUserInactive = false;
    2461             : 
    2462             :       // May need to kill the inter-slice GC runner
    2463           0 :       nsJSContext::KillInterSliceGCRunner();
    2464             : 
    2465           0 :       sCCollectedWaitingForGC = 0;
    2466           0 :       sCCollectedZonesWaitingForGC = 0;
    2467           0 :       sLikelyShortLivingObjectsNeedingGC = 0;
    2468           0 :       sCleanupsSinceLastGC = 0;
    2469           0 :       sNeedsFullCC = true;
    2470           0 :       sHasRunGC = true;
    2471           0 :       nsJSContext::MaybePokeCC();
    2472             : 
    2473           0 :       if (aDesc.isZone_) {
    2474           0 :         if (!sFullGCTimer && !sShuttingDown) {
    2475           0 :           CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer);
    2476           0 :           sFullGCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
    2477           0 :           sFullGCTimer->InitWithNamedFuncCallback(FullGCTimerFired,
    2478             :                                                   nullptr,
    2479             :                                                   NS_FULL_GC_DELAY,
    2480             :                                                   nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
    2481           0 :                                                   "FullGCTimerFired");
    2482             :         }
    2483             :       } else {
    2484           0 :         nsJSContext::KillFullGCTimer();
    2485             :       }
    2486             : 
    2487           0 :       if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
    2488           0 :         nsCycleCollector_dispatchDeferredDeletion();
    2489             :       }
    2490             : 
    2491           0 :       if (!aDesc.isZone_) {
    2492           0 :         sNeedsFullGC = false;
    2493             :       }
    2494             : 
    2495           0 :       break;
    2496             :     }
    2497             : 
    2498             :     case JS::GC_SLICE_BEGIN:
    2499           3 :       break;
    2500             : 
    2501             :     case JS::GC_SLICE_END:
    2502             :       sGCUnnotifiedTotalTime +=
    2503           3 :         aDesc.lastSliceEnd(aCx) - aDesc.lastSliceStart(aCx);
    2504             : 
    2505             :       // Schedule another GC slice if the GC has more work to do.
    2506           3 :       nsJSContext::KillInterSliceGCRunner();
    2507           3 :       if (!sShuttingDown && !aDesc.isComplete_) {
    2508             :         sInterSliceGCRunner =
    2509           6 :           CollectorRunner::Create(InterSliceGCRunnerFired, NS_INTERSLICE_GC_DELAY,
    2510           3 :                                   sActiveIntersliceGCBudget, false);
    2511             :       }
    2512             : 
    2513           3 :       if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
    2514           3 :         nsCycleCollector_dispatchDeferredDeletion();
    2515             :       }
    2516             : 
    2517           3 :       if (sPostGCEventsToConsole) {
    2518           0 :         nsString prefix, gcstats;
    2519           0 :         gcstats.Adopt(aDesc.formatSliceMessage(aCx));
    2520           0 :         prefix.Adopt(nsTextFormatter::smprintf(u"[%s-%i] ",
    2521             :                                                ProcessNameForCollectorLog(),
    2522           0 :                                                getpid()));
    2523           0 :         nsString msg = prefix + gcstats;
    2524           0 :         nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    2525           0 :         if (cs) {
    2526           0 :           cs->LogStringMessage(msg.get());
    2527             :         }
    2528             :       }
    2529             : 
    2530           3 :       break;
    2531             : 
    2532             :     default:
    2533           0 :       MOZ_CRASH("Unexpected GCProgress value");
    2534             :   }
    2535             : 
    2536           7 :   if (sPrevGCSliceCallback) {
    2537           7 :     (*sPrevGCSliceCallback)(aCx, aProgress, aDesc);
    2538             :   }
    2539             : 
    2540           7 : }
    2541             : 
    2542             : void
    2543           7 : nsJSContext::SetWindowProxy(JS::Handle<JSObject*> aWindowProxy)
    2544             : {
    2545           7 :   mWindowProxy = aWindowProxy;
    2546           7 : }
    2547             : 
    2548             : JSObject*
    2549          14 : nsJSContext::GetWindowProxy()
    2550             : {
    2551          14 :   return mWindowProxy;
    2552             : }
    2553             : 
    2554             : void
    2555           0 : nsJSContext::LikelyShortLivingObjectCreated()
    2556             : {
    2557           0 :   ++sLikelyShortLivingObjectsNeedingGC;
    2558           0 : }
    2559             : 
    2560             : void
    2561           3 : mozilla::dom::StartupJSEnvironment()
    2562             : {
    2563             :   // initialize all our statics, so that we can restart XPCOM
    2564           3 :   sGCTimer = sShrinkingGCTimer = sFullGCTimer = nullptr;
    2565           3 :   sCCLockedOut = false;
    2566           3 :   sCCLockedOutTime = 0;
    2567           3 :   sLastCCEndTime = TimeStamp();
    2568           3 :   sHasRunGC = false;
    2569           3 :   sPendingLoadCount = 0;
    2570           3 :   sLoadingInProgress = false;
    2571           3 :   sCCollectedWaitingForGC = 0;
    2572           3 :   sCCollectedZonesWaitingForGC = 0;
    2573           3 :   sLikelyShortLivingObjectsNeedingGC = 0;
    2574           3 :   sPostGCEventsToConsole = false;
    2575           3 :   sNeedsFullCC = false;
    2576           3 :   sNeedsFullGC = true;
    2577           3 :   sNeedsGCAfterCC = false;
    2578           3 :   gNameSpaceManager = nullptr;
    2579           3 :   sIsInitialized = false;
    2580           3 :   sDidShutdown = false;
    2581           3 :   sShuttingDown = false;
    2582           3 :   sContextCount = 0;
    2583           3 :   sSecurityManager = nullptr;
    2584           3 :   gCCStats.Init();
    2585           3 :   sExpensiveCollectorPokes = 0;
    2586           3 : }
    2587             : 
    2588             : static void
    2589          36 : SetGCParameter(JSGCParamKey aParam, uint32_t aValue)
    2590             : {
    2591          72 :   AutoJSAPI jsapi;
    2592          36 :   jsapi.Init();
    2593          36 :   JS_SetGCParameter(jsapi.cx(), aParam, aValue);
    2594          36 : }
    2595             : 
    2596             : static void
    2597           2 : SetMemoryHighWaterMarkPrefChangedCallback(const char* aPrefName, void* aClosure)
    2598             : {
    2599           2 :   int32_t highwatermark = Preferences::GetInt(aPrefName, 128);
    2600           2 :   SetGCParameter(JSGC_MAX_MALLOC_BYTES,
    2601           2 :                  highwatermark * 1024L * 1024L);
    2602           2 : }
    2603             : 
    2604             : static void
    2605           2 : SetMemoryMaxPrefChangedCallback(const char* aPrefName, void* aClosure)
    2606             : {
    2607           2 :   int32_t pref = Preferences::GetInt(aPrefName, -1);
    2608             :   // handle overflow and negative pref values
    2609           2 :   uint32_t max = (pref <= 0 || pref >= 0x1000) ? -1 : (uint32_t)pref * 1024 * 1024;
    2610           2 :   SetGCParameter(JSGC_MAX_BYTES, max);
    2611           2 : }
    2612             : 
    2613             : static void
    2614           4 : SetMemoryGCModePrefChangedCallback(const char* aPrefName, void* aClosure)
    2615             : {
    2616           4 :   bool enableZoneGC = Preferences::GetBool("javascript.options.mem.gc_per_zone");
    2617           4 :   bool enableIncrementalGC = Preferences::GetBool("javascript.options.mem.gc_incremental");
    2618             :   JSGCMode mode;
    2619           4 :   if (enableIncrementalGC) {
    2620           4 :     mode = JSGC_MODE_INCREMENTAL;
    2621           0 :   } else if (enableZoneGC) {
    2622           0 :     mode = JSGC_MODE_ZONE;
    2623             :   } else {
    2624           0 :     mode = JSGC_MODE_GLOBAL;
    2625             :   }
    2626             : 
    2627           4 :   SetGCParameter(JSGC_MODE, mode);
    2628           4 : }
    2629             : 
    2630             : static void
    2631           2 : SetMemoryGCSliceTimePrefChangedCallback(const char* aPrefName, void* aClosure)
    2632             : {
    2633           2 :   int32_t pref = Preferences::GetInt(aPrefName, -1);
    2634             :   // handle overflow and negative pref values
    2635           2 :   if (pref > 0 && pref < 100000) {
    2636           2 :     sActiveIntersliceGCBudget = pref;
    2637           2 :     SetGCParameter(JSGC_SLICE_TIME_BUDGET, pref);
    2638             :   }
    2639           2 : }
    2640             : 
    2641             : static void
    2642           2 : SetMemoryGCCompactingPrefChangedCallback(const char* aPrefName, void* aClosure)
    2643             : {
    2644           2 :   bool pref = Preferences::GetBool(aPrefName);
    2645           2 :   SetGCParameter(JSGC_COMPACTING_ENABLED, pref);
    2646           2 : }
    2647             : 
    2648             : static void
    2649          18 : SetMemoryGCPrefChangedCallback(const char* aPrefName, void* aClosure)
    2650             : {
    2651          18 :   int32_t pref = Preferences::GetInt(aPrefName, -1);
    2652             :   // handle overflow and negative pref values
    2653          18 :   if (pref >= 0 && pref < 10000) {
    2654          18 :     SetGCParameter((JSGCParamKey)(intptr_t)aClosure, pref);
    2655             :   }
    2656          18 : }
    2657             : 
    2658             : static void
    2659           2 : SetMemoryGCDynamicHeapGrowthPrefChangedCallback(const char* aPrefName, void* aClosure)
    2660             : {
    2661           2 :   bool pref = Preferences::GetBool(aPrefName);
    2662           2 :   SetGCParameter(JSGC_DYNAMIC_HEAP_GROWTH, pref);
    2663           2 : }
    2664             : 
    2665             : static void
    2666           2 : SetMemoryGCDynamicMarkSlicePrefChangedCallback(const char* aPrefName, void* aClosure)
    2667             : {
    2668           2 :   bool pref = Preferences::GetBool(aPrefName);
    2669           2 :   SetGCParameter(JSGC_DYNAMIC_MARK_SLICE, pref);
    2670           2 : }
    2671             : 
    2672             : static void
    2673           2 : SetMemoryGCRefreshFrameSlicesEnabledPrefChangedCallback(const char* aPrefName, void* aClosure)
    2674             : {
    2675           2 :   bool pref = Preferences::GetBool(aPrefName);
    2676           2 :   SetGCParameter(JSGC_REFRESH_FRAME_SLICES_ENABLED, pref);
    2677           2 : }
    2678             : 
    2679             : 
    2680             : static void
    2681           2 : SetIncrementalCCPrefChangedCallback(const char* aPrefName, void* aClosure)
    2682             : {
    2683           2 :   bool pref = Preferences::GetBool(aPrefName);
    2684           2 :   sIncrementalCC = pref;
    2685           2 : }
    2686             : 
    2687             : static bool
    2688           0 : AsmJSCacheOpenEntryForRead(JS::Handle<JSObject*> aGlobal,
    2689             :                            const char16_t* aBegin,
    2690             :                            const char16_t* aLimit,
    2691             :                            size_t* aSize,
    2692             :                            const uint8_t** aMemory,
    2693             :                            intptr_t *aHandle)
    2694             : {
    2695             :   nsIPrincipal* principal =
    2696           0 :     nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aGlobal)));
    2697             :   return asmjscache::OpenEntryForRead(principal, aBegin, aLimit, aSize, aMemory,
    2698           0 :                                       aHandle);
    2699             : }
    2700             : 
    2701             : static JS::AsmJSCacheResult
    2702           0 : AsmJSCacheOpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
    2703             :                             const char16_t* aBegin,
    2704             :                             const char16_t* aEnd,
    2705             :                             size_t aSize,
    2706             :                             uint8_t** aMemory,
    2707             :                             intptr_t* aHandle)
    2708             : {
    2709             :   nsIPrincipal* principal =
    2710           0 :     nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aGlobal)));
    2711             :   return asmjscache::OpenEntryForWrite(principal, aBegin, aEnd, aSize, aMemory,
    2712           0 :                                        aHandle);
    2713             : }
    2714             : 
    2715             : class AsyncTaskRunnable final : public Runnable
    2716             : {
    2717           0 :   ~AsyncTaskRunnable()
    2718           0 :   {
    2719           0 :     MOZ_ASSERT(!mTask);
    2720           0 :   }
    2721             : 
    2722             : public:
    2723           0 :   explicit AsyncTaskRunnable(JS::AsyncTask* aTask)
    2724           0 :     : mozilla::Runnable("AsyncTaskRunnable")
    2725           0 :     , mTask(aTask)
    2726             :   {
    2727           0 :     MOZ_ASSERT(mTask);
    2728           0 :   }
    2729             : 
    2730             : protected:
    2731           0 :   NS_IMETHOD Run() override
    2732             :   {
    2733           0 :     MOZ_ASSERT(NS_IsMainThread());
    2734             : 
    2735           0 :     AutoJSAPI jsapi;
    2736           0 :     jsapi.Init();
    2737           0 :     mTask->finish(jsapi.cx());
    2738           0 :     mTask = nullptr;  // mTask may delete itself
    2739             : 
    2740           0 :     return NS_OK;
    2741             :   }
    2742             : 
    2743             : private:
    2744             :   JS::AsyncTask* mTask;
    2745             : };
    2746             : 
    2747             : static bool
    2748           0 : StartAsyncTaskCallback(JSContext* aCx, JS::AsyncTask* aTask)
    2749             : {
    2750           0 :   return true;
    2751             : }
    2752             : 
    2753             : static bool
    2754           0 : FinishAsyncTaskCallback(JS::AsyncTask* aTask)
    2755             : {
    2756             :   // AsyncTasks can finish during shutdown so cannot simply
    2757             :   // NS_DispatchToMainThread.
    2758           0 :   nsCOMPtr<nsIEventTarget> mainTarget = GetMainThreadEventTarget();
    2759           0 :   if (!mainTarget) {
    2760           0 :     return false;
    2761             :   }
    2762             : 
    2763           0 :   RefPtr<AsyncTaskRunnable> r = new AsyncTaskRunnable(aTask);
    2764           0 :   MOZ_ALWAYS_SUCCEEDS(mainTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL));
    2765           0 :   return true;
    2766             : }
    2767             : 
    2768             : void
    2769           5 : nsJSContext::EnsureStatics()
    2770             : {
    2771           5 :   if (sIsInitialized) {
    2772           3 :     if (!nsContentUtils::XPConnect()) {
    2773           0 :       MOZ_CRASH();
    2774             :     }
    2775           3 :     return;
    2776             :   }
    2777             : 
    2778             :   nsresult rv = CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID,
    2779           2 :                                &sSecurityManager);
    2780           2 :   if (NS_FAILED(rv)) {
    2781           0 :     MOZ_CRASH();
    2782             :   }
    2783             : 
    2784             :   // Let's make sure that our main thread is the same as the xpcom main thread.
    2785           2 :   MOZ_ASSERT(NS_IsMainThread());
    2786             : 
    2787           4 :   AutoJSAPI jsapi;
    2788           2 :   jsapi.Init();
    2789             : 
    2790           2 :   sPrevGCSliceCallback = JS::SetGCSliceCallback(jsapi.cx(), DOMGCSliceCallback);
    2791             : 
    2792             :   // Set up the asm.js cache callbacks
    2793             :   static const JS::AsmJSCacheOps asmJSCacheOps = {
    2794             :     AsmJSCacheOpenEntryForRead,
    2795             :     asmjscache::CloseEntryForRead,
    2796             :     AsmJSCacheOpenEntryForWrite,
    2797             :     asmjscache::CloseEntryForWrite
    2798             :   };
    2799           2 :   JS::SetAsmJSCacheOps(jsapi.cx(), &asmJSCacheOps);
    2800             : 
    2801           2 :   JS::SetAsyncTaskCallbacks(jsapi.cx(), StartAsyncTaskCallback, FinishAsyncTaskCallback);
    2802             : 
    2803             :   // Set these global xpconnect options...
    2804             :   Preferences::RegisterCallbackAndCall(SetMemoryHighWaterMarkPrefChangedCallback,
    2805           2 :                                        "javascript.options.mem.high_water_mark");
    2806             : 
    2807             :   Preferences::RegisterCallbackAndCall(SetMemoryMaxPrefChangedCallback,
    2808           2 :                                        "javascript.options.mem.max");
    2809             : 
    2810             :   Preferences::RegisterCallbackAndCall(SetMemoryGCModePrefChangedCallback,
    2811           2 :                                        "javascript.options.mem.gc_per_zone");
    2812             : 
    2813             :   Preferences::RegisterCallbackAndCall(SetMemoryGCModePrefChangedCallback,
    2814           2 :                                        "javascript.options.mem.gc_incremental");
    2815             : 
    2816             :   Preferences::RegisterCallbackAndCall(SetMemoryGCSliceTimePrefChangedCallback,
    2817           2 :                                        "javascript.options.mem.gc_incremental_slice_ms");
    2818             : 
    2819             :   Preferences::RegisterCallbackAndCall(SetMemoryGCCompactingPrefChangedCallback,
    2820           2 :                                        "javascript.options.mem.gc_compacting");
    2821             : 
    2822             :   Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
    2823             :                                        "javascript.options.mem.gc_high_frequency_time_limit_ms",
    2824           2 :                                        (void *)JSGC_HIGH_FREQUENCY_TIME_LIMIT);
    2825             : 
    2826             :   Preferences::RegisterCallbackAndCall(SetMemoryGCDynamicMarkSlicePrefChangedCallback,
    2827           2 :                                        "javascript.options.mem.gc_dynamic_mark_slice");
    2828             : 
    2829             :   Preferences::RegisterCallbackAndCall(SetMemoryGCRefreshFrameSlicesEnabledPrefChangedCallback,
    2830           2 :                                        "javascript.options.mem.gc_refresh_frame_slices_enabled");
    2831             : 
    2832             :   Preferences::RegisterCallbackAndCall(SetMemoryGCDynamicHeapGrowthPrefChangedCallback,
    2833           2 :                                        "javascript.options.mem.gc_dynamic_heap_growth");
    2834             : 
    2835             :   Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
    2836             :                                        "javascript.options.mem.gc_low_frequency_heap_growth",
    2837           2 :                                        (void *)JSGC_LOW_FREQUENCY_HEAP_GROWTH);
    2838             : 
    2839             :   Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
    2840             :                                        "javascript.options.mem.gc_high_frequency_heap_growth_min",
    2841           2 :                                        (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN);
    2842             : 
    2843             :   Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
    2844             :                                        "javascript.options.mem.gc_high_frequency_heap_growth_max",
    2845           2 :                                        (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX);
    2846             : 
    2847             :   Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
    2848             :                                        "javascript.options.mem.gc_high_frequency_low_limit_mb",
    2849           2 :                                        (void *)JSGC_HIGH_FREQUENCY_LOW_LIMIT);
    2850             : 
    2851             :   Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
    2852             :                                        "javascript.options.mem.gc_high_frequency_high_limit_mb",
    2853           2 :                                        (void *)JSGC_HIGH_FREQUENCY_HIGH_LIMIT);
    2854             : 
    2855             :   Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
    2856             :                                        "javascript.options.mem.gc_allocation_threshold_mb",
    2857           2 :                                        (void *)JSGC_ALLOCATION_THRESHOLD);
    2858             : 
    2859             :   Preferences::RegisterCallbackAndCall(SetIncrementalCCPrefChangedCallback,
    2860           2 :                                        "dom.cycle_collector.incremental");
    2861             : 
    2862             :   Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
    2863             :                                        "javascript.options.mem.gc_min_empty_chunk_count",
    2864           2 :                                        (void *)JSGC_MIN_EMPTY_CHUNK_COUNT);
    2865             : 
    2866             :   Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback,
    2867             :                                        "javascript.options.mem.gc_max_empty_chunk_count",
    2868           2 :                                        (void *)JSGC_MAX_EMPTY_CHUNK_COUNT);
    2869             : 
    2870           4 :   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
    2871           2 :   if (!obs) {
    2872           0 :     MOZ_CRASH();
    2873             :   }
    2874             : 
    2875             :   Preferences::AddBoolVarCache(&sGCOnMemoryPressure,
    2876             :                                "javascript.options.gc_on_memory_pressure",
    2877           2 :                                true);
    2878             : 
    2879             :   Preferences::AddBoolVarCache(&sCompactOnUserInactive,
    2880             :                                "javascript.options.compact_on_user_inactive",
    2881           2 :                                true);
    2882             : 
    2883             :   Preferences::AddUintVarCache(&sCompactOnUserInactiveDelay,
    2884             :                                "javascript.options.compact_on_user_inactive_delay",
    2885           2 :                                NS_DEAULT_INACTIVE_GC_DELAY);
    2886             : 
    2887             :   Preferences::AddBoolVarCache(&sPostGCEventsToConsole,
    2888           2 :                                JS_OPTIONS_DOT_STR "mem.log");
    2889             :   Preferences::AddBoolVarCache(&sPostGCEventsToObserver,
    2890           2 :                                JS_OPTIONS_DOT_STR "mem.notify");
    2891             : 
    2892           2 :   nsIObserver* observer = new nsJSEnvironmentObserver();
    2893           2 :   obs->AddObserver(observer, "memory-pressure", false);
    2894           2 :   obs->AddObserver(observer, "user-interaction-inactive", false);
    2895           2 :   obs->AddObserver(observer, "user-interaction-active", false);
    2896           2 :   obs->AddObserver(observer, "quit-application", false);
    2897           2 :   obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
    2898             : 
    2899           2 :   sIsInitialized = true;
    2900             : }
    2901             : 
    2902             : nsScriptNameSpaceManager*
    2903        3170 : mozilla::dom::GetNameSpaceManager()
    2904             : {
    2905        3170 :   if (sDidShutdown)
    2906           0 :     return nullptr;
    2907             : 
    2908        3170 :   if (!gNameSpaceManager) {
    2909           3 :     gNameSpaceManager = new nsScriptNameSpaceManager;
    2910           3 :     NS_ADDREF(gNameSpaceManager);
    2911             : 
    2912           3 :     nsresult rv = gNameSpaceManager->Init();
    2913           3 :     NS_ENSURE_SUCCESS(rv, nullptr);
    2914             :   }
    2915             : 
    2916        3170 :   return gNameSpaceManager;
    2917             : }
    2918             : 
    2919             : nsScriptNameSpaceManager*
    2920           0 : mozilla::dom::PeekNameSpaceManager()
    2921             : {
    2922           0 :   return gNameSpaceManager;
    2923             : }
    2924             : 
    2925             : void
    2926           0 : mozilla::dom::ShutdownJSEnvironment()
    2927             : {
    2928           0 :   KillTimers();
    2929             : 
    2930           0 :   NS_IF_RELEASE(gNameSpaceManager);
    2931             : 
    2932           0 :   if (!sContextCount) {
    2933             :     // We're being shutdown, and there are no more contexts
    2934             :     // alive, release the security manager.
    2935           0 :     NS_IF_RELEASE(sSecurityManager);
    2936             :   }
    2937             : 
    2938           0 :   sShuttingDown = true;
    2939           0 :   sDidShutdown = true;
    2940           0 : }
    2941             : 
    2942             : // A fast-array class for JS.  This class supports both nsIJSScriptArray and
    2943             : // nsIArray.  If it is JS itself providing and consuming this class, all work
    2944             : // can be done via nsIJSScriptArray, and avoid the conversion of elements
    2945             : // to/from nsISupports.
    2946             : // When consumed by non-JS (eg, another script language), conversion is done
    2947             : // on-the-fly.
    2948             : class nsJSArgArray final : public nsIJSArgArray {
    2949             : public:
    2950             :   nsJSArgArray(JSContext *aContext, uint32_t argc, const JS::Value* argv,
    2951             :                nsresult *prv);
    2952             : 
    2953             :   // nsISupports
    2954             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    2955           0 :   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray,
    2956             :                                                          nsIJSArgArray)
    2957             : 
    2958             :   // nsIArray
    2959             :   NS_DECL_NSIARRAY
    2960             : 
    2961             :   // nsIJSArgArray
    2962             :   nsresult GetArgs(uint32_t* argc, void** argv) override;
    2963             : 
    2964             :   void ReleaseJSObjects();
    2965             : 
    2966             : protected:
    2967             :   ~nsJSArgArray();
    2968             :   JSContext *mContext;
    2969             :   JS::Heap<JS::Value> *mArgv;
    2970             :   uint32_t mArgc;
    2971             : };
    2972             : 
    2973           0 : nsJSArgArray::nsJSArgArray(JSContext *aContext, uint32_t argc,
    2974           0 :                            const JS::Value* argv, nsresult *prv)
    2975             :   : mContext(aContext)
    2976             :   , mArgv(nullptr)
    2977           0 :   , mArgc(argc)
    2978             : {
    2979             :   // copy the array - we don't know its lifetime, and ours is tied to xpcom
    2980             :   // refcounting.
    2981           0 :   if (argc) {
    2982           0 :     mArgv = new (fallible) JS::Heap<JS::Value>[argc];
    2983           0 :     if (!mArgv) {
    2984           0 :       *prv = NS_ERROR_OUT_OF_MEMORY;
    2985           0 :       return;
    2986             :     }
    2987             :   }
    2988             : 
    2989             :   // Callers are allowed to pass in a null argv even for argc > 0. They can
    2990             :   // then use GetArgs to initialize the values.
    2991           0 :   if (argv) {
    2992           0 :     for (uint32_t i = 0; i < argc; ++i)
    2993           0 :       mArgv[i] = argv[i];
    2994             :   }
    2995             : 
    2996           0 :   if (argc > 0) {
    2997           0 :     mozilla::HoldJSObjects(this);
    2998             :   }
    2999             : 
    3000           0 :   *prv = NS_OK;
    3001             : }
    3002             : 
    3003           0 : nsJSArgArray::~nsJSArgArray()
    3004             : {
    3005           0 :   ReleaseJSObjects();
    3006           0 : }
    3007             : 
    3008             : void
    3009           0 : nsJSArgArray::ReleaseJSObjects()
    3010             : {
    3011           0 :   if (mArgv) {
    3012           0 :     delete [] mArgv;
    3013             :   }
    3014           0 :   if (mArgc > 0) {
    3015           0 :     mArgc = 0;
    3016           0 :     mozilla::DropJSObjects(this);
    3017             :   }
    3018           0 : }
    3019             : 
    3020             : // QueryInterface implementation for nsJSArgArray
    3021             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray)
    3022             : 
    3023           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSArgArray)
    3024           0 :   tmp->ReleaseJSObjects();
    3025           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    3026           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray)
    3027           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    3028             : 
    3029           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray)
    3030           0 :   if (tmp->mArgv) {
    3031           0 :     for (uint32_t i = 0; i < tmp->mArgc; ++i) {
    3032           0 :       NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArgv[i])
    3033             :     }
    3034             :   }
    3035           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
    3036             : 
    3037           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray)
    3038           0 :   NS_INTERFACE_MAP_ENTRY(nsIArray)
    3039           0 :   NS_INTERFACE_MAP_ENTRY(nsIJSArgArray)
    3040           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSArgArray)
    3041           0 : NS_INTERFACE_MAP_END
    3042             : 
    3043           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSArgArray)
    3044           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSArgArray)
    3045             : 
    3046             : nsresult
    3047           0 : nsJSArgArray::GetArgs(uint32_t *argc, void **argv)
    3048             : {
    3049           0 :   *argv = (void *)mArgv;
    3050           0 :   *argc = mArgc;
    3051           0 :   return NS_OK;
    3052             : }
    3053             : 
    3054             : // nsIArray impl
    3055           0 : NS_IMETHODIMP nsJSArgArray::GetLength(uint32_t *aLength)
    3056             : {
    3057           0 :   *aLength = mArgc;
    3058           0 :   return NS_OK;
    3059             : }
    3060             : 
    3061           0 : NS_IMETHODIMP nsJSArgArray::QueryElementAt(uint32_t index, const nsIID & uuid, void * *result)
    3062             : {
    3063           0 :   *result = nullptr;
    3064           0 :   if (index >= mArgc)
    3065           0 :     return NS_ERROR_INVALID_ARG;
    3066             : 
    3067           0 :   if (uuid.Equals(NS_GET_IID(nsIVariant)) || uuid.Equals(NS_GET_IID(nsISupports))) {
    3068             :     // Have to copy a Heap into a Rooted to work with it.
    3069           0 :     JS::Rooted<JS::Value> val(mContext, mArgv[index]);
    3070           0 :     return nsContentUtils::XPConnect()->JSToVariant(mContext, val,
    3071           0 :                                                     (nsIVariant **)result);
    3072             :   }
    3073           0 :   NS_WARNING("nsJSArgArray only handles nsIVariant");
    3074           0 :   return NS_ERROR_NO_INTERFACE;
    3075             : }
    3076             : 
    3077           0 : NS_IMETHODIMP nsJSArgArray::IndexOf(uint32_t startIndex, nsISupports *element, uint32_t *_retval)
    3078             : {
    3079           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    3080             : }
    3081             : 
    3082           0 : NS_IMETHODIMP nsJSArgArray::Enumerate(nsISimpleEnumerator **_retval)
    3083             : {
    3084           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    3085             : }
    3086             : 
    3087             : // The factory function
    3088           0 : nsresult NS_CreateJSArgv(JSContext *aContext, uint32_t argc,
    3089             :                          const JS::Value* argv, nsIJSArgArray **aArray)
    3090             : {
    3091             :   nsresult rv;
    3092           0 :   nsCOMPtr<nsIJSArgArray> ret = new nsJSArgArray(aContext, argc, argv, &rv);
    3093           0 :   if (NS_FAILED(rv)) {
    3094           0 :     return rv;
    3095             :   }
    3096           0 :   ret.forget(aArray);
    3097           0 :   return NS_OK;
    3098             : }

Generated by: LCOV version 1.13