[gjs: 5/7] object: Use smaller data structure for closures



commit 93cf31db41b4a533f8e264da2213c15d0501f4e7
Author: Philip Chimento <philip chimento gmail com>
Date:   Wed Jun 20 00:36:44 2018 -0700

    object: Use smaller data structure for closures
    
    Some time ago, we switched from GList* to std::set to store the list of
    GClosures associated with an object. std::set was the most time-efficient
    container, but we need to optimize for space here. std::forward_list is
    comparable to GSList.
    
    This reduces ObjectInstance to 96 bytes and ObjectPrototype to 192 bytes.

 gi/object.cpp | 14 +++++++++++---
 gi/object.h   |  8 +++-----
 2 files changed, 14 insertions(+), 8 deletions(-)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index 322c586c..ed10722b 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -63,7 +63,7 @@
 #if defined(__x86_64__) && defined(__clang__)
 /* This isn't meant to be comprehensive, but should trip on at least one CI job
  * if sizeof(ObjectInstance) is increased. */
-static_assert(sizeof(ObjectInstance) <= 112,
+static_assert(sizeof(ObjectInstance) <= 96,
               "Think very hard before increasing the size of ObjectInstance. "
               "There can be tens of thousands of them alive in a typical "
               "gnome-shell run.");
@@ -1395,7 +1395,7 @@ void ObjectBase::invalidate_all_closures(void) {
         GClosure *closure = *m_closures.begin();
         g_closure_invalidate(closure);
         /* Erase element if not already erased */
-        m_closures.erase(closure);
+        m_closures.remove(closure);
     }
 }
 
@@ -1695,11 +1695,19 @@ void ObjectBase::associate_closure(JSContext* cx, GClosure* closure) {
 
     /* This is a weak reference, and will be cleared when the closure is
      * invalidated */
-    m_closures.insert(closure);
+    auto already_has = std::find(m_closures.begin(), m_closures.end(), closure);
+    g_assert(already_has == m_closures.end() &&
+             "This closure was already associated with this object");
+    m_closures.push_front(closure);
     g_closure_add_invalidate_notifier(closure, this,
                                       &ObjectBase::closure_invalidated_notify);
 }
 
+void ObjectBase::closure_invalidated_notify(void* data, GClosure* closure) {
+    auto* priv = static_cast<ObjectBase*>(data);
+    priv->m_closures.remove(closure);
+}
+
 bool ObjectBase::connect(JSContext* cx, unsigned argc, JS::Value* vp) {
     GJS_GET_PRIV(cx, argc, vp, args, obj, ObjectBase, priv);
     if (!priv)
diff --git a/gi/object.h b/gi/object.h
index 7c4327c7..4c6cd59f 100644
--- a/gi/object.h
+++ b/gi/object.h
@@ -27,8 +27,8 @@
 #include <glib-object.h>
 #include <girepository.h>
 
+#include <forward_list>
 #include <functional>
-#include <set>
 #include <stack>
 #include <vector>
 
@@ -89,7 +89,7 @@ class ObjectBase {
     /* a list of all GClosures installed on this object (from
      * signals, trampolines, explicit GClosures, and vfuncs on prototypes),
      * used when tracing */
-    std::set<GClosure*> m_closures;
+    std::forward_list<GClosure*> m_closures;
 
     explicit ObjectBase(ObjectPrototype* proto = nullptr) : m_proto(proto) {}
 
@@ -200,9 +200,7 @@ class ObjectBase {
 
  public:
     void associate_closure(JSContext* cx, GClosure* closure);
-    static void closure_invalidated_notify(void* data, GClosure* closure) {
-        static_cast<ObjectBase*>(data)->m_closures.erase(closure);
-    }
+    static void closure_invalidated_notify(void* data, GClosure* closure);
 
     /* JSClass operations */
 


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