[GLIB] Implement garbage collector timers
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 Nov 2015 13:52:45 +0000 (13:52 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 Nov 2015 13:52:45 +0000 (13:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=151391

Reviewed by Žan Doberšek.

Add GLib implementation using GSource.

* heap/EdenGCActivityCallback.cpp:
* heap/FullGCActivityCallback.cpp:
* heap/GCActivityCallback.cpp:
(JSC::GCActivityCallback::GCActivityCallback):
(JSC::GCActivityCallback::scheduleTimer):
(JSC::GCActivityCallback::cancelTimer):
* heap/GCActivityCallback.h:
* heap/Heap.cpp:
(JSC::Heap::Heap):
* heap/HeapTimer.cpp:
(JSC::HeapTimer::HeapTimer):
(JSC::HeapTimer::~HeapTimer):
(JSC::HeapTimer::timerDidFire):
* heap/HeapTimer.h:
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::IncrementalSweeper):
(JSC::IncrementalSweeper::scheduleTimer):
(JSC::IncrementalSweeper::cancelTimer):
* heap/IncrementalSweeper.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192773 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/heap/EdenGCActivityCallback.cpp
Source/JavaScriptCore/heap/FullGCActivityCallback.cpp
Source/JavaScriptCore/heap/GCActivityCallback.cpp
Source/JavaScriptCore/heap/GCActivityCallback.h
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/HeapTimer.cpp
Source/JavaScriptCore/heap/HeapTimer.h
Source/JavaScriptCore/heap/IncrementalSweeper.cpp
Source/JavaScriptCore/heap/IncrementalSweeper.h

index 644d76b..99f6878 100644 (file)
@@ -1,3 +1,32 @@
+2015-11-26  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GLIB] Implement garbage collector timers
+        https://bugs.webkit.org/show_bug.cgi?id=151391
+
+        Reviewed by Žan Doberšek.
+
+        Add GLib implementation using GSource.
+
+        * heap/EdenGCActivityCallback.cpp:
+        * heap/FullGCActivityCallback.cpp:
+        * heap/GCActivityCallback.cpp:
+        (JSC::GCActivityCallback::GCActivityCallback):
+        (JSC::GCActivityCallback::scheduleTimer):
+        (JSC::GCActivityCallback::cancelTimer):
+        * heap/GCActivityCallback.h:
+        * heap/Heap.cpp:
+        (JSC::Heap::Heap):
+        * heap/HeapTimer.cpp:
+        (JSC::HeapTimer::HeapTimer):
+        (JSC::HeapTimer::~HeapTimer):
+        (JSC::HeapTimer::timerDidFire):
+        * heap/HeapTimer.h:
+        * heap/IncrementalSweeper.cpp:
+        (JSC::IncrementalSweeper::IncrementalSweeper):
+        (JSC::IncrementalSweeper::scheduleTimer):
+        (JSC::IncrementalSweeper::cancelTimer):
+        * heap/IncrementalSweeper.h:
+
 2015-11-24  Caitlin Potter  <caitp@igalia.com>
 
         [JSC] support Computed Property Names in destructuring Patterns
