File gjs-aggressive-gc.patch of Package gjs.9860

diff --git a/gi/object.cpp b/gi/object.cpp
index 74121f8..23a1b4f 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -862,12 +862,34 @@ handle_toggle_down(GObject *gobj)
      * collected by the GC
      */
     if (priv->keep_alive != NULL) {
+        GjsContext *context;
+
         gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Removing object from keep alive");
         gjs_keep_alive_remove_child(priv->keep_alive,
                                     gobj_no_longer_kept_alive_func,
                                     obj,
                                     priv);
         priv->keep_alive = NULL;
+
+        /* During a GC, the collector asks each object which other
+         * objects that it wants to hold on to so if there's an entire
+         * section of the heap graph that's not connected to anything
+         * else, and not reachable from the root set, then it can be
+         * trashed all at once.
+         *
+         * GObjects, however, don't work like that, there's only a
+         * reference count but no notion of who owns the reference so,
+         * a JS object that's proxying a GObject is unconditionally held
+         * alive as long as the GObject has >1 references.
+         *
+         * Since we cannot know how many more wrapped GObjects are going
+         * be marked for garbage collection after the owner is destroyed,
+         * always queue a garbage collection when a toggle reference goes
+         * down.
+         */
+        context = gjs_context_get_current();
+        if (!_gjs_context_destroying(context))
+            _gjs_context_schedule_gc(context);
     }
 }
 
diff --git a/gjs/context-private.h b/gjs/context-private.h
index 1d4e6e0..0b6fd58 100644
--- a/gjs/context-private.h
+++ b/gjs/context-private.h
@@ -33,6 +33,8 @@ gboolean     _gjs_context_destroying                  (GjsContext *js_context);
 
 void         _gjs_context_schedule_gc_if_needed       (GjsContext *js_context);
 
+void _gjs_context_schedule_gc(GjsContext *js_context);
+
 G_END_DECLS
 
 #endif  /* __GJS_CONTEXT_PRIVATE_H__ */
diff --git a/gjs/context.cpp b/gjs/context.cpp
index 19120c4..b0cbbd3 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -70,6 +70,7 @@ struct _GjsContext {
     gboolean destroying;
 
     guint    auto_gc_id;
+    bool     force_gc;
 
     jsid const_strings[GJS_STRING_LAST];
 };
@@ -535,14 +536,25 @@ static gboolean
 trigger_gc_if_needed (gpointer user_data)
 {
     GjsContext *js_context = GJS_CONTEXT(user_data);
+
     js_context->auto_gc_id = 0;
-    gjs_gc_if_needed(js_context->context);
+
+    if (js_context->force_gc)
+        JS_GC(js_context->runtime);
+    else
+        gjs_gc_if_needed(js_context->context);
+
+    js_context->force_gc = FALSE;
+
     return FALSE;
 }
 
-void
-_gjs_context_schedule_gc_if_needed (GjsContext *js_context)
+static void
+_gjs_context_schedule_gc_internal (GjsContext *js_context,
+                                   bool        force_gc)
 {
+    js_context->force_gc |= force_gc;
+
     if (js_context->auto_gc_id > 0)
         return;
 
@@ -551,6 +563,18 @@ _gjs_context_schedule_gc_if_needed (GjsContext *js_context)
                                              js_context, NULL);
 }
 
+void
+_gjs_context_schedule_gc (GjsContext *js_context)
+{
+    _gjs_context_schedule_gc_internal(js_context, TRUE);
+}
+
+void
+_gjs_context_schedule_gc_if_needed (GjsContext *js_context)
+{
+    _gjs_context_schedule_gc_internal(js_context, FALSE);
+}
+
 /**
  * gjs_context_maybe_gc:
  * @context: a #GjsContext
openSUSE Build Service is sponsored by