[gjs: 2/3] objectbox: Keep a vector of wrappers to reuse them




commit 8ac2ed19b26e66ed981bb3f17917633a48867699
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Wed Jun 5 22:32:20 2019 -0500

    objectbox: Keep a vector of wrappers to reuse them
    
    When creating an ObjectBox, we might try to recreate a wrapper for an
    object that we're already rooting (for example when emitting the same
    object we received as signal parameter as another signal emission
    parameter).
    
    In such case, we can just ref the wrapper and reuse the one we have.

 gjs/objectbox.cpp     | 65 +++++++++++++++++++++++++++++++++++++++++++++------
 gjs/objectbox.h       | 10 ++++++--
 tools/process_iwyu.py |  1 +
 3 files changed, 67 insertions(+), 9 deletions(-)
---
diff --git a/gjs/objectbox.cpp b/gjs/objectbox.cpp
index 3bbef096..3c60c05e 100644
--- a/gjs/objectbox.cpp
+++ b/gjs/objectbox.cpp
@@ -6,10 +6,16 @@
 
 #include <stddef.h>  // for size_t
 
+#include <algorithm>  // for find
+
 #include <glib.h>
 
+#include <js/AllocPolicy.h>
 #include <js/ComparisonOperators.h>
+#include <js/GCPolicyAPI.h>
+#include <js/GCVector.h>
 #include <js/RootingAPI.h>
+#include <js/TracingAPI.h>
 #include <js/TypeDecls.h>
 
 #include "gjs/jsapi-util.h"
@@ -21,10 +27,35 @@
  * GObject property.
  */
 
+namespace JS {
+template <>
+struct GCPolicy<ObjectBox*> : NonGCPointerPolicy<ObjectBox*> {};
+}  // namespace JS
+
+namespace {
+JS::PersistentRooted<JS::GCVector<ObjectBox*, 0, js::SystemAllocPolicy>>
+    m_wrappers;
+}
+
 struct ObjectBox::impl {
-    impl(ObjectBox* parent, JSContext* cx, JSObject* obj)
-        : m_parent(parent), m_root(cx, obj) {
+    impl(ObjectBox* parent, JSObject* obj) : m_parent(parent), m_root(obj) {
         g_atomic_ref_count_init(&m_refcount);
+        debug("Constructed");
+    }
+
+    GJS_JSAPI_RETURN_CONVENTION
+    bool init(JSContext* cx) {
+        if (!m_wrappers.append(m_parent)) {
+            JS_ReportOutOfMemory(cx);
+            return false;
+        }
+        return true;
+    }
+
+    ~impl() {
+        auto it = std::find(m_wrappers.begin(), m_wrappers.end(), m_parent);
+        m_wrappers.erase(it);
+        debug("Finalized");
     }
 
     void ref() {
@@ -45,16 +76,32 @@ struct ObjectBox::impl {
     }
 
     ObjectBox* m_parent;
-    JS::PersistentRooted<JSObject*> m_root;
+    JS::Heap<JSObject*> m_root;
     gatomicrefcount m_refcount;
 };
 
-ObjectBox::ObjectBox(JSContext* cx, JSObject* obj)
-    : m_impl(std::make_unique<ObjectBox::impl>(this, cx, obj)) {}
+ObjectBox::ObjectBox(JSObject* obj)
+    : m_impl(std::make_unique<ObjectBox::impl>(this, obj)) {}
 
 ObjectBox::Ptr ObjectBox::boxed(JSContext* cx, JSObject* obj) {
-    return ObjectBox::Ptr(new ObjectBox(cx, obj),
-                          [](ObjectBox* box) { box->m_impl->unref(); });
+    ObjectBox* box = nullptr;
+
+    for (auto* b : m_wrappers) {
+        if (b->m_impl->m_root == obj) {
+            box = b;
+            box->m_impl->ref();
+            box->m_impl->debug("Reusing box");
+            break;
+        }
+    }
+
+    if (!box) {
+        box = new ObjectBox(obj);
+        if (!box->m_impl->init(cx))
+            return ObjectBox::Ptr(nullptr, [](ObjectBox*) {});
+    }
+
+    return ObjectBox::Ptr(box, [](ObjectBox* b) { b->m_impl->unref(); });
 }
 
 JSObject* ObjectBox::object_for_c_ptr(JSContext* cx, ObjectBox* box) {
@@ -87,3 +134,7 @@ GType ObjectBox::gtype() {
 
     return type_id;
 }
+
+void ObjectBox::trace(JSTracer* trc) {
+    JS::TraceEdge(trc, &m_impl->m_root, "object in ObjectBox");
+}
diff --git a/gjs/objectbox.h b/gjs/objectbox.h
index 62179fc2..276fd5b8 100644
--- a/gjs/objectbox.h
+++ b/gjs/objectbox.h
@@ -14,17 +14,23 @@
 
 #include "gjs/macros.h"
 
+class JSTracer;
+
 struct ObjectBox {
     using Ptr = std::unique_ptr<ObjectBox, void (*)(ObjectBox*)>;
 
     [[nodiscard]] static GType gtype();
-    [[nodiscard]] static ObjectBox::Ptr boxed(JSContext*, JSObject*);
+
+    GJS_JSAPI_RETURN_CONVENTION
+    static ObjectBox::Ptr boxed(JSContext*, JSObject*);
 
     GJS_JSAPI_RETURN_CONVENTION
     static JSObject* object_for_c_ptr(JSContext*, ObjectBox*);
 
+    void trace(JSTracer* trc);
+
  private:
-    ObjectBox(JSContext*, JSObject*);
+    explicit ObjectBox(JSObject*);
 
     struct impl;
     std::unique_ptr<impl> m_impl;
diff --git a/tools/process_iwyu.py b/tools/process_iwyu.py
index 7d4ac181..0bc6d5b9 100755
--- a/tools/process_iwyu.py
+++ b/tools/process_iwyu.py
@@ -80,6 +80,7 @@ FALSE_POSITIVES = (
     ('gi/value.cpp', '#include <utility>', 'for forward'),
     ('gjs/importer.cpp', '#include <utility>', 'for forward'),
     ('gjs/module.cpp', '#include <utility>', 'for forward'),
+    ('gjs/objectbox.cpp', '#include <utility>', 'for forward'),
 
     # False positive when using EnumType operators
     ('gi/arg-cache.h', '#include <type_traits>', 'for enable_if_t'),


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