Bug 1685822 [wpt PR 27117] - [Import Maps] Add tests for rejecting multiple import...
[gecko.git] / dom / performance / Performance.cpp
blobcd488fdcaf1da594852376babfb50ae22f13c4e2
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/. */
7 #include "Performance.h"
9 #include "GeckoProfiler.h"
10 #include "nsRFPService.h"
11 #include "PerformanceEntry.h"
12 #include "PerformanceMainThread.h"
13 #include "PerformanceMark.h"
14 #include "PerformanceMeasure.h"
15 #include "PerformanceObserver.h"
16 #include "PerformanceResourceTiming.h"
17 #include "PerformanceService.h"
18 #include "PerformanceWorker.h"
19 #include "mozilla/BasePrincipal.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/dom/PerformanceNavigationTiming.h"
26 #include "mozilla/IntegerPrintfMacros.h"
27 #include "mozilla/Preferences.h"
28 #include "mozilla/dom/WorkerPrivate.h"
29 #include "mozilla/dom/WorkerRunnable.h"
31 #define PERFLOG(msg, ...) printf_stderr(msg, ##__VA_ARGS__)
33 namespace mozilla::dom {
35 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Performance)
36 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
38 NS_IMPL_CYCLE_COLLECTION_INHERITED(Performance, DOMEventTargetHelper,
39 mUserEntries, mResourceEntries,
40 mSecondaryResourceEntries, mObservers);
42 NS_IMPL_ADDREF_INHERITED(Performance, DOMEventTargetHelper)
43 NS_IMPL_RELEASE_INHERITED(Performance, DOMEventTargetHelper)
45 /* static */
46 already_AddRefed<Performance> Performance::CreateForMainThread(
47 nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
48 nsDOMNavigationTiming* aDOMTiming, nsITimedChannel* aChannel) {
49 MOZ_ASSERT(NS_IsMainThread());
51 MOZ_ASSERT(aWindow->AsGlobal());
52 RefPtr<Performance> performance = new PerformanceMainThread(
53 aWindow, aDOMTiming, aChannel, aPrincipal->IsSystemPrincipal());
54 return performance.forget();
57 /* static */
58 already_AddRefed<Performance> Performance::CreateForWorker(
59 WorkerPrivate* aWorkerPrivate) {
60 MOZ_ASSERT(aWorkerPrivate);
61 aWorkerPrivate->AssertIsOnWorkerThread();
63 RefPtr<Performance> performance = new PerformanceWorker(aWorkerPrivate);
64 return performance.forget();
67 Performance::Performance(nsIGlobalObject* aGlobal, bool aSystemPrincipal)
68 : DOMEventTargetHelper(aGlobal),
69 mResourceTimingBufferSize(kDefaultResourceTimingBufferSize),
70 mPendingNotificationObserversTask(false),
71 mPendingResourceTimingBufferFullEvent(false),
72 mSystemPrincipal(aSystemPrincipal) {
73 MOZ_ASSERT(!NS_IsMainThread());
76 Performance::Performance(nsPIDOMWindowInner* aWindow, bool aSystemPrincipal)
77 : DOMEventTargetHelper(aWindow),
78 mResourceTimingBufferSize(kDefaultResourceTimingBufferSize),
79 mPendingNotificationObserversTask(false),
80 mPendingResourceTimingBufferFullEvent(false),
81 mSystemPrincipal(aSystemPrincipal) {
82 MOZ_ASSERT(NS_IsMainThread());
85 Performance::~Performance() = default;
87 DOMHighResTimeStamp Performance::TimeStampToDOMHighResForRendering(
88 TimeStamp aTimeStamp) const {
89 DOMHighResTimeStamp stamp = GetDOMTiming()->TimeStampToDOMHighRes(aTimeStamp);
90 if (!IsSystemPrincipal()) {
91 // 0 is an inappropriate mixin for this this area; however CSS Animations
92 // needs to have it's Time Reduction Logic refactored, so it's currently
93 // only clamping for RFP mode. RFP mode gives a much lower time precision,
94 // so we accept the security leak here for now.
95 return nsRFPService::ReduceTimePrecisionAsMSecsRFPOnly(stamp, 0);
97 return stamp;
100 DOMHighResTimeStamp Performance::Now() {
101 DOMHighResTimeStamp rawTime = NowUnclamped();
103 // XXX: Remove this would cause functions in pkcs11f.h to fail.
104 // Bug 1628021 will find out the root cause.
105 if (mSystemPrincipal) {
106 return rawTime;
109 return nsRFPService::ReduceTimePrecisionAsMSecs(
110 rawTime, GetRandomTimelineSeed(), mSystemPrincipal,
111 CrossOriginIsolated());
114 DOMHighResTimeStamp Performance::NowUnclamped() const {
115 TimeDuration duration = TimeStamp::NowUnfuzzed() - CreationTimeStamp();
116 return duration.ToMilliseconds();
119 DOMHighResTimeStamp Performance::TimeOrigin() {
120 if (!mPerformanceService) {
121 mPerformanceService = PerformanceService::GetOrCreate();
124 MOZ_ASSERT(mPerformanceService);
125 DOMHighResTimeStamp rawTimeOrigin =
126 mPerformanceService->TimeOrigin(CreationTimeStamp());
127 // Time Origin is an absolute timestamp, so we supply a 0 context mix-in
128 return nsRFPService::ReduceTimePrecisionAsMSecs(
129 rawTimeOrigin, 0, mSystemPrincipal, CrossOriginIsolated());
132 JSObject* Performance::WrapObject(JSContext* aCx,
133 JS::Handle<JSObject*> aGivenProto) {
134 return Performance_Binding::Wrap(aCx, this, aGivenProto);
137 void Performance::GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval) {
138 // We return an empty list when 'privacy.resistFingerprinting' is on.
139 if (nsContentUtils::ShouldResistFingerprinting()) {
140 aRetval.Clear();
141 return;
144 aRetval = mResourceEntries.Clone();
145 aRetval.AppendElements(mUserEntries);
146 aRetval.Sort(PerformanceEntryComparator());
149 void Performance::GetEntriesByType(
150 const nsAString& aEntryType, nsTArray<RefPtr<PerformanceEntry>>& aRetval) {
151 // We return an empty list when 'privacy.resistFingerprinting' is on.
152 if (nsContentUtils::ShouldResistFingerprinting()) {
153 aRetval.Clear();
154 return;
157 if (aEntryType.EqualsLiteral("resource")) {
158 aRetval = mResourceEntries.Clone();
159 return;
162 aRetval.Clear();
164 if (aEntryType.EqualsLiteral("mark") || aEntryType.EqualsLiteral("measure")) {
165 for (PerformanceEntry* entry : mUserEntries) {
166 if (entry->GetEntryType().Equals(aEntryType)) {
167 aRetval.AppendElement(entry);
173 void Performance::GetEntriesByName(
174 const nsAString& aName, const Optional<nsAString>& aEntryType,
175 nsTArray<RefPtr<PerformanceEntry>>& aRetval) {
176 aRetval.Clear();
178 // We return an empty list when 'privacy.resistFingerprinting' is on.
179 if (nsContentUtils::ShouldResistFingerprinting()) {
180 return;
183 // ::Measure expects that results from this function are already
184 // passed through ReduceTimePrecision. mResourceEntries and mUserEntries
185 // are, so the invariant holds.
186 for (PerformanceEntry* entry : mResourceEntries) {
187 if (entry->GetName().Equals(aName) &&
188 (!aEntryType.WasPassed() ||
189 entry->GetEntryType().Equals(aEntryType.Value()))) {
190 aRetval.AppendElement(entry);
194 for (PerformanceEntry* entry : mUserEntries) {
195 if (entry->GetName().Equals(aName) &&
196 (!aEntryType.WasPassed() ||
197 entry->GetEntryType().Equals(aEntryType.Value()))) {
198 aRetval.AppendElement(entry);
202 aRetval.Sort(PerformanceEntryComparator());
205 void Performance::ClearUserEntries(const Optional<nsAString>& aEntryName,
206 const nsAString& aEntryType) {
207 mUserEntries.RemoveElementsBy([&aEntryName, &aEntryType](const auto& entry) {
208 return (!aEntryName.WasPassed() ||
209 entry->GetName().Equals(aEntryName.Value())) &&
210 (aEntryType.IsEmpty() || entry->GetEntryType().Equals(aEntryType));
214 void Performance::ClearResourceTimings() { mResourceEntries.Clear(); }
216 #ifdef MOZ_GECKO_PROFILER
217 struct UserTimingMarker {
218 static constexpr Span<const char> MarkerTypeName() {
219 return MakeStringSpan("UserTiming");
221 static void StreamJSONMarkerData(
222 baseprofiler::SpliceableJSONWriter& aWriter,
223 const ProfilerString16View& aName, bool aIsMeasure,
224 const Maybe<ProfilerString16View>& aStartMark,
225 const Maybe<ProfilerString16View>& aEndMark) {
226 aWriter.StringProperty("name", NS_ConvertUTF16toUTF8(aName.Data()));
227 if (aIsMeasure) {
228 aWriter.StringProperty("entryType", "measure");
229 } else {
230 aWriter.StringProperty("entryType", "mark");
233 if (aStartMark.isSome()) {
234 aWriter.StringProperty("startMark",
235 NS_ConvertUTF16toUTF8(aStartMark->Data()));
236 } else {
237 aWriter.NullProperty("startMark");
239 if (aEndMark.isSome()) {
240 aWriter.StringProperty("endMark",
241 NS_ConvertUTF16toUTF8(aEndMark->Data()));
242 } else {
243 aWriter.NullProperty("endMark");
246 static MarkerSchema MarkerTypeDisplay() {
247 using MS = MarkerSchema;
248 MS schema{MS::Location::markerChart, MS::Location::markerTable};
249 schema.SetAllLabels("{marker.data.name}");
250 schema.AddStaticLabelValue("Marker", "UserTiming");
251 schema.AddKeyLabelFormat("entryType", "Entry Type", MS::Format::string);
252 schema.AddKeyLabelFormat("name", "Name", MS::Format::string);
253 schema.AddKeyLabelFormat("startMark", "Start Mark", MS::Format::string);
254 schema.AddKeyLabelFormat("endMark", "End Mark", MS::Format::string);
255 schema.AddStaticLabelValue("Description",
256 "UserTimingMeasure is created using the DOM API "
257 "performance.measure().");
258 return schema;
261 #endif
263 void Performance::Mark(const nsAString& aName, ErrorResult& aRv) {
264 // We add nothing when 'privacy.resistFingerprinting' is on.
265 if (nsContentUtils::ShouldResistFingerprinting()) {
266 return;
269 if (IsPerformanceTimingAttribute(aName)) {
270 aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
271 return;
274 RefPtr<PerformanceMark> performanceMark =
275 new PerformanceMark(GetParentObject(), aName, Now());
276 InsertUserEntry(performanceMark);
278 #ifdef MOZ_GECKO_PROFILER
279 if (profiler_can_accept_markers()) {
280 Maybe<uint64_t> innerWindowId;
281 if (GetOwner()) {
282 innerWindowId = Some(GetOwner()->WindowID());
284 profiler_add_marker("UserTiming", geckoprofiler::category::DOM,
285 MarkerInnerWindowId(innerWindowId), UserTimingMarker{},
286 aName, /* aIsMeasure */ false, Nothing{}, Nothing{});
288 #endif
291 void Performance::ClearMarks(const Optional<nsAString>& aName) {
292 ClearUserEntries(aName, u"mark"_ns);
295 DOMHighResTimeStamp Performance::ResolveTimestampFromName(
296 const nsAString& aName, ErrorResult& aRv) {
297 AutoTArray<RefPtr<PerformanceEntry>, 1> arr;
298 Optional<nsAString> typeParam;
299 nsAutoString str;
300 str.AssignLiteral("mark");
301 typeParam = &str;
302 GetEntriesByName(aName, typeParam, arr);
303 if (!arr.IsEmpty()) {
304 return arr.LastElement()->StartTime();
307 if (!IsPerformanceTimingAttribute(aName)) {
308 aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
309 return 0;
312 DOMHighResTimeStamp ts = GetPerformanceTimingFromString(aName);
313 if (!ts) {
314 aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
315 return 0;
318 return ts - CreationTime();
321 void Performance::Measure(const nsAString& aName,
322 const Optional<nsAString>& aStartMark,
323 const Optional<nsAString>& aEndMark,
324 ErrorResult& aRv) {
325 // We add nothing when 'privacy.resistFingerprinting' is on.
326 if (nsContentUtils::ShouldResistFingerprinting()) {
327 return;
330 DOMHighResTimeStamp startTime;
331 DOMHighResTimeStamp endTime;
333 if (aStartMark.WasPassed()) {
334 startTime = ResolveTimestampFromName(aStartMark.Value(), aRv);
335 if (NS_WARN_IF(aRv.Failed())) {
336 return;
338 } else {
339 // Navigation start is used in this case, but since DOMHighResTimeStamp is
340 // in relation to navigation start, this will be zero if a name is not
341 // passed.
342 startTime = 0;
345 if (aEndMark.WasPassed()) {
346 endTime = ResolveTimestampFromName(aEndMark.Value(), aRv);
347 if (NS_WARN_IF(aRv.Failed())) {
348 return;
350 } else {
351 endTime = Now();
354 RefPtr<PerformanceMeasure> performanceMeasure =
355 new PerformanceMeasure(GetParentObject(), aName, startTime, endTime);
356 InsertUserEntry(performanceMeasure);
358 #ifdef MOZ_GECKO_PROFILER
359 if (profiler_can_accept_markers()) {
360 TimeStamp startTimeStamp =
361 CreationTimeStamp() + TimeDuration::FromMilliseconds(startTime);
362 TimeStamp endTimeStamp =
363 CreationTimeStamp() + TimeDuration::FromMilliseconds(endTime);
365 // Convert to Maybe values so that Optional types do not need to be used in
366 // the profiler.
367 Maybe<nsString> startMark;
368 if (aStartMark.WasPassed()) {
369 startMark.emplace(aStartMark.Value());
371 Maybe<nsString> endMark;
372 if (aEndMark.WasPassed()) {
373 endMark.emplace(aEndMark.Value());
376 Maybe<uint64_t> innerWindowId;
377 if (GetOwner()) {
378 innerWindowId = Some(GetOwner()->WindowID());
380 profiler_add_marker("UserTiming", geckoprofiler::category::DOM,
381 {MarkerTiming::Interval(startTimeStamp, endTimeStamp),
382 MarkerInnerWindowId(innerWindowId)},
383 UserTimingMarker{}, aName, /* aIsMeasure */ true,
384 startMark, endMark);
386 #endif
389 void Performance::ClearMeasures(const Optional<nsAString>& aName) {
390 ClearUserEntries(aName, u"measure"_ns);
393 void Performance::LogEntry(PerformanceEntry* aEntry,
394 const nsACString& aOwner) const {
395 PERFLOG(
396 "Performance Entry: %s|%s|%s|%f|%f|%" PRIu64 "\n", aOwner.BeginReading(),
397 NS_ConvertUTF16toUTF8(aEntry->GetEntryType()).get(),
398 NS_ConvertUTF16toUTF8(aEntry->GetName()).get(), aEntry->StartTime(),
399 aEntry->Duration(), static_cast<uint64_t>(PR_Now() / PR_USEC_PER_MSEC));
402 void Performance::TimingNotification(PerformanceEntry* aEntry,
403 const nsACString& aOwner,
404 uint64_t aEpoch) {
405 PerformanceEntryEventInit init;
406 init.mBubbles = false;
407 init.mCancelable = false;
408 init.mName = aEntry->GetName();
409 init.mEntryType = aEntry->GetEntryType();
410 init.mStartTime = aEntry->StartTime();
411 init.mDuration = aEntry->Duration();
412 init.mEpoch = aEpoch;
413 CopyUTF8toUTF16(aOwner, init.mOrigin);
415 RefPtr<PerformanceEntryEvent> perfEntryEvent =
416 PerformanceEntryEvent::Constructor(this, u"performanceentry"_ns, init);
418 nsCOMPtr<EventTarget> et = do_QueryInterface(GetOwner());
419 if (et) {
420 et->DispatchEvent(*perfEntryEvent);
424 void Performance::InsertUserEntry(PerformanceEntry* aEntry) {
425 mUserEntries.InsertElementSorted(aEntry, PerformanceEntryComparator());
427 QueueEntry(aEntry);
431 * Steps are labeled according to the description found at
432 * https://w3c.github.io/resource-timing/#sec-extensions-performance-interface.
434 * Buffer Full Event
436 void Performance::BufferEvent() {
438 * While resource timing secondary buffer is not empty,
439 * run the following substeps:
441 while (!mSecondaryResourceEntries.IsEmpty()) {
442 uint32_t secondaryResourceEntriesBeforeCount = 0;
443 uint32_t secondaryResourceEntriesAfterCount = 0;
446 * Let number of excess entries before be resource
447 * timing secondary buffer current size.
449 secondaryResourceEntriesBeforeCount = mSecondaryResourceEntries.Length();
452 * If can add resource timing entry returns false,
453 * then fire an event named resourcetimingbufferfull
454 * at the Performance object.
456 if (!CanAddResourceTimingEntry()) {
457 DispatchBufferFullEvent();
461 * Run copy secondary buffer.
463 * While resource timing secondary buffer is not
464 * empty and can add resource timing entry returns
465 * true ...
467 while (!mSecondaryResourceEntries.IsEmpty() &&
468 CanAddResourceTimingEntry()) {
470 * Let entry be the oldest PerformanceResourceTiming
471 * in resource timing secondary buffer. Add entry to
472 * the end of performance entry buffer. Increment
473 * resource timing buffer current size by 1.
475 mResourceEntries.InsertElementSorted(
476 mSecondaryResourceEntries.ElementAt(0), PerformanceEntryComparator());
478 * Remove entry from resource timing secondary buffer.
479 * Decrement resource timing secondary buffer current
480 * size by 1.
482 mSecondaryResourceEntries.RemoveElementAt(0);
486 * Let number of excess entries after be resource
487 * timing secondary buffer current size.
489 secondaryResourceEntriesAfterCount = mSecondaryResourceEntries.Length();
492 * If number of excess entries before is lower than
493 * or equals number of excess entries after, then
494 * remove all entries from resource timing secondary
495 * buffer, set resource timing secondary buffer current
496 * size to 0, and abort these steps.
498 if (secondaryResourceEntriesBeforeCount <=
499 secondaryResourceEntriesAfterCount) {
500 mSecondaryResourceEntries.Clear();
501 break;
505 * Set resource timing buffer full event pending flag
506 * to false.
508 mPendingResourceTimingBufferFullEvent = false;
511 void Performance::SetResourceTimingBufferSize(uint64_t aMaxSize) {
512 mResourceTimingBufferSize = aMaxSize;
516 * Steps are labeled according to the description found at
517 * https://w3c.github.io/resource-timing/#sec-extensions-performance-interface.
519 * Can Add Resource Timing Entry
521 MOZ_ALWAYS_INLINE bool Performance::CanAddResourceTimingEntry() {
523 * If resource timing buffer current size is smaller than resource timing
524 * buffer size limit, return true. [Otherwise,] [r]eturn false.
526 return mResourceEntries.Length() < mResourceTimingBufferSize;
530 * Steps are labeled according to the description found at
531 * https://w3c.github.io/resource-timing/#sec-extensions-performance-interface.
533 * Add a PerformanceResourceTiming Entry
535 void Performance::InsertResourceEntry(PerformanceEntry* aEntry) {
536 MOZ_ASSERT(aEntry);
538 if (nsContentUtils::ShouldResistFingerprinting()) {
539 return;
543 * Let new entry be the input PerformanceEntry to be added.
545 * If can add resource timing entry returns true and resource
546 * timing buffer full event pending flag is false ...
548 if (CanAddResourceTimingEntry() && !mPendingResourceTimingBufferFullEvent) {
550 * Add new entry to the performance entry buffer.
551 * Increase resource timing buffer current size by 1.
553 mResourceEntries.InsertElementSorted(aEntry, PerformanceEntryComparator());
554 QueueEntry(aEntry);
555 return;
559 * If resource timing buffer full event pending flag is
560 * false ...
562 if (!mPendingResourceTimingBufferFullEvent) {
564 * Set resource timing buffer full event pending flag
565 * to true.
567 mPendingResourceTimingBufferFullEvent = true;
570 * Queue a task to run fire a buffer full event.
572 NS_DispatchToCurrentThread(NewCancelableRunnableMethod(
573 "Performance::BufferEvent", this, &Performance::BufferEvent));
576 * Add new entry to the resource timing secondary buffer.
577 * Increase resource timing secondary buffer current size
578 * by 1.
580 mSecondaryResourceEntries.InsertElementSorted(aEntry,
581 PerformanceEntryComparator());
584 void Performance::AddObserver(PerformanceObserver* aObserver) {
585 mObservers.AppendElementUnlessExists(aObserver);
588 void Performance::RemoveObserver(PerformanceObserver* aObserver) {
589 mObservers.RemoveElement(aObserver);
592 void Performance::NotifyObservers() {
593 mPendingNotificationObserversTask = false;
594 NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers, Notify, ());
597 void Performance::CancelNotificationObservers() {
598 mPendingNotificationObserversTask = false;
601 class NotifyObserversTask final : public CancelableRunnable {
602 public:
603 explicit NotifyObserversTask(Performance* aPerformance)
604 : CancelableRunnable("dom::NotifyObserversTask"),
605 mPerformance(aPerformance) {
606 MOZ_ASSERT(mPerformance);
609 // MOZ_CAN_RUN_SCRIPT_BOUNDARY for now until Runnable::Run is
610 // MOZ_CAN_RUN_SCRIPT.
611 MOZ_CAN_RUN_SCRIPT_BOUNDARY
612 NS_IMETHOD Run() override {
613 MOZ_ASSERT(mPerformance);
614 RefPtr<Performance> performance(mPerformance);
615 performance->NotifyObservers();
616 return NS_OK;
619 nsresult Cancel() override {
620 mPerformance->CancelNotificationObservers();
621 mPerformance = nullptr;
622 return NS_OK;
625 private:
626 ~NotifyObserversTask() = default;
628 RefPtr<Performance> mPerformance;
631 void Performance::QueueNotificationObserversTask() {
632 if (!mPendingNotificationObserversTask) {
633 RunNotificationObserversTask();
637 void Performance::RunNotificationObserversTask() {
638 mPendingNotificationObserversTask = true;
639 nsCOMPtr<nsIRunnable> task = new NotifyObserversTask(this);
640 nsresult rv;
641 if (GetOwnerGlobal()) {
642 rv = GetOwnerGlobal()->Dispatch(TaskCategory::Other, task.forget());
643 } else {
644 rv = NS_DispatchToCurrentThread(task);
646 if (NS_WARN_IF(NS_FAILED(rv))) {
647 mPendingNotificationObserversTask = false;
651 void Performance::QueueEntry(PerformanceEntry* aEntry) {
652 if (mObservers.IsEmpty()) {
653 return;
656 nsTObserverArray<PerformanceObserver*> interestedObservers;
657 const auto [begin, end] = mObservers.NonObservingRange();
658 std::copy_if(begin, end, MakeBackInserter(interestedObservers),
659 [aEntry](PerformanceObserver* observer) {
660 return observer->ObservesTypeOfEntry(aEntry);
663 if (interestedObservers.IsEmpty()) {
664 return;
667 NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(interestedObservers, QueueEntry,
668 (aEntry));
670 QueueNotificationObserversTask();
673 void Performance::MemoryPressure() { mUserEntries.Clear(); }
675 size_t Performance::SizeOfUserEntries(
676 mozilla::MallocSizeOf aMallocSizeOf) const {
677 size_t userEntries = 0;
678 for (const PerformanceEntry* entry : mUserEntries) {
679 userEntries += entry->SizeOfIncludingThis(aMallocSizeOf);
681 return userEntries;
684 size_t Performance::SizeOfResourceEntries(
685 mozilla::MallocSizeOf aMallocSizeOf) const {
686 size_t resourceEntries = 0;
687 for (const PerformanceEntry* entry : mResourceEntries) {
688 resourceEntries += entry->SizeOfIncludingThis(aMallocSizeOf);
690 return resourceEntries;
693 } // namespace mozilla::dom