Refactor PerformanceObserver to use hash tables for entry type validation and improve ThrottleInputStream state management

This commit is contained in:
wuggy 2026-04-26 11:13:27 -07:00
commit a2a4c62a9b
4 changed files with 55 additions and 12 deletions

View file

@ -10,9 +10,11 @@
#include "mozilla/dom/PerformanceEntryBinding.h" #include "mozilla/dom/PerformanceEntryBinding.h"
#include "mozilla/dom/PerformanceObserverBinding.h" #include "mozilla/dom/PerformanceObserverBinding.h"
#include "nsIScriptError.h" #include "nsIScriptError.h"
#include "nsHashKeys.h"
#include "nsPIDOMWindow.h" #include "nsPIDOMWindow.h"
#include "nsQueryObject.h" #include "nsQueryObject.h"
#include "nsString.h" #include "nsString.h"
#include "nsTHashtable.h"
#include "PerformanceEntry.h" #include "PerformanceEntry.h"
#include "PerformanceObserverEntryList.h" #include "PerformanceObserverEntryList.h"
#include "WorkerPrivate.h" #include "WorkerPrivate.h"
@ -225,19 +227,28 @@ void PerformanceObserver::Observe(const PerformanceObserverInit& aOptions,
} }
/* 3.3.1.5.2 */ /* 3.3.1.5.2 */
nsTHashtable<nsStringHashKey> requestedTypes(entryTypes.Length());
for (const auto& type : entryTypes) {
requestedTypes.PutEntry(type);
}
nsTArray<nsString> validEntryTypes; nsTArray<nsString> validEntryTypes;
for (const char16_t* name : sValidTypeNames) { for (const char16_t* name : sValidTypeNames) {
nsDependentString validTypeName(name); nsDependentString validTypeName(name);
if (entryTypes.Contains<nsString>(validTypeName) && if (requestedTypes.GetEntry(validTypeName)) {
!validEntryTypes.Contains<nsString>(validTypeName)) {
validEntryTypes.AppendElement(validTypeName); validEntryTypes.AppendElement(validTypeName);
} }
} }
nsTHashtable<nsStringHashKey> validTypeSet(validEntryTypes.Length());
for (const auto& validType : validEntryTypes) {
validTypeSet.PutEntry(validType);
}
nsAutoString invalidTypesJoined; nsAutoString invalidTypesJoined;
bool addComma = false; bool addComma = false;
for (const auto& type : entryTypes) { for (const auto& type : entryTypes) {
if (!validEntryTypes.Contains<nsString>(type)) { if (!validTypeSet.GetEntry(type)) {
if (addComma) { if (addComma) {
invalidTypesJoined.AppendLiteral(", "); invalidTypesJoined.AppendLiteral(", ");
} }
@ -289,13 +300,13 @@ void PerformanceObserver::Observe(const PerformanceObserverInit& aOptions,
/* 3.3.1.6.4, 3.3.1.6.4 */ /* 3.3.1.6.4, 3.3.1.6.4 */
bool didUpdateOptionsList = false; bool didUpdateOptionsList = false;
nsTArray<PerformanceObserverInit> updatedOptionsList; nsTArray<PerformanceObserverInit> updatedOptionsList(mOptions.Length() + 1);
for (auto& option : mOptions) { for (auto& option : mOptions) {
if (option.mType.WasPassed() && option.mType.Value() == type) { if (option.mType.WasPassed() && option.mType.Value() == type) {
updatedOptionsList.AppendElement(aOptions); updatedOptionsList.AppendElement(aOptions);
didUpdateOptionsList = true; didUpdateOptionsList = true;
} else { } else {
updatedOptionsList.AppendElement(option); updatedOptionsList.AppendElement(Move(option));
} }
} }
if (!didUpdateOptionsList) { if (!didUpdateOptionsList) {

View file

@ -103,13 +103,23 @@ static LayerSortOrder CompareDepth(Layer* aOne, Layer* aTwo) {
// Could we just check Contains() on the bounds rects. ie, is it possible // Could we just check Contains() on the bounds rects. ie, is it possible
// for layers to overlap without intersections (in 2d space) and yet still // for layers to overlap without intersections (in 2d space) and yet still
// have their bounds rects not completely enclose each other? // have their bounds rects not completely enclose each other?
nsTArray<gfxPoint> points; AutoTArray<gfxPoint, 24> points;
auto appendUniquePoint = [&points](const gfxPoint& aPoint) {
static const gfxFloat kDuplicateEpsilon = 0.01;
for (const auto& point : points) {
if (fabs(point.x - aPoint.x) < kDuplicateEpsilon &&
fabs(point.y - aPoint.y) < kDuplicateEpsilon) {
return;
}
}
points.AppendElement(aPoint);
};
for (uint32_t i = 0; i < 4; i++) { for (uint32_t i = 0; i < 4; i++) {
if (ourTransformedRect.Contains(otherTransformedRect.mPoints[i])) { if (ourTransformedRect.Contains(otherTransformedRect.mPoints[i])) {
points.AppendElement(otherTransformedRect.mPoints[i]); appendUniquePoint(otherTransformedRect.mPoints[i]);
} }
if (otherTransformedRect.Contains(ourTransformedRect.mPoints[i])) { if (otherTransformedRect.Contains(ourTransformedRect.mPoints[i])) {
points.AppendElement(ourTransformedRect.mPoints[i]); appendUniquePoint(ourTransformedRect.mPoints[i]);
} }
} }
@ -123,7 +133,7 @@ static LayerSortOrder CompareDepth(Layer* aOne, Layer* aTwo) {
gfxLineSegment two(otherTransformedRect.mPoints[j], gfxLineSegment two(otherTransformedRect.mPoints[j],
otherTransformedRect.mPoints[(j + 1) % 4]); otherTransformedRect.mPoints[(j + 1) % 4]);
if (one.Intersects(two, intersection)) { if (one.Intersects(two, intersection)) {
points.AppendElement(intersection); appendUniquePoint(intersection);
} }
} }
} }

View file

@ -30,6 +30,8 @@ public:
NS_DECL_NSIASYNCINPUTSTREAM NS_DECL_NSIASYNCINPUTSTREAM
void AllowInput(); void AllowInput();
bool IsQueued() const;
void SetQueued(bool aQueued);
private: private:
@ -41,6 +43,7 @@ private:
nsCOMPtr<nsIInputStreamCallback> mCallback; nsCOMPtr<nsIInputStreamCallback> mCallback;
nsCOMPtr<nsIEventTarget> mEventTarget; nsCOMPtr<nsIEventTarget> mEventTarget;
bool mIsQueued;
}; };
NS_IMPL_ISUPPORTS(ThrottleInputStream, nsIAsyncInputStream, nsIInputStream, nsISeekableStream) NS_IMPL_ISUPPORTS(ThrottleInputStream, nsIAsyncInputStream, nsIInputStream, nsISeekableStream)
@ -49,6 +52,7 @@ ThrottleInputStream::ThrottleInputStream(nsIInputStream *aStream, ThrottleQueue*
: mStream(aStream) : mStream(aStream)
, mQueue(aQueue) , mQueue(aQueue)
, mClosedStatus(NS_OK) , mClosedStatus(NS_OK)
, mIsQueued(false)
{ {
MOZ_ASSERT(aQueue != nullptr); MOZ_ASSERT(aQueue != nullptr);
} }
@ -233,6 +237,18 @@ ThrottleInputStream::AllowInput()
callbackEvent->OnInputStreamReady(this); callbackEvent->OnInputStreamReady(this);
} }
bool
ThrottleInputStream::IsQueued() const
{
return mIsQueued;
}
void
ThrottleInputStream::SetQueued(bool aQueued)
{
mIsQueued = aQueued;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS(ThrottleQueue, nsIInputChannelThrottleQueue, nsITimerCallback) NS_IMPL_ISUPPORTS(ThrottleQueue, nsIInputChannelThrottleQueue, nsITimerCallback)
@ -348,6 +364,7 @@ ThrottleQueue::Notify(nsITimer* aTimer)
// Optimistically notify all the waiting readers, and then let them // Optimistically notify all the waiting readers, and then let them
// requeue if there isn't enough bandwidth. // requeue if there isn't enough bandwidth.
for (size_t i = 0; i < events.Length(); ++i) { for (size_t i = 0; i < events.Length(); ++i) {
events[i]->SetQueued(false);
events[i]->AllowInput(); events[i]->AllowInput();
} }
@ -359,7 +376,8 @@ void
ThrottleQueue::QueueStream(ThrottleInputStream* aStream) ThrottleQueue::QueueStream(ThrottleInputStream* aStream)
{ {
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
if (mAsyncEvents.IndexOf(aStream) == mAsyncEvents.NoIndex) { if (!aStream->IsQueued()) {
aStream->SetQueued(true);
mAsyncEvents.AppendElement(aStream); mAsyncEvents.AppendElement(aStream);
if (!mTimerArmed) { if (!mTimerArmed) {
@ -386,7 +404,12 @@ void
ThrottleQueue::DequeueStream(ThrottleInputStream* aStream) ThrottleQueue::DequeueStream(ThrottleInputStream* aStream)
{ {
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
if (!aStream->IsQueued()) {
return;
}
mAsyncEvents.RemoveElement(aStream); mAsyncEvents.RemoveElement(aStream);
aStream->SetQueued(false);
} }
} }

View file

@ -354,8 +354,7 @@ TimerThread::Shutdown()
// might potentially call some code reentering the same lock // might potentially call some code reentering the same lock
// that leads to unexpected behavior or deadlock. // that leads to unexpected behavior or deadlock.
// See bug 422472. // See bug 422472.
timers.AppendElements(mTimers); timers.SwapElements(mTimers);
mTimers.Clear();
} }
uint32_t timersCount = timers.Length(); uint32_t timersCount = timers.Length();