index 2be4e67..7774075 100644 (file)
@@ -30,7 +30,7 @@
 
 namespace JSC {
 
-#if USE(CF) || PLATFORM(EFL)
+#if USE(CF) || USE(GLIB)
 
 EdenGCActivityCallback::EdenGCActivityCallback(Heap* heap)
     : GCActivityCallback(heap)
index fe2615b..91051a6 100644 (file)
@@ -30,7 +30,7 @@
 
 namespace JSC {
 
-#if USE(CF) || PLATFORM(EFL)
+#if USE(CF) || USE(GLIB)
 
 #if !PLATFORM(IOS)
 const double pagingTimeOut = 0.1; // Time in seconds to allow opportunistic timer to iterate over all blocks to see if the Heap is paged out.
index d324b37..4c37b19 100644 (file)
 
 #if PLATFORM(EFL)
 #include <wtf/MainThread.h>
+#elif USE(GLIB)
+#include <glib.h>
 #endif
 
 namespace JSC {
 
 bool GCActivityCallback::s_shouldCreateGCTimer = true;
 
-#if USE(CF) || PLATFORM(EFL)
+#if USE(CF) || USE(GLIB)
 
 const double timerSlop = 2.0; // Fudge factor to avoid performance cost of resetting timer.
 
@@ -64,6 +66,11 @@ GCActivityCallback::GCActivityCallback(Heap* heap)
     : GCActivityCallback(heap->vm(), WTF::isMainThread())
 {
 }
+#elif USE(GLIB)
+GCActivityCallback::GCActivityCallback(Heap* heap)
+    : GCActivityCallback(heap->vm())
+{
+}
 #endif
 
 void GCActivityCallback::doWork()
@@ -114,6 +121,34 @@ void GCActivityCallback::cancelTimer()
     m_delay = s_hour;
     stop();
 }
+#elif USE(GLIB)
+void GCActivityCallback::scheduleTimer(double newDelay)
+{
+    ASSERT(newDelay >= 0);
+    if (m_delay != -1 && newDelay * timerSlop > m_delay)
+        return;
+
+    m_delay = newDelay;
+    if (!m_delay) {
+        g_source_set_ready_time(m_timer.get(), 0);
+        return;
+    }
+
+    auto delayDuration = std::chrono::duration<double>(m_delay);
+    auto safeDelayDuration = std::chrono::microseconds::max();
+    if (delayDuration < safeDelayDuration)
+        safeDelayDuration = std::chrono::duration_cast<std::chrono::microseconds>(delayDuration);
+    gint64 currentTime = g_get_monotonic_time();
+    gint64 targetTime = currentTime + std::min<gint64>(G_MAXINT64 - currentTime, safeDelayDuration.count());
+    ASSERT(targetTime >= currentTime);
+    g_source_set_ready_time(m_timer.get(), targetTime);
+}
+
+void GCActivityCallback::cancelTimer()
+{
+    m_delay = -1;
+    g_source_set_ready_time(m_timer.get(), -1);
+}
 #endif
 
 void GCActivityCallback::didAllocate(size_t bytes)
index 73d0e89..57bd999 100644 (file)
@@ -81,6 +81,13 @@ protected:
         , m_delay(s_hour)
     {
     }
+#elif USE(GLIB)
+    GCActivityCallback(VM* vm)
+        : HeapTimer(vm)
+        , m_enabled(true)
+        , m_delay(-1)
+    {
+    }
 #else
     GCActivityCallback(VM* vm)
         : HeapTimer(vm)
@@ -95,7 +102,7 @@ protected:
 protected:
     GCActivityCallback(Heap*, CFRunLoopRef);
 #endif
-#if USE(CF) || PLATFORM(EFL)
+#if USE(CF) || USE(GLIB)
 protected:
     void cancelTimer();
     void scheduleTimer(double);
index 87e8bb7..3c7df9c 100644 (file)
@@ -347,7 +347,7 @@ Heap::Heap(VM* vm, HeapType heapType)
 #if USE(CF)
     , m_sweeper(std::make_unique<IncrementalSweeper>(this, CFRunLoopGetCurrent()))
 #else
-    , m_sweeper(std::make_unique<IncrementalSweeper>(this->vm()))
+    , m_sweeper(std::make_unique<IncrementalSweeper>(this))
 #endif
     , m_deferralDepth(0)
 #if USE(CF)
index 15e5484..4cda049 100644 (file)
@@ -36,6 +36,8 @@
 
 #if PLATFORM(EFL)
 #include <Ecore.h>
+#elif USE(GLIB)
+#include <glib.h>
 #endif
 
 namespace JSC {
@@ -140,6 +142,61 @@ bool HeapTimer::timerEvent(void* info)
     
     return ECORE_CALLBACK_CANCEL;
 }
+
+#elif USE(GLIB)
+
+static GSourceFuncs heapTimerSourceFunctions = {
+    nullptr, // prepare
+    nullptr, // check
+    // dispatch
+    [](GSource* source, GSourceFunc callback, gpointer userData) -> gboolean
+    {
+        if (g_source_get_ready_time(source) == -1)
+            return G_SOURCE_CONTINUE;
+        g_source_set_ready_time(source, -1);
+        return callback(userData);
+    },
+    nullptr, // finalize
+    nullptr, // closure_callback
+    nullptr, // closure_marshall
+};
+
+HeapTimer::HeapTimer(VM* vm)
+    : m_vm(vm)
+    , m_apiLock(&vm->apiLock())
+    , m_timer(adoptGRef(g_source_new(&heapTimerSourceFunctions, sizeof(GSource))))
+{
+    g_source_set_name(m_timer.get(), "[JavaScriptCore] HeapTimer");
+    g_source_set_callback(m_timer.get(), [](gpointer userData) -> gboolean {
+        static_cast<HeapTimer*>(userData)->timerDidFire();
+        return G_SOURCE_CONTINUE;
+    }, this, nullptr);
+    g_source_attach(m_timer.get(), g_main_context_get_thread_default());
+}
+
+HeapTimer::~HeapTimer()
+{
+    g_source_destroy(m_timer.get());
+}
+
+void HeapTimer::timerDidFire()
+{
+    m_apiLock->lock();
+
+    if (!m_apiLock->vm()) {
+        // The VM has been destroyed, so we should just give up.
+        m_apiLock->unlock();
+        return;
+    }
+
+    {
+        JSLockHolder locker(m_vm);
+        doWork();
+    }
+
+    m_apiLock->unlock();
+}
+
 #else
 HeapTimer::HeapTimer(VM* vm)
     : m_vm(vm)
index bbce5f9..ac92b94 100644 (file)
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
+#if USE(GLIB) && !PLATFORM(EFL)
+#include <wtf/glib/GRefPtr.h>
+#endif
+
 namespace JSC {
 
+class JSLock;
 class VM;
 
 class HeapTimer {
@@ -66,6 +71,10 @@ protected:
     Ecore_Timer* add(double delay, void* agent);
     void stop();
     Ecore_Timer* m_timer;
+#elif USE(GLIB)
+    void timerDidFire();
+    RefPtr<JSLock> m_apiLock;
+    GRefPtr<GSource> m_timer;
 #endif
     
 private:
index e0783d6..77e0fac 100644 (file)
 #include <wtf/HashSet.h>
 #include <wtf/WTFThreadData.h>
 
+#if USE(GLIB) && !PLATFORM(EFL)
+#include <glib.h>
+#endif
+
 namespace JSC {
 
-#if USE(CF)
+#if USE(CF) || (USE(GLIB) && !PLATFORM(EFL))
 
 static const double sweepTimeSlice = .01; // seconds
 static const double sweepTimeTotal = .10;
 static const double sweepTimeMultiplier = 1.0 / sweepTimeTotal;
 
+#if USE(CF)
 IncrementalSweeper::IncrementalSweeper(Heap* heap, CFRunLoopRef runLoop)
     : HeapTimer(heap->vm(), runLoop)
     , m_blocksToSweep(heap->m_blockSnapshot)
@@ -58,6 +63,27 @@ void IncrementalSweeper::cancelTimer()
 {
     CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade);
 }
+#elif USE(GLIB)
+IncrementalSweeper::IncrementalSweeper(Heap* heap)
+    : HeapTimer(heap->vm())
+    , m_blocksToSweep(heap->m_blockSnapshot)
+{
+}
+
+void IncrementalSweeper::scheduleTimer()
+{
+    auto delayDuration = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(sweepTimeSlice * sweepTimeMultiplier));
+    gint64 currentTime = g_get_monotonic_time();
+    gint64 targetTime = currentTime + std::min<gint64>(G_MAXINT64 - currentTime, delayDuration.count());
+    ASSERT(targetTime >= currentTime);
+    g_source_set_ready_time(m_timer.get(), targetTime);
+}
+
+void IncrementalSweeper::cancelTimer()
+{
+    g_source_set_ready_time(m_timer.get(), -1);
+}
+#endif
 
 void IncrementalSweeper::doWork()
 {
@@ -110,8 +136,8 @@ void IncrementalSweeper::willFinishSweeping()
 
 #else
 
-IncrementalSweeper::IncrementalSweeper(VM* vm)
-    : HeapTimer(vm)
+IncrementalSweeper::IncrementalSweeper(Heap* heap)
+    : HeapTimer(heap->vm())
 {
 }
 
index a86fd1c..10ffba4 100644 (file)
@@ -40,7 +40,7 @@ public:
 #if USE(CF)
     JS_EXPORT_PRIVATE IncrementalSweeper(Heap*, CFRunLoopRef);
 #else
-    explicit IncrementalSweeper(VM*);
+    explicit IncrementalSweeper(Heap*);
 #endif
 
     void startSweeping();
@@ -49,7 +49,7 @@ public:
     bool sweepNextBlock();
     void willFinishSweeping();
 
-#if USE(CF)
+#if USE(CF) || (USE(GLIB) && !PLATFORM(EFL))
 private:
     void doSweep(double startTime);
     void scheduleTimer();