Commit ecf24191 authored by Tom McKee's avatar Tom McKee Committed by Commit Bot

[UserTimingL3] Make PerformanceTiming own its attribute name mapping

In the User Timing spec, it is an error to make a PerformanceMark with
the same name as a read-only attribute from the PerformanceTiming
interface[1]. E.g. it is an error to call
`performance.mark("navigationStart")` as this would lead to ambiguity
when trying to resolve calls like
`performance.measure("m", "navigationStart")`.

Since the read-only attributes are defined on the PerformanceTiming
interface[2], it makes more sense to declare a name/attribute mapping
locally instead of in the PerformanceUserTiming class.

[1]: https://w3c.github.io/user-timing/#the-performancemark-constructor
[2]: https://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface

Bug: 805566
Change-Id: I2466d123a0d93965555c06d2434cb839fafabb72
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1967567
Commit-Queue: Tom McKee <tommckee@chromium.org>
Reviewed-by: default avatarNicolás Peña Moreno <npm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#733395}
parent 39b28ec3
...@@ -586,30 +586,47 @@ std::unique_ptr<TracedValue> PerformanceTiming::GetNavigationTracingData() { ...@@ -586,30 +586,47 @@ std::unique_ptr<TracedValue> PerformanceTiming::GetNavigationTracingData() {
return data; return data;
} }
// static
const PerformanceTiming::NameToAttributeMap&
PerformanceTiming::GetAttributeMapping() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<NameToAttributeMap>, map, ());
if (!map.IsSet()) {
*map = {
{"navigationStart", &PerformanceTiming::navigationStart},
{"unloadEventStart", &PerformanceTiming::unloadEventStart},
{"unloadEventEnd", &PerformanceTiming::unloadEventEnd},
{"redirectStart", &PerformanceTiming::redirectStart},
{"redirectEnd", &PerformanceTiming::redirectEnd},
{"fetchStart", &PerformanceTiming::fetchStart},
{"domainLookupStart", &PerformanceTiming::domainLookupStart},
{"domainLookupEnd", &PerformanceTiming::domainLookupEnd},
{"connectStart", &PerformanceTiming::connectStart},
{"connectEnd", &PerformanceTiming::connectEnd},
{"secureConnectionStart", &PerformanceTiming::secureConnectionStart},
{"requestStart", &PerformanceTiming::requestStart},
{"responseStart", &PerformanceTiming::responseStart},
{"responseEnd", &PerformanceTiming::responseEnd},
{"domLoading", &PerformanceTiming::domLoading},
{"domInteractive", &PerformanceTiming::domInteractive},
{"domContentLoadedEventStart",
&PerformanceTiming::domContentLoadedEventStart},
{"domContentLoadedEventEnd",
&PerformanceTiming::domContentLoadedEventEnd},
{"domComplete", &PerformanceTiming::domComplete},
{"loadEventStart", &PerformanceTiming::loadEventStart},
{"loadEventEnd", &PerformanceTiming::loadEventEnd},
};
}
return *map;
}
ScriptValue PerformanceTiming::toJSONForBinding( ScriptValue PerformanceTiming::toJSONForBinding(
ScriptState* script_state) const { ScriptState* script_state) const {
V8ObjectBuilder result(script_state); V8ObjectBuilder result(script_state);
result.AddNumber("navigationStart", navigationStart()); for (const auto& name_attribute_pair : GetAttributeMapping()) {
result.AddNumber("unloadEventStart", unloadEventStart()); result.AddNumber(name_attribute_pair.key,
result.AddNumber("unloadEventEnd", unloadEventEnd()); (this->*(name_attribute_pair.value))());
result.AddNumber("redirectStart", redirectStart()); }
result.AddNumber("redirectEnd", redirectEnd());
result.AddNumber("fetchStart", fetchStart());
result.AddNumber("domainLookupStart", domainLookupStart());
result.AddNumber("domainLookupEnd", domainLookupEnd());
result.AddNumber("connectStart", connectStart());
result.AddNumber("connectEnd", connectEnd());
result.AddNumber("secureConnectionStart", secureConnectionStart());
result.AddNumber("requestStart", requestStart());
result.AddNumber("responseStart", responseStart());
result.AddNumber("responseEnd", responseEnd());
result.AddNumber("domLoading", domLoading());
result.AddNumber("domInteractive", domInteractive());
result.AddNumber("domContentLoadedEventStart", domContentLoadedEventStart());
result.AddNumber("domContentLoadedEventEnd", domContentLoadedEventEnd());
result.AddNumber("domComplete", domComplete());
result.AddNumber("loadEventStart", loadEventStart());
result.AddNumber("loadEventEnd", loadEventEnd());
return result.GetScriptValue(); return result.GetScriptValue();
} }
......
...@@ -143,6 +143,10 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable, ...@@ -143,6 +143,10 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable,
uint64_t ParseBlockedOnScriptExecutionDuration() const; uint64_t ParseBlockedOnScriptExecutionDuration() const;
uint64_t ParseBlockedOnScriptExecutionFromDocumentWriteDuration() const; uint64_t ParseBlockedOnScriptExecutionFromDocumentWriteDuration() const;
typedef uint64_t (PerformanceTiming::*PerformanceTimingGetter)() const;
using NameToAttributeMap = HashMap<AtomicString, PerformanceTimingGetter>;
static const NameToAttributeMap& GetAttributeMapping();
ScriptValue toJSONForBinding(ScriptState*) const; ScriptValue toJSONForBinding(ScriptState*) const;
void Trace(blink::Visitor*) override; void Trace(blink::Visitor*) override;
......
...@@ -34,45 +34,6 @@ ...@@ -34,45 +34,6 @@
namespace blink { namespace blink {
namespace {
typedef uint64_t (PerformanceTiming::*NavigationTimingFunction)() const;
using RestrictedKeyMap = HashMap<AtomicString, NavigationTimingFunction>;
const RestrictedKeyMap& GetRestrictedKeyMap() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<RestrictedKeyMap>, map, ());
if (!map.IsSet()) {
*map = {
{"navigationStart", &PerformanceTiming::navigationStart},
{"unloadEventStart", &PerformanceTiming::unloadEventStart},
{"unloadEventEnd", &PerformanceTiming::unloadEventEnd},
{"redirectStart", &PerformanceTiming::redirectStart},
{"redirectEnd", &PerformanceTiming::redirectEnd},
{"fetchStart", &PerformanceTiming::fetchStart},
{"domainLookupStart", &PerformanceTiming::domainLookupStart},
{"domainLookupEnd", &PerformanceTiming::domainLookupEnd},
{"connectStart", &PerformanceTiming::connectStart},
{"connectEnd", &PerformanceTiming::connectEnd},
{"secureConnectionStart", &PerformanceTiming::secureConnectionStart},
{"requestStart", &PerformanceTiming::requestStart},
{"responseStart", &PerformanceTiming::responseStart},
{"responseEnd", &PerformanceTiming::responseEnd},
{"domLoading", &PerformanceTiming::domLoading},
{"domInteractive", &PerformanceTiming::domInteractive},
{"domContentLoadedEventStart",
&PerformanceTiming::domContentLoadedEventStart},
{"domContentLoadedEventEnd",
&PerformanceTiming::domContentLoadedEventEnd},
{"domComplete", &PerformanceTiming::domComplete},
{"loadEventStart", &PerformanceTiming::loadEventStart},
{"loadEventEnd", &PerformanceTiming::loadEventEnd},
};
}
return *map;
}
} // namespace
UserTiming::UserTiming(Performance& performance) : performance_(&performance) {} UserTiming::UserTiming(Performance& performance) : performance_(&performance) {}
static void InsertPerformanceEntry(PerformanceEntryMap& performance_entry_map, static void InsertPerformanceEntry(PerformanceEntryMap& performance_entry_map,
...@@ -122,7 +83,8 @@ PerformanceMark* UserTiming::CreatePerformanceMark( ...@@ -122,7 +83,8 @@ PerformanceMark* UserTiming::CreatePerformanceMark(
bool is_worker_global_scope = bool is_worker_global_scope =
performance_->GetExecutionContext() && performance_->GetExecutionContext() &&
performance_->GetExecutionContext()->IsWorkerGlobalScope(); performance_->GetExecutionContext()->IsWorkerGlobalScope();
if (!is_worker_global_scope && GetRestrictedKeyMap().Contains(mark_name)) { if (!is_worker_global_scope &&
PerformanceTiming::GetAttributeMapping().Contains(mark_name)) {
exception_state.ThrowDOMException( exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError, DOMExceptionCode::kSyntaxError,
"'" + mark_name + "'" + mark_name +
...@@ -155,8 +117,8 @@ double UserTiming::FindExistingMarkStartTime(const AtomicString& mark_name, ...@@ -155,8 +117,8 @@ double UserTiming::FindExistingMarkStartTime(const AtomicString& mark_name,
if (marks_map_.Contains(mark_name)) if (marks_map_.Contains(mark_name))
return marks_map_.at(mark_name).back()->startTime(); return marks_map_.at(mark_name).back()->startTime();
NavigationTimingFunction timing_function = PerformanceTiming::PerformanceTimingGetter timing_function =
GetRestrictedKeyMap().at(mark_name); PerformanceTiming::GetAttributeMapping().at(mark_name);
if (!timing_function) { if (!timing_function) {
exception_state.ThrowDOMException( exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError, DOMExceptionCode::kSyntaxError,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment