[gjs: 10/26] object: Port object_init_list to GCVector



commit c5c8d9f5757c591d57557c2b7e0657570148ca81
Author: Philip Chimento <philip chimento gmail com>
Date:   Tue Jan 22 22:38:07 2019 -0800

    object: Port object_init_list to GCVector
    
    Previously we used a std::stack with individual instances of
    JS::PersistentRootedObject in it, to hold a list of JSObjects in between
    the time of their creation and the time their GObject instance init
    function runs. This is wasteful because each individual PersistentRooted
    is part of a linked list of permanently rooted objects. Instead, we can
    put them in a GCVector and persistently root the whole thing once.
    
    We also move that storage from a static variable to a member of the
    GjsContext class.

 gi/gobject.cpp        | 17 ++++++++++-------
 gi/object.cpp         | 10 +++++++---
 gi/object.h           |  4 ----
 gjs/context-private.h |  9 +++++++++
 gjs/context.cpp       |  1 +
 5 files changed, 27 insertions(+), 14 deletions(-)
---
diff --git a/gi/gobject.cpp b/gi/gobject.cpp
index debfa6a5..0c54f4e4 100644
--- a/gi/gobject.cpp
+++ b/gi/gobject.cpp
@@ -80,7 +80,10 @@ static void gjs_object_base_finalize(void* klass) {
 static GObject* gjs_object_constructor(
     GType type, unsigned n_construct_properties,
     GObjectConstructParam* construct_properties) {
-    if (!ObjectInstance::object_init_list.empty()) {
+    JSContext* cx = current_context();
+    GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
+
+    if (!gjs->object_init_list().empty()) {
         GType parent_type = g_type_parent(type);
 
         /* The object is being constructed from JS:
@@ -98,7 +101,6 @@ static GObject* gjs_object_constructor(
      * Construct the JS object from the constructor, then use the GObject
      * that was associated in gjs_object_custom_init()
      */
-    JSContext *cx = current_context();
     JSAutoRequest ar(cx);
     JSAutoCompartment ac(cx, gjs_get_import_global(cx));
 
@@ -182,12 +184,13 @@ static void gjs_object_class_init(void* class_pointer, void* user_data) {
 }
 
 static void gjs_object_custom_init(GTypeInstance* instance, void* klass) {
-    if (ObjectInstance::object_init_list.empty())
-        return;
-
     JSContext *cx = current_context();
+    GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
+
+    if (gjs->object_init_list().empty())
+        return;
 
-    JS::RootedObject object(cx, ObjectInstance::object_init_list.top());
+    JS::RootedObject object(cx, gjs->object_init_list().back());
     auto* priv_base = ObjectBase::for_js_nocheck(object);
     g_assert(priv_base);  // Should have been set in init_impl()
     ObjectInstance* priv = priv_base->to_instance();
@@ -199,7 +202,7 @@ static void gjs_object_custom_init(GTypeInstance* instance, void* klass) {
         return;
     }
 
-    ObjectInstance::object_init_list.pop();
+    gjs->object_init_list().popBack();
 
     if (!priv->init_custom_class_from_gobject(cx, object, G_OBJECT(instance)))
         gjs_log_exception(cx);
diff --git a/gi/object.cpp b/gi/object.cpp
index 3d9dc25b..1a9cf50c 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -69,7 +69,6 @@ static_assert(sizeof(ObjectInstance) <= 88,
               "gnome-shell run.");
 #endif  // x86-64 clang
 
-std::stack<JS::PersistentRootedObject> ObjectInstance::object_init_list{};
 bool ObjectInstance::s_weak_pointer_callback = false;
 ObjectInstance *ObjectInstance::wrapped_gobject_list = nullptr;
 
@@ -1469,8 +1468,13 @@ ObjectInstance::init_impl(JSContext              *context,
        will be popped in gjs_object_custom_init() later
        down.
     */
-    if (g_type_get_qdata(gtype(), ObjectInstance::custom_type_quark()))
-        object_init_list.emplace(context, object);
+    if (g_type_get_qdata(gtype(), ObjectInstance::custom_type_quark())) {
+        GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context);
+        if (!gjs->object_init_list().append(object)) {
+            JS_ReportOutOfMemory(context);
+            return false;
+        }
+    }
 
     g_assert(names.size() == values.size());
     GObject* gobj = g_object_new_with_properties(gtype(), values.size(),
diff --git a/gi/object.h b/gi/object.h
index 8a7be4c5..f8b90785 100644
--- a/gi/object.h
+++ b/gi/object.h
@@ -29,7 +29,6 @@
 
 #include <forward_list>
 #include <functional>
-#include <stack>
 #include <vector>
 
 #include "gi/wrapperutils.h"
@@ -300,9 +299,6 @@ class ObjectInstance : public GIWrapperInstance<ObjectBase, ObjectPrototype,
 
     static bool s_weak_pointer_callback;
 
- public:
-    static std::stack<JS::PersistentRootedObject> object_init_list;
-
     /* Constructors */
 
  private:
diff --git a/gjs/context-private.h b/gjs/context-private.h
index 5474e1e9..24ec33e5 100644
--- a/gjs/context-private.h
+++ b/gjs/context-private.h
@@ -38,6 +38,7 @@
 #include "js/SweepingAPI.h"
 
 using JobQueue = JS::GCVector<JSObject*, 0, js::SystemAllocPolicy>;
+using ObjectInitList = JS::GCVector<JSObject*, 0, js::SystemAllocPolicy>;
 using FundamentalTable =
     JS::GCHashMap<void*, JS::Heap<JSObject*>, js::DefaultHasher<void*>,
                   js::SystemAllocPolicy>;
@@ -99,6 +100,11 @@ class GjsContextPrivate {
     JS::WeakCache<FundamentalTable>* m_fundamental_table;
     JS::WeakCache<GTypeTable>* m_gtype_table;
 
+    // List that holds JSObject GObject wrappers for JS-created classes, from
+    // the time of their creation until their GObject instance init function is
+    // called
+    ObjectInitList m_object_init_list;
+
     uint8_t m_exit_code;
 
     /* flags */
@@ -158,6 +164,9 @@ class GjsContextPrivate {
     GJS_USE JS::WeakCache<GTypeTable>& gtype_table(void) {
         return *m_gtype_table;
     }
+    GJS_USE ObjectInitList& object_init_list(void) {
+        return m_object_init_list;
+    }
     GJS_USE
     static const GjsAtoms& atoms(JSContext* cx) { return from_cx(cx)->m_atoms; }
 
diff --git a/gjs/context.cpp b/gjs/context.cpp
index e55bc5f9..d90e540c 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -300,6 +300,7 @@ void GjsContextPrivate::trace(JSTracer* trc, void* data) {
     JS::TraceEdge<JSObject*>(trc, &gjs->m_global, "GJS global object");
     gjs->m_atoms.trace(trc);
     gjs->m_job_queue.trace(trc);
+    gjs->m_object_init_list.trace(trc);
 }
 
 void GjsContextPrivate::warn_about_unhandled_promise_rejections(void) {


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