mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-09 09:18:42 +09:00
Issue #2053 - Part 3: Update PerformanceMark to User Timing L3
There are a few minor differences between this and Mozilla's implementation: (a) The type error messages were not hardcoded to the Performance class and were moved to Errors.msg or domerr.msg instead. (b) Resist fingerprinting-pref changes were skipped. Partially based on https://bugzilla.mozilla.org/show_bug.cgi?id=1724645
This commit is contained in:
parent
23519e0c22
commit
3b57ba1415
8 changed files with 197 additions and 19 deletions
|
|
@ -659,6 +659,12 @@ DOMInterfaces = {
|
|||
'wrapperCache': False
|
||||
},
|
||||
|
||||
'Performance' : {
|
||||
'implicitJSContext': [
|
||||
'mark'
|
||||
],
|
||||
},
|
||||
|
||||
'Plugin': {
|
||||
'headerFile' : 'nsPluginArray.h',
|
||||
'nativeType': 'nsPluginElement',
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue