Commit 77861963 authored by Chia-Hung Duan's avatar Chia-Hung Duan
Browse files

Bug 1376891 - Support idle runnable for nursery collection. r=jonco, r=smaug

parent c683f813
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ namespace JS {
    D(EVICT_NURSERY)                            \
    D(DELAYED_ATOMS_GC)                         \
    D(SHARED_MEMORY_LIMIT)                      \
    D(UNUSED1)                                  \
    D(IDLE_TIME_COLLECTION)                     \
    D(INCREMENTAL_TOO_SLOW)                     \
    D(ABORT_GC)                                 \
    D(FULL_WHOLE_CELL_BUFFER)                   \
+8 −0
Original line number Diff line number Diff line
@@ -279,12 +279,20 @@ class Nursery
    JS::gcreason::Reason minorGCTriggerReason() const { return minorGCTriggerReason_; }
    void clearMinorGCRequest() { minorGCTriggerReason_ = JS::gcreason::NO_REASON; }

    bool needIdleTimeCollection() const {
        return minorGCRequested() ||
               (freeSpace() < kIdleTimeCollectionThreshold);
    }

    bool enableProfiling() const { return enableProfiling_; }

  private:
    /* The amount of space in the mapped nursery available to allocations. */
    static const size_t NurseryChunkUsableSize = gc::ChunkSize - gc::ChunkTrailerSize;

    /* Attemp to run a minor GC in the idle time if the free space falls below this threshold. */
    static constexpr size_t kIdleTimeCollectionThreshold = NurseryChunkUsableSize / 4;

    JSRuntime* runtime_;

    /* Vector of allocated chunks to allocate from. */
+14 −0
Original line number Diff line number Diff line
@@ -1439,6 +1439,20 @@ JS_RemoveExtraGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data)
    return cx->runtime()->gc.removeBlackRootsTracer(traceOp, data);
}

JS_PUBLIC_API(bool)
JS::IsIdleGCTaskNeeded(JSRuntime* rt) {
  // Currently, we only collect nursery during idle time.
  return rt->gc.nursery().needIdleTimeCollection();
}

JS_PUBLIC_API(void)
JS::RunIdleTimeGCTask(JSRuntime* rt) {
  GCRuntime& gc = rt->gc;
  if (gc.nursery().needIdleTimeCollection()) {
    gc.minorGC(JS::gcreason::IDLE_TIME_COLLECTION);
  }
}

JS_PUBLIC_API(void)
JS_GC(JSContext* cx)
{
+10 −0
Original line number Diff line number Diff line
@@ -1748,6 +1748,16 @@ JS_RemoveExtraGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data);
/*
 * Garbage collector API.
 */
namespace JS {

extern JS_PUBLIC_API(bool)
IsIdleGCTaskNeeded(JSRuntime* rt);

extern JS_PUBLIC_API(void)
RunIdleTimeGCTask(JSRuntime* rt);

} // namespace JS

extern JS_PUBLIC_API(void)
JS_GC(JSContext* cx);

+33 −0
Original line number Diff line number Diff line
@@ -370,6 +370,9 @@ CycleCollectedJSContext::AfterProcessTask(uint32_t aRecursionDepth)

  // Step 4.2 Execute any events that were waiting for a stable state.
  ProcessStableStateQueue();

  // This should be a fast test so that it won't affect the next task processing.
  IsIdleGCTaskNeeded();
}

void
@@ -379,6 +382,36 @@ CycleCollectedJSContext::AfterProcessMicrotask()
  AfterProcessMicrotask(RecursionDepth());
}

void CycleCollectedJSContext::IsIdleGCTaskNeeded()
{
  class IdleTimeGCTaskRunnable : public mozilla::IdleRunnable
  {
  public:
    using mozilla::IdleRunnable::IdleRunnable;

  public:
    NS_IMETHOD Run() override
    {
      CycleCollectedJSRuntime* ccrt = CycleCollectedJSRuntime::Get();
      if (ccrt) {
        ccrt->RunIdleTimeGCTask();
      }
      return NS_OK;
    }

    nsresult Cancel() override
    {
      return NS_OK;
    }
  };

  if (Runtime()->IsIdleGCTaskNeeded()) {
    nsCOMPtr<nsIRunnable> gc_task = new IdleTimeGCTaskRunnable();
    NS_IdleDispatchToCurrentThread(gc_task.forget());
    Runtime()->SetPendingIdleGCTask();
  }
}

void
CycleCollectedJSContext::AfterProcessMicrotask(uint32_t aRecursionDepth)
{
Loading