summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dom/bindings/Bindings.conf6
-rw-r--r--dom/bindings/Errors.msg3
-rwxr-xr-xdom/performance/Performance.cpp53
-rw-r--r--dom/performance/Performance.h20
-rw-r--r--dom/performance/PerformanceMark.cpp95
-rw-r--r--dom/performance/PerformanceMark.h28
-rw-r--r--dom/webidl/Performance.webidl8
-rw-r--r--dom/webidl/PerformanceMark.webidl3
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;
};