Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2023-10-03 22:04:58 +08:00
commit 35ff27f838
8 changed files with 87 additions and 43 deletions

View file

@ -12703,41 +12703,22 @@ nsGlobalWindow::SetTimeout(JSContext* aCx, const nsAString& aHandler,
return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aError); return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aError);
} }
static bool
IsInterval(const Optional<int32_t>& aTimeout, int32_t& aResultTimeout)
{
if (aTimeout.WasPassed()) {
aResultTimeout = aTimeout.Value();
return true;
}
// If no interval was specified, treat this like a timeout, to avoid setting
// an interval of 0 milliseconds.
aResultTimeout = 0;
return false;
}
int32_t int32_t
nsGlobalWindow::SetInterval(JSContext* aCx, Function& aFunction, nsGlobalWindow::SetInterval(JSContext* aCx, Function& aFunction,
const Optional<int32_t>& aTimeout, const int32_t aTimeout,
const Sequence<JS::Value>& aArguments, const Sequence<JS::Value>& aArguments,
ErrorResult& aError) ErrorResult& aError)
{ {
int32_t timeout; return SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments, true, aError);
bool isInterval = IsInterval(aTimeout, timeout);
return SetTimeoutOrInterval(aCx, aFunction, timeout, aArguments, isInterval,
aError);
} }
int32_t int32_t
nsGlobalWindow::SetInterval(JSContext* aCx, const nsAString& aHandler, nsGlobalWindow::SetInterval(JSContext* aCx, const nsAString& aHandler,
const Optional<int32_t>& aTimeout, const int32_t aTimeout,
const Sequence<JS::Value>& /* unused */, const Sequence<JS::Value>& /* unused */,
ErrorResult& aError) ErrorResult& aError)
{ {
int32_t timeout; return SetTimeoutOrInterval(aCx, aHandler, aTimeout, true, aError);
bool isInterval = IsInterval(aTimeout, timeout);
return SetTimeoutOrInterval(aCx, aHandler, timeout, isInterval, aError);
} }
nsresult nsresult

View file

@ -953,11 +953,11 @@ public:
mozilla::ErrorResult& aError); mozilla::ErrorResult& aError);
void ClearTimeout(int32_t aHandle); void ClearTimeout(int32_t aHandle);
int32_t SetInterval(JSContext* aCx, mozilla::dom::Function& aFunction, int32_t SetInterval(JSContext* aCx, mozilla::dom::Function& aFunction,
const mozilla::dom::Optional<int32_t>& aTimeout, const int32_t aTimeout,
const mozilla::dom::Sequence<JS::Value>& aArguments, const mozilla::dom::Sequence<JS::Value>& aArguments,
mozilla::ErrorResult& aError); mozilla::ErrorResult& aError);
int32_t SetInterval(JSContext* aCx, const nsAString& aHandler, int32_t SetInterval(JSContext* aCx, const nsAString& aHandler,
const mozilla::dom::Optional<int32_t>& aTimeout, const int32_t aTimeout,
const mozilla::dom::Sequence<JS::Value>& /* unused */, const mozilla::dom::Sequence<JS::Value>& /* unused */,
mozilla::ErrorResult& aError); mozilla::ErrorResult& aError);
void ClearInterval(int32_t aHandle); void ClearInterval(int32_t aHandle);

View file

