зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1267297 - Use AutoEntryScript for script activity bookkeeping instead of the request machinery. r=bholley
Differential Revision: https://phabricator.services.mozilla.com/D4085 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
56ca0b122a
Коммит
53f1370b5f
|
@ -662,8 +662,11 @@ AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
|||
{
|
||||
MOZ_ASSERT(aGlobalObject);
|
||||
|
||||
if (aIsMainThread && gRunToCompletionListeners > 0) {
|
||||
mDocShellEntryMonitor.emplace(cx(), aReason);
|
||||
if (aIsMainThread) {
|
||||
if (gRunToCompletionListeners > 0) {
|
||||
mDocShellEntryMonitor.emplace(cx(), aReason);
|
||||
}
|
||||
mScriptActivity.emplace(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -815,11 +818,12 @@ AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMP
|
|||
}
|
||||
|
||||
AutoSlowOperation::AutoSlowOperation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
|
||||
: AutoJSAPI()
|
||||
: mIsMainThread(NS_IsMainThread())
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
Init();
|
||||
if (mIsMainThread) {
|
||||
mScriptActivity.emplace(true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -828,8 +832,10 @@ AutoSlowOperation::CheckForInterrupt()
|
|||
// For now we support only main thread!
|
||||
if (mIsMainThread) {
|
||||
// JS_CheckForInterrupt expects us to be in a realm.
|
||||
JSAutoRealm ar(cx(), xpc::UnprivilegedJunkScope());
|
||||
JS_CheckForInterrupt(cx());
|
||||
AutoJSAPI jsapi;
|
||||
if (jsapi.Init(xpc::UnprivilegedJunkScope())) {
|
||||
JS_CheckForInterrupt(jsapi.cx());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "MainThreadUtils.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
|
@ -383,6 +384,7 @@ private:
|
|||
friend nsIPrincipal* GetWebIDLCallerPrincipal();
|
||||
|
||||
Maybe<DocshellEntryMonitor> mDocShellEntryMonitor;
|
||||
Maybe<xpc::AutoScriptActivity> mScriptActivity;
|
||||
JS::AutoHideScriptedCaller mCallerOverride;
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
AutoProfilerLabel mAutoProfilerLabel;
|
||||
|
@ -455,17 +457,21 @@ private:
|
|||
* Use AutoSlowOperation when native side calls many JS callbacks in a row
|
||||
* and slow script dialog should be activated if too much time is spent going
|
||||
* through those callbacks.
|
||||
* AutoSlowOperation puts a JSAutoRequest on the stack so that we don't continue
|
||||
* to reset the watchdog and CheckForInterrupt can be then used to check whether
|
||||
* JS execution should be interrupted.
|
||||
* AutoSlowOperation puts an AutoScriptActivity on the stack so that we don't
|
||||
* continue to reset the watchdog. CheckForInterrupt can then be used to check
|
||||
* whether JS execution should be interrupted.
|
||||
* This class (including CheckForInterrupt) is a no-op when used off the main
|
||||
* thread.
|
||||
*/
|
||||
class MOZ_RAII AutoSlowOperation : public dom::AutoJSAPI
|
||||
class MOZ_RAII AutoSlowOperation
|
||||
{
|
||||
public:
|
||||
explicit AutoSlowOperation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
void CheckForInterrupt();
|
||||
private:
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
bool mIsMainThread;
|
||||
Maybe<xpc::AutoScriptActivity> mScriptActivity;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -551,28 +551,49 @@ XPCJSContext::GetWatchdogTimestamp(WatchdogTimestampCategory aCategory)
|
|||
mWatchdogManager->GetTimestamp(aCategory, lock);
|
||||
}
|
||||
|
||||
void
|
||||
xpc::SimulateActivityCallback(bool aActive)
|
||||
{
|
||||
XPCJSContext::ActivityCallback(XPCJSContext::Get(), aActive);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
XPCJSContext::ActivityCallback(void* arg, bool active)
|
||||
bool
|
||||
XPCJSContext::RecordScriptActivity(bool aActive)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
XPCJSContext* xpccx = XPCJSContext::Get();
|
||||
if (!xpccx) {
|
||||
// mozilla::SpinEventLoopUntil may use AutoScriptActivity(false) after
|
||||
// we destroyed the XPCJSContext.
|
||||
MOZ_ASSERT(!aActive);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool oldValue = xpccx->SetHasScriptActivity(aActive);
|
||||
if (aActive == oldValue) {
|
||||
// Nothing to do.
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
// Since the slow script dialog never activates if we are recording or
|
||||
// replaying, don't record/replay JS activity notifications.
|
||||
if (recordreplay::IsRecordingOrReplaying()) {
|
||||
return;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
if (!active) {
|
||||
if (!aActive) {
|
||||
ProcessHangMonitor::ClearHang();
|
||||
}
|
||||
xpccx->mWatchdogManager->RecordContextActivity(xpccx, aActive);
|
||||
|
||||
XPCJSContext* self = static_cast<XPCJSContext*>(arg);
|
||||
self->mWatchdogManager->RecordContextActivity(self, active);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
AutoScriptActivity::AutoScriptActivity(bool aActive)
|
||||
: mActive(aActive)
|
||||
, mOldValue(XPCJSContext::RecordScriptActivity(aActive))
|
||||
{
|
||||
}
|
||||
|
||||
AutoScriptActivity::~AutoScriptActivity()
|
||||
{
|
||||
MOZ_ALWAYS_TRUE(mActive == XPCJSContext::RecordScriptActivity(mOldValue));
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -890,8 +911,6 @@ XPCJSContext::~XPCJSContext()
|
|||
Preferences::UnregisterCallback(ReloadPrefsCallback, "fuzzing.enabled", this);
|
||||
#endif
|
||||
|
||||
js::SetActivityCallback(Context(), nullptr, nullptr);
|
||||
|
||||
// Clear any pending exception. It might be an XPCWrappedJS, and if we try
|
||||
// to destroy it later we will crash.
|
||||
SetPendingException(nullptr);
|
||||
|
@ -926,6 +945,7 @@ XPCJSContext::XPCJSContext()
|
|||
mWatchdogManager(GetWatchdogManager()),
|
||||
mSlowScriptSecondHalf(false),
|
||||
mTimeoutAccumulated(false),
|
||||
mHasScriptActivity(false),
|
||||
mPendingResult(NS_OK),
|
||||
mActive(CONTEXT_INACTIVE),
|
||||
mLastStateChange(PR_Now())
|
||||
|
@ -1140,7 +1160,6 @@ XPCJSContext::Initialize(XPCJSContext* aPrimaryContext)
|
|||
|
||||
PROFILER_SET_JS_CONTEXT(cx);
|
||||
|
||||
js::SetActivityCallback(cx, ActivityCallback, this);
|
||||
JS_AddInterruptCallback(cx, InterruptCallback);
|
||||
|
||||
if (!aPrimaryContext) {
|
||||
|
|
|
@ -590,15 +590,21 @@ SetInterruptCallback(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
static bool
|
||||
SimulateActivityCallback(JSContext* cx, unsigned argc, Value* vp)
|
||||
SimulateNoScriptActivity(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
// Sanity-check args.
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 1 || !args[0].isBoolean()) {
|
||||
JS_ReportErrorASCII(cx, "Wrong number of arguments");
|
||||
if (args.length() != 1 || !args[0].isInt32() || args[0].toInt32() < 0) {
|
||||
JS_ReportErrorASCII(cx, "Expected a positive integer argument");
|
||||
return false;
|
||||
}
|
||||
xpc::SimulateActivityCallback(args[0].toBoolean());
|
||||
|
||||
// This mimics mozilla::SpinEventLoopUntil but instead of spinning the
|
||||
// event loop we sleep, to make sure we don't run script.
|
||||
xpc::AutoScriptActivity asa(false);
|
||||
PR_Sleep(PR_SecondsToInterval(args[0].toInt32()));
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -665,7 +671,7 @@ static const JSFunctionSpec glob_functions[] = {
|
|||
JS_FN("atob", xpc::Atob, 1,0),
|
||||
JS_FN("btoa", xpc::Btoa, 1,0),
|
||||
JS_FN("setInterruptCallback", SetInterruptCallback, 1,0),
|
||||
JS_FN("simulateActivityCallback", SimulateActivityCallback, 1,0),
|
||||
JS_FN("simulateNoScriptActivity", SimulateNoScriptActivity, 1,0),
|
||||
JS_FN("registerAppManifest", RegisterAppManifest, 1, 0),
|
||||
#ifdef ENABLE_TESTS
|
||||
JS_FN("registerXPCTestComponents", RegisterXPCTestComponents, 0, 0),
|
||||
|
|
|
@ -373,7 +373,14 @@ public:
|
|||
|
||||
PRTime GetWatchdogTimestamp(WatchdogTimestampCategory aCategory);
|
||||
|
||||
static void ActivityCallback(void* arg, bool active);
|
||||
static bool RecordScriptActivity(bool aActive);
|
||||
|
||||
bool SetHasScriptActivity(bool aActive) {
|
||||
bool oldValue = mHasScriptActivity;
|
||||
mHasScriptActivity = aActive;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
static bool InterruptCallback(JSContext* cx);
|
||||
|
||||
// Mapping of often used strings to jsid atoms that live 'forever'.
|
||||
|
@ -461,6 +468,8 @@ private:
|
|||
mozilla::TimeDuration mSlowScriptActualWait;
|
||||
bool mTimeoutAccumulated;
|
||||
|
||||
bool mHasScriptActivity;
|
||||
|
||||
// mPendingResult is used to implement Components.returnCode. Only really
|
||||
// meaningful while calling through XPCWrappedJS.
|
||||
nsresult mPendingResult;
|
||||
|
|
|
@ -550,8 +550,14 @@ WindowGlobalOrNull(JSObject* aObj);
|
|||
nsGlobalWindowInner*
|
||||
CurrentWindowOrNull(JSContext* cx);
|
||||
|
||||
void
|
||||
SimulateActivityCallback(bool aActive);
|
||||
class MOZ_RAII AutoScriptActivity
|
||||
{
|
||||
bool mActive;
|
||||
bool mOldValue;
|
||||
public:
|
||||
explicit AutoScriptActivity(bool aActive);
|
||||
~AutoScriptActivity();
|
||||
};
|
||||
|
||||
// This function may be used off-main-thread, in which case it is benignly
|
||||
// racey.
|
||||
|
|
|
@ -23,13 +23,11 @@ async function testBody() {
|
|||
// scheduling, we should never have more than 3 seconds of inactivity without
|
||||
// hibernating. To add some padding for automation, we mandate that hibernation
|
||||
// must begin between 2 and 5 seconds from now.
|
||||
await new Promise(resolve => {
|
||||
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(resolve, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
simulateActivityCallback(false);
|
||||
});
|
||||
|
||||
simulateActivityCallback(true);
|
||||
// Sleep for 10 seconds. Note: we don't use nsITimer here because then we may run
|
||||
// arbitrary (idle) events involving script before it fires.
|
||||
simulateNoScriptActivity(10);
|
||||
|
||||
busyWait(1000); // Give the watchdog time to wake up on the condvar.
|
||||
var stateChange = Cu.getWatchdogTimestamp("ContextStateChange");
|
||||
startHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStart");
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Tuple.h"
|
||||
|
@ -320,6 +322,14 @@ SpinEventLoopUntil(Pred&& aPredicate, nsIThread* aThread = nullptr)
|
|||
{
|
||||
nsIThread* thread = aThread ? aThread : NS_GetCurrentThread();
|
||||
|
||||
// From a latency perspective, spinning the event loop is like leaving script
|
||||
// and returning to the event loop. Tell the watchdog we stopped running
|
||||
// script (until we return).
|
||||
mozilla::Maybe<xpc::AutoScriptActivity> asa;
|
||||
if (NS_IsMainThread()) {
|
||||
asa.emplace(false);
|
||||
}
|
||||
|
||||
while (!aPredicate()) {
|
||||
bool didSomething = NS_ProcessNextEvent(thread, true);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче