[gjs] context: Drain toggle queue at start of GC



commit 404e7053ac9805ed2cb0259138e9ac0e4464f03f
Author: Philip Chimento <philip endlessm com>
Date:   Thu Mar 9 18:45:48 2017 -0800

    context: Drain toggle queue at start of GC
    
    In order to minimize the chances of a JS object being garbage collected
    while it is queued to toggle up, we handle all pending object toggles
    when garbage collection starts.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=778862

 gi/object.cpp   |    5 ++---
 gjs/context.cpp |   20 +++++++++++++++-----
 2 files changed, 17 insertions(+), 8 deletions(-)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index 91a10bc..0bd4b12 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -1021,9 +1021,8 @@ wrapped_gobj_toggle_notify(gpointer      data,
      * is dead, and attempting to keep it alive would soon crash
      * the process. Plus, if we touch the JSAPI, libmozjs aborts in
      * the first BeginRequest.
-     * Thus, in the toggleup+sweeping case we deassociate the object
-     * and the wrapper and let the wrapper die. Then, if the object
-     * appears again, we log a critical.
+     * Thus, we drain the toggle queue when GC starts, in order to
+     * prevent this from happening.
      * In practice, a toggle up during JS finalize can only happen
      * for temporary refs/unrefs of objects that are garbage anyway,
      * because JS code is never invoked while the finalizers run
diff --git a/gjs/context.cpp b/gjs/context.cpp
index 30c9ca6..e55e667 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -279,6 +279,19 @@ gjs_printerr(JSContext *context,
     return true;
 }
 
+static void
+on_garbage_collect(JSRuntime *rt,
+                   JSGCStatus status,
+                   void      *data)
+{
+    /* We finalize any pending toggle refs before doing any garbage collection,
+     * so that we can collect the JS wrapper objects, and in order to minimize
+     * the chances of objects having a pending toggle up queued when they are
+     * garbage collected. */
+    if (status == JSGC_BEGIN)
+        gjs_object_clear_toggles();
+}
+
 /* Requires request, does not throw error */
 static bool
 gjs_define_promise_object(JSContext       *cx,
@@ -403,11 +416,6 @@ gjs_context_dispose(GObject *object)
         gjs_debug(GJS_DEBUG_CONTEXT,
                   "Destroying JS context");
 
-        /* Finalize any pending toggle refs left over on the main context,
-         * before doing any garbage collection, so that we can collect the JS
-         * wrapper objects */
-        gjs_object_clear_toggles();
-
         JS_BeginRequest(js_context->context);
 
         /* Do a full GC here before tearing down, since once we do
@@ -505,6 +513,8 @@ gjs_context_constructed(GObject *object)
 
     JS_BeginRequest(js_context->context);
 
+    JS_SetGCCallback(js_context->runtime, on_garbage_collect, js_context);
+
     /* set ourselves as the private data */
     JS_SetContextPrivate(js_context->context, js_context);
     JS::RootedObject global(js_context->context);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]