LCOV - code coverage report
Current view: top level - gjs - objectbox.cpp (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 87.1 % 62 54
Test Date: 2024-04-20 17:42:51 Functions: 93.8 % 16 15
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 66.7 % 18 12

             Branch data     Line data    Source code
       1                 :             : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
       2                 :             : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
       3                 :             : // SPDX-FileCopyrightText: 2019 Marco Trevisan <marco.trevisan@canonical.com>
       4                 :             : 
       5                 :             : #include <config.h>
       6                 :             : 
       7                 :             : #include <algorithm>  // for find
       8                 :             : 
       9                 :             : #include <glib.h>
      10                 :             : 
      11                 :             : #include <js/AllocPolicy.h>
      12                 :             : #include <js/ComparisonOperators.h>
      13                 :             : #include <js/ErrorReport.h>  // for JS_ReportOutOfMemory
      14                 :             : #include <js/GCPolicyAPI.h>  // for GCPolicy (ptr only), NonGCPointe...
      15                 :             : #include <js/GCVector.h>
      16                 :             : #include <js/RootingAPI.h>
      17                 :             : #include <js/TracingAPI.h>
      18                 :             : #include <js/TypeDecls.h>
      19                 :             : 
      20                 :             : #include "gjs/jsapi-util.h"
      21                 :             : #include "gjs/macros.h"
      22                 :             : #include "gjs/objectbox.h"
      23                 :             : #include "util/log.h"
      24                 :             : 
      25                 :             : /* gjs/objectbox.cpp - GObject boxed type used to "box" a JS object so that it
      26                 :             :  * can be passed to or returned from a GObject signal, or used as the type of a
      27                 :             :  * GObject property.
      28                 :             :  */
      29                 :             : 
      30                 :             : namespace JS {
      31                 :             : template <>
      32                 :             : struct GCPolicy<ObjectBox*> : NonGCPointerPolicy<ObjectBox*> {};
      33                 :             : }  // namespace JS
      34                 :             : 
      35                 :             : namespace {
      36                 :             : JS::PersistentRooted<JS::GCVector<ObjectBox*, 0, js::SystemAllocPolicy>>
      37                 :             :     m_wrappers;
      38                 :             : }
      39                 :             : 
      40                 :             : struct ObjectBox::impl {
      41                 :          32 :     impl(ObjectBox* parent, JSObject* obj) : m_parent(parent), m_root(obj) {
      42                 :          32 :         g_atomic_ref_count_init(&m_refcount);
      43                 :          32 :         debug("Constructed");
      44                 :          32 :     }
      45                 :             : 
      46                 :             :     GJS_JSAPI_RETURN_CONVENTION
      47                 :          32 :     bool init(JSContext* cx) {
      48         [ -  + ]:          32 :         if (!m_wrappers.append(m_parent)) {
      49                 :           0 :             JS_ReportOutOfMemory(cx);
      50                 :           0 :             return false;
      51                 :             :         }
      52                 :          32 :         return true;
      53                 :             :     }
      54                 :             : 
      55                 :          32 :     ~impl() {
      56                 :          32 :         auto it = std::find(m_wrappers.begin(), m_wrappers.end(), m_parent);
      57                 :          32 :         m_wrappers.erase(it);
      58                 :          32 :         debug("Finalized");
      59                 :          32 :     }
      60                 :             : 
      61                 :          47 :     void ref() {
      62                 :          47 :         debug("incref");
      63                 :          47 :         g_atomic_ref_count_inc(&m_refcount);
      64                 :          47 :     }
      65                 :             : 
      66                 :          79 :     void unref() {
      67                 :          79 :         debug("decref");
      68         [ +  + ]:          79 :         if (g_atomic_ref_count_dec(&m_refcount))
      69         [ +  - ]:          32 :             delete m_parent;
      70                 :          79 :     }
      71                 :             : 
      72                 :         223 :     void debug(const char* what GJS_USED_VERBOSE_LIFECYCLE) {
      73                 :             :         gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
      74                 :             :                             "%s: ObjectBox %p, JSObject %s", what, m_parent,
      75                 :             :                             gjs_debug_object(m_root).c_str());
      76                 :         223 :     }
      77                 :             : 
      78                 :             :     ObjectBox* m_parent;
      79                 :             :     JS::Heap<JSObject*> m_root;
      80                 :             :     gatomicrefcount m_refcount;
      81                 :             : };
      82                 :             : 
      83                 :          32 : ObjectBox::ObjectBox(JSObject* obj) : m_impl(new ObjectBox::impl(this, obj)) {}
      84                 :             : 
      85                 :          35 : void ObjectBox::destroy(ObjectBox* object) { object->m_impl->unref(); }
      86                 :             : 
      87         [ +  - ]:          32 : void ObjectBox::destroy_impl(ObjectBox::impl* impl) { delete impl; }
      88                 :             : 
      89                 :          35 : ObjectBox::Ptr ObjectBox::boxed(JSContext* cx, JSObject* obj) {
      90                 :          35 :     ObjectBox::Ptr box;
      91                 :             : 
      92                 :             :     ObjectBox** found =
      93                 :          35 :         std::find_if(m_wrappers.begin(), m_wrappers.end(),
      94                 :          10 :                      [obj](ObjectBox* b) { return b->m_impl->m_root == obj; });
      95         [ +  + ]:          35 :     if (found != m_wrappers.end()) {
      96                 :           3 :         box = *found;
      97                 :           3 :         box->m_impl->ref();
      98                 :           3 :         box->m_impl->debug("Reusing box");
      99                 :             :     } else {
     100                 :          32 :         box = new ObjectBox(obj);
     101         [ -  + ]:          32 :         if (!box->m_impl->init(cx))
     102                 :           0 :             return nullptr;
     103                 :             :     }
     104                 :             : 
     105                 :          35 :     return box;
     106                 :          35 : }
     107                 :             : 
     108                 :          30 : JSObject* ObjectBox::object_for_c_ptr(JSContext* cx, ObjectBox* box) {
     109         [ -  + ]:          30 :     if (!box) {
     110                 :           0 :         gjs_throw(cx, "Cannot get JSObject for null ObjectBox pointer");
     111                 :           0 :         return nullptr;
     112                 :             :     }
     113                 :             : 
     114                 :          30 :     box->m_impl->debug("retrieved JSObject");
     115                 :          30 :     return box->m_impl->m_root.get();
     116                 :             : }
     117                 :             : 
     118                 :          44 : void* ObjectBox::boxed_copy(void* boxed) {
     119                 :          44 :     auto* box = static_cast<ObjectBox*>(boxed);
     120                 :          44 :     box->m_impl->ref();
     121                 :          44 :     return box;
     122                 :             : }
     123                 :             : 
     124                 :          44 : void ObjectBox::boxed_free(void* boxed) {
     125                 :          44 :     auto* box = static_cast<ObjectBox*>(boxed);
     126                 :          44 :     box->m_impl->unref();
     127                 :          44 : }
     128                 :             : 
     129                 :         536 : GType ObjectBox::gtype() {
     130                 :             :     // Initialization of static local variable guaranteed only once in C++11
     131                 :         102 :     static GType type_id = g_boxed_type_register_static(
     132   [ +  +  +  - ]:         536 :         "JSObject", &ObjectBox::boxed_copy, &ObjectBox::boxed_free);
     133                 :         536 :     return type_id;
     134                 :             : }
     135                 :             : 
     136                 :           0 : void ObjectBox::trace(JSTracer* trc) {
     137                 :           0 :     JS::TraceEdge(trc, &m_impl->m_root, "object in ObjectBox");
     138                 :           0 : }
        

Generated by: LCOV version 2.0-1