[gjs/wip/ptomato/mozjs38: 5/28] keep-alive: Update hash keys when objects move



commit 71a48cad17432859304d9890ccb4c46436514add
Author: Philip Chimento <philip endlessm com>
Date:   Wed Jan 18 17:18:43 2017 -0800

    keep-alive: Update hash keys when objects move
    
    The garbage collector can change the locations of objects. Since we use
    the object pointer as part of the hash function for the keep-alive hash
    table, an object moving would invalidate the hash table key. Therefore,
    we remove and reinsert each key if tracing changed the pointer's
    location.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=776966

 gi/keep-alive.cpp |   35 +++++++++++++++++++++++++----------
 1 files changed, 25 insertions(+), 10 deletions(-)
---
diff --git a/gi/keep-alive.cpp b/gi/keep-alive.cpp
index 8adbabc..488a771 100644
--- a/gi/keep-alive.cpp
+++ b/gi/keep-alive.cpp
@@ -113,16 +113,10 @@ keep_alive_finalize(JSFreeOp *fop,
 }
 
 static void
-trace_foreach(void *key,
-              void *value,
-              void *data)
+reinsert(Child      *child,
+         GHashTable *children)
 {
-    Child *child = (Child *) value;
-    JSTracer *tracer = (JSTracer *) data;
-
-    if (child->child != NULL) {
-        JS_CallHeapObjectTracer(tracer, &child->child, "keep-alive::val");
-    }
+    g_hash_table_replace(children, child, child);
 }
 
 static void
@@ -138,7 +132,28 @@ keep_alive_trace(JSTracer *tracer,
 
     g_assert(!priv->inside_trace);
     priv->inside_trace = true;
-    g_hash_table_foreach(priv->children, trace_foreach, tracer);
+
+    GHashTableIter iter;
+    void *key;
+    GSList *children_to_reinsert = NULL;
+    g_hash_table_iter_init(&iter, priv->children);
+    while (g_hash_table_iter_next(&iter, &key, NULL)) {
+        Child *child = static_cast<Child *>(key);
+        JSObject *old_key = child->child.get();
+        JS_CallHeapObjectTracer(tracer, &child->child, "keep-alive::val");
+
+        /* Remove and reinsert if the pointer's location was updated,
+         * because that means the hash value is different */
+        if (child->child.get() != old_key) {
+            g_hash_table_iter_steal(&iter);
+            children_to_reinsert = g_slist_prepend(children_to_reinsert,
+                                                   child);
+        }
+    }
+    g_slist_foreach(children_to_reinsert, (GFunc) reinsert,
+                    priv->children);
+    g_slist_free(children_to_reinsert);
+
     priv->inside_trace = false;
 }
 


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