Bug 1560931 - Set JS engine low memory state based on memory pressure notifications r=smaug

Update the memory pressure observers for main thread and workers to call the new JS API to set/clear the low memory state.

Differential Revision: https://phabricator.services.mozilla.com/D35682
This commit is contained in:
Jon Coppeard 2019-06-24 18:24:47 +01:00
parent ca04a00e08
commit 22952620f8
7 changed files with 79 additions and 7 deletions

View File

@ -332,12 +332,15 @@ nsJSEnvironmentObserver::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
if (!nsCRT::strcmp(aTopic, "memory-pressure")) {
if (StaticPrefs::javascript_options_gc_on_memory_pressure()) {
if (StringBeginsWith(nsDependentString(aData),
NS_LITERAL_STRING("low-memory-ongoing"))) {
nsDependentString data(aData);
if (data.EqualsLiteral("low-memory-ongoing")) {
// Don't GC/CC if we are in an ongoing low-memory state since its very
// slow and it likely won't help us anyway.
return NS_OK;
}
if (data.EqualsLiteral("low-memory")) {
nsJSContext::SetLowMemoryState(true);
}
nsJSContext::GarbageCollectNow(JS::GCReason::MEM_PRESSURE,
nsJSContext::NonIncrementalGC,
nsJSContext::ShrinkingGC);
@ -348,6 +351,8 @@ nsJSEnvironmentObserver::Observe(nsISupports* aSubject, const char* aTopic,
nsJSContext::ShrinkingGC);
}
}
} else if (!nsCRT::strcmp(aTopic, "memory-pressure-stop")) {
nsJSContext::SetLowMemoryState(false);
} else if (!nsCRT::strcmp(aTopic, "user-interaction-inactive")) {
if (StaticPrefs::javascript_options_compact_on_user_inactive()) {
nsJSContext::PokeShrinkingGC();
@ -1080,6 +1085,12 @@ void FullGCTimerFired(nsITimer* aTimer, void* aClosure) {
nsJSContext::IncrementalGC);
}
// static
void nsJSContext::SetLowMemoryState(bool aState) {
JSContext* cx = danger::GetJSContext();
JS::SetLowMemoryState(cx, aState);
}
// static
void nsJSContext::GarbageCollectNow(JS::GCReason aReason,
IsIncremental aIncremental,

View File

@ -66,6 +66,8 @@ class nsJSContext : public nsIScriptContext {
// Setup all the statics etc - safe to call multiple times after Startup().
static void EnsureStatics();
static void SetLowMemoryState(bool aState);
static void GarbageCollectNow(JS::GCReason reason,
IsIncremental aIncremental = NonIncrementalGC,
IsShrinking aShrinking = NonShrinkingGC,

View File

@ -139,7 +139,9 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 1,
#define GC_REQUEST_OBSERVER_TOPIC "child-gc-request"
#define CC_REQUEST_OBSERVER_TOPIC "child-cc-request"
#define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
#define MEMORY_PRESSURE_ONGOING_DATA "low-memory-ongoing"
#define LOW_MEMORY_DATA "low-memory"
#define LOW_MEMORY_ONGOING_DATA "low-memory-ongoing"
#define MEMORY_PRESSURE_STOP_OBSERVER_TOPIC "memory-pressure-stop"
#define BROADCAST_ALL_WORKERS(_func, ...) \
PR_BEGIN_MACRO \
@ -2121,6 +2123,10 @@ void RuntimeService::UpdateAllWorkerGCZeal() {
}
#endif
void RuntimeService::SetLowMemoryStateAllWorkers(bool aState) {
BROADCAST_ALL_WORKERS(SetLowMemoryState, aState);
}
void RuntimeService::GarbageCollectAllWorkers(bool aShrinking) {
BROADCAST_ALL_WORKERS(GarbageCollect, aShrinking);
}
@ -2200,13 +2206,22 @@ RuntimeService::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK;
}
if (!strcmp(aTopic, MEMORY_PRESSURE_OBSERVER_TOPIC)) {
nsDependentString data(aData);
// Don't continue to GC/CC if we are in an ongoing low-memory state since
// its very slow and it likely won't help us anyway.
if (!nsDependentString(aData).EqualsLiteral(MEMORY_PRESSURE_ONGOING_DATA)) {
GarbageCollectAllWorkers(/* shrinking = */ true);
CycleCollectAllWorkers();
MemoryPressureAllWorkers();
if (data.EqualsLiteral(LOW_MEMORY_ONGOING_DATA)) {
return NS_OK;
}
if (data.EqualsLiteral(LOW_MEMORY_DATA)) {
SetLowMemoryStateAllWorkers(true);
}
GarbageCollectAllWorkers(/* shrinking = */ true);
CycleCollectAllWorkers();
MemoryPressureAllWorkers();
return NS_OK;
}
if (!strcmp(aTopic, MEMORY_PRESSURE_STOP_OBSERVER_TOPIC)) {
SetLowMemoryStateAllWorkers(false);
return NS_OK;
}
if (!strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {

View File

@ -158,6 +158,8 @@ class RuntimeService final : public nsIObserver {
void UpdateAllWorkerGCZeal();
#endif
void SetLowMemoryStateAllWorkers(bool aState);
void GarbageCollectAllWorkers(bool aShrinking);
void CycleCollectAllWorkers();

View File

@ -696,6 +696,22 @@ class UpdateGCZealRunnable final : public WorkerControlRunnable {
};
#endif
class SetLowMemoryStateRunnable final : public WorkerControlRunnable {
bool mState;
public:
SetLowMemoryStateRunnable(WorkerPrivate* aWorkerPrivate, bool aState)
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
mState(aState) {}
private:
virtual bool WorkerRun(JSContext* aCx,
WorkerPrivate* aWorkerPrivate) override {
aWorkerPrivate->SetLowMemoryStateInternal(aCx, mState);
return true;
}
};
class GarbageCollectRunnable final : public WorkerControlRunnable {
bool mShrinking;
bool mCollectChildren;
@ -1819,6 +1835,16 @@ void WorkerPrivate::UpdateGCZeal(uint8_t aGCZeal, uint32_t aFrequency) {
}
#endif
void WorkerPrivate::SetLowMemoryState(bool aState) {
AssertIsOnParentThread();
RefPtr<SetLowMemoryStateRunnable> runnable =
new SetLowMemoryStateRunnable(this, aState);
if (!runnable->Dispatch()) {
NS_WARNING("Failed to set low memory state!");
}
}
void WorkerPrivate::GarbageCollect(bool aShrinking) {
AssertIsOnParentThread();
@ -4502,6 +4528,16 @@ void WorkerPrivate::UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal,
}
#endif
void WorkerPrivate::SetLowMemoryStateInternal(JSContext* aCx, bool aState) {
MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible, data);
JS::SetLowMemoryState(aCx, aState);
for (uint32_t index = 0; index < data->mChildWorkers.Length(); index++) {
data->mChildWorkers[index]->SetLowMemoryState(aState);
}
}
void WorkerPrivate::GarbageCollectInternal(JSContext* aCx, bool aShrinking,
bool aCollectChildren) {
MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible, data);

View File

@ -278,6 +278,8 @@ class WorkerPrivate : public RelativeTimeline {
uint32_t aFrequency);
#endif
void SetLowMemoryStateInternal(JSContext* aCx, bool aState);
void GarbageCollectInternal(JSContext* aCx, bool aShrinking,
bool aCollectChildren);
@ -803,6 +805,8 @@ class WorkerPrivate : public RelativeTimeline {
bool ProxyReleaseMainThreadObjects();
void SetLowMemoryState(bool aState);
void GarbageCollect(bool aShrinking);
void CycleCollect(bool aDummy);

View File

@ -922,6 +922,8 @@ class JS_PUBLIC_API AutoCheckCannotGC : public AutoRequireNoGC {
} JS_HAZ_GC_INVALIDATED;
#endif
extern JS_PUBLIC_API void SetLowMemoryState(JSContext* cx, bool newState);
/*
* Internal to Firefox.
*/