@ -31,9 +31,9 @@ interface WindowOrWorkerGlobalScope {
long setTimeout(DOMString handler, optional long timeout = 0, any... unused); long setTimeout(DOMString handler, optional long timeout = 0, any... unused);
void clearTimeout(optional long handle = 0); void clearTimeout(optional long handle = 0);
[Throws] [Throws]
long setInterval(Function handler, optional long timeout, any... arguments); long setInterval(Function handler, optional long timeout = 0, any... arguments);
[Throws] [Throws]
long setInterval(DOMString handler, optional long timeout, any... unused); long setInterval(DOMString handler, optional long timeout = 0, any... unused);
void clearInterval(optional long handle = 0); void clearInterval(optional long handle = 0);
// microtask queuing // microtask queuing

View file

@ -167,6 +167,9 @@ const nsIID kDEBUGWorkerEventTargetIID = {
#endif #endif
// The number of nested timeouts before we start clamping. HTML says 5.
const uint32_t kClampTimeoutNestingLevel = 5u;
template <class T> template <class T>
class AutoPtrComparator class AutoPtrComparator
{ {
@ -1956,7 +1959,11 @@ NS_IMPL_QUERY_INTERFACE(WorkerLoadInfo::InterfaceRequestor, nsIInterfaceRequesto
struct WorkerPrivate::TimeoutInfo struct WorkerPrivate::TimeoutInfo
{ {
TimeoutInfo() TimeoutInfo()
: mId(0), mIsInterval(false), mCanceled(false) : mId(0)
, mNestingLevel(0)
, mIsInterval(false)
, mCanceled(false)
, mOnChromeWorker(false)
{ {
MOZ_COUNT_CTOR(mozilla::dom::workers::WorkerPrivate::TimeoutInfo); MOZ_COUNT_CTOR(mozilla::dom::workers::WorkerPrivate::TimeoutInfo);
} }
@ -1976,12 +1983,33 @@ struct WorkerPrivate::TimeoutInfo
return mTargetTime < aOther.mTargetTime; return mTargetTime < aOther.mTargetTime;
} }
void AccumulateNestingLevel(const uint32_t& aBaseLevel) {
if (aBaseLevel < kClampTimeoutNestingLevel) {
mNestingLevel = aBaseLevel + 1;
return;
}
mNestingLevel = kClampTimeoutNestingLevel;
}
void CalculateTargetTime() {
auto target = mInterval;
// Clamp timeout for workers, except chrome workers
if (mNestingLevel >= kClampTimeoutNestingLevel && !mOnChromeWorker) {
target = TimeDuration::Max(
mInterval,
TimeDuration::FromMilliseconds(Preferences::GetInt("dom.min_timeout_value")));
}
mTargetTime = TimeStamp::Now() + target;
}
nsCOMPtr<nsIScriptTimeoutHandler> mHandler; nsCOMPtr<nsIScriptTimeoutHandler> mHandler;
mozilla::TimeStamp mTargetTime; mozilla::TimeStamp mTargetTime;
mozilla::TimeDuration mInterval; mozilla::TimeDuration mInterval;
int32_t mId; int32_t mId;
uint32_t mNestingLevel;
bool mIsInterval; bool mIsInterval;
bool mCanceled; bool mCanceled;
bool mOnChromeWorker;
}; };
class WorkerJSContextStats final : public JS::RuntimeStats class WorkerJSContextStats final : public JS::RuntimeStats
@ -4130,6 +4158,7 @@ WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
, mMainThreadEventTarget(do_GetMainThread()) , mMainThreadEventTarget(do_GetMainThread())
, mErrorHandlerRecursionCount(0) , mErrorHandlerRecursionCount(0)
, mNextTimeoutId(1) , mNextTimeoutId(1)
, mCurrentTimerNestingLevel(0)
, mStatus(Pending) , mStatus(Pending)
, mFrozen(false) , mFrozen(false)
, mTimerRunning(false) , mTimerRunning(false)
@ -6074,8 +6103,10 @@ WorkerPrivate::SetTimeout(JSContext* aCx,
} }
nsAutoPtr<TimeoutInfo> newInfo(new TimeoutInfo()); nsAutoPtr<TimeoutInfo> newInfo(new TimeoutInfo());
newInfo->mOnChromeWorker = mIsChromeWorker;
newInfo->mIsInterval = aIsInterval; newInfo->mIsInterval = aIsInterval;
newInfo->mId = timerId; newInfo->mId = timerId;
newInfo->AccumulateNestingLevel(this->mCurrentTimerNestingLevel);
if (MOZ_UNLIKELY(timerId == INT32_MAX)) { if (MOZ_UNLIKELY(timerId == INT32_MAX)) {
NS_WARNING("Timeout ids overflowed!"); NS_WARNING("Timeout ids overflowed!");
@ -6188,14 +6219,21 @@ WorkerPrivate::RunExpiredTimeouts(JSContext* aCx)
// Guard against recursion. // Guard against recursion.
mRunningExpiredTimeouts = true; mRunningExpiredTimeouts = true;
MOZ_DIAGNOSTIC_ASSERT(data->mCurrentTimerNestingLevel == 0);
// Run expired timeouts. // Run expired timeouts.
for (uint32_t index = 0; index < expiredTimeouts.Length(); index++) { for (uint32_t index = 0; index < expiredTimeouts.Length(); index++) {
TimeoutInfo*& info = expiredTimeouts[index]; TimeoutInfo*& info = expiredTimeouts[index];
AutoRestore<uint32_t> nestingLevel(this->mCurrentTimerNestingLevel);
if (info->mCanceled) { if (info->mCanceled) {
continue; continue;
} }
// Set current timer nesting level to current running timer handler's
// nesting level
this->mCurrentTimerNestingLevel = info->mNestingLevel;
LOG(TimeoutsLog(), ("Worker %p executing timeout with original delay %f ms.\n", LOG(TimeoutsLog(), ("Worker %p executing timeout with original delay %f ms.\n",
this, info->mInterval.ToMilliseconds())); this, info->mInterval.ToMilliseconds()));
@ -6273,8 +6311,10 @@ WorkerPrivate::RunExpiredTimeouts(JSContext* aCx)
info->mCanceled) { info->mCanceled) {
if (info->mIsInterval && !info->mCanceled) { if (info->mIsInterval && !info->mCanceled) {
// Reschedule intervals. // Reschedule intervals.
info->mTargetTime = info->mTargetTime + info->mInterval; // Reschedule a timeout and, if needed, increase the nesting level.
// Don't resort the list here, we'll do that at the end. info->AccumulateNestingLevel(info->mNestingLevel);
info->CalculateTargetTime();
// Don't re-sort the list here, we'll do that at the end.
++index; ++index;
} }
else { else {

View file

@ -17,6 +17,7 @@
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/CondVar.h" #include "mozilla/CondVar.h"
#include "mozilla/ConsoleReportCollector.h" #include "mozilla/ConsoleReportCollector.h"
#include "mozilla/DOMEventTargetHelper.h" #include "mozilla/DOMEventTargetHelper.h"
@ -212,6 +213,9 @@ protected:
RefPtr<EventTarget> mEventTarget; RefPtr<EventTarget> mEventTarget;
nsTArray<RefPtr<WorkerRunnable>> mPreStartRunnables; nsTArray<RefPtr<WorkerRunnable>> mPreStartRunnables;
// True if the worker is used in the UI
bool mIsChromeWorker;
private: private:
WorkerPrivate* mParent; WorkerPrivate* mParent;
nsString mScriptURL; nsString mScriptURL;
@ -241,7 +245,6 @@ private:
uint32_t mParentWindowPausedDepth; uint32_t mParentWindowPausedDepth;
Status mParentStatus; Status mParentStatus;
bool mParentFrozen; bool mParentFrozen;
bool mIsChromeWorker;
bool mMainThreadObjectsForgotten; bool mMainThreadObjectsForgotten;
// mIsSecureContext is set once in our constructor; after that it can be read // mIsSecureContext is set once in our constructor; after that it can be read
// from various threads. We could make this const if we were OK with setting // from various threads. We could make this const if we were OK with setting
@ -1016,6 +1019,20 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
uint32_t mErrorHandlerRecursionCount; uint32_t mErrorHandlerRecursionCount;
uint32_t mNextTimeoutId; uint32_t mNextTimeoutId;
Status mStatus; Status mStatus;
// Tracks the current setTimeout/setInterval nesting level.
// When there isn't a TimeoutHandler on the stack, this will be 0.
// Whenever setTimeout/setInterval are called, a new TimeoutInfo will be
// created with a nesting level one more than the current nesting level,
// saturating at the kClampTimeoutNestingLevel.
//
// When RunExpiredTimeouts is run, it sets this value to the
// TimeoutInfo::mNestingLevel for the duration of
// the WorkerScriptTimeoutHandler::Call which will explicitly trigger a
// microtask checkpoint so that any immediately-resolved promises will
// still see the nesting level.
uint32_t mCurrentTimerNestingLevel;
bool mFrozen; bool mFrozen;
bool mTimerRunning; bool mTimerRunning;
bool mRunningExpiredTimeouts; bool mRunningExpiredTimeouts;

View file

@ -299,28 +299,25 @@ WorkerGlobalScope::ClearTimeout(int32_t aHandle)
int32_t int32_t
WorkerGlobalScope::SetInterval(JSContext* aCx, WorkerGlobalScope::SetInterval(JSContext* aCx,
Function& aHandler, Function& aHandler,
const Optional<int32_t>& aTimeout, const int32_t aTimeout,
const Sequence<JS::Value>& aArguments, const Sequence<JS::Value>& aArguments,
ErrorResult& aRv) ErrorResult& aRv)
{ {
mWorkerPrivate->AssertIsOnWorkerThread(); mWorkerPrivate->AssertIsOnWorkerThread();
bool isInterval = aTimeout.WasPassed();
int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0;
nsCOMPtr<nsIScriptTimeoutHandler> handler = nsCOMPtr<nsIScriptTimeoutHandler> handler =
NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aArguments, aRv); NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aArguments, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return 0; return 0;
} }
return mWorkerPrivate->SetTimeout(aCx, handler, timeout, isInterval, aRv); return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, true, aRv);
} }
int32_t int32_t
WorkerGlobalScope::SetInterval(JSContext* aCx, WorkerGlobalScope::SetInterval(JSContext* aCx,
const nsAString& aHandler, const nsAString& aHandler,
const Optional<int32_t>& aTimeout, const int32_t aTimeout,
const Sequence<JS::Value>& /* unused */, const Sequence<JS::Value>& /* unused */,
ErrorResult& aRv) ErrorResult& aRv)
{ {
@ -328,12 +325,9 @@ WorkerGlobalScope::SetInterval(JSContext* aCx,
Sequence<JS::Value> dummy; Sequence<JS::Value> dummy;
bool isInterval = aTimeout.WasPassed();
int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0;
nsCOMPtr<nsIScriptTimeoutHandler> handler = nsCOMPtr<nsIScriptTimeoutHandler> handler =
NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler); NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler);
return mWorkerPrivate->SetTimeout(aCx, handler, timeout, isInterval, aRv); return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, true, aRv);
} }
void void

View file

@ -132,11 +132,11 @@ public:
ClearTimeout(int32_t aHandle); ClearTimeout(int32_t aHandle);
int32_t int32_t
SetInterval(JSContext* aCx, Function& aHandler, SetInterval(JSContext* aCx, Function& aHandler,
const Optional<int32_t>& aTimeout, const int32_t aTimeout,
const Sequence<JS::Value>& aArguments, ErrorResult& aRv); const Sequence<JS::Value>& aArguments, ErrorResult& aRv);
int32_t int32_t
SetInterval(JSContext* aCx, const nsAString& aHandler, SetInterval(JSContext* aCx, const nsAString& aHandler,
const Optional<int32_t>& aTimeout, const int32_t aTimeout,
const Sequence<JS::Value>& /* unused */, ErrorResult& aRv); const Sequence<JS::Value>& /* unused */, ErrorResult& aRv);
void void
ClearInterval(int32_t aHandle); ClearInterval(int32_t aHandle);

View file

@ -7,6 +7,7 @@
#define mozilla_TimeStamp_h #define mozilla_TimeStamp_h
#include <stdint.h> #include <stdint.h>
#include <algorithm> // for std::min, std::max
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h" #include "mozilla/FloatingPoint.h"
@ -173,6 +174,17 @@ public:
return FromTicks(ticks); return FromTicks(ticks);
} }
static BaseTimeDuration Max(const BaseTimeDuration& aA,
const BaseTimeDuration& aB)
{
return FromTicks(std::max(aA.mValue, aB.mValue));
}
static BaseTimeDuration Min(const BaseTimeDuration& aA,
const BaseTimeDuration& aB)
{
return FromTicks(std::min(aA.mValue, aB.mValue));
}
private: private:
// Block double multiplier (slower, imprecise if long duration) - Bug 853398. // Block double multiplier (slower, imprecise if long duration) - Bug 853398.