diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index abb2dbf6d..532375448 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -13,7 +13,6 @@ #include "jsgc.h" #include "gc/Heap.h" -#include "gc/IdleGC.h" #include "gc/Nursery.h" #include "gc/Statistics.h" #include "gc/StoreBuffer.h" @@ -651,13 +650,6 @@ class GCRuntime void onOutOfMallocMemory(); void onOutOfMallocMemory(const AutoLockGC& lock); - /* Idle-time GC notifications. */ - void notifyJSExecutionStart(); - void notifyJSExecutionEnd(); - IdleGCManager& idleGCMgr() { - return idleGC; - } - size_t maxMallocBytesAllocated() { return maxMallocBytes; } uint64_t nextCellUniqueId() { @@ -1027,9 +1019,6 @@ class GCRuntime GCSchedulingTunables tunables; GCSchedulingState schedulingState; - /* Idle-time garbage collection manager. */ - IdleGCManager idleGC; - MemProfiler mMemProfiler; private: diff --git a/js/src/gc/IdleGC.cpp b/js/src/gc/IdleGC.cpp deleted file mode 100644 index ac5c0d305..000000000 --- a/js/src/gc/IdleGC.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * IDLE-TIME GARBAGE COLLECTION SYSTEM - * - * Overview - * -------- - * This system implements idle-time-only garbage collection, deferring GC work - * to periods when the JavaScript engine is not actively processing code. - * This improves perceived responsiveness by avoiding GC pauses during critical - * execution windows. - * - * Architecture - * ----------- - * - * The system consists of several key components: - * - * 1. IdleGCManager (gc/IdleGC.h, gc/IdleGC.cpp) - * - Tracks when the JS engine is executing vs. idle - * - Maintains timestamp of last execution activity - * - Checks if sufficient idle time has passed - * - Configurable idle threshold (default: 100ms) - * - Can determine which GC reasons should bypass idle checks - * - * 2. GCRuntime Integration (gc/GCRuntime.h) - * - Contains an IdleGCManager instance - * - Provides public methods: notifyJSExecutionStart/End() - * - Modified checkIfGCAllowedInCurrentState() to check idle status - * - * 3. Activity Tracking (vm/Runtime.cpp) - * - triggerActivityCallback() now notifies IdleGCManager - * - Called when JS enters/exits request (execution boundary) - * - Updated in jsapi.cpp's StartRequest/StopRequest functions - * - * 4. Public API (jsapi.h, jsapi.cpp) - * - JS_SetIdleGCEnabled() / JS_IsIdleGCEnabled() - * - JS_SetIdleGCThreshold() / JS_GetIdleGCThreshold() - * - JS_GetIdleTimeSinceLastExecution() - * - Allows embedders to configure idle GC behavior - * - * Behavior - * -------- - * - * Normal GC Trigger (Idle GC Enabled): - * - * 1. JS code executes → notifyJSExecutionStart() called - * 2. JS code finishes → notifyJSExecutionEnd() called, timestamp recorded - * 3. GC needed → checkIfGCAllowedInCurrentState() checks idle status - * 4a. If idle >= threshold → GC proceeds normally - * 4b. If still executing/idle < threshold → GC is deferred - * 5. Once idle threshold is met, next GC request proceeds - * - * Critical GC Triggers (Always Proceed): - * - * The following GC reasons bypass idle checking: - * - OUT_OF_MEMORY: Memory pressure conditions - * - ALLOC_TRIGGER: Allocation threshold exceeded - * - MALLOC_PRESSURE: Malloc pressure from OS - * - EAGER_ALLOC_TRIGGER: Eager allocation trigger - * - API: Explicit JS API calls - * - DETERMINISTIC: Deterministic tests - * - EVICT_NURSERY: Nursery eviction - * - SHUTDOWN_CC, DESTROY_RUNTIME, LAST_DITCH: Shutdown GCs - * - DESTROY_ZONE, COMPARTMENT_REVOKED: Zone/compartment destruction - * - * Configuration - * ------------- - * - * Idle GC Enabled (default: true): - * - Enables idle-time-only GC mode - * - Can be toggled dynamically via JS_SetIdleGCEnabled() - * - * Idle Threshold (default: 100ms): - * - Minimum idle time before GC is permitted - * - Configurable via JS_SetIdleGCThreshold(ms) - * - Typical values: 50-200ms depending on application - * - * Integration Examples - * -------------------- - * - * Browser Integration: - * - * // When browser loads configuration - * JS_SetIdleGCEnabled(cx, true); - * JS_SetIdleGCThreshold(cx, 100); // 100ms idle threshold - * - * // Monitor idle GC effectiveness (optional) - * uint64_t idleTime = JS_GetIdleTimeSinceLastExecution(cx); - * if (idleTime > JS_GetIdleGCThreshold(cx)) { - * // System is idle, GC would be allowed if triggered - * } - * - * Disabling for Specific Scenarios: - * - * // During initialization when nothing is "idle" yet - * JS_SetIdleGCEnabled(cx, false); - * // ... do initial setup ... - * JS_SetIdleGCEnabled(cx, true); // Re-enable for normal operation - * - * Performance Considerations - * -------------------------- - * - * Benefits: - * - Reduced jank during active JS execution - * - GC pauses moved to idle periods where users won't notice - * - Especially effective for interactive applications - * - Improves Time-to-Interactive and First Input Delay metrics - * - * Tradeoffs: - * - May accumulate more garbage before collection - * - Requires predictable idle periods (not suitable for all workloads) - * - Critical memory pressure GCs still proceed immediately - * - * Tuning: - * - Lower threshold (50ms) = more frequent GC, less memory overhead - * - Higher threshold (200ms) = less GC overhead, more memory usage - * - Optimal value depends on application's execution pattern - * - * Testing - * ------- - * - * Unit Tests: - * // Test idle detection - * JS_SetIdleGCThreshold(cx, 100); - * // Simulate JS execution - * cx->runtime()->gc.notifyJSExecutionStart(); - * // ... wait 50ms ... - * MOZ_ASSERT(!cx->runtime()->gc.idleGCMgr().isIdleEnough()); - * cx->runtime()->gc.notifyJSExecutionEnd(); - * // ... wait 150ms ... - * MOZ_ASSERT(cx->runtime()->gc.idleGCMgr().isIdleEnough()); - * - * Integration Tests: - * - Verify GC is deferred during active execution - * - Verify GC proceeds after idle period - * - Verify critical GC reasons bypass idle check - * - Measure latency improvements - * - * Implementation Notes - * -------------------- - * - * Thread Safety: - * - IdleGCManager uses mozilla::Atomic for thread-safe state - * - TimeStamp operations are atomic - * - No additional locking needed beyond existing GC locks - * - * Compatibility: - * - Works with both incremental and non-incremental GC - * - Compatible with generational GC - * - Works with zone GC and full GC - * - Respects existing GC suppression mechanisms - * - * Future Enhancements - * ------------------- - * - * Potential improvements: - * - Adaptive idle threshold based on historical GC times - * - Per-zone idle configuration - * - Integration with browser rendering idle callback API - * - Metrics/telemetry for idle GC effectiveness - * - Machine learning-based prediction of idle periods - * - Cooperative GC scheduling with other subsystems - * - */ - -#include "gc/IdleGC.h" -#include "jsapi.h" - -namespace js { -namespace gc { - -IdleGCManager::IdleGCManager() - : lastExecutionTime_(mozilla::TimeStamp::Now()), - idleGCEnabled_(true), - idleThresholdMs_(100), // 100ms default idle threshold - isExecuting_(false) -{ -} - -void -IdleGCManager::notifyJSExecutionStart() -{ - isExecuting_ = true; -} - -void -IdleGCManager::notifyJSExecutionEnd() -{ - isExecuting_ = false; - lastExecutionTime_ = mozilla::TimeStamp::Now(); -} - -bool -IdleGCManager::isIdleEnough() const -{ - if (!idleGCEnabled_) { - return true; // If disabled, always consider idle - } - - if (isExecuting_) { - return false; // Still executing, not idle - } - - uint64_t idleTime = idleTimeSinceLastExecution(); - return idleTime >= idleThresholdMs_; -} - -uint64_t -IdleGCManager::idleTimeSinceLastExecution() const -{ - mozilla::TimeStamp now = mozilla::TimeStamp::Now(); - mozilla::TimeDuration idle = now - lastExecutionTime_; - return idle.ToMilliseconds(); -} - -bool -IdleGCManager::shouldBypassIdleCheck(JS::gcreason::Reason reason) -{ - // These reasons indicate urgent GC needs that should bypass idle checking - switch (reason) { - // Allocation and memory pressure conditions. - case JS::gcreason::ALLOC_TRIGGER: - case JS::gcreason::EAGER_ALLOC_TRIGGER: - case JS::gcreason::TOO_MUCH_MALLOC: - case JS::gcreason::MEM_PRESSURE: - case JS::gcreason::LAST_DITCH: - - // Nursery/store-buffer pressure. - case JS::gcreason::OUT_OF_NURSERY: - case JS::gcreason::EVICT_NURSERY: - case JS::gcreason::FULL_STORE_BUFFER: - case JS::gcreason::SHARED_MEMORY_LIMIT: - - // Explicit API calls - case JS::gcreason::API: - case JS::gcreason::ABORT_GC: - - // Shutdown and finalization - case JS::gcreason::SHUTDOWN_CC: - case JS::gcreason::DESTROY_RUNTIME: - case JS::gcreason::NSJSCONTEXT_DESTROY: - case JS::gcreason::XPCONNECT_SHUTDOWN: - - return true; - - default: - return false; - } -} - -void -IdleGCManager::reset() -{ - lastExecutionTime_ = mozilla::TimeStamp::Now(); - isExecuting_ = false; -} - -} // namespace gc -} // namespace js diff --git a/js/src/gc/IdleGC.h b/js/src/gc/IdleGC.h deleted file mode 100644 index 876369978..000000000 --- a/js/src/gc/IdleGC.h +++ /dev/null @@ -1,118 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef gc_IdleGC_h -#define gc_IdleGC_h - -#include -#include "mozilla/Atomics.h" -#include "mozilla/TimeStamp.h" -#include "js/GCAPI.h" - -namespace js { -namespace gc { - -/* - * Idle-Time Garbage Collection System - * ==================================== - * - * This system defers garbage collection to occur only during periods when - * the browser is not actively processing JavaScript. This helps maintain - * responsiveness by avoiding GC pauses during critical execution windows. - * - * When JavaScript execution is active, GC triggers are deferred. Once the - * JS engine has been idle for a configurable threshold period, pending GC - * work is performed immediately or incrementally as appropriate. - * - * Key characteristics: - * - Tracks JavaScript activity via hooks in the execution engine - * - Configurable idle time threshold (default: 100ms) - * - Can be disabled per-zone or globally - * - Works with both incremental and non-incremental GC modes - * - Respects critical GC reasons that override idle checking - */ - -class IdleGCManager -{ - public: - // Initialize the idle GC manager - IdleGCManager(); - - /* - * Called when JavaScript execution begins. Marks the engine as active. - */ - void notifyJSExecutionStart(); - - /* - * Called when JavaScript execution ends. Records the end time for - * idle detection purposes. - */ - void notifyJSExecutionEnd(); - - /* - * Check if the system has been idle for long enough to permit GC. - * Returns true if sufficient idle time has passed since last JS execution. - */ - bool isIdleEnough() const; - - /* - * Get the amount of idle time since the last JS execution. - * Returns time in milliseconds. - */ - uint64_t idleTimeSinceLastExecution() const; - - /* - * Set the idle threshold - minimum idle time before GC is permitted. - * Time is in milliseconds. Default is 100ms. - */ - void setIdleThresholdMs(uint64_t thresholdMs) { - idleThresholdMs_ = thresholdMs; - } - - uint64_t idleThresholdMs() const { - return idleThresholdMs_; - } - - /* - * Enable or disable idle-time-only GC mode. - */ - void setIdleGCEnabled(bool enabled) { - idleGCEnabled_ = enabled; - } - - bool isIdleGCEnabled() const { - return idleGCEnabled_; - } - - /* - * Check if a GC reason should bypass idle checking. - * Critical reasons (OOM-like pressure, nursery pressure, explicit requests) - * always proceed. - */ - static bool shouldBypassIdleCheck(JS::gcreason::Reason reason); - - /* - * Reset idle tracking state (used during GC or at shutdown). - */ - void reset(); - - private: - // Timestamp of the last JavaScript execution activity - mozilla::TimeStamp lastExecutionTime_; - - // Whether idle-time-only GC mode is enabled - mozilla::Atomic idleGCEnabled_; - - // Minimum idle time (in milliseconds) before GC is permitted - mozilla::Atomic idleThresholdMs_; - - // Whether the JS engine is currently executing - mozilla::Atomic isExecuting_; -}; - -} // namespace gc -} // namespace js - -#endif // gc_IdleGC_h diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 7313747b3..368dbd9f0 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1495,36 +1495,6 @@ JS_SetGCParametersBasedOnAvailableMemory(JSContext* cx, uint32_t availMem) JS_SetGCParameter(cx, config[i].key, config[i].value); } -JS_PUBLIC_API(void) -JS_SetIdleGCEnabled(JSContext* cx, bool enabled) -{ - cx->gc.idleGCMgr().setIdleGCEnabled(enabled); -} - -JS_PUBLIC_API(bool) -JS_IsIdleGCEnabled(JSContext* cx) -{ - return cx->gc.idleGCMgr().isIdleGCEnabled(); -} - -JS_PUBLIC_API(void) -JS_SetIdleGCThreshold(JSContext* cx, uint64_t milliseconds) -{ - cx->gc.idleGCMgr().setIdleThresholdMs(milliseconds); -} - -JS_PUBLIC_API(uint64_t) -JS_GetIdleGCThreshold(JSContext* cx) -{ - return cx->gc.idleGCMgr().idleThresholdMs(); -} - -JS_PUBLIC_API(uint64_t) -JS_GetIdleTimeSinceLastExecution(JSContext* cx) -{ - return cx->gc.idleGCMgr().idleTimeSinceLastExecution(); -} - JS_PUBLIC_API(JSString*) JS_NewExternalString(JSContext* cx, const char16_t* chars, size_t length, diff --git a/js/src/jsapi.h b/js/src/jsapi.h index e68bea917..6c9b93237 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1758,40 +1758,6 @@ JS_GetGCParameter(JSContext* cx, JSGCParamKey key); extern JS_PUBLIC_API(void) JS_SetGCParametersBasedOnAvailableMemory(JSContext* cx, uint32_t availMem); -/* - * Idle-time garbage collection control. - * These functions allow control over when GC occurs - specifically, whether - * GC should only run when the browser/application is not doing active JS work. - */ - -/** - * Enable or disable idle-time-only GC mode. - * When enabled, GC is deferred until the JS engine has been idle for the - * configured threshold period (default: 100ms). - */ -extern JS_PUBLIC_API(void) -JS_SetIdleGCEnabled(JSContext* cx, bool enabled); - -extern JS_PUBLIC_API(bool) -JS_IsIdleGCEnabled(JSContext* cx); - -/** - * Set the minimum idle time (in milliseconds) before GC is permitted. - * Use this to configure how long the JS engine must be inactive before - * pending GC work can proceed. - */ -extern JS_PUBLIC_API(void) -JS_SetIdleGCThreshold(JSContext* cx, uint64_t milliseconds); - -extern JS_PUBLIC_API(uint64_t) -JS_GetIdleGCThreshold(JSContext* cx); - -/** - * Get the current idle time since the last JS execution. - */ -extern JS_PUBLIC_API(uint64_t) -JS_GetIdleTimeSinceLastExecution(JSContext* cx); - /** * Create a new JSString whose chars member refers to external memory, i.e., * memory requiring application-specific finalization. diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 729cc48db..6aecd2fa0 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -215,7 +215,6 @@ #include "gc/FindSCCs.h" #include "gc/GCInternals.h" #include "gc/GCTrace.h" -#include "gc/IdleGC.h" #include "gc/Marking.h" #include "gc/Memory.h" #include "gc/Policy.h" @@ -6013,10 +6012,6 @@ GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason) if (rt->isBeingDestroyed() && !IsShutdownGC(reason)) return false; - // Check if the system is idle enough for GC, unless this is a critical GC - if (!IdleGCManager::shouldBypassIdleCheck(reason) && !idleGC.isIdleEnough()) - return false; - return true; } @@ -6180,18 +6175,6 @@ GCRuntime::notifyDidPaint() interFrameGC = false; } -void -GCRuntime::notifyJSExecutionStart() -{ - idleGC.notifyJSExecutionStart(); -} - -void -GCRuntime::notifyJSExecutionEnd() -{ - idleGC.notifyJSExecutionEnd(); -} - static bool ZonesSelected(JSRuntime* rt) { diff --git a/js/src/moz.build b/js/src/moz.build index 30c05b1da..b62efe6f0 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -216,7 +216,6 @@ main_deunified_sources = [ 'gc/Allocator.cpp', 'gc/Barrier.cpp', 'gc/GCTrace.cpp', - 'gc/IdleGC.cpp', 'gc/Iteration.cpp', 'gc/Marking.cpp', 'gc/Memory.cpp', diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 9e30a8186..92d2da750 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -747,12 +747,6 @@ JSRuntime::traceSharedIntlData(JSTracer* trc) void JSRuntime::triggerActivityCallback(bool active) { - if (active) { - gc.notifyJSExecutionStart(); - } else { - gc.notifyJSExecutionEnd(); - } - if (!activityCallback) return;