Bug 1386660 - Part 6: Clarify relationships between prefs. r=sfink
authorPaul Bone <pbone@mozilla.com>
Wed, 16 Aug 2017 15:40:39 +1000
changeset 648506 ed8427cb4342edaa7b0ec40a36afb3b4b8277d3e
parent 648505 f1fcbcb67951f04de3e86909c205e7aa2798319f
child 648507 2a790986a5716f9a070a601019de2a244f13e150
child 648931 b3d8ae8983974f171bfc00c114e180942c2b95ce
push id74775
push userbmo:ted@mielczarek.org
push dateThu, 17 Aug 2017 21:15:41 +0000
reviewerssfink
bugs1386660
milestone57.0a1
Bug 1386660 - Part 6: Clarify relationships between prefs. r=sfink Make it clearer how prefs, JSGC params, and their defaults relate to one another.
js/src/gc/GCRuntime.h
js/src/jsapi.h
js/src/jsgc.cpp
modules/libpref/init/all.js
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -135,86 +135,107 @@ class BackgroundDecommitTask : public GC
 
 /*
  * Encapsulates all of the GC tunables. These are effectively constant and
  * should only be modified by setParameter.
  */
 class GCSchedulingTunables
 {
     /*
-     * Soft limit on the number of bytes we are allowed to allocate in the GC
-     * heap. Attempts to allocate gcthings over this limit will return null and
-     * subsequently invoke the standard OOM machinery, independent of available
-     * physical memory.
+     * JSGC_MAX_BYTES
+     *
+     * Maximum nominal heap before last ditch GC.
      */
     UnprotectedData<size_t> gcMaxBytes_;
 
     /*
+     * JSGC_MAX_NURSERY_BYTES
+     *
      * Maximum nursery size for each zone group.
-     * Initially DefaultNurseryBytes and can be set by
-     * javascript.options.mem.nursery.max_kb
      */
     ActiveThreadData<size_t> gcMaxNurseryBytes_;
 
     /*
+     * JSGC_ALLOCATION_THRESHOLD
+     *
      * The base value used to compute zone->threshold.gcTriggerBytes(). When
      * usage.gcBytes() surpasses threshold.gcTriggerBytes() for a zone, the
      * zone may be scheduled for a GC, depending on the exact circumstances.
      */
     ActiveThreadOrGCTaskData<size_t> gcZoneAllocThresholdBase_;
 
     /* Fraction of threshold.gcBytes() which triggers an incremental GC. */
     UnprotectedData<float> zoneAllocThresholdFactor_;
     /* The same except when doing so would interrupt an already running GC. */
     UnprotectedData<float> zoneAllocThresholdFactorAvoidInterrupt_;
 
     /*
      * Number of bytes to allocate between incremental slices in GCs triggered
      * by the zone allocation threshold.
+     *
+     * This value does not have a JSGCParamKey parameter yet.
      */
     UnprotectedData<size_t> zoneAllocDelayBytes_;
 
     /*
+     * JSGC_DYNAMIC_HEAP_GROWTH
+     *
      * Totally disables |highFrequencyGC|, the HeapGrowthFactor, and other
      * tunables that make GC non-deterministic.
      */
     ActiveThreadData<bool> dynamicHeapGrowthEnabled_;
 
     /*
+     * JSGC_HIGH_FREQUENCY_TIME_LIMIT
+     *
      * We enter high-frequency mode if we GC a twice within this many
      * microseconds. This value is stored directly in microseconds.
      */
     ActiveThreadData<uint64_t> highFrequencyThresholdUsec_;
 
     /*
+     * JSGC_HIGH_FREQUENCY_LOW_LIMIT
+     * JSGC_HIGH_FREQUENCY_HIGH_LIMIT
+     * JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX
+     * JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN
+     *
      * When in the |highFrequencyGC| mode, these parameterize the per-zone
      * "HeapGrowthFactor" computation.
      */
     ActiveThreadData<uint64_t> highFrequencyLowLimitBytes_;
     ActiveThreadData<uint64_t> highFrequencyHighLimitBytes_;
     ActiveThreadData<double> highFrequencyHeapGrowthMax_;
     ActiveThreadData<double> highFrequencyHeapGrowthMin_;
 
     /*
+     * JSGC_LOW_FREQUENCY_HEAP_GROWTH
+     *
      * When not in |highFrequencyGC| mode, this is the global (stored per-zone)
      * "HeapGrowthFactor".
      */
     ActiveThreadData<double> lowFrequencyHeapGrowth_;
 
     /*
+     * JSGC_DYNAMIC_MARK_SLICE
+     *
      * Doubles the length of IGC slices when in the |highFrequencyGC| mode.
      */
     ActiveThreadData<bool> dynamicMarkSliceEnabled_;
 
     /*
+     * JSGC_REFRESH_FRAME_SLICES_ENABLED
+     *
      * Controls whether painting can trigger IGC slices.
      */
     ActiveThreadData<bool> refreshFrameSlicesEnabled_;
 
     /*
+     * JSGC_MIN_EMPTY_CHUNK_COUNT
+     * JSGC_MAX_EMPTY_CHUNK_COUNT
+     *
      * Controls the number of empty chunks reserved for future allocation.
      */
     UnprotectedData<uint32_t> minEmptyChunkCount_;
     UnprotectedData<uint32_t> maxEmptyChunkCount_;
 
   public:
     GCSchedulingTunables();
 
@@ -1146,16 +1167,21 @@ class GCRuntime
      */
     mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> numArenasFreeCommitted;
     ActiveThreadData<VerifyPreTracer*> verifyPreData;
 
   private:
     UnprotectedData<bool> chunkAllocationSinceLastGC;
     ActiveThreadData<int64_t> lastGCTime;
 
+    /*
+     * JSGC_MODE
+     * prefs: javascript.options.mem.gc_per_zone and
+     *   javascript.options.mem.gc_incremental.
+     */
     ActiveThreadData<JSGCMode> mode;
 
     mozilla::Atomic<size_t, mozilla::ReleaseAcquire> numActiveZoneIters;
 
     /* During shutdown, the GC needs to clean up every possible object. */
     ActiveThreadData<bool> cleanUpEverything;
 
     // Gray marking must be done after all black marking is complete. However,
@@ -1280,27 +1306,35 @@ class GCRuntime
 
     /*
      * Indicates that a GC slice has taken place in the middle of an animation
      * frame, rather than at the beginning. In this case, the next slice will be
      * delayed so that we don't get back-to-back slices.
      */
     ActiveThreadData<bool> interFrameGC;
 
-    /* Default budget for incremental GC slice. See js/SliceBudget.h. */
+    /*
+     * Default budget for incremental GC slice. See js/SliceBudget.h.
+     *
+     * JSGC_SLICE_TIME_BUDGET
+     * pref: javascript.options.mem.gc_incremental_slice_ms,
+     */
     ActiveThreadData<int64_t> defaultTimeBudget_;
 
     /*
      * We disable incremental GC if we encounter a Class with a trace hook
      * that does not implement write barriers.
      */
     ActiveThreadData<bool> incrementalAllowed;
 
     /*
      * Whether compacting GC can is enabled globally.
+     *
+     * JSGC_COMPACTING_ENABLED
+     * pref: javascript.options.mem.gc_compacting
      */
     ActiveThreadData<bool> compactingEnabled;
 
     ActiveThreadData<bool> rootsRemoved;
 
     /*
      * These options control the zealousness of the GC. At every allocation,
      * nextScheduled is decremented. When it reaches zero we do a full GC.
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1788,92 +1788,195 @@ JS_RemoveWeakPointerCompartmentCallback(
 
 extern JS_PUBLIC_API(void)
 JS_UpdateWeakPointerAfterGC(JS::Heap<JSObject*>* objp);
 
 extern JS_PUBLIC_API(void)
 JS_UpdateWeakPointerAfterGCUnbarriered(JSObject** objp);
 
 typedef enum JSGCParamKey {
-    /** Maximum nominal heap before last ditch GC. */
+    /**
+     * Maximum nominal heap before last ditch GC.
+     *
+     * Soft limit on the number of bytes we are allowed to allocate in the GC
+     * heap. Attempts to allocate gcthings over this limit will return null and
+     * subsequently invoke the standard OOM machinery, independent of available
+     * physical memory.
+     *
+     * Pref: javascript.options.mem.max
+     * Default: 0xffffffff
+     */
     JSGC_MAX_BYTES          = 0,
 
-    /** Number of JS_malloc bytes before last ditch GC. */
+    /**
+     * Number of JS_malloc bytes before last ditch GC.
+     *
+     * Pref; javascript.options.mem.high_water_mark
+     * Default: 0xffffffff
+     */
     JSGC_MAX_MALLOC_BYTES   = 1,
 
-    /** Maximum size of the generational GC nurseries. */
+    /**
+     * Maximum size of the generational GC nurseries.
+     *
+     * Pref: javascript.options.mem.nursery.max_kb
+     * Default: JS::DefaultNurseryBytes
+     */
     JSGC_MAX_NURSERY_BYTES  = 2,
 
     /** Amount of bytes allocated by the GC. */
     JSGC_BYTES = 3,
 
     /** Number of times GC has been invoked. Includes both major and minor GC. */
     JSGC_NUMBER = 4,
 
-    /** Select GC mode. */
+    /**
+     * Select GC mode.
+     *
+     * See: JSGCMode in GCAPI.h
+     * prefs: javascript.options.mem.gc_per_zone and
+     *   javascript.options.mem.gc_incremental.
+     * Default: JSGC_MODE_INCREMENTAL
+     */
     JSGC_MODE = 6,
 
     /** Number of cached empty GC chunks. */
     JSGC_UNUSED_CHUNKS = 7,
 
     /** Total number of allocated GC chunks. */
     JSGC_TOTAL_CHUNKS = 8,
 
-    /** Max milliseconds to spend in an incremental GC slice. */
+    /**
+     * Max milliseconds to spend in an incremental GC slice.
+     *
+     * Pref: javascript.options.mem.gc_incremental_slice_ms
+     * Default: DefaultTimeBudget.
+     */
     JSGC_SLICE_TIME_BUDGET = 9,
 
-    /** Maximum size the GC mark stack can grow to. */
+    /**
+     * Maximum size the GC mark stack can grow to.
+     *
+     * Pref: none
+     * Default: MarkStack::DefaultCapacity
+     */
     JSGC_MARK_STACK_LIMIT = 10,
 
     /**
-     * GCs less than this far apart in time will be considered 'high-frequency GCs'.
+     * GCs less than this far apart in time will be considered 'high-frequency
+     * GCs'.
+     *
      * See setGCLastBytes in jsgc.cpp.
+     *
+     * Pref: javascript.options.mem.gc_high_frequency_time_limit_ms
+     * Default: HighFrequencyThresholdUsec
      */
     JSGC_HIGH_FREQUENCY_TIME_LIMIT = 11,
 
-    /** Start of dynamic heap growth. */
+    /**
+     * Start of dynamic heap growth.
+     *
+     * Pref: javascript.options.mem.gc_high_frequency_low_limit_mb
+     * Default: HighFrequencyLowLimitBytes
+     */
     JSGC_HIGH_FREQUENCY_LOW_LIMIT = 12,
 
-    /** End of dynamic heap growth. */
+    /**
+     * End of dynamic heap growth.
+     *
+     * Pref: javascript.options.mem.gc_high_frequency_high_limit_mb
+     * Default: HighFrequencyHighLimitBytes
+     */
     JSGC_HIGH_FREQUENCY_HIGH_LIMIT = 13,
 
-    /** Upper bound of heap growth. */
+    /**
+     * Upper bound of heap growth.
+     *
+     * Pref: javascript.options.mem.gc_high_frequency_heap_growth_max
+     * Default: HighFrequencyHeapGrowthMax
+     */
     JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX = 14,
 
-    /** Lower bound of heap growth. */
+    /**
+     * Lower bound of heap growth.
+     *
+     * Pref: javascript.options.mem.gc_high_frequency_heap_growth_min
+     * Default: HighFrequencyHeapGrowthMin
+     */
     JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN = 15,
 
-    /** Heap growth for low frequency GCs. */
+    /**
+     * Heap growth for low frequency GCs.
+     *
+     * Pref: javascript.options.mem.gc_low_frequency_heap_growth
+     * Default: LowFrequencyHeapGrowth
+     */
     JSGC_LOW_FREQUENCY_HEAP_GROWTH = 16,
 
     /**
      * If false, the heap growth factor is fixed at 3. If true, it is determined
      * based on whether GCs are high- or low- frequency.
+     *
+     * Pref: javascript.options.mem.gc_dynamic_heap_growth
+     * Default: DynamicHeapGrowthEnabled
      */
     JSGC_DYNAMIC_HEAP_GROWTH = 17,
 
-    /** If true, high-frequency GCs will use a longer mark slice. */
+    /**
+     * If true, high-frequency GCs will use a longer mark slice.
+     *
+     * Pref: javascript.options.mem.gc_dynamic_mark_slice
+     * Default: DynamicMarkSliceEnabled
+     */
     JSGC_DYNAMIC_MARK_SLICE = 18,
 
-    /** Lower limit after which we limit the heap growth. */
+    /**
+     * Lower limit after which we limit the heap growth.
+     *
+     * The base value used to compute zone->threshold.gcTriggerBytes(). When
+     * usage.gcBytes() surpasses threshold.gcTriggerBytes() for a zone, the
+     * zone may be scheduled for a GC, depending on the exact circumstances.
+     *
+     * Pref: javascript.options.mem.gc_allocation_threshold_mb
+     * Default GCZoneAllocThresholdBase
+     */
     JSGC_ALLOCATION_THRESHOLD = 19,
 
     /**
      * We try to keep at least this many unused chunks in the free chunk pool at
      * all times, even after a shrinking GC.
+     *
+     * Pref: javascript.options.mem.gc_min_empty_chunk_count
+     * Default: MinEmptyChunkCount
      */
     JSGC_MIN_EMPTY_CHUNK_COUNT = 21,
 
-    /** We never keep more than this many unused chunks in the free chunk pool. */
+    /**
+     * We never keep more than this many unused chunks in the free chunk
+     * pool.
+     *
+     * Pref: javascript.options.mem.gc_min_empty_chunk_count
+     * Default: MinEmptyChunkCount
+     */
     JSGC_MAX_EMPTY_CHUNK_COUNT = 22,
 
-    /** Whether compacting GC is enabled. */
+    /**
+     * Whether compacting GC is enabled.
+     *
+     * Pref: javascript.options.mem.gc_compacting
+     * Default: CompactingEnabled
+     */
     JSGC_COMPACTING_ENABLED = 23,
 
-    /** If true, painting can trigger IGC slices. */
+    /**
+     * If true, painting can trigger IGC slices.
+     *
+     * Pref: javascript.options.mem.gc_refresh_frame_slices_enabled
+     * Default: RefreshFrameSlicesEnabled
+     */
     JSGC_REFRESH_FRAME_SLICES_ENABLED = 24,
 } JSGCParamKey;
 
 extern JS_PUBLIC_API(void)
 JS_SetGCParameter(JSContext* cx, JSGCParamKey key, uint32_t value);
 
 extern JS_PUBLIC_API(void)
 JS_ResetGCParameter(JSContext* cx, JSGCParamKey key);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -262,47 +262,76 @@ using mozilla::Move;
 using mozilla::Swap;
 using mozilla::TimeStamp;
 
 using JS::AutoGCRooter;
 
 /*
  * Default settings for tuning the GC.  Some of these can be set at runtime,
  * This list is not complete, some tuning parameters are not listed here.
+ *
+ * If you change the values here, please also consider changing them in
+ * modules/libpref/init/all.js where they are duplicated for the Firefox
+ * preferences.
  */
 namespace js {
 namespace gc {
 namespace TuningDefaults {
 
+    /* JSGC_ALLOCATION_THRESHOLD */
     static const size_t GCZoneAllocThresholdBase = 30 * 1024 * 1024;
     static const float ZoneAllocThresholdFactor = 0.9f;
     static const float ZoneAllocThresholdFactorAvoidInterrupt = 0.9f;
+
+    /* no parameter */
     static const size_t ZoneAllocDelayBytes = 1024 * 1024;
+
+    /* JSGC_DYNAMIC_HEAP_GROWTH */
     static const bool DynamicHeapGrowthEnabled = false;
+
+    /* JSGC_HIGH_FREQUENCY_TIME_LIMIT */
     static const uint64_t HighFrequencyThresholdUsec = 1000000;
+
+    /* JSGC_HIGH_FREQUENCY_LOW_LIMIT */
     static const uint64_t HighFrequencyLowLimitBytes = 100 * 1024 * 1024;
+
+    /* JSGC_HIGH_FREQUENCY_HIGH_LIMIT */
     static const uint64_t HighFrequencyHighLimitBytes = 500 * 1024 * 1024;
+
+    /* JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX */
     static const double HighFrequencyHeapGrowthMax = 3.0;
+
+    /* JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN */
     static const double HighFrequencyHeapGrowthMin = 1.5;
+
+    /* JSGC_LOW_FREQUENCY_HEAP_GROWTH */
     static const double LowFrequencyHeapGrowth = 1.5;
+
+    /* JSGC_DYNAMIC_MARK_SLICE */
     static const bool DynamicMarkSliceEnabled = false;
+
+    /* JSGC_REFRESH_FRAME_SLICES_ENABLED */
     static const bool RefreshFrameSlicesEnabled = true;
+
+    /* JSGC_MIN_EMPTY_CHUNK_COUNT */
     static const uint32_t MinEmptyChunkCount = 1;
+
+    /* JSGC_MAX_EMPTY_CHUNK_COUNT */
     static const uint32_t MaxEmptyChunkCount = 30;
 
-    /*
-     * JSGC_SLICE_TIME_BUDGET.
-     * javascript.options.mem.gc_incremental_slice_ms
-     */
+    /* JSGC_SLICE_TIME_BUDGET */
     static const int64_t DefaultTimeBudget =
         SliceBudget::UnlimitedTimeBudget;
 
+    /* JSGC_MODE */
     static const JSGCMode Mode = JSGC_MODE_INCREMENTAL;
 
+    /* JSGC_COMPACTING_ENABLED */
     static const bool CompactingEnabled = true;
+
 }}} // namespace js::gc::TuningDefaults
 
 /* Increase the IGC marking slice time if we are in highFrequencyGC mode. */
 static const int IGC_MARK_SLICE_MULTIPLIER = 2;
 
 const AllocKind gc::slotsToThingKind[] = {
     /*  0 */ AllocKind::OBJECT0,  AllocKind::OBJECT2,  AllocKind::OBJECT2,  AllocKind::OBJECT4,
     /*  4 */ AllocKind::OBJECT4,  AllocKind::OBJECT8,  AllocKind::OBJECT8,  AllocKind::OBJECT8,
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1437,48 +1437,98 @@ pref("javascript.options.ion.offthread_c
 #ifdef DEBUG
 pref("javascript.options.jit.full_debug_checks", true);
 #endif
 // This preference instructs the JS engine to discard the
 // source of any privileged JS after compilation. This saves
 // memory, but makes things like Function.prototype.toSource()
 // fail.
 pref("javascript.options.discardSystemSource", false);
-// This preference limits the memory usage of javascript.
+
+// Many of the the following preferences tune the SpiderMonkey GC, if you
+// change the defaults here please also consider changing them in
+// js/src/jsgc.cpp.  They're documented in js/src/jsapi.h.
+
+// JSGC_MAX_MALLOC_BYTES
+// This preference limits the malloc memory that javascript objects may use.
 // If you want to change these values for your device,
 // please find Bug 417052 comment 17 and Bug 456721
 // Comment 32 and Bug 613551.
+// Override the shell's default of 0xffffffff
 pref("javascript.options.mem.high_water_mark", 128);
+
+// JSGC_MAX_BYTES
+// SpiderMonkey defaults to 2^32-1 bytes, but this is measured in MB so that
+// cannot be represented directly in order to show it in about:config.
 pref("javascript.options.mem.max", -1);
-pref("javascript.options.mem.nursery.max_kb", -1);
+
+// JSGC_MAX_NURSERY_BYTES
+#if defined(ANDROID) || defined(XP_IOS) || defined(MOZ_B2G)
+pref("javascript.options.mem.nursery.max_kb", 4096);
+#else
+pref("javascript.options.mem.nursery.max_kb", 16384);
+#endif
+
+// JSGC_MODE
 pref("javascript.options.mem.gc_per_zone", true);
 pref("javascript.options.mem.gc_incremental", true);
+
+// JSGC_SLICE_TIME_BUDGET
+// Override the shell's default of unlimited slice time.
 pref("javascript.options.mem.gc_incremental_slice_ms", 5);
+
+// JSGC_COMPACTING_ENABLED
 pref("javascript.options.mem.gc_compacting", true);
+
 pref("javascript.options.mem.log", false);
 pref("javascript.options.mem.notify", false);
 pref("javascript.options.gc_on_memory_pressure", true);
 pref("javascript.options.compact_on_user_inactive", true);
 #ifdef NIGHTLY_BUILD
 pref("javascript.options.compact_on_user_inactive_delay", 15000); // ms
 #else
 pref("javascript.options.compact_on_user_inactive_delay", 300000); // ms
 #endif
 
+// JSGC_HIGH_FREQUENCY_TIME_LIMIT
 pref("javascript.options.mem.gc_high_frequency_time_limit_ms", 1000);
+
+// JSGC_HIGH_FREQUENCY_LOW_LIMIT
 pref("javascript.options.mem.gc_high_frequency_low_limit_mb", 100);
+
+// JSGC_HIGH_FREQUENCY_HIGH_LIMIT
 pref("javascript.options.mem.gc_high_frequency_high_limit_mb", 500);
+
+// JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX
 pref("javascript.options.mem.gc_high_frequency_heap_growth_max", 300);
+
+// JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN
 pref("javascript.options.mem.gc_high_frequency_heap_growth_min", 150);
+
+// JSGC_LOW_FREQUENCY_HEAP_GROWTH
 pref("javascript.options.mem.gc_low_frequency_heap_growth", 150);
+
+// JSGC_DYNAMIC_HEAP_GROWTH
+// Override SpiderMonkey default (false).
 pref("javascript.options.mem.gc_dynamic_heap_growth", true);
+
+// JSGC_DYNAMIC_MARK_SLICE
+// Override SpiderMonkey default (false).
 pref("javascript.options.mem.gc_dynamic_mark_slice", true);
+
+// JSGC_REFRESH_FRAME_SLICES_ENABLED
 pref("javascript.options.mem.gc_refresh_frame_slices_enabled", true);
+
+// JSGC_ALLOCATION_THRESHOLD
 pref("javascript.options.mem.gc_allocation_threshold_mb", 30);
+
+// JSGC_MIN_EMPTY_CHUNK_COUNT
 pref("javascript.options.mem.gc_min_empty_chunk_count", 1);
+
+// JSGC_MAX_EMPTY_CHUNK_COUNT
 pref("javascript.options.mem.gc_max_empty_chunk_count", 30);
 
 pref("javascript.options.showInConsole", false);
 
 pref("javascript.options.shared_memory", true);
 
 pref("javascript.options.throw_on_debuggee_would_run", false);
 pref("javascript.options.dump_stack_on_debuggee_would_run", false);