Bug 1599160 - Add a performance resource entry when hitting the cache for the first time in a document. r=mayhemer,valentin

This matches other browsers, our current behavior, and the test
expectations from various WPTs.

Differential Revision: https://phabricator.services.mozilla.com/D77842
This commit is contained in:
Emilio Cobos Álvarez 2020-06-11 11:41:59 +00:00
Родитель 208b60eed2
Коммит d999791a43
7 изменённых файлов: 106 добавлений и 26 удалений

Просмотреть файл

@ -147,15 +147,18 @@ void PerformanceMainThread::AddEntry(nsIHttpChannel* channel,
if (!performanceTimingData) {
return;
}
AddRawEntry(std::move(performanceTimingData), initiatorType, entryName);
}
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.
RefPtr<PerformanceResourceTiming> performanceEntry =
new PerformanceResourceTiming(std::move(performanceTimingData), this,
entryName);
performanceEntry->SetInitiatorType(initiatorType);
InsertResourceEntry(performanceEntry);
auto entry =
MakeRefPtr<PerformanceResourceTiming>(std::move(aData), this, aEntryName);
entry->SetInitiatorType(aInitiatorType);
InsertResourceEntry(entry);
}
// To be removed once bug 1124165 lands

Просмотреть файл

@ -35,6 +35,10 @@ class PerformanceMainThread final : public Performance,
virtual void AddEntry(nsIHttpChannel* channel,
nsITimedChannel* timedChannel) override;
void AddRawEntry(UniquePtr<PerformanceTimingData>,
const nsAString& aInitiatorType,
const nsAString& aEntryName);
TimeStamp CreationTimeStamp() const override;
DOMHighResTimeStamp CreationTime() const override;

Просмотреть файл

