diff options
-rw-r--r-- | dom/bindings/Bindings.conf | 6 | ||||
-rw-r--r-- | dom/bindings/Errors.msg | 3 | ||||
-rwxr-xr-x | dom/performance/Performance.cpp | 53 | ||||
-rw-r--r-- | dom/performance/Performance.h | 20 | ||||
-rw-r--r-- | dom/performance/PerformanceMark.cpp | 95 | ||||
-rw-r--r-- | dom/performance/PerformanceMark.h | 28 | ||||
-rw-r--r-- | dom/webidl/Performance.webidl | 8 | ||||
-rw-r--r-- | dom/webidl/PerformanceMark.webidl | 3 |
8 files changed, 197 insertions, 19 deletions
diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 146bf8d15b..8b13babdbb 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -642,6 +642,12 @@ DOMInterfaces = { 'wrapperCache': False }, +'Performance' : { + 'implicitJSContext': [ + 'mark' + ], +}, + 'Plugin': { 'headerFile' : 'nsPluginArray.h', 'nativeType': 'nsPluginElement', diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index d663c8fed9..7f53a24966 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -105,3 +105,6 @@ MSG_DEF(MSG_PMO_NO_SEPARATE_ENDMARK, 0, JSEXN_TYPEERR, "Cannot provide separate MSG_DEF(MSG_PMO_MISSING_STARTENDMARK, 0, JSEXN_TYPEERR, "PerformanceMeasureOptions must have start and/or end member.") MSG_DEF(MSG_PMO_INVALID_MEMBERS, 0, JSEXN_TYPEERR, "PerformanceMeasureOptions cannot have all of the following members: start, duration, and end.") MSG_DEF(MSG_PMO_UNKNOWN_MARK_NAME, 1, JSEXN_SYNTAXERR, "Given mark name, {0}, is unknown.") +MSG_DEF(MSG_PMO_CONSTRUCTOR_INACCESSIBLE, 0, JSEXN_TYPEERR, "Can't access PerformanceMark constructor, performance is null.") +MSG_DEF(MSG_PMO_INVALID_TIMING_ATTR, 0, JSEXN_SYNTAXERR, "markName cannot be a performance timing attribute.") +MSG_DEF(MSG_PMO_UNEXPECTED_START_TIME, 0, JSEXN_TYPEERR, "Expected startTime >= 0.") diff --git a/dom/performance/Performance.cpp b/dom/performance/Performance.cpp index ebdddeb835..f3523293a4 100755 --- a/dom/performance/Performance.cpp +++ b/dom/performance/Performance.cpp @@ -26,6 +26,7 @@ #include "mozilla/TimerClamping.h" #include "WorkerPrivate.h" #include "WorkerRunnable.h" +#include "WorkerScope.h" #define PERFLOG(msg, ...) printf_stderr(msg, ##__VA_ARGS__) @@ -105,6 +106,27 @@ Performance::CreateForWorker(workers::WorkerPrivate* aWorkerPrivate) return performance.forget(); } +/* static */ +already_AddRefed<Performance> Performance::Get(JSContext* aCx, + nsIGlobalObject* aGlobal) { + RefPtr<Performance> performance; + nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal); + if (window) { + performance = window->GetPerformance(); + } else { + const WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + if (!workerPrivate) { + return nullptr; + } + + WorkerGlobalScope* scope = workerPrivate->GlobalScope(); + MOZ_ASSERT(scope); + performance = scope->GetPerformance(); + } + + return performance.forget(); +} + Performance::Performance() : mResourceTimingBufferSize(kDefaultResourceTimingBufferSize) , mPendingNotificationObserversTask(false) @@ -234,27 +256,42 @@ Performance::RoundTime(double aTime) const return floor(aTime / maxResolutionMs) * maxResolutionMs; } - -void -Performance::Mark(const nsAString& aName, ErrorResult& aRv) +already_AddRefed<PerformanceMark> Performance::Mark( + JSContext* aCx, + const nsAString& aName, + const PerformanceMarkOptions& aMarkOptions, + ErrorResult& aRv) { // Don't add the entry if the buffer is full. XXX should be removed by bug 1159003. if (mUserEntries.Length() >= mResourceTimingBufferSize) { - return; + return nullptr; } - if (IsPerformanceTimingAttribute(aName)) { - aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); - return; + nsCOMPtr<nsIGlobalObject> parent = GetParentObject(); + if (!parent || parent->IsDying() || !parent->GetGlobalJSObject()) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + + GlobalObject global(aCx, parent->GetGlobalJSObject()); + if (global.Failed()) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; } RefPtr<PerformanceMark> performanceMark = - new PerformanceMark(GetAsISupports(), aName, Now()); + PerformanceMark::Constructor(global, aName, aMarkOptions, aRv); + if (aRv.Failed()) { + return nullptr; + } + InsertUserEntry(performanceMark); if (profiler_is_active()) { PROFILER_MARKER(NS_ConvertUTF16toUTF8(aName).get()); } + + return performanceMark.forget(); } void diff --git a/dom/performance/Performance.h b/dom/performance/Performance.h index 772e88c6da..6bdd42a8e8 100644 --- a/dom/performance/Performance.h +++ b/dom/performance/Performance.h @@ -23,6 +23,8 @@ namespace dom { class OwningStringOrDouble; class StringOrPerformanceMeasureOptions; class PerformanceEntry; +class PerformanceMark; +struct PerformanceMarkOptions; struct PerformanceMeasureOptions; class PerformanceMeasure; class PerformanceNavigation; @@ -55,6 +57,10 @@ public: static already_AddRefed<Performance> CreateForWorker(workers::WorkerPrivate* aWorkerPrivate); + // This will return nullptr if called outside of a Window or Worker. + static already_AddRefed<Performance> Get(JSContext* aCx, + nsIGlobalObject* aGlobal); + JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override; @@ -76,7 +82,9 @@ public: DOMHighResTimeStamp TimeOrigin(); - void Mark(const nsAString& aName, ErrorResult& aRv); + already_AddRefed<PerformanceMark> Mark( + JSContext* aCx, const nsAString& aName, + const PerformanceMarkOptions& aMarkOptions, ErrorResult& aRv); void ClearMarks(const Optional<nsAString>& aName); @@ -109,6 +117,11 @@ public: virtual nsITimedChannel* GetChannel() const = 0; + virtual bool IsPerformanceTimingAttribute(const nsAString& aName) + { + return false; + } + protected: Performance(); explicit Performance(nsPIDOMWindowInner* aWindow); @@ -129,11 +142,6 @@ protected: virtual DOMHighResTimeStamp CreationTime() const = 0; - virtual bool IsPerformanceTimingAttribute(const nsAString& aName) - { - return false; - } - virtual DOMHighResTimeStamp GetPerformanceTimingFromString(const nsAString& aTimingName) { diff --git a/dom/performance/PerformanceMark.cpp b/dom/performance/PerformanceMark.cpp index c37d057b66..cd6d1bb39d 100644 --- a/dom/performance/PerformanceMark.cpp +++ b/dom/performance/PerformanceMark.cpp @@ -6,25 +6,118 @@ #include "PerformanceMark.h" #include "MainThreadUtils.h" #include "mozilla/dom/PerformanceMarkBinding.h" +#include "mozilla/dom/MessagePortBinding.h" +using mozilla::dom::StructuredSerializeOptions; using namespace mozilla::dom; PerformanceMark::PerformanceMark(nsISupports* aParent, const nsAString& aName, - DOMHighResTimeStamp aStartTime) + DOMHighResTimeStamp aStartTime, + const JS::Handle<JS::Value>& aDetail) : PerformanceEntry(aParent, aName, NS_LITERAL_STRING("mark")) , mStartTime(aStartTime) + , mDetail(aDetail) { // mParent is null in workers. MOZ_ASSERT(mParent || !NS_IsMainThread()); + mozilla::HoldJSObjects(this); +} + + +already_AddRefed<PerformanceMark> PerformanceMark::Constructor( + const GlobalObject& aGlobal, + const nsAString& aMarkName, + const PerformanceMarkOptions& aMarkOptions, + ErrorResult& aRv) +{ + const nsCOMPtr<nsIGlobalObject> global = + do_QueryInterface(aGlobal.GetAsSupports()); + return PerformanceMark::Constructor(aGlobal.Context(), global, aMarkName, + aMarkOptions, aRv); +} + +already_AddRefed<PerformanceMark> PerformanceMark::Constructor( + JSContext* aCx, + nsIGlobalObject* aGlobal, + const nsAString& aMarkName, + const PerformanceMarkOptions& aMarkOptions, + ErrorResult& aRv) +{ + RefPtr<Performance> performance = Performance::Get(aCx, aGlobal); + if (!performance) { + // This is similar to the message that occurs when accessing `performance` + // from outside a valid global. + aRv.ThrowTypeError<MSG_PMO_CONSTRUCTOR_INACCESSIBLE>(); + return nullptr; + } + + if (performance->IsPerformanceTimingAttribute(aMarkName)) { + aRv.ThrowTypeError<MSG_PMO_INVALID_TIMING_ATTR>(); + return nullptr; + } + + DOMHighResTimeStamp startTime = aMarkOptions.mStartTime.WasPassed() ? + aMarkOptions.mStartTime.Value() : + performance->Now(); + if (startTime < 0) { + aRv.ThrowTypeError<MSG_PMO_UNEXPECTED_START_TIME>(); + return nullptr; + } + + JS::Rooted<JS::Value> detail(aCx); + if (aMarkOptions.mDetail.isNullOrUndefined()) { + detail.setNull(); + } else { + StructuredSerializeOptions serializeOptions; + JS::Rooted<JS::Value> valueToClone(aCx, aMarkOptions.mDetail); + nsContentUtils::StructuredClone(aCx, aGlobal, valueToClone, + serializeOptions, &detail, aRv); + if (aRv.Failed()) { + return nullptr; + } + } + + return do_AddRef(new PerformanceMark(aGlobal, aMarkName, startTime, detail)); } PerformanceMark::~PerformanceMark() { + mozilla::DropJSObjects(this); } +NS_IMPL_CYCLE_COLLECTION_CLASS(PerformanceMark) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PerformanceMark, + PerformanceEntry) + tmp->mDetail.setUndefined(); + mozilla::DropJSObjects(tmp); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PerformanceMark, + PerformanceEntry) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceMark, + PerformanceEntry) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDetail) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceMark) +NS_INTERFACE_MAP_END_INHERITING(PerformanceEntry) +NS_IMPL_ADDREF_INHERITED(PerformanceMark, PerformanceEntry) +NS_IMPL_RELEASE_INHERITED(PerformanceMark, PerformanceEntry) + JSObject* PerformanceMark::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return PerformanceMarkBinding::Wrap(aCx, this, aGivenProto); } + +void PerformanceMark::GetDetail(JSContext* aCx, + JS::MutableHandle<JS::Value> aRv) +{ + // Return a copy so that this method always returns the value it is set to + // (i.e. it'll return the same value even if the caller assigns to it). Note + // that if detail is an object, its contents can be mutated and this is + // expected. + aRv.set(mDetail); +} diff --git a/dom/performance/PerformanceMark.h b/dom/performance/PerformanceMark.h index a080af6a82..4e98bfaa92 100644 --- a/dom/performance/PerformanceMark.h +++ b/dom/performance/PerformanceMark.h @@ -11,16 +11,40 @@ namespace mozilla { namespace dom { +struct PerformanceMarkOptions; + // http://www.w3.org/TR/user-timing/#performancemark class PerformanceMark final : public PerformanceEntry { -public: +private: PerformanceMark(nsISupports* aParent, const nsAString& aName, - DOMHighResTimeStamp aStartTime); + DOMHighResTimeStamp aStartTime, + const JS::Handle<JS::Value>& aDetail); + + JS::Heap<JS::Value> mDetail; + +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PerformanceMark, + PerformanceEntry); + + static already_AddRefed<PerformanceMark> Constructor( + const GlobalObject& aGlobal, + const nsAString& aMarkName, + const PerformanceMarkOptions& aMarkOptions, + ErrorResult& aRv); + + static already_AddRefed<PerformanceMark> Constructor( + JSContext* aCx, nsIGlobalObject* aGlobal, + const nsAString& aMarkName, + const PerformanceMarkOptions& aMarkOptions, + ErrorResult& aRv); virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; + void GetDetail(JSContext* aCx, JS::MutableHandle<JS::Value> aRv); + virtual DOMHighResTimeStamp StartTime() const override { return mStartTime; diff --git a/dom/webidl/Performance.webidl b/dom/webidl/Performance.webidl index e681505216..7cd6c67172 100644 --- a/dom/webidl/Performance.webidl +++ b/dom/webidl/Performance.webidl @@ -72,11 +72,17 @@ partial interface Performance { }; #endif +// https://w3c.github.io/user-timing/#extensions-performance-interface +dictionary PerformanceMarkOptions { + any detail; + DOMHighResTimeStamp startTime; +}; + // http://www.w3.org/TR/user-timing/ [Exposed=(Window,Worker)] partial interface Performance { [Func="Performance::IsEnabled", Throws] - void mark(DOMString markName); + PerformanceMark mark(DOMString markName, optional PerformanceMarkOptions markOptions); [Func="Performance::IsEnabled"] void clearMarks(optional DOMString markName); [Func="Performance::IsEnabled", Throws] diff --git a/dom/webidl/PerformanceMark.webidl b/dom/webidl/PerformanceMark.webidl index 20e9e92c02..2ef9fcd844 100644 --- a/dom/webidl/PerformanceMark.webidl +++ b/dom/webidl/PerformanceMark.webidl @@ -7,7 +7,8 @@ * http://www.w3.org/TR/user-timing/#performancemark */ -[Exposed=(Window,Worker)] +[Exposed=(Window,Worker), Constructor(DOMString markName, optional PerformanceMarkOptions markOptions)] interface PerformanceMark : PerformanceEntry { + readonly attribute any detail; }; |