/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// QueryInterface implementation for PerformanceMainThread
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceMainThread)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
NS_INTERFACE_MAP_END_INHERITING(Performance)
PerformanceMainThread::PerformanceMainThread(nsPIDOMWindowInner* aWindow,
nsDOMNavigationTiming* aDOMTiming,
nsITimedChannel* aChannel)
: Performance(aWindow->AsGlobal()),
mDOMTiming(aDOMTiming),
mChannel(aChannel) {
MOZ_ASSERT(aWindow, "Parent window object should be provided"); if (StaticPrefs::dom_enable_event_timing()) {
mEventCounts = newclass EventCounts(GetParentObject());
}
CreateNavigationTimingEntry();
if (StaticPrefs::dom_enable_largest_contentful_paint()) {
nsGlobalWindowInner* owner = GetOwnerWindow();
MarkerInnerWindowId innerWindowID =
owner ? MarkerInnerWindowId(owner->WindowID())
: MarkerInnerWindowId::NoId(); // There might be multiple LCP entries and we only care about the latest one // which is also the biggest value. That's why we need to record these // markers in two different places: // - During the Document unload, so we can record the closed pages. // - During the profile capture, so we can record the open pages. // We are capturing the second one here. // Our static analysis doesn't allow capturing ref-counted pointers in // lambdas, so we need to hide it in a uintptr_t. This is safe because this // lambda will be destroyed in ~PerformanceMainThread().
uintptr_t self = reinterpret_cast<uintptr_t>(this);
profiler_add_state_change_callback( // Using the "Pausing" state as "GeneratingProfile" profile happens too // late; we can not record markers if the profiler is already paused.
ProfilingState::Pausing,
[self, innerWindowID](ProfilingState aProfilingState) { const PerformanceMainThread* selfPtr = reinterpret_cast<const PerformanceMainThread*>(self);
void PerformanceMainThread::GetMozMemory(JSContext* aCx,
JS::MutableHandle<JSObject*> aObj) { if (!mMozMemory) {
JS::Rooted<JSObject*> mozMemoryObj(aCx, JS_NewPlainObject(aCx));
JS::Rooted<JSObject*> gcMemoryObj(aCx, js::gc::NewMemoryInfoObject(aCx)); if (!mozMemoryObj || !gcMemoryObj) {
MOZ_CRASH("out of memory creating performance.mozMemory");
} if (!JS_DefineProperty(aCx, mozMemoryObj, "gc", gcMemoryObj,
JSPROP_ENUMERATE)) {
MOZ_CRASH("out of memory creating performance.mozMemory");
}
mMozMemory = mozMemoryObj;
mozilla::HoldJSObjects(this);
}
aObj.set(mMozMemory);
}
PerformanceTiming* PerformanceMainThread::Timing() { if (!mTiming) { // For navigation timing, the third argument (an nsIHttpChannel) is null // since the cross-domain redirect were already checked. The last // argument (zero time) for performance.timing is the navigation start // value.
mTiming = new PerformanceTiming(this, mChannel, nullptr,
mDOMTiming->GetNavigationStart());
}
return mTiming;
}
void PerformanceMainThread::DispatchBufferFullEvent() {
RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr); // it bubbles, and it isn't cancelable
event->InitEvent(u"resourcetimingbufferfull"_ns, true, false);
event->SetTrusted(true);
DispatchEvent(*event);
}
PerformanceNavigation* PerformanceMainThread::Navigation() { if (!mNavigation) {
mNavigation = new PerformanceNavigation(this);
}
return mNavigation;
}
/** * An entry should be added only after the resource is loaded. * This method is not thread safe and can only be called on the main thread.
*/ void PerformanceMainThread::AddEntry(nsIHttpChannel* channel,
nsITimedChannel* timedChannel) {
MOZ_ASSERT(NS_IsMainThread());
void PerformanceMainThread::AddRawEntry(UniquePtr<PerformanceTimingData> aData, const nsAString& aInitiatorType, const nsAString& aEntryName) { // The PerformanceResourceTiming object will use the PerformanceTimingData // object to get all the required timings. auto entry =
MakeRefPtr<PerformanceResourceTiming>(std::move(aData), this, aEntryName);
entry->SetInitiatorType(aInitiatorType);
InsertResourceEntry(entry);
}
PresShell* presShell = GetPresShell(); if (!presShell) { return;
}
nsPresContext* presContext = presShell->GetPresContext(); if (!presContext) { return;
}
// Using PostRefreshObserver is fine because we don't // run any JS between the `mark paint timing` step and the // `pending Event Timing entries` step. So mixing the order // here is fine.
mHasQueuedRefreshdriverObserver = true;
presContext->RegisterManagedPostRefreshObserver( new ManagedPostRefreshObserver(
presContext, [performance = RefPtr<PerformanceMainThread>(this)]( bool aWasCanceled) { if (!aWasCanceled) { // XXX Should we do this even if canceled?
performance->DispatchPendingEventTimingEntries();
}
performance->mHasQueuedRefreshdriverObserver = false; return ManagedPostRefreshObserver::Unregister::Yes;
}));
}
if (NS_FAILED(rv)) { // If we have no URI, just put in "none".
uri.AssignLiteral("none");
}
// PR_Now() returns a signed 64-bit integer. Since it represents a // timestamp, only ~32-bits will represent the value which should safely fit // into a double.
markCreationEpoch = static_cast<double>(PR_Now() / PR_USEC_PER_MSEC);
if (StaticPrefs::dom_performance_enable_user_timing_logging()) {
Performance::LogEntry(aEntry, uri);
}
}
if (StaticPrefs::dom_performance_enable_notify_performance_timing()) {
TimingNotification(aEntry, uri, markCreationEpoch);
}
if (StaticPrefs::dom_enable_largest_contentful_paint()) { if (aEntryType.EqualsLiteral("largest-contentful-paint")) {
aRetval.AppendElements(mLargestContentfulPaintEntries); return;
}
}
// The navigation entry is the first one. If it exists and the name matches, // let put it in front. if (mDocEntry && mDocEntry->GetName()->Equals(aName)) {
aRetval.InsertElementAt(0, mDocEntry); return;
}
}
// This occurs when the pref was false when the performance // object was first created, and became true later. It's // okay to return early because eventCounts is not exposed. if (!mEventCounts) { return;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.