LCOV - code coverage report
Current view: top level - xpcom/base - CycleCollectedJSContext.h (source / functions) Hit Total Coverage
Test: output.info Lines: 22 39 56.4 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
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             : #ifndef mozilla_CycleCollectedJSContext_h
       8             : #define mozilla_CycleCollectedJSContext_h
       9             : 
      10             : #include <queue>
      11             : 
      12             : #include "mozilla/DeferredFinalize.h"
      13             : #include "mozilla/LinkedList.h"
      14             : #include "mozilla/mozalloc.h"
      15             : #include "mozilla/MemoryReporting.h"
      16             : #include "mozilla/dom/AtomList.h"
      17             : #include "jsapi.h"
      18             : #include "jsfriendapi.h"
      19             : 
      20             : #include "nsCOMPtr.h"
      21             : #include "nsCycleCollectionParticipant.h"
      22             : #include "nsTArray.h"
      23             : 
      24             : class nsCycleCollectionNoteRootCallback;
      25             : class nsIRunnable;
      26             : class nsThread;
      27             : class nsWrapperCache;
      28             : 
      29             : namespace mozilla {
      30             : class AutoSlowOperation;
      31             : 
      32             : class CycleCollectedJSRuntime;
      33             : 
      34             : namespace dom {
      35             : class Exception;
      36             : class WorkerJSContext;
      37             : class WorkletJSContext;
      38             : } // namespace dom
      39             : 
      40             : // Contains various stats about the cycle collection.
      41             : struct CycleCollectorResults
      42             : {
      43             :   CycleCollectorResults()
      44           4 :   {
      45             :     // Initialize here so when we increment mNumSlices the first time we're
      46             :     // not using uninitialized memory.
      47           4 :     Init();
      48             :   }
      49             : 
      50           0 :   void Init()
      51             :   {
      52           0 :     mForcedGC = false;
      53           0 :     mMergedZones = false;
      54           0 :     mAnyManual = false;
      55           0 :     mVisitedRefCounted = 0;
      56           0 :     mVisitedGCed = 0;
      57           0 :     mFreedRefCounted = 0;
      58           0 :     mFreedGCed = 0;
      59           4 :     mFreedJSZones = 0;
      60           4 :     mNumSlices = 1;
      61             :     // mNumSlices is initialized to one, because we call Init() after the
      62             :     // per-slice increment of mNumSlices has already occurred.
      63           4 :   }
      64             : 
      65             :   bool mForcedGC;
      66             :   bool mMergedZones;
      67             :   bool mAnyManual; // true if any slice of the CC was manually triggered, or at shutdown.
      68             :   uint32_t mVisitedRefCounted;
      69             :   uint32_t mVisitedGCed;
      70             :   uint32_t mFreedRefCounted;
      71             :   uint32_t mFreedGCed;
      72             :   uint32_t mFreedJSZones;
      73             :   uint32_t mNumSlices;
      74             : };
      75             : 
      76             : class MicroTaskRunnable
      77             : {
      78             : public:
      79        8310 :   MicroTaskRunnable() {}
      80           0 :   NS_INLINE_DECL_REFCOUNTING(MicroTaskRunnable)
      81             :   virtual void Run(AutoSlowOperation& aAso) = 0;
      82           5 :   virtual bool Suppressed() { return false; }
      83             : protected:
      84             :   virtual ~MicroTaskRunnable() {}
      85             : };
      86             : 
      87             : class CycleCollectedJSContext
      88             :   : dom::PerThreadAtomCache
      89             :   , public LinkedListElement<CycleCollectedJSContext>
      90             : {
      91             :   friend class CycleCollectedJSRuntime;
      92             : 
      93             : protected:
      94             :   CycleCollectedJSContext();
      95             :   virtual ~CycleCollectedJSContext();
      96             : 
      97             :   MOZ_IS_CLASS_INIT
      98             :   nsresult Initialize(JSRuntime* aParentRuntime,
      99             :                       uint32_t aMaxBytes,
     100             :                       uint32_t aMaxNurseryBytes);
     101             : 
     102             :   // See explanation in mIsPrimaryContext.
     103             :   MOZ_IS_CLASS_INIT
     104             :   nsresult InitializeNonPrimary(CycleCollectedJSContext* aPrimaryContext);
     105             : 
     106             :   virtual CycleCollectedJSRuntime* CreateRuntime(JSContext* aCx) = 0;
     107             : 
     108             :   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
     109             : 
     110             : private:
     111             :   MOZ_IS_CLASS_INIT
     112             :   void InitializeCommon();
     113             : 
     114             :   static JSObject* GetIncumbentGlobalCallback(JSContext* aCx);
     115             :   static bool EnqueuePromiseJobCallback(JSContext* aCx,
     116             :                                         JS::HandleObject aJob,
     117             :                                         JS::HandleObject aAllocationSite,
     118             :                                         JS::HandleObject aIncumbentGlobal,
     119             :                                         void* aData);
     120             :   static void PromiseRejectionTrackerCallback(JSContext* aCx,
     121             :                                               JS::HandleObject aPromise,
     122             :                                               JS::PromiseRejectionHandlingState state,
     123             :                                               void* aData);
     124             : 
     125             :   void AfterProcessMicrotasks();
     126             : public:
     127             :   void ProcessStableStateQueue();
     128             : private:
     129             :   void CleanupIDBTransactions(uint32_t aRecursionDepth);
     130             : 
     131             : public:
     132             :   enum DeferredFinalizeType {
     133             :     FinalizeIncrementally,
     134             :     FinalizeNow,
     135             :   };
     136             : 
     137           0 :   virtual dom::WorkerJSContext* GetAsWorkerJSContext() { return nullptr; }
     138           0 :   virtual dom::WorkletJSContext* GetAsWorkletJSContext() { return nullptr; }
     139             : 
     140       21779 :   CycleCollectedJSRuntime* Runtime() const
     141             :   {
     142       21779 :     MOZ_ASSERT(mRuntime);
     143       21779 :     return mRuntime;
     144             :   }
     145             : 
     146             :   already_AddRefed<dom::Exception> GetPendingException() const;
     147             :   void SetPendingException(dom::Exception* aException);
     148             : 
     149             :   std::queue<RefPtr<MicroTaskRunnable>>& GetMicroTaskQueue();
     150             :   std::queue<RefPtr<MicroTaskRunnable>>& GetDebuggerMicroTaskQueue();
     151             : 
     152      118710 :   JSContext* Context() const
     153             :   {
     154           0 :     MOZ_ASSERT(mJSContext);
     155      118710 :     return mJSContext;
     156             :   }
     157             : 
     158        1285 :   JS::RootingContext* RootingCx() const
     159             :   {
     160        1285 :     MOZ_ASSERT(mJSContext);
     161        1285 :     return JS::RootingContext::get(mJSContext);
     162             :   }
     163             : 
     164             :   void SetTargetedMicroTaskRecursionDepth(uint32_t aDepth)
     165             :   {
     166           3 :     mTargetedMicroTaskRecursionDepth = aDepth;
     167             :   }
     168             : 
     169             : protected:
     170             :   JSContext* MaybeContext() const { return mJSContext; }
     171             : 
     172             : public:
     173             :   // nsThread entrypoints
     174             :   virtual void BeforeProcessTask(bool aMightBlock);
     175             :   virtual void AfterProcessTask(uint32_t aRecursionDepth);
     176             : 
     177             :   // Check whether we need an idle GC task.
     178             :   void IsIdleGCTaskNeeded();
     179             : 
     180             :   uint32_t RecursionDepth();
     181             : 
     182             :   // Run in stable state (call through nsContentUtils)
     183             :   void RunInStableState(already_AddRefed<nsIRunnable>&& aRunnable);
     184             : 
     185             :   void AddPendingIDBTransaction(already_AddRefed<nsIRunnable>&& aTransaction);
     186             : 
     187             :   // Get the CycleCollectedJSContext for a JSContext.
     188             :   // Returns null only if Initialize() has not completed on or during
     189             :   // destruction of the CycleCollectedJSContext.
     190             :   static CycleCollectedJSContext* GetFor(JSContext* aCx);
     191             : 
     192             :   // Get the current thread's CycleCollectedJSContext.  Returns null if there
     193             :   // isn't one.
     194             :   static CycleCollectedJSContext* Get();
     195             : 
     196             :   // Queue an async microtask to the current main or worker thread.
     197             :   virtual void DispatchToMicroTask(already_AddRefed<MicroTaskRunnable> aRunnable);
     198             : 
     199             :   // Call EnterMicroTask when you're entering JS execution.
     200             :   // Usually the best way to do this is to use nsAutoMicroTask.
     201             :   void EnterMicroTask()
     202             :   {
     203        4851 :     ++mMicroTaskLevel;
     204             :   }
     205             : 
     206        4851 :   void LeaveMicroTask()
     207             :   {
     208        4851 :     if (--mMicroTaskLevel == 0) {
     209        4607 :       PerformMicroTaskCheckPoint();
     210             :     }
     211        4851 :   }
     212             : 
     213             :   bool IsInMicroTask()
     214             :   {
     215             :     return mMicroTaskLevel != 0;
     216             :   }
     217             : 
     218             :   uint32_t MicroTaskLevel()
     219             :   {
     220             :     return mMicroTaskLevel;
     221             :   }
     222             : 
     223             :   void SetMicroTaskLevel(uint32_t aLevel)
     224             :   {
     225           0 :     mMicroTaskLevel = aLevel;
     226             :   }
     227             : 
     228             :   bool PerformMicroTaskCheckPoint();
     229             : 
     230             :   void PerformDebuggerMicroTaskCheckpoint();
     231             : 
     232             :   bool IsInStableOrMetaStableState()
     233             :   {
     234             :     return mDoingStableStates;
     235             :   }
     236             : 
     237             :   // Storage for watching rejected promises waiting for some client to
     238             :   // consume their rejection.
     239             :   // Promises in this list have been rejected in the last turn of the
     240             :   // event loop without the rejection being handled.
     241             :   // Note that this can contain nullptrs in place of promises removed because
     242             :   // they're consumed before it'd be reported.
     243             :   JS::PersistentRooted<JS::GCVector<JSObject*, 0, js::SystemAllocPolicy>> mUncaughtRejections;
     244             : 
     245             :   // Promises in this list have previously been reported as rejected
     246             :   // (because they were in the above list), but the rejection was handled
     247             :   // in the last turn of the event loop.
     248             :   JS::PersistentRooted<JS::GCVector<JSObject*, 0, js::SystemAllocPolicy>> mConsumedRejections;
     249             :   nsTArray<nsCOMPtr<nsISupports /* UncaughtRejectionObserver */ >> mUncaughtRejectionObservers;
     250             : 
     251             :   virtual bool IsSystemCaller() const = 0;
     252             : 
     253             : private:
     254             :   // A primary context owns the mRuntime. Non-main-thread contexts should always
     255             :   // be primary. On the main thread, the primary context should be the first one
     256             :   // created and the last one destroyed. Non-primary contexts are used for
     257             :   // cooperatively scheduled threads.
     258             :   bool mIsPrimaryContext;
     259             : 
     260             :   CycleCollectedJSRuntime* mRuntime;
     261             : 
     262             :   JSContext* mJSContext;
     263             : 
     264             :   nsCOMPtr<dom::Exception> mPendingException;
     265             :   nsThread* mOwningThread; // Manual refcounting to avoid include hell.
     266             : 
     267           0 :   struct PendingIDBTransactionData
     268             :   {
     269             :     nsCOMPtr<nsIRunnable> mTransaction;
     270             :     uint32_t mRecursionDepth;
     271             :   };
     272             : 
     273             :   nsTArray<nsCOMPtr<nsIRunnable>> mStableStateEvents;
     274             :   nsTArray<PendingIDBTransactionData> mPendingIDBTransactions;
     275             :   uint32_t mBaseRecursionDepth;
     276             :   bool mDoingStableStates;
     277             : 
     278             :   // If set to none 0, microtasks will be processed only when recursion depth
     279             :   // is the set value.
     280             :   uint32_t mTargetedMicroTaskRecursionDepth;
     281             : 
     282             :   uint32_t mMicroTaskLevel;
     283             : 
     284             :   std::queue<RefPtr<MicroTaskRunnable>> mPendingMicroTaskRunnables;
     285             :   std::queue<RefPtr<MicroTaskRunnable>> mDebuggerMicroTaskQueue;
     286             : 
     287             :   uint32_t mMicroTaskRecursionDepth;
     288             : };
     289             : 
     290             : class MOZ_STACK_CLASS nsAutoMicroTask
     291             : {
     292             : public:
     293           0 :   nsAutoMicroTask()
     294             :   {
     295           0 :     CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
     296         443 :     if (ccjs) {
     297           0 :       ccjs->EnterMicroTask();
     298             :     }
     299             :   }
     300             :   ~nsAutoMicroTask()
     301             :   {
     302             :     CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
     303             :     if (ccjs) {
     304             :       ccjs->LeaveMicroTask();
     305             :     }
     306             :   }
     307             : };
     308             : 
     309             : } // namespace mozilla
     310             : 
     311             : #endif // mozilla_CycleCollectedJSContext_h

Generated by: LCOV version 1.13-14-ga5dd952