LCOV - code coverage report
Current view: top level - gi - arg-cache.h (source / functions) Coverage Total Hit
Test: gjs-1.87.1 Code Coverage Lines: 93.0 % 57 53
Test Date: 2026-01-05 03:41:30 Functions: 88.9 % 27 24
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 95.5 % 22 21

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

Generated by: LCOV version 2.0-1