LCOV - code coverage report
Current view: top level - dom/performance - Performance.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 53 256 20.7 %
Date: 2017-07-14 16:53:18 Functions: 17 49 34.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 "Performance.h"
       8             : 
       9             : #include "GeckoProfiler.h"
      10             : #include "nsRFPService.h"
      11             : #include "ProfilerMarkerPayload.h"
      12             : #include "PerformanceEntry.h"
      13             : #include "PerformanceMainThread.h"
      14             : #include "PerformanceMark.h"
      15             : #include "PerformanceMeasure.h"
      16             : #include "PerformanceObserver.h"
      17             : #include "PerformanceResourceTiming.h"
      18             : #include "PerformanceService.h"
      19             : #include "PerformanceWorker.h"
      20             : #include "mozilla/ErrorResult.h"
      21             : #include "mozilla/dom/PerformanceBinding.h"
      22             : #include "mozilla/dom/PerformanceEntryEvent.h"
      23             : #include "mozilla/dom/PerformanceNavigationBinding.h"
      24             : #include "mozilla/dom/PerformanceObserverBinding.h"
      25             : #include "mozilla/IntegerPrintfMacros.h"
      26             : #include "mozilla/Preferences.h"
      27             : #include "WorkerPrivate.h"
      28             : #include "WorkerRunnable.h"
      29             : 
      30             : #ifdef MOZ_WIDGET_GONK
      31             : #define PERFLOG(msg, ...)  __android_log_print(ANDROID_LOG_INFO, "PerformanceTiming", msg, ##__VA_ARGS__)
      32             : #else
      33             : #define PERFLOG(msg, ...) printf_stderr(msg, ##__VA_ARGS__)
      34             : #endif
      35             : 
      36             : namespace mozilla {
      37             : namespace dom {
      38             : 
      39             : using namespace workers;
      40             : 
      41             : namespace {
      42             : 
      43             : // Helper classes
      44             : class MOZ_STACK_CLASS PerformanceEntryComparator final
      45             : {
      46             : public:
      47           0 :   bool Equals(const PerformanceEntry* aElem1,
      48             :               const PerformanceEntry* aElem2) const
      49             :   {
      50           0 :     MOZ_ASSERT(aElem1 && aElem2,
      51             :                "Trying to compare null performance entries");
      52           0 :     return aElem1->StartTime() == aElem2->StartTime();
      53             :   }
      54             : 
      55           1 :   bool LessThan(const PerformanceEntry* aElem1,
      56             :                 const PerformanceEntry* aElem2) const
      57             :   {
      58           1 :     MOZ_ASSERT(aElem1 && aElem2,
      59             :                "Trying to compare null performance entries");
      60           1 :     return aElem1->StartTime() < aElem2->StartTime();
      61             :   }
      62             : };
      63             : 
      64           6 : class PrefEnabledRunnable final
      65             :   : public WorkerCheckAPIExposureOnMainThreadRunnable
      66             : {
      67             : public:
      68           2 :   PrefEnabledRunnable(WorkerPrivate* aWorkerPrivate,
      69             :                       const nsCString& aPrefName)
      70           2 :     : WorkerCheckAPIExposureOnMainThreadRunnable(aWorkerPrivate)
      71             :     , mEnabled(false)
      72           2 :     , mPrefName(aPrefName)
      73           2 :   { }
      74             : 
      75           2 :   bool MainThreadRun() override
      76             :   {
      77           2 :     MOZ_ASSERT(NS_IsMainThread());
      78           2 :     mEnabled = Preferences::GetBool(mPrefName.get(), false);
      79           2 :     return true;
      80             :   }
      81             : 
      82           2 :   bool IsEnabled() const
      83             :   {
      84           2 :     return mEnabled;
      85             :   }
      86             : 
      87             : private:
      88             :   bool mEnabled;
      89             :   nsCString mPrefName;
      90             : };
      91             : 
      92             : } // anonymous namespace
      93             : 
      94           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Performance)
      95           0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
      96             : 
      97           7 : NS_IMPL_CYCLE_COLLECTION_INHERITED(Performance,
      98             :                                    DOMEventTargetHelper,
      99             :                                    mUserEntries,
     100             :                                    mResourceEntries);
     101             : 
     102          19 : NS_IMPL_ADDREF_INHERITED(Performance, DOMEventTargetHelper)
     103           2 : NS_IMPL_RELEASE_INHERITED(Performance, DOMEventTargetHelper)
     104             : 
     105             : /* static */ already_AddRefed<Performance>
     106           7 : Performance::CreateForMainThread(nsPIDOMWindowInner* aWindow,
     107             :                                  nsDOMNavigationTiming* aDOMTiming,
     108             :                                  nsITimedChannel* aChannel)
     109             : {
     110           7 :   MOZ_ASSERT(NS_IsMainThread());
     111             : 
     112             :   RefPtr<Performance> performance =
     113          14 :     new PerformanceMainThread(aWindow, aDOMTiming, aChannel);
     114          14 :   return performance.forget();
     115             : }
     116             : 
     117             : /* static */ already_AddRefed<Performance>
     118           0 : Performance::CreateForWorker(workers::WorkerPrivate* aWorkerPrivate)
     119             : {
     120           0 :   MOZ_ASSERT(aWorkerPrivate);
     121           0 :   aWorkerPrivate->AssertIsOnWorkerThread();
     122             : 
     123           0 :   RefPtr<Performance> performance = new PerformanceWorker(aWorkerPrivate);
     124           0 :   return performance.forget();
     125             : }
     126             : 
     127           0 : Performance::Performance()
     128             :   : mResourceTimingBufferSize(kDefaultResourceTimingBufferSize)
     129           0 :   , mPendingNotificationObserversTask(false)
     130             : {
     131           0 :   MOZ_ASSERT(!NS_IsMainThread());
     132           0 : }
     133             : 
     134           7 : Performance::Performance(nsPIDOMWindowInner* aWindow)
     135             :   : DOMEventTargetHelper(aWindow)
     136             :   , mResourceTimingBufferSize(kDefaultResourceTimingBufferSize)
     137           7 :   , mPendingNotificationObserversTask(false)
     138             : {
     139           7 :   MOZ_ASSERT(NS_IsMainThread());
     140           7 : }
     141             : 
     142           0 : Performance::~Performance()
     143           0 : {}
     144             : 
     145             : DOMHighResTimeStamp
     146          58 : Performance::Now() const
     147             : {
     148          58 :   TimeDuration duration = TimeStamp::Now() - CreationTimeStamp();
     149          58 :   return RoundTime(duration.ToMilliseconds());
     150             : }
     151             : 
     152             : DOMHighResTimeStamp
     153           0 : Performance::TimeOrigin()
     154             : {
     155           0 :   if (!mPerformanceService) {
     156           0 :     mPerformanceService = PerformanceService::GetOrCreate();
     157             :   }
     158             : 
     159           0 :   MOZ_ASSERT(mPerformanceService);
     160           0 :   return mPerformanceService->TimeOrigin(CreationTimeStamp());
     161             : }
     162             : 
     163             : JSObject*
     164           7 : Performance::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     165             : {
     166           7 :   return PerformanceBinding::Wrap(aCx, this, aGivenProto);
     167             : }
     168             : 
     169             : void
     170           0 : Performance::GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval)
     171             : {
     172             :   // We return an empty list when 'privacy.resistFingerprinting' is on.
     173           0 :   if (nsContentUtils::ShouldResistFingerprinting()) {
     174           0 :     aRetval.Clear();
     175           0 :     return;
     176             :   }
     177             : 
     178           0 :   aRetval = mResourceEntries;
     179           0 :   aRetval.AppendElements(mUserEntries);
     180           0 :   aRetval.Sort(PerformanceEntryComparator());
     181             : }
     182             : 
     183             : void
     184           0 : Performance::GetEntriesByType(const nsAString& aEntryType,
     185             :                               nsTArray<RefPtr<PerformanceEntry>>& aRetval)
     186             : {
     187             :   // We return an empty list when 'privacy.resistFingerprinting' is on.
     188           0 :   if (nsContentUtils::ShouldResistFingerprinting()) {
     189           0 :     aRetval.Clear();
     190           0 :     return;
     191             :   }
     192             : 
     193           0 :   if (aEntryType.EqualsLiteral("resource")) {
     194           0 :     aRetval = mResourceEntries;
     195           0 :     return;
     196             :   }
     197             : 
     198           0 :   aRetval.Clear();
     199             : 
     200           0 :   if (aEntryType.EqualsLiteral("mark") ||
     201           0 :       aEntryType.EqualsLiteral("measure")) {
     202           0 :     for (PerformanceEntry* entry : mUserEntries) {
     203           0 :       if (entry->GetEntryType().Equals(aEntryType)) {
     204           0 :         aRetval.AppendElement(entry);
     205             :       }
     206             :     }
     207             :   }
     208             : }
     209             : 
     210             : void
     211           0 : Performance::GetEntriesByName(const nsAString& aName,
     212             :                               const Optional<nsAString>& aEntryType,
     213             :                               nsTArray<RefPtr<PerformanceEntry>>& aRetval)
     214             : {
     215           0 :   aRetval.Clear();
     216             : 
     217             :   // We return an empty list when 'privacy.resistFingerprinting' is on.
     218           0 :   if (nsContentUtils::ShouldResistFingerprinting()) {
     219           0 :     return;
     220             :   }
     221             : 
     222           0 :   for (PerformanceEntry* entry : mResourceEntries) {
     223           0 :     if (entry->GetName().Equals(aName) &&
     224           0 :         (!aEntryType.WasPassed() ||
     225           0 :          entry->GetEntryType().Equals(aEntryType.Value()))) {
     226           0 :       aRetval.AppendElement(entry);
     227             :     }
     228             :   }
     229             : 
     230           0 :   for (PerformanceEntry* entry : mUserEntries) {
     231           0 :     if (entry->GetName().Equals(aName) &&
     232           0 :         (!aEntryType.WasPassed() ||
     233           0 :          entry->GetEntryType().Equals(aEntryType.Value()))) {
     234           0 :       aRetval.AppendElement(entry);
     235             :     }
     236             :   }
     237             : 
     238           0 :   aRetval.Sort(PerformanceEntryComparator());
     239             : }
     240             : 
     241             : void
     242           0 : Performance::ClearUserEntries(const Optional<nsAString>& aEntryName,
     243             :                               const nsAString& aEntryType)
     244             : {
     245           0 :   for (uint32_t i = 0; i < mUserEntries.Length();) {
     246           0 :     if ((!aEntryName.WasPassed() ||
     247           0 :          mUserEntries[i]->GetName().Equals(aEntryName.Value())) &&
     248           0 :         (aEntryType.IsEmpty() ||
     249           0 :          mUserEntries[i]->GetEntryType().Equals(aEntryType))) {
     250           0 :       mUserEntries.RemoveElementAt(i);
     251             :     } else {
     252           0 :       ++i;
     253             :     }
     254             :   }
     255           0 : }
     256             : 
     257             : void
     258           0 : Performance::ClearResourceTimings()
     259             : {
     260           0 :   MOZ_ASSERT(NS_IsMainThread());
     261           0 :   mResourceEntries.Clear();
     262           0 : }
     263             : 
     264             : DOMHighResTimeStamp
     265          58 : Performance::RoundTime(double aTime) const
     266             : {
     267             :   // Round down to the nearest 5us, because if the timer is too accurate people
     268             :   // can do nasty timing attacks with it.  See similar code in the worker
     269             :   // Performance implementation.
     270          58 :   const double maxResolutionMs = 0.005;
     271          58 :   return nsRFPService::ReduceTimePrecisionAsMSecs(
     272         116 :     floor(aTime / maxResolutionMs) * maxResolutionMs);
     273             : }
     274             : 
     275             : 
     276             : void
     277           0 : Performance::Mark(const nsAString& aName, ErrorResult& aRv)
     278             : {
     279             :   // We add nothing when 'privacy.resistFingerprinting' is on.
     280           0 :   if (nsContentUtils::ShouldResistFingerprinting()) {
     281           0 :     return;
     282             :   }
     283             : 
     284             :   // Don't add the entry if the buffer is full. XXX should be removed by bug 1159003.
     285           0 :   if (mUserEntries.Length() >= mResourceTimingBufferSize) {
     286           0 :     return;
     287             :   }
     288             : 
     289           0 :   if (IsPerformanceTimingAttribute(aName)) {
     290           0 :     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     291           0 :     return;
     292             :   }
     293             : 
     294             :   RefPtr<PerformanceMark> performanceMark =
     295           0 :     new PerformanceMark(GetAsISupports(), aName, Now());
     296           0 :   InsertUserEntry(performanceMark);
     297             : 
     298           0 :   if (profiler_is_active()) {
     299           0 :     profiler_add_marker(
     300             :       "UserTiming",
     301           0 :       MakeUnique<UserTimingMarkerPayload>(aName, TimeStamp::Now()));
     302             :   }
     303             : }
     304             : 
     305             : void
     306           0 : Performance::ClearMarks(const Optional<nsAString>& aName)
     307             : {
     308           0 :   ClearUserEntries(aName, NS_LITERAL_STRING("mark"));
     309           0 : }
     310             : 
     311             : DOMHighResTimeStamp
     312           0 : Performance::ResolveTimestampFromName(const nsAString& aName,
     313             :                                       ErrorResult& aRv)
     314             : {
     315           0 :   AutoTArray<RefPtr<PerformanceEntry>, 1> arr;
     316             :   DOMHighResTimeStamp ts;
     317           0 :   Optional<nsAString> typeParam;
     318           0 :   nsAutoString str;
     319           0 :   str.AssignLiteral("mark");
     320           0 :   typeParam = &str;
     321           0 :   GetEntriesByName(aName, typeParam, arr);
     322           0 :   if (!arr.IsEmpty()) {
     323           0 :     return arr.LastElement()->StartTime();
     324             :   }
     325             : 
     326           0 :   if (!IsPerformanceTimingAttribute(aName)) {
     327           0 :     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     328           0 :     return 0;
     329             :   }
     330             : 
     331           0 :   ts = GetPerformanceTimingFromString(aName);
     332           0 :   if (!ts) {
     333           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     334           0 :     return 0;
     335             :   }
     336             : 
     337           0 :   return ts - CreationTime();
     338             : }
     339             : 
     340             : void
     341           0 : Performance::Measure(const nsAString& aName,
     342             :                      const Optional<nsAString>& aStartMark,
     343             :                      const Optional<nsAString>& aEndMark,
     344             :                      ErrorResult& aRv)
     345             : {
     346             :   // We add nothing when 'privacy.resistFingerprinting' is on.
     347           0 :   if (nsContentUtils::ShouldResistFingerprinting()) {
     348           0 :     return;
     349             :   }
     350             : 
     351             :   // Don't add the entry if the buffer is full. XXX should be removed by bug
     352             :   // 1159003.
     353           0 :   if (mUserEntries.Length() >= mResourceTimingBufferSize) {
     354           0 :     return;
     355             :   }
     356             : 
     357             :   DOMHighResTimeStamp startTime;
     358             :   DOMHighResTimeStamp endTime;
     359             : 
     360           0 :   if (IsPerformanceTimingAttribute(aName)) {
     361           0 :     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     362           0 :     return;
     363             :   }
     364             : 
     365           0 :   if (aStartMark.WasPassed()) {
     366           0 :     startTime = ResolveTimestampFromName(aStartMark.Value(), aRv);
     367           0 :     if (NS_WARN_IF(aRv.Failed())) {
     368           0 :       return;
     369             :     }
     370             :   } else {
     371             :     // Navigation start is used in this case, but since DOMHighResTimeStamp is
     372             :     // in relation to navigation start, this will be zero if a name is not
     373             :     // passed.
     374           0 :     startTime = 0;
     375             :   }
     376             : 
     377           0 :   if (aEndMark.WasPassed()) {
     378           0 :     endTime = ResolveTimestampFromName(aEndMark.Value(), aRv);
     379           0 :     if (NS_WARN_IF(aRv.Failed())) {
     380           0 :       return;
     381             :     }
     382             :   } else {
     383           0 :     endTime = Now();
     384             :   }
     385             : 
     386             :   RefPtr<PerformanceMeasure> performanceMeasure =
     387           0 :     new PerformanceMeasure(GetAsISupports(), aName, startTime, endTime);
     388           0 :   InsertUserEntry(performanceMeasure);
     389             : 
     390           0 :   if (profiler_is_active()) {
     391           0 :     TimeStamp startTimeStamp = CreationTimeStamp() +
     392           0 :                                TimeDuration::FromMilliseconds(startTime);
     393           0 :     TimeStamp endTimeStamp = CreationTimeStamp() +
     394           0 :                              TimeDuration::FromMilliseconds(endTime);
     395           0 :     profiler_add_marker(
     396             :       "UserTiming",
     397           0 :       MakeUnique<UserTimingMarkerPayload>(aName, startTimeStamp, endTimeStamp));
     398             :   }
     399             : }
     400             : 
     401             : void
     402           0 : Performance::ClearMeasures(const Optional<nsAString>& aName)
     403             : {
     404           0 :   ClearUserEntries(aName, NS_LITERAL_STRING("measure"));
     405           0 : }
     406             : 
     407             : void
     408           0 : Performance::LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const
     409             : {
     410           0 :   PERFLOG("Performance Entry: %s|%s|%s|%f|%f|%" PRIu64 "\n",
     411             :           aOwner.BeginReading(),
     412             :           NS_ConvertUTF16toUTF8(aEntry->GetEntryType()).get(),
     413             :           NS_ConvertUTF16toUTF8(aEntry->GetName()).get(),
     414             :           aEntry->StartTime(),
     415             :           aEntry->Duration(),
     416           0 :           static_cast<uint64_t>(PR_Now() / PR_USEC_PER_MSEC));
     417           0 : }
     418             : 
     419             : void
     420           0 : Performance::TimingNotification(PerformanceEntry* aEntry,
     421             :                                 const nsACString& aOwner, uint64_t aEpoch)
     422             : {
     423           0 :   PerformanceEntryEventInit init;
     424           0 :   init.mBubbles = false;
     425           0 :   init.mCancelable = false;
     426           0 :   init.mName = aEntry->GetName();
     427           0 :   init.mEntryType = aEntry->GetEntryType();
     428           0 :   init.mStartTime = aEntry->StartTime();
     429           0 :   init.mDuration = aEntry->Duration();
     430           0 :   init.mEpoch = aEpoch;
     431           0 :   init.mOrigin = NS_ConvertUTF8toUTF16(aOwner.BeginReading());
     432             : 
     433             :   RefPtr<PerformanceEntryEvent> perfEntryEvent =
     434           0 :     PerformanceEntryEvent::Constructor(this, NS_LITERAL_STRING("performanceentry"), init);
     435             : 
     436           0 :   nsCOMPtr<EventTarget> et = do_QueryInterface(GetOwner());
     437           0 :   if (et) {
     438           0 :     bool dummy = false;
     439           0 :     et->DispatchEvent(perfEntryEvent, &dummy);
     440             :   }
     441           0 : }
     442             : 
     443             : void
     444           0 : Performance::InsertUserEntry(PerformanceEntry* aEntry)
     445             : {
     446           0 :   mUserEntries.InsertElementSorted(aEntry,
     447           0 :                                    PerformanceEntryComparator());
     448             : 
     449           0 :   QueueEntry(aEntry);
     450           0 : }
     451             : 
     452             : void
     453           0 : Performance::SetResourceTimingBufferSize(uint64_t aMaxSize)
     454             : {
     455           0 :   mResourceTimingBufferSize = aMaxSize;
     456           0 : }
     457             : 
     458             : void
     459           2 : Performance::InsertResourceEntry(PerformanceEntry* aEntry)
     460             : {
     461           2 :   MOZ_ASSERT(aEntry);
     462           2 :   MOZ_ASSERT(mResourceEntries.Length() < mResourceTimingBufferSize);
     463             : 
     464             :   // We won't add an entry when 'privacy.resistFingerprint' is true.
     465           2 :   if (nsContentUtils::ShouldResistFingerprinting()) {
     466           0 :     return;
     467             :   }
     468             : 
     469           2 :   if (mResourceEntries.Length() >= mResourceTimingBufferSize) {
     470           0 :     return;
     471             :   }
     472             : 
     473           2 :   mResourceEntries.InsertElementSorted(aEntry,
     474           2 :                                        PerformanceEntryComparator());
     475           2 :   if (mResourceEntries.Length() == mResourceTimingBufferSize) {
     476             :     // call onresourcetimingbufferfull
     477           0 :     DispatchBufferFullEvent();
     478             :   }
     479           2 :   QueueEntry(aEntry);
     480             : }
     481             : 
     482             : void
     483           0 : Performance::AddObserver(PerformanceObserver* aObserver)
     484             : {
     485           0 :   mObservers.AppendElementUnlessExists(aObserver);
     486           0 : }
     487             : 
     488             : void
     489           0 : Performance::RemoveObserver(PerformanceObserver* aObserver)
     490             : {
     491           0 :   mObservers.RemoveElement(aObserver);
     492           0 : }
     493             : 
     494             : void
     495           0 : Performance::NotifyObservers()
     496             : {
     497           0 :   mPendingNotificationObserversTask = false;
     498           0 :   NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers,
     499             :                                            PerformanceObserver,
     500             :                                            Notify, ());
     501           0 : }
     502             : 
     503             : void
     504           0 : Performance::CancelNotificationObservers()
     505             : {
     506           0 :   mPendingNotificationObserversTask = false;
     507           0 : }
     508             : 
     509             : class NotifyObserversTask final : public CancelableRunnable
     510             : {
     511             : public:
     512           0 :   explicit NotifyObserversTask(Performance* aPerformance)
     513           0 :     : CancelableRunnable("dom::NotifyObserversTask")
     514           0 :     , mPerformance(aPerformance)
     515             :   {
     516           0 :     MOZ_ASSERT(mPerformance);
     517           0 :   }
     518             : 
     519           0 :   NS_IMETHOD Run() override
     520             :   {
     521           0 :     MOZ_ASSERT(mPerformance);
     522           0 :     mPerformance->NotifyObservers();
     523           0 :     return NS_OK;
     524             :   }
     525             : 
     526           0 :   nsresult Cancel() override
     527             :   {
     528           0 :     mPerformance->CancelNotificationObservers();
     529           0 :     mPerformance = nullptr;
     530           0 :     return NS_OK;
     531             :   }
     532             : 
     533             : private:
     534           0 :   ~NotifyObserversTask()
     535           0 :   {
     536           0 :   }
     537             : 
     538             :   RefPtr<Performance> mPerformance;
     539             : };
     540             : 
     541             : void
     542           0 : Performance::RunNotificationObserversTask()
     543             : {
     544           0 :   mPendingNotificationObserversTask = true;
     545           0 :   nsCOMPtr<nsIRunnable> task = new NotifyObserversTask(this);
     546           0 :   nsresult rv = NS_DispatchToCurrentThread(task);
     547           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     548           0 :     mPendingNotificationObserversTask = false;
     549             :   }
     550           0 : }
     551             : 
     552             : void
     553           2 : Performance::QueueEntry(PerformanceEntry* aEntry)
     554             : {
     555           2 :   if (mObservers.IsEmpty()) {
     556           2 :     return;
     557             :   }
     558           0 :   NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers,
     559             :                                            PerformanceObserver,
     560             :                                            QueueEntry, (aEntry));
     561             : 
     562           0 :   if (!mPendingNotificationObserversTask) {
     563           0 :     RunNotificationObserversTask();
     564             :   }
     565             : }
     566             : 
     567             : /* static */ bool
     568           2 : Performance::IsObserverEnabled(JSContext* aCx, JSObject* aGlobal)
     569             : {
     570           2 :   if (NS_IsMainThread()) {
     571           0 :     return Preferences::GetBool("dom.enable_performance_observer", false);
     572             :   }
     573             : 
     574           2 :   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     575           2 :   MOZ_ASSERT(workerPrivate);
     576           2 :   workerPrivate->AssertIsOnWorkerThread();
     577             : 
     578             :   RefPtr<PrefEnabledRunnable> runnable =
     579             :     new PrefEnabledRunnable(workerPrivate,
     580           6 :                             NS_LITERAL_CSTRING("dom.enable_performance_observer"));
     581             : 
     582           2 :   return runnable->Dispatch() && runnable->IsEnabled();
     583             : }
     584             : 
     585             : } // dom namespace
     586             : } // mozilla namespace

Generated by: LCOV version 1.13