@ -205,6 +205,14 @@ PerformanceTimingData::PerformanceTimingData(nsITimedChannel* aChannel,
}
}
void PerformanceTimingData::InitializeForMemoryCacheHit() {
auto now = TimeStamp::Now();
mInitialized = true;
mAsyncOpen = mRequestStart = mResponseStart = mResponseEnd =
mDomainLookupStart = mDomainLookupEnd = mConnectStart = mConnectEnd =
mCacheReadStart = mCacheReadEnd = now;
}
void PerformanceTimingData::SetPropertiesFromHttpChannel(
nsIHttpChannel* aHttpChannel, nsITimedChannel* aChannel) {
MOZ_ASSERT(aHttpChannel);

Просмотреть файл

@ -112,6 +112,18 @@ class PerformanceTimingData final {
return duration.ToMilliseconds() + mZeroTime;
}
/**
* Initializes the timestamps to represent a synchronous cache hit in an
* in-memory cache.
*
* This is used right now for the shared stylesheet cache, which doesn't
* always go through necko and thus there isn't an HTTP channel, etc.
*
* We fill the values with the current timestamp to represent an "instant"
* resource fetch.
*/
void InitializeForMemoryCacheHit();
// The last channel's AsyncOpen time. This may occur before the FetchStart
// in some cases.
DOMHighResTimeStamp AsyncOpenHighRes(Performance* aPerformance);

Просмотреть файл

@ -10,6 +10,7 @@ with Files("**"):
EXPORTS.mozilla.dom += [
'Performance.h',
'PerformanceEntry.h',
'PerformanceMainThread.h',
'PerformanceMark.h',
'PerformanceMeasure.h',
'PerformanceNavigation.h',

Просмотреть файл

@ -28,6 +28,8 @@
#include "nsIContent.h"
#include "nsIContentInlines.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/PerformanceTiming.h"
#include "mozilla/dom/PerformanceMainThread.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsContentUtils.h"
@ -263,10 +265,6 @@ SheetLoadData::SheetLoadData(Loader* aLoader, nsIURI* aURI, StyleSheet* aSheet,
mCompatMode(aLoader->mCompatMode) {
MOZ_ASSERT(mLoader, "Must have a loader!");
MOZ_ASSERT(mTriggeringPrincipal);
if (mParentData) {
++mParentData->mPendingChildren;
}
MOZ_ASSERT(!mUseSystemPrincipal || mSyncLoad,
"Shouldn't use system principal for async loads");
}
@ -648,18 +646,14 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus,
mSheet->SetPrincipal(principal);
if (mSheet->GetCORSMode() == CORS_NONE) {
bool subsumed;
result = mTriggeringPrincipal->Subsumes(principal, &subsumed);
if (NS_FAILED(result) || !subsumed) {
mIsCrossOriginNoCORS = true;
}
if (mSheet->GetCORSMode() == CORS_NONE &&
!mTriggeringPrincipal->Subsumes(principal)) {
mIsCrossOriginNoCORS = true;
}
// If it's an HTTP channel, we want to make sure this is not an
// error document we got.
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
if (httpChannel) {
if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel)) {
bool requestSucceeded;
result = httpChannel->GetRequestSucceeded(&requestSucceeded);
if (NS_SUCCEEDED(result) && !requestSucceeded) {
@ -829,6 +823,48 @@ nsresult Loader::CheckContentPolicy(nsIPrincipal* aLoadingPrincipal,
return NS_OK;
}
void Loader::MaybeNotifyOfResourceTiming(SheetLoadData& aData) {
SheetLoadDataHashKey key(aData);
if (!mLoadsPerformed.EnsureInserted(key)) {
// We've already reported this subresource load.
return;
}
if (!mDocument) {
// No document means no performance object to report to.
return;
}
nsPIDOMWindowInner* win = mDocument->GetInnerWindow();
if (!win) {
return;
}
auto* perf = static_cast<dom::PerformanceMainThread*>(win->GetPerformance());
if (!perf) {
return;
}
// If any ancestor is cross-origin, then we don't report it, see
// mIsCrossOriginNoCORS and so.
for (auto* parent = aData.mSheet->GetParentSheet(); parent;
parent = parent->GetParentSheet()) {
if (parent->GetCORSMode() == CORS_NONE &&
!aData.mTriggeringPrincipal->Subsumes(parent->Principal())) {
return;
}
}
nsLiteralString initiatorType = aData.mSheet->GetParentSheet()
? NS_LITERAL_STRING("css")
: NS_LITERAL_STRING("link");
nsAutoCString entryName;
aData.mSheet->GetOriginalURI()->GetSpec(entryName);
auto data = MakeUnique<dom::PerformanceTimingData>(nullptr, nullptr, 0);
data->InitializeForMemoryCacheHit();
perf->AddRawEntry(std::move(data), initiatorType,
NS_ConvertUTF8toUTF16(entryName));
}
/**
* CreateSheet() creates a StyleSheet object for the given URI.
*
@ -1048,6 +1084,9 @@ nsresult Loader::LoadSheet(SheetLoadData& aLoadData, SheetState aSheetState) {
LOG_URI(" Load from: '%s'", aLoadData.mURI);
++mOngoingLoadCount;
if (aLoadData.mParentData) {
++aLoadData.mParentData->mPendingChildren;
}
nsresult rv = NS_OK;
@ -1306,6 +1345,8 @@ nsresult Loader::LoadSheet(SheetLoadData& aLoadData, SheetState aSheetState) {
// sub-resource and so we set the flag on ourself too to propagate it
// on down.
//
// If you add more conditions here make sure to add them to
// MaybeNotifyResourceTiming too.
if (aLoadData.mParentData->mIsCrossOriginNoCORS ||
aLoadData.mParentData->mBlockResourceTiming) {
// Set a flag so any other stylesheet triggered by this one will
@ -1684,6 +1725,7 @@ Result<Loader::LoadSheetResult, nsresult> Loader::LoadStyleLink(
aInfo.mReferrerInfo, context);
if (state == SheetState::Complete) {
LOG((" Sheet already complete: 0x%p", sheet.get()));
MaybeNotifyOfResourceTiming(*data);
if (aObserver || !mObservers.IsEmpty() || aInfo.mContent) {
rv = PostLoadEvent(std::move(data));
if (NS_FAILED(rv)) {
@ -1833,18 +1875,22 @@ nsresult Loader::LoadChildSheet(StyleSheet& aParentSheet,
MOZ_ASSERT(sheet);
InsertChildSheet(*sheet, aParentSheet);
if (state == SheetState::Complete) {
LOG((" Sheet already complete"));
// We're completely done. No need to notify, even, since the
// @import rule addition/modification will trigger the right style
// changes automatically.
return NS_OK;
}
auto data = MakeRefPtr<SheetLoadData>(
this, aURL, sheet, aParentData, observer, principal,
aParentSheet.GetReferrerInfo(), context);
if (state == SheetState::Complete) {
LOG((" Sheet already complete"));
MaybeNotifyOfResourceTiming(*data);
// We're completely done. No need to notify, even, since the
// @import rule addition/modification will trigger the right style
// changes automatically.
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
data->mIntentionallyDropped = true;
#endif
return NS_OK;
}
bool syncLoad = data->mSyncLoad;
// Load completion will release the data
@ -1925,6 +1971,7 @@ Result<RefPtr<StyleSheet>, nsresult> Loader::InternalLoadNonDocumentSheet(
mDocument);
if (state == SheetState::Complete) {
LOG((" Sheet already complete"));
MaybeNotifyOfResourceTiming(*data);
if (aObserver || !mObservers.IsEmpty()) {
rv = PostLoadEvent(std::move(data));
if (NS_FAILED(rv)) {

Просмотреть файл

@ -358,6 +358,11 @@ class Loader final {
nsIURI* aURL, dom::MediaList* aMedia,
LoaderReusableStyleSheets* aSavedSheets);
// If we hit the shared cache and this is the first load for a given resource,
// we still post a resource timing entry, because tests expect this, and other
// browsers behave like this too.
void MaybeNotifyOfResourceTiming(SheetLoadData&);
enum class UseSystemPrincipal { No, Yes };
/**