LCOV - code coverage report
Current view: top level - gi - arg-cache.h (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 93.0 % 57 53
Test Date: 2025-05-07 12:25:00 Functions: 88.9 % 27 24
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 86.4 % 22 19

             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: 2013 Giovanni Campagna <scampa.giovanni@gmail.com>
       4                 :             : // SPDX-FileCopyrightText: 2020 Marco Trevisan <marco.trevisan@canonical.com>
       5                 :             : 
       6                 :             : #ifndef GI_ARG_CACHE_H_
       7                 :             : #define GI_ARG_CACHE_H_
       8                 :             : 
       9                 :             : #include <config.h>
      10                 :             : 
      11                 :             : #include <stdint.h>
      12                 :             : 
      13                 :             : #include <limits>
      14                 :             : 
      15                 :             : #include <girepository.h>
      16                 :             : #include <glib-object.h>
      17                 :             : 
      18                 :             : #include <js/TypeDecls.h>
      19                 :             : #include <mozilla/Maybe.h>
      20                 :             : 
      21                 :             : #include "gi/arg.h"
      22                 :             : #include "gi/info.h"
      23                 :             : #include "gjs/auto.h"
      24                 :             : #include "gjs/enum-utils.h"
      25                 :             : #include "gjs/macros.h"
      26                 :             : 
      27                 :             : class GjsFunctionCallState;
      28                 :             : 
      29                 :             : enum NotIntrospectableReason : uint8_t {
      30                 :             :     CALLBACK_OUT,
      31                 :             :     DESTROY_NOTIFY_NO_CALLBACK,
      32                 :             :     DESTROY_NOTIFY_NO_USER_DATA,
      33                 :             :     INTERFACE_TRANSFER_CONTAINER,
      34                 :             :     OUT_CALLER_ALLOCATES_NON_STRUCT,
      35                 :             :     UNREGISTERED_BOXED_WITH_TRANSFER,
      36                 :             :     UNREGISTERED_UNION,
      37                 :             :     UNSUPPORTED_TYPE,
      38                 :             :     LAST_REASON
      39                 :             : };
      40                 :             : 
      41                 :             : namespace Gjs {
      42                 :             : namespace Arg {
      43                 :             : 
      44                 :             : struct Instance;
      45                 :             : 
      46                 :             : enum class Kind {
      47                 :             :     NORMAL,
      48                 :             :     INSTANCE,
      49                 :             :     RETURN_VALUE,
      50                 :             : };
      51                 :             : 
      52                 :             : class ReturnTag {
      53                 :             :     GITypeTag m_tag : 5;
      54                 :             :     GIInfoType m_info_type : 5;
      55                 :             :     bool m_is_pointer : 1;
      56                 :             : 
      57                 :             :  public:
      58                 :       18003 :     constexpr explicit ReturnTag(GITypeTag tag)
      59                 :       18003 :         : m_tag(tag), m_info_type(GI_INFO_TYPE_INVALID), m_is_pointer(false) {}
      60                 :             :     constexpr explicit ReturnTag(GITypeTag tag, GIInfoType info_type,
      61                 :             :                                  bool is_pointer)
      62                 :             :         : m_tag(tag), m_info_type(info_type), m_is_pointer(is_pointer) {}
      63                 :       21560 :     explicit ReturnTag(GITypeInfo* type_info)
      64                 :       21560 :         : m_tag(g_type_info_get_tag(type_info)),
      65                 :       21560 :           m_info_type(GI_INFO_TYPE_INVALID),
      66                 :       21560 :           m_is_pointer(g_type_info_is_pointer(type_info)) {
      67         [ +  + ]:       21560 :         if (m_tag == GI_TYPE_TAG_INTERFACE) {
      68                 :             :             GI::AutoBaseInfo interface_info{
      69                 :       21446 :                 g_type_info_get_interface(type_info)};
      70                 :       21446 :             m_info_type = g_base_info_get_type(interface_info);
      71                 :       21446 :         }
      72                 :       21560 :     }
      73                 :             : 
      74                 :       59666 :     constexpr GITypeTag tag() const { return m_tag; }
      75                 :             :     [[nodiscard]]
      76                 :        2100 :     constexpr bool is_enum_or_flags_interface() const {
      77         [ +  - ]:        4200 :         return m_tag == GI_TYPE_TAG_INTERFACE &&
      78         [ +  + ]:        2100 :                (m_info_type == GI_INFO_TYPE_ENUM ||
      79         [ +  - ]:        2216 :                 m_info_type == GI_INFO_TYPE_FLAGS);
      80                 :             :     }
      81                 :       39563 :     constexpr GIInfoType interface_type() const { return m_info_type; }
      82                 :       39563 :     constexpr bool is_pointer() const { return m_is_pointer; }
      83                 :             : };
      84                 :             : 
      85                 :             : }  // namespace Arg
      86                 :             : 
      87                 :             : // When creating an Argument, pass it directly to ArgsCache::set_argument() or
      88                 :             : // one of the similar methods, which will call init_common() on it and store it
      89                 :             : // in the appropriate place in the arguments cache.
      90                 :             : struct Argument {
      91                 :             :     // Convenience struct to prevent long argument lists to make() and the
      92                 :             :     // functions that call it
      93                 :             :     struct Init {
      94                 :             :         const char* name;
      95                 :             :         uint8_t index;
      96                 :             :         GITransfer transfer : 2;
      97                 :             :         GjsArgumentFlags flags : 6;
      98                 :             :     };
      99                 :             : 
     100                 :       35419 :     virtual ~Argument() = default;
     101                 :             : 
     102                 :             :     GJS_JSAPI_RETURN_CONVENTION
     103                 :             :     virtual bool in(JSContext* cx, GjsFunctionCallState*,
     104                 :             :                     GIArgument* in_argument, JS::HandleValue value);
     105                 :             : 
     106                 :             :     GJS_JSAPI_RETURN_CONVENTION
     107                 :             :     virtual bool out(JSContext* cx, GjsFunctionCallState*,
     108                 :             :                      GIArgument* out_argument, JS::MutableHandleValue value);
     109                 :             : 
     110                 :             :     GJS_JSAPI_RETURN_CONVENTION
     111                 :             :     virtual bool release(JSContext* cx, GjsFunctionCallState*,
     112                 :             :                          GIArgument* in_argument, GIArgument* out_argument);
     113                 :             : 
     114                 :        2146 :     virtual GjsArgumentFlags flags() const {
     115                 :        2146 :         GjsArgumentFlags flags = GjsArgumentFlags::NONE;
     116         [ +  + ]:        2146 :         if (m_skip_in)
     117                 :        1535 :             flags |= GjsArgumentFlags::SKIP_IN;
     118                 :             :         else
     119                 :         611 :             flags |= GjsArgumentFlags::ARG_IN;
     120         [ +  + ]:        2146 :         if (m_skip_out)
     121                 :         553 :             flags |= GjsArgumentFlags::SKIP_OUT;
     122                 :             :         else
     123                 :        1593 :             flags |= GjsArgumentFlags::ARG_OUT;
     124                 :             : 
     125                 :        2146 :         return flags;
     126                 :             :     }
     127                 :             : 
     128                 :             :     // Introspected functions can have up to 253 arguments. The callback
     129                 :             :     // closure or destroy notify parameter may have a value of 255 to indicate
     130                 :             :     // that it is absent.
     131                 :             :     static constexpr uint8_t MAX_ARGS = std::numeric_limits<uint8_t>::max() - 2;
     132                 :             :     static constexpr uint8_t ABSENT = std::numeric_limits<uint8_t>::max();
     133                 :             : 
     134                 :          78 :     constexpr const char* arg_name() const { return m_arg_name; }
     135                 :             : 
     136                 :       83858 :     constexpr bool skip_in() const { return m_skip_in; }
     137                 :             : 
     138                 :      121431 :     constexpr bool skip_out() const { return m_skip_out; }
     139                 :             : 
     140                 :             :  protected:
     141                 :       35981 :     constexpr Argument() : m_skip_in(false), m_skip_out(false) {}
     142                 :             : 
     143                 :           0 :     virtual mozilla::Maybe<Arg::ReturnTag> return_tag() const { return {}; }
     144                 :           0 :     virtual mozilla::Maybe<const Arg::Instance*> as_instance() const {
     145                 :           0 :         return {};
     146                 :             :     }
     147                 :             : 
     148                 :        3609 :     constexpr void set_instance_parameter() {
     149                 :        3609 :         m_arg_name = "instance parameter";
     150                 :        3609 :         m_skip_out = true;
     151                 :        3609 :     }
     152                 :             : 
     153                 :        9370 :     constexpr void set_return_value() { m_arg_name = "return value"; }
     154                 :             : 
     155                 :             :     bool invalid(JSContext*, const char* func = nullptr) const;
     156                 :             : 
     157                 :             :     const char* m_arg_name = nullptr;
     158                 :             :     bool m_skip_in : 1;
     159                 :             :     bool m_skip_out : 1;
     160                 :             : 
     161                 :             :  private:
     162                 :             :     friend struct ArgsCache;
     163                 :             : 
     164                 :             :     template <typename T, Arg::Kind ArgKind>
     165                 :             :     static void init_common(const Init&, T* arg);
     166                 :             : };
     167                 :             : 
     168                 :             : using ArgumentPtr = AutoCppPointer<Argument>;
     169                 :             : 
     170                 :             : // This is a trick to print out the sizes of the structs at compile time, in
     171                 :             : // an error message:
     172                 :             : // template <int s> struct Measure;
     173                 :             : // Measure<sizeof(Argument)> arg_cache_size;
     174                 :             : 
     175                 :             : #if defined(__x86_64__) && defined(__clang__) && !defined(_MSC_VER)
     176                 :             : #    define GJS_DO_ARGUMENTS_SIZE_CHECK 1
     177                 :             : // This isn't meant to be comprehensive, but should trip on at least one CI job
     178                 :             : // if sizeof(Gjs::Argument) is increased.
     179                 :             : // Note that this check is not applicable for clang-cl builds, as Windows is
     180                 :             : // an LLP64 system
     181                 :             : static_assert(sizeof(Argument) <= 24,
     182                 :             :               "Think very hard before increasing the size of Gjs::Argument. "
     183                 :             :               "One is allocated for every argument to every introspected "
     184                 :             :               "function.");
     185                 :             : #endif  // x86-64 clang
     186                 :             : 
     187                 :             : struct ArgsCache {
     188                 :             :     GJS_JSAPI_RETURN_CONVENTION
     189                 :             :     bool initialize(JSContext* cx, GICallableInfo* callable);
     190                 :             : 
     191                 :             :     // COMPAT: in C++20, use default initializers for these bitfields
     192                 :       11926 :     ArgsCache() : m_is_method(false), m_has_return(false) {}
     193                 :             : 
     194                 :             :     constexpr bool initialized() { return m_args != nullptr; }
     195                 :             :     constexpr void clear() { m_args.reset(); }
     196                 :             : 
     197                 :             :     void build_arg(uint8_t gi_index, GIDirection, GIArgInfo*, GICallableInfo*,
     198                 :             :                    bool* inc_counter_out);
     199                 :             : 
     200                 :             :     void build_return(GICallableInfo* callable, bool* inc_counter_out);
     201                 :             : 
     202                 :             :     void build_instance(GICallableInfo* callable);
     203                 :             : 
     204                 :             :     mozilla::Maybe<GType> instance_type() const;
     205                 :             :     mozilla::Maybe<Arg::ReturnTag> return_tag() const;
     206                 :             : 
     207                 :             :  private:
     208                 :             :     void build_normal_in_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*,
     209                 :             :                              GjsArgumentFlags);
     210                 :             :     void build_normal_out_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*,
     211                 :             :                               GjsArgumentFlags);
     212                 :             :     void build_normal_inout_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*,
     213                 :             :                                 GjsArgumentFlags);
     214                 :             : 
     215                 :             :     // GITypeInfo is not available for instance parameters (see
     216                 :             :     // https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/334) but
     217                 :             :     // for other parameters, this function additionally takes a GITypeInfo.
     218                 :             :     template <Arg::Kind ArgKind = Arg::Kind::NORMAL>
     219                 :             :     void build_interface_in_arg(const Argument::Init&,
     220                 :             :                                 GIBaseInfo* interface_info);
     221                 :             : 
     222                 :             :     template <Arg::Kind ArgKind = Arg::Kind::NORMAL, typename T>
     223                 :             :     constexpr void set_argument(T* arg, const Argument::Init&);
     224                 :             : 
     225                 :             :     void set_array_argument(GICallableInfo* callable, uint8_t gi_index,
     226                 :             :                             GITypeInfo*, GIDirection, GIArgInfo*,
     227                 :             :                             GjsArgumentFlags flags, int length_pos);
     228                 :             : 
     229                 :             :     void set_array_return(GICallableInfo*, GITypeInfo*, GjsArgumentFlags,
     230                 :             :                           int length_pos);
     231                 :             : 
     232                 :             :     void init_out_array_length_argument(GIArgInfo*, GjsArgumentFlags,
     233                 :             :                                         int length_pos);
     234                 :             : 
     235                 :             :     template <typename T>
     236                 :             :     constexpr void set_return(T* arg, GITransfer, GjsArgumentFlags);
     237                 :             : 
     238                 :             :     template <typename T>
     239                 :             :     constexpr void set_instance(
     240                 :             :         T* arg, GITransfer, GjsArgumentFlags flags = GjsArgumentFlags::NONE);
     241                 :             : 
     242                 :             :     void set_skip_all(uint8_t index, const char* name = nullptr);
     243                 :             : 
     244                 :             :     template <Arg::Kind ArgKind = Arg::Kind::NORMAL>
     245                 :      544261 :     constexpr uint8_t arg_index(uint8_t index
     246                 :             :                                 [[maybe_unused]] = Argument::MAX_ARGS) const {
     247                 :             :         if constexpr (ArgKind == Arg::Kind::RETURN_VALUE)
     248                 :      128112 :             return 0;
     249                 :             :         else if constexpr (ArgKind == Arg::Kind::INSTANCE)
     250         [ +  + ]:      123770 :             return (m_has_return ? 1 : 0);
     251                 :             :         else if constexpr (ArgKind == Arg::Kind::NORMAL)
     252   [ +  +  +  + ]:      292379 :             return (m_has_return ? 1 : 0) + (m_is_method ? 1 : 0) + index;
     253                 :             :     }
     254                 :             : 
     255                 :             :     template <Arg::Kind ArgKind = Arg::Kind::NORMAL>
     256                 :      544261 :     constexpr ArgumentPtr& arg_get(uint8_t index = Argument::MAX_ARGS) const {
     257                 :      544261 :         return m_args[arg_index<ArgKind>(index)];
     258                 :             :     }
     259                 :             : 
     260                 :             :  public:
     261                 :      269377 :     constexpr Argument* argument(uint8_t index) const {
     262                 :      269377 :         return arg_get(index).get();
     263                 :             :     }
     264                 :             : 
     265                 :      120161 :     constexpr mozilla::Maybe<Argument*> instance() const {
     266         [ -  + ]:      120161 :         if (!m_is_method)
     267                 :           0 :             return {};
     268                 :             : 
     269                 :      120161 :         return mozilla::Some(arg_get<Arg::Kind::INSTANCE>().get());
     270                 :             :     }
     271                 :             : 
     272                 :      220145 :     constexpr mozilla::Maybe<Argument*> return_value() const {
     273         [ +  + ]:      220145 :         if (!m_has_return)
     274                 :      101403 :             return {};
     275                 :             : 
     276                 :      118742 :         return mozilla::Some(arg_get<Arg::Kind::RETURN_VALUE>().get());
     277                 :             :     }
     278                 :             : 
     279                 :             :  private:
     280                 :             :     AutoCppPointer<ArgumentPtr[]> m_args;
     281                 :             : 
     282                 :             :     bool m_is_method : 1;
     283                 :             :     bool m_has_return : 1;
     284                 :             : };
     285                 :             : 
     286                 :             : }  // namespace Gjs
     287                 :             : 
     288                 :             : #endif  // GI_ARG_CACHE_H_
        

Generated by: LCOV version 2.0-1