Bug 903519 - Default nursery strings to off, add ability to enable, r=jonco
☠☠ backed out by 65e92478e09d ☠ ☠
authorSteve Fink <sfink@mozilla.com>
Fri, 03 Nov 2017 14:00:14 -0700
changeset 453161 71831e232df2957c9ea178986218e3d6eeef6c0b
parent 453160 6f3666e9540e849056347f7b9d8a40e41396115e
child 453162 38f4e0426bdd81c0acdce3929e3e3d81370d1273
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs903519
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 903519 - Default nursery strings to off, add ability to enable, r=jonco
js/public/HeapAPI.h
js/src/gc/Allocator.cpp
js/src/gc/Nursery.cpp
js/src/gc/Nursery.h
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -489,16 +489,22 @@ GCThingIsMarkedGray(GCCellPtr thing)
     if (thing.mayBeOwnedByOtherRuntime())
         return false;
     return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell());
 }
 
 extern JS_PUBLIC_API(JS::TraceKind)
 GCThingTraceKind(void* thing);
 
+extern JS_PUBLIC_API(void)
+EnableNurseryStrings(JSContext* cx);
+
+extern JS_PUBLIC_API(void)
+DisableNurseryStrings(JSContext* cx);
+
 /*
  * Returns true when writes to GC thing pointers (and reads from weak pointers)
  * must call an incremental barrier. This is generally only true when running
  * mutator code in-between GC slices. At other times, the barrier may be elided
  * for performance.
  */
 extern JS_PUBLIC_API(bool)
 IsIncrementalBarrierNeeded(JSContext* cx);
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -174,17 +174,17 @@ js::AllocateString(JSContext* cx, Initia
             ReportOutOfMemory(cx);
         return str;
     }
 
     JSRuntime* rt = cx->runtime();
     if (!rt->gc.checkAllocatorState<allowGC>(cx, kind))
         return nullptr;
 
-    if (cx->nursery().isEnabled() && heap != TenuredHeap) {
+    if (cx->nursery().isEnabled() && heap != TenuredHeap && cx->nursery().canAllocateStrings()) {
         auto str = static_cast<StringAllocT*>(rt->gc.tryNewNurseryString<allowGC>(cx, size, kind));
         if (str)
             return str;
 
         // Our most common non-jit allocation path is NoGC; thus, if we fail the
         // alloc and cannot GC, we *must* return nullptr here so that the caller
         // will do a CanGC allocation to clear the nursery. Failing to do so will
         // cause all allocations on this path to land in Tenured, and we will not
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -116,24 +116,29 @@ js::Nursery::Nursery(JSRuntime* rt)
   , currentEnd_(0)
   , currentChunk_(0)
   , maxChunkCount_(0)
   , chunkCountLimit_(0)
   , timeInChunkAlloc_(0)
   , previousPromotionRate_(0)
   , profileThreshold_(0)
   , enableProfiling_(false)
+  , canAllocateStrings_(false)
   , reportTenurings_(0)
   , minorGCTriggerReason_(JS::gcreason::NO_REASON)
   , minorGcCount_(0)
   , freeMallocedBuffersTask(nullptr)
 #ifdef JS_GC_ZEAL
   , lastCanary_(nullptr)
 #endif
-{}
+{
+    const char* env = getenv("MOZ_ENABLE_NURSERY_STRINGS");
+    if (env && *env)
+        canAllocateStrings_ = true;
+}
 
 bool
 js::Nursery::init(uint32_t maxNurseryBytes, AutoLockGCBgAlloc& lock)
 {
     if (!mallocedBuffers.init())
         return false;
 
     freeMallocedBuffersTask = js_new<FreeMallocedBuffersTask>(runtime()->defaultFreeOp());
@@ -228,16 +233,30 @@ js::Nursery::disable()
     freeChunksFrom(0);
     maxChunkCount_ = 0;
 
     currentEnd_ = 0;
 
     runtime()->gc.storeBuffer().disable();
 }
 
+void
+js::Nursery::enableStrings()
+{
+    MOZ_ASSERT(isEmpty());
+    canAllocateStrings_ = true;
+}
+
+void
+js::Nursery::disableStrings()
+{
+    MOZ_ASSERT(isEmpty());
+    canAllocateStrings_ = false;
+}
+
 bool
 js::Nursery::isEmpty() const
 {
     if (!isEnabled())
         return true;
 
     if (!runtime()->hasZealMode(ZealMode::GenerationalGC)) {
         MOZ_ASSERT(currentStartChunk_ == 0);
@@ -1172,8 +1191,25 @@ js::Nursery::sweepDictionaryModeObjects(
     for (auto obj : dictionaryModeObjects_) {
         if (!IsForwarded(obj))
             obj->sweepDictionaryListPointer();
         else
             Forwarded(obj)->updateDictionaryListPointerAfterMinorGC(obj);
     }
     dictionaryModeObjects_.clear();
 }
+
+
+JS_PUBLIC_API(void)
+JS::EnableNurseryStrings(JSContext* cx)
+{
+    AutoEmptyNursery empty(cx);
+    ReleaseAllJITCode(cx->runtime()->defaultFreeOp());
+    cx->runtime()->gc.nursery().enableStrings();
+}
+
+JS_PUBLIC_API(void)
+JS::DisableNurseryStrings(JSContext* cx)
+{
+    AutoEmptyNursery empty(cx);
+    ReleaseAllJITCode(cx->runtime()->defaultFreeOp());
+    cx->runtime()->gc.nursery().disableStrings();
+}
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -165,16 +165,20 @@ class Nursery
     unsigned maxChunkCount() const { return maxChunkCount_; }
 
     bool exists() const { return chunkCountLimit() != 0; }
 
     void enable();
     void disable();
     bool isEnabled() const { return maxChunkCount() != 0; }
 
+    void enableStrings();
+    void disableStrings();
+    bool canAllocateStrings() const { return canAllocateStrings_; }
+
     /* Return true if no allocations have been made since the last collection. */
     bool isEmpty() const;
 
     /*
      * Check whether an arbitrary pointer is within the nursery. This is
      * slower than IsInsideNursery(Cell*), but works on all types of pointers.
      */
     MOZ_ALWAYS_INLINE bool isInside(gc::Cell* cellp) const = delete;
@@ -380,17 +384,20 @@ class Nursery
 
     /* Promotion rate for the previous minor collection. */
     float previousPromotionRate_;
 
     /* Report minor collections taking at least this long, if enabled. */
     mozilla::TimeDuration profileThreshold_;
     bool enableProfiling_;
 
-    /* Report ObjectGroups with at lest this many instances tenured. */
+    /* Whether we will nursery-allocate strings. */
+    bool canAllocateStrings_;
+
+    /* Report ObjectGroups with at least this many instances tenured. */
     int64_t reportTenurings_;
 
     /*
      * Whether and why a collection of this nursery has been requested. This is
      * mutable as it is set by the store buffer, which otherwise cannot modify
      * anything in the nursery.
      */
     mutable JS::gcreason::Reason minorGCTriggerReason_;