mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 00:05:36 +00:00
18fae65f38
This requires replacing inclusions of it with inclusions of more specific prefs files. The exception is that StaticPrefsAll.h, which is equivalent to StaticPrefs.h, and is used in `Codegen.py` because doing something smarter is tricky and suitable for a follow-up. As a result, any change to StaticPrefList.yaml will still trigger recompilation of all the generated DOM bindings files, but that's still a big improvement over trigger recompilation of every file that uses static prefs. Most of the changes in this commit are very boring. The only changes that are not boring are modules/libpref/*, Codegen.py, and ServoBindings.toml. Differential Revision: https://phabricator.services.mozilla.com/D39138 --HG-- extra : moz-landing-system : lando
399 lines
12 KiB
C++
399 lines
12 KiB
C++
/* -*- 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/. */
|
|
|
|
#include "PerformanceMainThread.h"
|
|
#include "PerformanceNavigation.h"
|
|
#include "mozilla/StaticPrefs_dom.h"
|
|
#include "nsICacheInfoChannel.h"
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
namespace {
|
|
|
|
void GetURLSpecFromChannel(nsITimedChannel* aChannel, nsAString& aSpec) {
|
|
aSpec.AssignLiteral("document");
|
|
|
|
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aChannel);
|
|
if (!channel) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
nsresult rv = channel->GetURI(getter_AddRefs(uri));
|
|
if (NS_WARN_IF(NS_FAILED(rv)) || !uri) {
|
|
return;
|
|
}
|
|
|
|
nsAutoCString spec;
|
|
rv = uri->GetSpec(spec);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return;
|
|
}
|
|
|
|
aSpec = NS_ConvertUTF8toUTF16(spec);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(PerformanceMainThread)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PerformanceMainThread,
|
|
Performance)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTiming, mNavigation, mDocEntry)
|
|
tmp->mMozMemory = nullptr;
|
|
mozilla::DropJSObjects(this);
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PerformanceMainThread,
|
|
Performance)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTiming, mNavigation, mDocEntry)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceMainThread,
|
|
Performance)
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mMozMemory)
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
NS_IMPL_ADDREF_INHERITED(PerformanceMainThread, Performance)
|
|
NS_IMPL_RELEASE_INHERITED(PerformanceMainThread, Performance)
|
|
|
|
// QueryInterface implementation for PerformanceMainThread
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceMainThread)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_END_INHERITING(Performance)
|
|
|
|
PerformanceMainThread::PerformanceMainThread(nsPIDOMWindowInner* aWindow,
|
|
nsDOMNavigationTiming* aDOMTiming,
|
|
nsITimedChannel* aChannel,
|
|
bool aPrincipal)
|
|
: Performance(aWindow, aPrincipal),
|
|
mDOMTiming(aDOMTiming),
|
|
mChannel(aChannel) {
|
|
MOZ_ASSERT(aWindow, "Parent window object should be provided");
|
|
CreateNavigationTimingEntry();
|
|
}
|
|
|
|
PerformanceMainThread::~PerformanceMainThread() {
|
|
mozilla::DropJSObjects(this);
|
|
}
|
|
|
|
void PerformanceMainThread::GetMozMemory(JSContext* aCx,
|
|
JS::MutableHandle<JSObject*> aObj) {
|
|
if (!mMozMemory) {
|
|
mMozMemory = js::gc::NewMemoryInfoObject(aCx);
|
|
if (mMozMemory) {
|
|
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(NS_LITERAL_STRING("resourcetimingbufferfull"), 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());
|
|
|
|
nsAutoString initiatorType;
|
|
nsAutoString entryName;
|
|
|
|
UniquePtr<PerformanceTimingData> performanceTimingData(
|
|
PerformanceTimingData::Create(timedChannel, channel, 0, initiatorType,
|
|
entryName));
|
|
if (!performanceTimingData) {
|
|
return;
|
|
}
|
|
|
|
// The PerformanceResourceTiming object will use the PerformanceTimingData
|
|
// object to get all the required timings.
|
|
RefPtr<PerformanceResourceTiming> performanceEntry =
|
|
new PerformanceResourceTiming(std::move(performanceTimingData), this,
|
|
entryName);
|
|
|
|
performanceEntry->SetInitiatorType(initiatorType);
|
|
InsertResourceEntry(performanceEntry);
|
|
}
|
|
|
|
// To be removed once bug 1124165 lands
|
|
bool PerformanceMainThread::IsPerformanceTimingAttribute(
|
|
const nsAString& aName) {
|
|
// Note that toJSON is added to this list due to bug 1047848
|
|
static const char* attributes[] = {"navigationStart",
|
|
"unloadEventStart",
|
|
"unloadEventEnd",
|
|
"redirectStart",
|
|
"redirectEnd",
|
|
"fetchStart",
|
|
"domainLookupStart",
|
|
"domainLookupEnd",
|
|
"connectStart",
|
|
"secureConnectionStart",
|
|
"connectEnd",
|
|
"requestStart",
|
|
"responseStart",
|
|
"responseEnd",
|
|
"domLoading",
|
|
"domInteractive",
|
|
"domContentLoadedEventStart",
|
|
"domContentLoadedEventEnd",
|
|
"domComplete",
|
|
"loadEventStart",
|
|
"loadEventEnd",
|
|
nullptr};
|
|
|
|
for (uint32_t i = 0; attributes[i]; ++i) {
|
|
if (aName.EqualsASCII(attributes[i])) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
DOMHighResTimeStamp PerformanceMainThread::GetPerformanceTimingFromString(
|
|
const nsAString& aProperty) {
|
|
if (!IsPerformanceTimingAttribute(aProperty)) {
|
|
return 0;
|
|
}
|
|
if (aProperty.EqualsLiteral("navigationStart")) {
|
|
// DOMHighResTimeStamp is in relation to navigationStart, so this will be
|
|
// zero.
|
|
return GetDOMTiming()->GetNavigationStart();
|
|
}
|
|
if (aProperty.EqualsLiteral("unloadEventStart")) {
|
|
return GetDOMTiming()->GetUnloadEventStart();
|
|
}
|
|
if (aProperty.EqualsLiteral("unloadEventEnd")) {
|
|
return GetDOMTiming()->GetUnloadEventEnd();
|
|
}
|
|
if (aProperty.EqualsLiteral("redirectStart")) {
|
|
return Timing()->RedirectStart();
|
|
}
|
|
if (aProperty.EqualsLiteral("redirectEnd")) {
|
|
return Timing()->RedirectEnd();
|
|
}
|
|
if (aProperty.EqualsLiteral("fetchStart")) {
|
|
return Timing()->FetchStart();
|
|
}
|
|
if (aProperty.EqualsLiteral("domainLookupStart")) {
|
|
return Timing()->DomainLookupStart();
|
|
}
|
|
if (aProperty.EqualsLiteral("domainLookupEnd")) {
|
|
return Timing()->DomainLookupEnd();
|
|
}
|
|
if (aProperty.EqualsLiteral("connectStart")) {
|
|
return Timing()->ConnectStart();
|
|
}
|
|
if (aProperty.EqualsLiteral("secureConnectionStart")) {
|
|
return Timing()->SecureConnectionStart();
|
|
}
|
|
if (aProperty.EqualsLiteral("connectEnd")) {
|
|
return Timing()->ConnectEnd();
|
|
}
|
|
if (aProperty.EqualsLiteral("requestStart")) {
|
|
return Timing()->RequestStart();
|
|
}
|
|
if (aProperty.EqualsLiteral("responseStart")) {
|
|
return Timing()->ResponseStart();
|
|
}
|
|
if (aProperty.EqualsLiteral("responseEnd")) {
|
|
return Timing()->ResponseEnd();
|
|
}
|
|
if (aProperty.EqualsLiteral("domLoading")) {
|
|
return GetDOMTiming()->GetDomLoading();
|
|
}
|
|
if (aProperty.EqualsLiteral("domInteractive")) {
|
|
return GetDOMTiming()->GetDomInteractive();
|
|
}
|
|
if (aProperty.EqualsLiteral("domContentLoadedEventStart")) {
|
|
return GetDOMTiming()->GetDomContentLoadedEventStart();
|
|
}
|
|
if (aProperty.EqualsLiteral("domContentLoadedEventEnd")) {
|
|
return GetDOMTiming()->GetDomContentLoadedEventEnd();
|
|
}
|
|
if (aProperty.EqualsLiteral("domComplete")) {
|
|
return GetDOMTiming()->GetDomComplete();
|
|
}
|
|
if (aProperty.EqualsLiteral("loadEventStart")) {
|
|
return GetDOMTiming()->GetLoadEventStart();
|
|
}
|
|
if (aProperty.EqualsLiteral("loadEventEnd")) {
|
|
return GetDOMTiming()->GetLoadEventEnd();
|
|
}
|
|
MOZ_CRASH(
|
|
"IsPerformanceTimingAttribute and GetPerformanceTimingFromString are out "
|
|
"of sync");
|
|
return 0;
|
|
}
|
|
|
|
void PerformanceMainThread::InsertUserEntry(PerformanceEntry* aEntry) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
nsAutoCString uri;
|
|
uint64_t markCreationEpoch = 0;
|
|
|
|
if (StaticPrefs::dom_performance_enable_user_timing_logging() ||
|
|
StaticPrefs::dom_performance_enable_notify_performance_timing()) {
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
|
|
if (owner && owner->GetDocumentURI()) {
|
|
rv = owner->GetDocumentURI()->GetHost(uri);
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
// If we have no URI, just put in "none".
|
|
uri.AssignLiteral("none");
|
|
}
|
|
markCreationEpoch = static_cast<uint64_t>(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);
|
|
}
|
|
|
|
Performance::InsertUserEntry(aEntry);
|
|
}
|
|
|
|
TimeStamp PerformanceMainThread::CreationTimeStamp() const {
|
|
return GetDOMTiming()->GetNavigationStartTimeStamp();
|
|
}
|
|
|
|
DOMHighResTimeStamp PerformanceMainThread::CreationTime() const {
|
|
return GetDOMTiming()->GetNavigationStart();
|
|
}
|
|
|
|
void PerformanceMainThread::CreateNavigationTimingEntry() {
|
|
MOZ_ASSERT(!mDocEntry, "mDocEntry should be null.");
|
|
|
|
if (!StaticPrefs::dom_enable_performance_navigation_timing()) {
|
|
return;
|
|
}
|
|
|
|
nsAutoString name;
|
|
GetURLSpecFromChannel(mChannel, name);
|
|
|
|
UniquePtr<PerformanceTimingData> timing(
|
|
new PerformanceTimingData(mChannel, nullptr, 0));
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
|
|
if (httpChannel) {
|
|
timing->SetPropertiesFromHttpChannel(httpChannel, mChannel);
|
|
}
|
|
|
|
mDocEntry = new PerformanceNavigationTiming(std::move(timing), this, name);
|
|
}
|
|
|
|
void PerformanceMainThread::QueueNavigationTimingEntry() {
|
|
if (!mDocEntry) {
|
|
return;
|
|
}
|
|
|
|
// Let's update some values.
|
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
|
|
if (httpChannel) {
|
|
mDocEntry->UpdatePropertiesFromHttpChannel(httpChannel, mChannel);
|
|
}
|
|
|
|
QueueEntry(mDocEntry);
|
|
}
|
|
|
|
void PerformanceMainThread::GetEntries(
|
|
nsTArray<RefPtr<PerformanceEntry>>& aRetval) {
|
|
// We return an empty list when 'privacy.resistFingerprinting' is on.
|
|
if (nsContentUtils::ShouldResistFingerprinting()) {
|
|
aRetval.Clear();
|
|
return;
|
|
}
|
|
|
|
aRetval = mResourceEntries;
|
|
aRetval.AppendElements(mUserEntries);
|
|
|
|
if (mDocEntry) {
|
|
aRetval.AppendElement(mDocEntry);
|
|
}
|
|
|
|
aRetval.Sort(PerformanceEntryComparator());
|
|
}
|
|
|
|
void PerformanceMainThread::GetEntriesByType(
|
|
const nsAString& aEntryType, nsTArray<RefPtr<PerformanceEntry>>& aRetval) {
|
|
// We return an empty list when 'privacy.resistFingerprinting' is on.
|
|
if (nsContentUtils::ShouldResistFingerprinting()) {
|
|
aRetval.Clear();
|
|
return;
|
|
}
|
|
|
|
if (aEntryType.EqualsLiteral("navigation")) {
|
|
aRetval.Clear();
|
|
|
|
if (mDocEntry) {
|
|
aRetval.AppendElement(mDocEntry);
|
|
}
|
|
return;
|
|
}
|
|
|
|
Performance::GetEntriesByType(aEntryType, aRetval);
|
|
}
|
|
|
|
void PerformanceMainThread::GetEntriesByName(
|
|
const nsAString& aName, const Optional<nsAString>& aEntryType,
|
|
nsTArray<RefPtr<PerformanceEntry>>& aRetval) {
|
|
// We return an empty list when 'privacy.resistFingerprinting' is on.
|
|
if (nsContentUtils::ShouldResistFingerprinting()) {
|
|
aRetval.Clear();
|
|
return;
|
|
}
|
|
|
|
Performance::GetEntriesByName(aName, aEntryType, aRetval);
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|