LCOV - code coverage report
Current view: top level - gi - arg-cache.cpp (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 86.2 % 1179 1016
Test Date: 2024-03-26 02:45:07 Functions: 86.6 % 629 545
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 78.7 % 521 410

             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                 :             : #include <config.h>
       7                 :             : 
       8                 :             : #include <inttypes.h>
       9                 :             : #include <stddef.h>  // for size_t
      10                 :             : #include <stdint.h>
      11                 :             : #include <string.h>
      12                 :             : 
      13                 :             : #include <limits>
      14                 :             : #include <tuple>
      15                 :             : #include <type_traits>
      16                 :             : #include <unordered_set>  // for unordered_set::erase(), insert()
      17                 :             : #include <utility>
      18                 :             : 
      19                 :             : #include <ffi.h>
      20                 :             : #include <girepository.h>
      21                 :             : #include <glib.h>
      22                 :             : 
      23                 :             : #include <js/Conversions.h>
      24                 :             : #include <js/RootingAPI.h>
      25                 :             : #include <js/TypeDecls.h>
      26                 :             : #include <js/Utility.h>  // for UniqueChars
      27                 :             : #include <js/Value.h>
      28                 :             : #include <js/experimental/TypedData.h>
      29                 :             : #include <jsapi.h>        // for InformalValueTypeName, JS_TypeOfValue
      30                 :             : #include <jspubtd.h>      // for JSTYPE_FUNCTION
      31                 :             : 
      32                 :             : #include "gi/arg-cache.h"
      33                 :             : #include "gi/arg-inl.h"
      34                 :             : #include "gi/arg-types-inl.h"
      35                 :             : #include "gi/arg.h"
      36                 :             : #include "gi/boxed.h"
      37                 :             : #include "gi/closure.h"
      38                 :             : #include "gi/foreign.h"
      39                 :             : #include "gi/function.h"
      40                 :             : #include "gi/fundamental.h"
      41                 :             : #include "gi/gerror.h"
      42                 :             : #include "gi/gtype.h"
      43                 :             : #include "gi/js-value-inl.h"
      44                 :             : #include "gi/object.h"
      45                 :             : #include "gi/param.h"
      46                 :             : #include "gi/union.h"
      47                 :             : #include "gi/value.h"
      48                 :             : #include "gi/wrapperutils.h"  // for GjsTypecheckNoThrow
      49                 :             : #include "gjs/byteArray.h"
      50                 :             : #include "gjs/enum-utils.h"  // for operator&, operator|=, operator|
      51                 :             : #include "gjs/jsapi-util.h"
      52                 :             : #include "gjs/macros.h"
      53                 :             : #include "util/log.h"
      54                 :             : 
      55                 :             : enum ExpectedType {
      56                 :             :     OBJECT,
      57                 :             :     FUNCTION,
      58                 :             :     STRING,
      59                 :             :     LAST,
      60                 :             : };
      61                 :             : 
      62                 :             : static const char* expected_type_names[] = {"object", "function", "string"};
      63                 :             : static_assert(G_N_ELEMENTS(expected_type_names) == ExpectedType::LAST,
      64                 :             :               "Names must match the values in ExpectedType");
      65                 :             : 
      66                 :         333 : static constexpr void gjs_gi_argument_set_array_length(GITypeTag tag,
      67                 :             :                                                        GIArgument* arg,
      68                 :             :                                                        size_t value) {
      69   [ -  +  -  -  :         333 :     switch (tag) {
             +  +  +  +  
                      - ]
      70                 :           0 :         case GI_TYPE_TAG_INT8:
      71                 :           0 :             gjs_arg_set<int8_t>(arg, value);
      72                 :           0 :             break;
      73                 :           1 :         case GI_TYPE_TAG_UINT8:
      74                 :           1 :             gjs_arg_set<uint8_t>(arg, value);
      75                 :           1 :             break;
      76                 :           0 :         case GI_TYPE_TAG_INT16:
      77                 :           0 :             gjs_arg_set<int16_t>(arg, value);
      78                 :           0 :             break;
      79                 :           0 :         case GI_TYPE_TAG_UINT16:
      80                 :           0 :             gjs_arg_set<uint16_t>(arg, value);
      81                 :           0 :             break;
      82                 :          67 :         case GI_TYPE_TAG_INT32:
      83                 :          67 :             gjs_arg_set<int32_t>(arg, value);
      84                 :          67 :             break;
      85                 :           4 :         case GI_TYPE_TAG_UINT32:
      86                 :           4 :             gjs_arg_set<uint32_t>(arg, value);
      87                 :           4 :             break;
      88                 :          17 :         case GI_TYPE_TAG_INT64:
      89                 :          17 :             gjs_arg_set<int64_t>(arg, value);
      90                 :          17 :             break;
      91                 :         244 :         case GI_TYPE_TAG_UINT64:
      92                 :         244 :             gjs_arg_set<uint64_t>(arg, value);
      93                 :         244 :             break;
      94                 :           0 :         default:
      95                 :             :             g_assert_not_reached();
      96                 :             :     }
      97                 :         333 : }
      98                 :             : 
      99                 :             : GJS_JSAPI_RETURN_CONVENTION
     100                 :           0 : static bool report_typeof_mismatch(JSContext* cx, const char* arg_name,
     101                 :             :                                    JS::HandleValue value,
     102                 :             :                                    ExpectedType expected) {
     103                 :           0 :     gjs_throw(cx, "Expected type %s for argument '%s' but got type %s",
     104                 :           0 :               expected_type_names[expected], arg_name,
     105                 :             :               JS::InformalValueTypeName(value));
     106                 :           0 :     return false;
     107                 :             : }
     108                 :             : 
     109                 :             : GJS_JSAPI_RETURN_CONVENTION
     110                 :           0 : static bool report_gtype_mismatch(JSContext* cx, const char* arg_name,
     111                 :             :                                   JS::Value value, GType expected) {
     112                 :           0 :     gjs_throw(
     113                 :             :         cx, "Expected an object of type %s for argument '%s' but got type %s",
     114                 :             :         g_type_name(expected), arg_name, JS::InformalValueTypeName(value));
     115                 :           0 :     return false;
     116                 :             : }
     117                 :             : 
     118                 :             : GJS_JSAPI_RETURN_CONVENTION
     119                 :           2 : static bool report_invalid_null(JSContext* cx, const char* arg_name) {
     120                 :           2 :     gjs_throw(cx, "Argument %s may not be null", arg_name);
     121                 :           2 :     return false;
     122                 :             : }
     123                 :             : 
     124                 :             : // Overload operator| so that Visual Studio won't complain
     125                 :             : // when converting unsigned char to GjsArgumentFlags
     126                 :       25497 : GjsArgumentFlags operator|(
     127                 :             :     GjsArgumentFlags const& v1, GjsArgumentFlags const& v2) {
     128                 :       25497 :     return static_cast<GjsArgumentFlags>(std::underlying_type<GjsArgumentFlags>::type(v1) |
     129                 :       25497 :                                          std::underlying_type<GjsArgumentFlags>::type(v2));
     130                 :             : }
     131                 :             : 
     132                 :             : namespace Gjs {
     133                 :             : namespace Arg {
     134                 :             : 
     135                 :             : // Arguments Interfaces:
     136                 :             : //
     137                 :             : // Each of these types are meant to be used to extend each Gjs::Argument
     138                 :             : // implementation, taking advantage of the C++ multiple inheritance.
     139                 :             : 
     140                 :             : struct BasicType {
     141                 :        1063 :     constexpr BasicType() : m_tag(GI_TYPE_TAG_VOID) {}
     142                 :             :     constexpr explicit BasicType(GITypeTag tag) : m_tag(tag) {}
     143                 :             :     constexpr operator GITypeTag() const { return m_tag; }
     144                 :             : 
     145                 :             :     GITypeTag m_tag : 5;
     146                 :             : };
     147                 :             : 
     148                 :             : struct TypeInfo {
     149                 :             :     constexpr GITypeInfo* type_info() const {
     150                 :             :         // Should be const GITypeInfo*, but G-I APIs won't accept that
     151                 :             :         return const_cast<GITypeInfo*>(&m_type_info);
     152                 :             :     }
     153                 :             : 
     154                 :             :     GITypeInfo m_type_info{};
     155                 :             : };
     156                 :             : 
     157                 :             : struct Transferable {
     158                 :       13662 :     constexpr Transferable() : m_transfer(GI_TRANSFER_NOTHING) {}
     159                 :             :     constexpr explicit Transferable(GITransfer transfer)
     160                 :             :         : m_transfer(transfer) {}
     161                 :             :     GITransfer m_transfer : 2;
     162                 :             : };
     163                 :             : 
     164                 :             : struct Nullable {
     165                 :       17973 :     constexpr Nullable() : m_nullable(false) {}
     166                 :             :     bool m_nullable : 1;
     167                 :             : 
     168                 :             :     bool handle_nullable(JSContext* cx, GIArgument* arg, const char* arg_name);
     169                 :             : 
     170                 :         516 :     constexpr GjsArgumentFlags flags() const {
     171         [ +  + ]:         516 :         return m_nullable ? GjsArgumentFlags::MAY_BE_NULL
     172                 :         516 :                           : GjsArgumentFlags::NONE;
     173                 :             :     }
     174                 :             : };
     175                 :             : 
     176                 :             : struct Positioned {
     177                 :        1776 :     void set_arg_pos(int pos) {
     178                 :        1776 :         g_assert(pos <= Argument::MAX_ARGS &&
     179                 :             :                  "No more than 253 arguments allowed");
     180                 :        1776 :         m_arg_pos = pos;
     181                 :        1776 :     }
     182                 :             : 
     183                 :         716 :     constexpr bool set_out_parameter(GjsFunctionCallState* state,
     184                 :             :                                      GIArgument* arg) {
     185                 :         716 :         gjs_arg_unset<void*>(&state->out_cvalue(m_arg_pos));
     186                 :         716 :         gjs_arg_set(arg, &gjs_arg_member<void*>(&state->out_cvalue(m_arg_pos)));
     187                 :         716 :         return true;
     188                 :             :     }
     189                 :             : 
     190                 :          43 :     constexpr bool set_inout_parameter(GjsFunctionCallState* state,
     191                 :             :                                        GIArgument* arg) {
     192                 :          43 :         state->out_cvalue(m_arg_pos) = state->inout_original_cvalue(m_arg_pos) =
     193                 :             :             *arg;
     194                 :          43 :         gjs_arg_set(arg, &state->out_cvalue(m_arg_pos));
     195                 :          43 :         return true;
     196                 :             :     }
     197                 :             : 
     198                 :             :     uint8_t m_arg_pos = 0;
     199                 :             : };
     200                 :             : 
     201                 :             : struct Array : BasicType {
     202                 :             :     uint8_t m_length_pos = 0;
     203                 :             :     GIDirection m_length_direction : 2;
     204                 :             : 
     205                 :        1063 :     Array() : BasicType(), m_length_direction(GI_DIRECTION_IN) {}
     206                 :             : 
     207                 :        1063 :     void set_array_length(int pos, GITypeTag tag, GIDirection direction) {
     208                 :        1063 :         g_assert(pos >= 0 && pos <= Argument::MAX_ARGS &&
     209                 :             :                  "No more than 253 arguments allowed");
     210                 :        1063 :         m_length_pos = pos;
     211                 :        1063 :         m_length_direction = direction;
     212                 :        1063 :         m_tag = tag;
     213                 :        1063 :     }
     214                 :             : };
     215                 :             : 
     216                 :             : struct HasIntrospectionInfo {
     217                 :        1136 :     constexpr explicit HasIntrospectionInfo(GIBaseInfo* info,
     218                 :             :                                             const GjsAutoTakeOwnership& add_ref)
     219                 :        1136 :         : m_info(info, add_ref) {}
     220                 :             :     constexpr explicit HasIntrospectionInfo(GIBaseInfo* info) : m_info(info) {}
     221                 :             : 
     222                 :             :     GjsAutoBaseInfo m_info;
     223                 :             : };
     224                 :             : 
     225                 :             : // boxed / union / GObject
     226                 :             : struct GTypedType {
     227                 :        6924 :     explicit GTypedType(GType gtype) : m_gtype(gtype) {}
     228                 :       95958 :     constexpr GType gtype() const { return m_gtype; }
     229                 :             : 
     230                 :             :  protected:
     231                 :             :     GType m_gtype;
     232                 :             : };
     233                 :             : 
     234                 :             : struct RegisteredType : GTypedType {
     235                 :           7 :     RegisteredType(GType gtype, GIInfoType info_type)
     236                 :           7 :         : GTypedType(gtype), m_info_type(info_type) {}
     237                 :        6431 :     explicit RegisteredType(GIRegisteredTypeInfo* info)
     238                 :        6431 :         : GTypedType(g_registered_type_info_get_g_type(info)),
     239                 :        6431 :           m_info_type(g_base_info_get_type(info)) {
     240                 :        6431 :         g_assert(m_gtype != G_TYPE_NONE &&
     241                 :             :                  "Use RegisteredInterface for this type");
     242                 :        6431 :     }
     243                 :             : 
     244                 :             :     GIInfoType m_info_type : 5;
     245                 :             : };
     246                 :             : 
     247                 :             : struct RegisteredInterface : HasIntrospectionInfo, GTypedType {
     248                 :         480 :     explicit RegisteredInterface(GIRegisteredTypeInfo* info)
     249                 :         960 :         : HasIntrospectionInfo(info, GjsAutoTakeOwnership{}),
     250                 :         480 :           GTypedType(g_registered_type_info_get_g_type(m_info)) {}
     251                 :             : };
     252                 :             : 
     253                 :             : struct Callback : Nullable, HasIntrospectionInfo {
     254                 :         649 :     explicit Callback(GICallbackInfo* info)
     255                 :        1298 :         : HasIntrospectionInfo(info, GjsAutoTakeOwnership{}),
     256                 :         649 :           m_scope(GI_SCOPE_TYPE_INVALID) {}
     257                 :             : 
     258                 :         648 :     inline void set_callback_destroy_pos(int pos) {
     259                 :         648 :         g_assert(pos <= Argument::MAX_ARGS &&
     260                 :             :                  "No more than 253 arguments allowed");
     261         [ +  + ]:         648 :         m_destroy_pos = pos < 0 ? Argument::ABSENT : pos;
     262                 :         648 :     }
     263                 :             : 
     264                 :         492 :     [[nodiscard]] constexpr bool has_callback_destroy() {
     265                 :         492 :         return m_destroy_pos != Argument::ABSENT;
     266                 :             :     }
     267                 :             : 
     268                 :         648 :     inline void set_callback_closure_pos(int pos) {
     269                 :         648 :         g_assert(pos <= Argument::MAX_ARGS &&
     270                 :             :                  "No more than 253 arguments allowed");
     271         [ +  + ]:         648 :         m_closure_pos = pos < 0 ? Argument::ABSENT : pos;
     272                 :         648 :     }
     273                 :             : 
     274                 :         246 :     [[nodiscard]] constexpr bool has_callback_closure() {
     275                 :         246 :         return m_closure_pos != Argument::ABSENT;
     276                 :             :     }
     277                 :             : 
     278                 :             :     uint8_t m_closure_pos = Argument::ABSENT;
     279                 :             :     uint8_t m_destroy_pos = Argument::ABSENT;
     280                 :             :     GIScopeType m_scope : 3;
     281                 :             : };
     282                 :             : 
     283                 :             : struct Enum {
     284                 :             :     explicit Enum(GIEnumInfo*);
     285                 :             :     bool m_unsigned : 1;
     286                 :             :     uint32_t m_min = 0;
     287                 :             :     uint32_t m_max = 0;
     288                 :             : };
     289                 :             : 
     290                 :             : struct Flags {
     291                 :             :     explicit Flags(GIEnumInfo*);
     292                 :             :     unsigned m_mask = 0;
     293                 :             : };
     294                 :             : 
     295                 :             : struct CallerAllocates {
     296                 :             :     size_t m_allocates_size = 0;
     297                 :             : };
     298                 :             : 
     299                 :             : // Gjs::Arguments:
     300                 :             : //
     301                 :             : // Each argument, irrespective of the direction, is processed in three phases:
     302                 :             : // - before calling the function [in]
     303                 :             : // - after calling it, when converting the return value and out arguments [out]
     304                 :             : // - at the end of the invocation, to release any allocated memory [release]
     305                 :             : //
     306                 :             : // Some types don't have direction (for example, caller_allocates is only out,
     307                 :             : // and callback is only in), in which case it is implied.
     308                 :             : 
     309                 :             : struct SkipAll : Argument {
     310                 :         657 :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     311                 :             :             JS::HandleValue) override {
     312                 :         657 :         return skip();
     313                 :             :     }
     314                 :             : 
     315                 :       32044 :     bool out(JSContext*, GjsFunctionCallState*, GIArgument*,
     316                 :             :              JS::MutableHandleValue) override {
     317                 :       32044 :         return skip();
     318                 :             :     }
     319                 :             : 
     320                 :       41149 :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     321                 :             :                  GIArgument*) override {
     322                 :       41149 :         return skip();
     323                 :             :     }
     324                 :             : 
     325                 :             :  protected:
     326                 :      174928 :     constexpr bool skip() { return true; }
     327                 :             : };
     328                 :             : 
     329                 :             : struct Generic : SkipAll, Transferable, TypeInfo {};
     330                 :             : 
     331                 :             : struct GenericIn : Generic {
     332                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     333                 :             :             JS::HandleValue) override;
     334                 :           0 :     bool out(JSContext* cx, GjsFunctionCallState*, GIArgument*,
     335                 :             :              JS::MutableHandleValue) override {
     336                 :           0 :         return invalid(cx, G_STRFUNC);
     337                 :             :     }
     338                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     339                 :             :                  GIArgument*) override;
     340                 :             : };
     341                 :             : 
     342                 :             : struct GenericInOut : GenericIn, Positioned {
     343                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     344                 :             :             JS::HandleValue) override;
     345                 :             :     bool out(JSContext*, GjsFunctionCallState*, GIArgument*,
     346                 :             :              JS::MutableHandleValue) override;
     347                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     348                 :             :                  GIArgument*) override;
     349                 :             : };
     350                 :             : 
     351                 :             : struct GenericOut : GenericInOut {
     352                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     353                 :             :             JS::HandleValue) override;
     354                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     355                 :             :                  GIArgument*) override;
     356                 :             : 
     357                 :       21306 :     GITypeTag return_tag() const override {
     358                 :       21306 :         return g_type_info_get_tag(&const_cast<GenericOut*>(this)->m_type_info);
     359                 :             :     }
     360                 :       21306 :     const GITypeInfo* return_type() const override { return &m_type_info; }
     361                 :             : };
     362                 :             : 
     363                 :             : struct GenericReturn : ReturnValue {
     364                 :             :     // No in!
     365                 :           0 :     bool in(JSContext* cx, GjsFunctionCallState*, GIArgument*,
     366                 :             :             JS::HandleValue) override {
     367                 :           0 :         return invalid(cx, G_STRFUNC);
     368                 :             :     }
     369                 :             : };
     370                 :             : 
     371                 :             : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     372                 :             : struct NumericOut : SkipAll, Positioned {
     373                 :             :     static_assert(std::is_arithmetic_v<T>, "Not arithmetic type");
     374                 :         541 :     bool in(JSContext*, GjsFunctionCallState* state, GIArgument* arg,
     375                 :             :             JS::HandleValue) override {
     376                 :         541 :         return set_out_parameter(state, arg);
     377                 :             :     }
     378                 :         541 :     bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
     379                 :             :              JS::MutableHandleValue value) override {
     380                 :         541 :         return Gjs::c_value_to_js_checked<T, TAG>(cx, gjs_arg_get<T>(arg),
     381                 :         541 :                                                   value);
     382                 :             :     }
     383                 :             : };
     384                 :             : 
     385                 :             : using BooleanOut = NumericOut<gboolean, GI_TYPE_TAG_BOOLEAN>;
     386                 :             : 
     387                 :             : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     388                 :             : struct NumericReturn : SkipAll {
     389                 :             :     static_assert(std::is_arithmetic_v<T>, "Not arithmetic type");
     390                 :           0 :     bool in(JSContext* cx, GjsFunctionCallState*, GIArgument*,
     391                 :             :             JS::HandleValue) override {
     392                 :           0 :         return invalid(cx, G_STRFUNC);
     393                 :             :     }
     394                 :       13680 :     bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
     395                 :             :              JS::MutableHandleValue value) override {
     396                 :       13680 :         return Gjs::c_value_to_js_checked<T, TAG>(cx, gjs_arg_get<T>(arg),
     397                 :       13680 :                                                   value);
     398                 :             :     }
     399                 :       13680 :     GITypeTag return_tag() const override { return TAG; }
     400                 :             : };
     401                 :             : 
     402                 :             : using BooleanReturn = NumericReturn<gboolean, GI_TYPE_TAG_BOOLEAN>;
     403                 :             : 
     404                 :             : struct SimpleOut : SkipAll, Positioned {
     405                 :          21 :     bool in(JSContext*, GjsFunctionCallState* state, GIArgument* arg,
     406                 :             :             JS::HandleValue) override {
     407                 :          21 :         return set_out_parameter(state, arg);
     408                 :             :     };
     409                 :             : };
     410                 :             : 
     411                 :             : struct ExplicitArray : GenericOut, Array, Nullable {
     412                 :         338 :     GjsArgumentFlags flags() const override {
     413                 :         338 :         return Argument::flags() | Nullable::flags();
     414                 :             :     }
     415                 :             : };
     416                 :             : 
     417                 :             : struct ExplicitArrayIn : ExplicitArray {
     418                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     419                 :             :             JS::HandleValue) override;
     420                 :         317 :     bool out(JSContext*, GjsFunctionCallState*, GIArgument*,
     421                 :             :              JS::MutableHandleValue) override {
     422                 :         317 :         return skip();
     423                 :             :     };
     424                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     425                 :             :                  GIArgument*) override;
     426                 :             : };
     427                 :             : 
     428                 :             : struct ExplicitArrayInOut : ExplicitArrayIn {
     429                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     430                 :             :             JS::HandleValue) override;
     431                 :             :     bool out(JSContext*, GjsFunctionCallState*, GIArgument*,
     432                 :             :              JS::MutableHandleValue) override;
     433                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     434                 :             :                  GIArgument*) override;
     435                 :             : };
     436                 :             : 
     437                 :             : struct ExplicitArrayOut : ExplicitArrayInOut {
     438                 :           0 :     bool in(JSContext* cx, GjsFunctionCallState*, GIArgument*,
     439                 :             :             JS::HandleValue) override {
     440                 :           0 :         return invalid(cx, G_STRFUNC);
     441                 :             :     }
     442                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     443                 :             :                  GIArgument*) override;
     444                 :             : };
     445                 :             : 
     446                 :             : struct ReturnArray : ExplicitArrayOut {
     447                 :          14 :     bool in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg,
     448                 :             :             JS::HandleValue value) override {
     449         [ -  + ]:          14 :         if (m_length_direction != GI_DIRECTION_OUT) {
     450                 :           0 :             gjs_throw(cx,
     451                 :             :                       "Using different length argument direction for array %s"
     452                 :             :                       "is not supported for out arrays",
     453                 :             :                       m_arg_name);
     454                 :           0 :             return false;
     455                 :             :         }
     456                 :          14 :         return GenericOut::in(cx, state, arg, value);
     457                 :             :     };
     458                 :             : };
     459                 :             : 
     460                 :             : using ArrayLengthOut = SimpleOut;
     461                 :             : 
     462                 :             : struct FallbackIn : GenericIn, Nullable {
     463                 :          35 :     bool out(JSContext*, GjsFunctionCallState*, GIArgument*,
     464                 :             :              JS::MutableHandleValue) override {
     465                 :          35 :         return skip();
     466                 :             :     }
     467                 :             : 
     468                 :          35 :     GjsArgumentFlags flags() const override {
     469                 :          35 :         return Argument::flags() | Nullable::flags();
     470                 :             :     }
     471                 :             : };
     472                 :             : 
     473                 :             : using FallbackInOut = GenericInOut;
     474                 :             : using FallbackOut = GenericOut;
     475                 :             : 
     476                 :             : struct NotIntrospectable : GenericIn {
     477                 :          68 :     explicit NotIntrospectable(NotIntrospectableReason reason)
     478                 :          68 :         : m_reason(reason) {}
     479                 :             :     NotIntrospectableReason m_reason;
     480                 :             : 
     481                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     482                 :             :             JS::HandleValue) override;
     483                 :             : };
     484                 :             : 
     485                 :             : struct NullableIn : SkipAll, Nullable {
     486                 :       11983 :     inline bool in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
     487                 :             :                    JS::HandleValue) override {
     488                 :       11983 :         return handle_nullable(cx, arg, m_arg_name);
     489                 :             :     }
     490                 :             : 
     491                 :         129 :     GjsArgumentFlags flags() const override {
     492                 :         129 :         return Argument::flags() | Nullable::flags();
     493                 :             :     }
     494                 :             : };
     495                 :             : 
     496                 :             : struct Instance : NullableIn {
     497                 :             :     //  Some calls accept null for the instance (thus we inherit from
     498                 :             :     //  NullableIn), but generally in an object oriented language it's wrong to
     499                 :             :     //  call a method on null.
     500                 :             :     //  As per this we actually default to SkipAll methods.
     501                 :             : 
     502                 :           0 :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     503                 :             :             JS::HandleValue) override {
     504                 :           0 :         return skip();
     505                 :             :     }
     506                 :       38157 :     bool out(JSContext*, GjsFunctionCallState*, GIArgument*,
     507                 :             :              JS::MutableHandleValue) override {
     508                 :       38157 :         return skip();
     509                 :             :     }
     510                 :        3084 :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     511                 :             :                  GIArgument*) override {
     512                 :        3084 :         return skip();
     513                 :             :     }
     514                 :             : 
     515                 :       35469 :     const Instance* as_instance() const override { return this; }
     516                 :             : 
     517                 :             :     //  The instance GType can be useful only in few cases such as GObjects and
     518                 :             :     //  GInterfaces, so we don't store it by default, unless needed.
     519                 :             :     //  See Function's code to see where this is relevant.
     520                 :         248 :     virtual GType gtype() const { return G_TYPE_NONE; }
     521                 :             : };
     522                 :             : 
     523                 :             : struct EnumIn : Instance, Enum {
     524                 :             :     using Enum::Enum;
     525                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     526                 :             :             JS::HandleValue) override;
     527                 :             : };
     528                 :             : 
     529                 :             : struct FlagsIn : Instance, Flags {
     530                 :             :     using Flags::Flags;
     531                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     532                 :             :             JS::HandleValue) override;
     533                 :             : };
     534                 :             : 
     535                 :             : struct RegisteredIn : Instance, RegisteredType, Transferable {
     536                 :             :     using RegisteredType::RegisteredType;
     537                 :             : 
     538                 :       35221 :     GType gtype() const override { return RegisteredType::gtype(); }
     539                 :             : };
     540                 :             : 
     541                 :             : struct RegisteredInterfaceIn : Instance, RegisteredInterface, Transferable {
     542                 :             :     using RegisteredInterface::RegisteredInterface;
     543                 :             : 
     544                 :           0 :     GType gtype() const override { return RegisteredInterface::gtype(); }
     545                 :             : };
     546                 :             : 
     547                 :             : struct ForeignStructInstanceIn : RegisteredInterfaceIn {
     548                 :             :     using RegisteredInterfaceIn::RegisteredInterfaceIn;
     549                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     550                 :             :             JS::HandleValue) override;
     551                 :             : };
     552                 :             : 
     553                 :             : struct ForeignStructIn : ForeignStructInstanceIn {
     554                 :             :     using ForeignStructInstanceIn::ForeignStructInstanceIn;
     555                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     556                 :             :                  GIArgument*) override;
     557                 :             : };
     558                 :             : 
     559                 :             : struct FallbackInterfaceIn : RegisteredInterfaceIn, TypeInfo {
     560                 :             :     using RegisteredInterfaceIn::RegisteredInterfaceIn;
     561                 :             : 
     562                 :         127 :     bool in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
     563                 :             :             JS::HandleValue value) override {
     564                 :         254 :         return gjs_value_to_gi_argument(cx, value, &m_type_info, m_arg_name,
     565                 :         127 :                                         GJS_ARGUMENT_ARGUMENT, m_transfer,
     566                 :         254 :                                         flags(), arg);
     567                 :             :     }
     568                 :             : };
     569                 :             : 
     570                 :             : struct BoxedInTransferNone : RegisteredIn {
     571                 :             :     using RegisteredIn::RegisteredIn;
     572                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     573                 :             :             JS::HandleValue) override;
     574                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     575                 :             :                  GIArgument*) override;
     576                 :             : 
     577                 :       47118 :     virtual GIBaseInfo* info() const { return nullptr; }
     578                 :             : };
     579                 :             : 
     580                 :             : struct BoxedIn : BoxedInTransferNone {
     581                 :             :     using BoxedInTransferNone::BoxedInTransferNone;
     582                 :             :     // This is a smart argument, no release needed
     583                 :       58803 :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     584                 :             :                  GIArgument*) override {
     585                 :       58803 :         return skip();
     586                 :             :     }
     587                 :             : };
     588                 :             : 
     589                 :             : struct UnregisteredBoxedIn : BoxedIn, HasIntrospectionInfo {
     590                 :           7 :     explicit UnregisteredBoxedIn(GIStructInfo* info)
     591                 :           7 :         : BoxedIn(g_registered_type_info_get_g_type(info),
     592                 :             :                   g_base_info_get_type(info)),
     593                 :           7 :           HasIntrospectionInfo(info, GjsAutoTakeOwnership{}) {}
     594                 :             :     // This is a smart argument, no release needed
     595                 :           8 :     GIBaseInfo* info() const override { return m_info; }
     596                 :             : };
     597                 :             : 
     598                 :             : struct GValueIn : BoxedIn {
     599                 :             :     using BoxedIn::BoxedIn;
     600                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     601                 :             :             JS::HandleValue) override;
     602                 :             : };
     603                 :             : 
     604                 :             : struct GValueInTransferNone : GValueIn {
     605                 :             :     using GValueIn::GValueIn;
     606                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     607                 :             :                  GIArgument*) override;
     608                 :             : };
     609                 :             : 
     610                 :             : struct GClosureInTransferNone : BoxedInTransferNone {
     611                 :             :     using BoxedInTransferNone::BoxedInTransferNone;
     612                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     613                 :             :             JS::HandleValue) override;
     614                 :             : };
     615                 :             : 
     616                 :             : struct GClosureIn : GClosureInTransferNone {
     617                 :             :     using GClosureInTransferNone::GClosureInTransferNone;
     618                 :           0 :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     619                 :             :                  GIArgument*) override {
     620                 :           0 :         return skip();
     621                 :             :     }
     622                 :             : };
     623                 :             : 
     624                 :             : struct GBytesIn : BoxedIn {
     625                 :             :     using BoxedIn::BoxedIn;
     626                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     627                 :             :             JS::HandleValue) override;
     628                 :             :     bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg,
     629                 :             :                  GIArgument* out_arg) override;
     630                 :             : };
     631                 :             : 
     632                 :             : struct GBytesInTransferNone : GBytesIn {
     633                 :             :     using GBytesIn::GBytesIn;
     634                 :          37 :     bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg,
     635                 :             :                  GIArgument* out_arg) override {
     636                 :          37 :         return BoxedInTransferNone::release(cx, state, in_arg, out_arg);
     637                 :             :     }
     638                 :             : };
     639                 :             : 
     640                 :             : struct ObjectIn : RegisteredIn {
     641                 :             :     using RegisteredIn::RegisteredIn;
     642                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     643                 :             :             JS::HandleValue) override;
     644                 :             :     // This is a smart argument, no release needed
     645                 :             : };
     646                 :             : 
     647                 :             : struct InterfaceIn : RegisteredIn {
     648                 :             :     using RegisteredIn::RegisteredIn;
     649                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     650                 :             :             JS::HandleValue) override;
     651                 :             :     // This is a smart argument, no release needed
     652                 :             : };
     653                 :             : 
     654                 :             : struct FundamentalIn : RegisteredIn {
     655                 :             :     using RegisteredIn::RegisteredIn;
     656                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     657                 :             :             JS::HandleValue) override;
     658                 :             :     // This is a smart argument, no release needed
     659                 :             : };
     660                 :             : 
     661                 :             : struct UnionIn : RegisteredIn {
     662                 :             :     using RegisteredIn::RegisteredIn;
     663                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     664                 :             :             JS::HandleValue) override;
     665                 :             :     // This is a smart argument, no release needed
     666                 :             : };
     667                 :             : 
     668                 :             : struct NullIn : NullableIn {
     669                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     670                 :             :             JS::HandleValue) override;
     671                 :             : };
     672                 :             : 
     673                 :             : struct BooleanIn : SkipAll {
     674                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     675                 :             :             JS::HandleValue) override;
     676                 :             : };
     677                 :             : 
     678                 :             : template <typename T>
     679                 :             : struct NumericIn : SkipAll {
     680                 :             :     static_assert(std::is_arithmetic_v<T>, "Not arithmetic type");
     681                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     682                 :             :             JS::HandleValue) override;
     683                 :             : };
     684                 :             : 
     685                 :             : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     686                 :             : struct NumericInOut : NumericIn<T>, Positioned {
     687                 :             :     static_assert(std::is_arithmetic_v<T>, "Not arithmetic type");
     688                 :          26 :     bool in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg,
     689                 :             :             JS::HandleValue value) override {
     690         [ -  + ]:          26 :         if (!NumericIn<T>::in(cx, state, arg, value))
     691                 :           0 :             return false;
     692                 :             : 
     693                 :          26 :         return set_inout_parameter(state, arg);
     694                 :             :     }
     695                 :          26 :     bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
     696                 :             :              JS::MutableHandleValue value) override {
     697                 :          26 :         return Gjs::c_value_to_js_checked<T, TAG>(cx, gjs_arg_get<T>(arg),
     698                 :          26 :                                                   value);
     699                 :             :     }
     700                 :             : };
     701                 :             : 
     702                 :             : using BooleanInOut = NumericInOut<gboolean, GI_TYPE_TAG_BOOLEAN>;
     703                 :             : 
     704                 :             : struct UnicharIn : SkipAll {
     705                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     706                 :             :             JS::HandleValue) override;
     707                 :             : };
     708                 :             : 
     709                 :             : struct GTypeIn : SkipAll {
     710                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     711                 :             :             JS::HandleValue) override;
     712                 :             : };
     713                 :             : 
     714                 :             : template <GITypeTag TAG = GI_TYPE_TAG_UTF8>
     715                 :             : struct StringInTransferNone : NullableIn {
     716                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     717                 :             :             JS::HandleValue) override;
     718                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     719                 :             :                  GIArgument*) override;
     720                 :             : };
     721                 :             : 
     722                 :             : struct StringIn : StringInTransferNone<GI_TYPE_TAG_UTF8> {
     723                 :           0 :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     724                 :             :                  GIArgument*) override {
     725                 :           0 :         return skip();
     726                 :             :     }
     727                 :             : };
     728                 :             : 
     729                 :             : template <GITransfer TRANSFER = GI_TRANSFER_NOTHING>
     730                 :             : struct StringOutBase : SkipAll {
     731                 :         704 :     bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
     732                 :             :              JS::MutableHandleValue value) override {
     733                 :         704 :         return Gjs::c_value_to_js(cx, gjs_arg_get<char*>(arg), value);
     734                 :             :     }
     735                 :         704 :     bool release(JSContext* cx, GjsFunctionCallState*, GIArgument*,
     736                 :             :                  GIArgument* out_arg [[maybe_unused]]) override {
     737                 :             :         if constexpr (TRANSFER == GI_TRANSFER_NOTHING) {
     738                 :         667 :             return skip();
     739                 :             :         } else if constexpr (TRANSFER == GI_TRANSFER_EVERYTHING) {
     740         [ +  + ]:          37 :             g_clear_pointer(&gjs_arg_member<char*>(out_arg), g_free);
     741                 :          37 :             return true;
     742                 :             :         } else {
     743                 :             :             return invalid(cx, G_STRFUNC);
     744                 :             :         }
     745                 :             :     }
     746                 :             : };
     747                 :             : 
     748                 :             : template <GITransfer TRANSFER = GI_TRANSFER_NOTHING>
     749                 :             : struct StringReturn : StringOutBase<TRANSFER> {
     750                 :           0 :     bool in(JSContext* cx, GjsFunctionCallState*, GIArgument*,
     751                 :             :             JS::HandleValue) override {
     752                 :           0 :         return Argument::invalid(cx, G_STRFUNC);
     753                 :             :     }
     754                 :             : 
     755                 :         688 :     GITypeTag return_tag() const override { return GI_TYPE_TAG_UTF8; }
     756                 :             : };
     757                 :             : 
     758                 :             : template <GITransfer TRANSFER = GI_TRANSFER_NOTHING>
     759                 :             : struct StringOut : StringOutBase<TRANSFER>, Positioned {
     760                 :          16 :     bool in(JSContext*, GjsFunctionCallState* state, GIArgument* arg,
     761                 :             :             JS::HandleValue) override {
     762                 :          16 :         return set_out_parameter(state, arg);
     763                 :             :     }
     764                 :             : };
     765                 :             : 
     766                 :             : using FilenameInTransferNone = StringInTransferNone<GI_TYPE_TAG_FILENAME>;
     767                 :             : 
     768                 :             : struct FilenameIn : FilenameInTransferNone {
     769                 :           0 :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     770                 :             :                  GIArgument*) override {
     771                 :           0 :         return skip();
     772                 :             :     }
     773                 :             : };
     774                 :             : 
     775                 :             : // .out is ignored for the instance parameter
     776                 :             : struct GTypeStructInstanceIn : Instance {
     777                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     778                 :             :             JS::HandleValue) override;
     779                 :             :     // no out
     780                 :           0 :     bool out(JSContext* cx, GjsFunctionCallState*, GIArgument*,
     781                 :             :              JS::MutableHandleValue) override {
     782                 :           0 :         return invalid(cx, G_STRFUNC);
     783                 :             :     };
     784                 :             : };
     785                 :             : 
     786                 :             : struct ParamInstanceIn : Instance, Transferable {
     787                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     788                 :             :             JS::HandleValue) override;
     789                 :             :     // no out
     790                 :           0 :     bool out(JSContext* cx, GjsFunctionCallState*, GIArgument*,
     791                 :             :              JS::MutableHandleValue) override {
     792                 :           0 :         return invalid(cx, G_STRFUNC);
     793                 :             :     };
     794                 :             : };
     795                 :             : 
     796                 :             : struct CallbackIn : SkipAll, Callback {
     797                 :             :     using Callback::Callback;
     798                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     799                 :             :             JS::HandleValue) override;
     800                 :             : 
     801                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     802                 :             :                  GIArgument*) override;
     803                 :             :  private:
     804                 :             :     ffi_closure *m_ffi_closure;
     805                 :             : };
     806                 :             : 
     807                 :             : using CArrayIn = ExplicitArrayIn;
     808                 :             : 
     809                 :             : using CArrayInOut = ExplicitArrayInOut;
     810                 :             : 
     811                 :             : using CArrayOut = ReturnArray;
     812                 :             : 
     813                 :             : struct CallerAllocatesOut : GenericOut, CallerAllocates {
     814                 :             :     bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
     815                 :             :             JS::HandleValue) override;
     816                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     817                 :             :                  GIArgument*) override;
     818                 :             : 
     819                 :           0 :     GjsArgumentFlags flags() const override {
     820                 :           0 :         return GenericOut::flags() | GjsArgumentFlags::CALLER_ALLOCATES;
     821                 :             :     }
     822                 :             : };
     823                 :             : 
     824                 :             : struct BoxedCallerAllocatesOut : CallerAllocatesOut, GTypedType {
     825                 :             :     using GTypedType::GTypedType;
     826                 :             :     bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
     827                 :             :                  GIArgument*) override;
     828                 :             : };
     829                 :             : 
     830                 :             : struct ZeroTerminatedArrayInOut : GenericInOut {
     831                 :           2 :     bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument*,
     832                 :             :                  GIArgument* out_arg) override {
     833                 :             :         GITransfer transfer =
     834         [ +  - ]:           2 :             state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING;
     835                 :           2 :         GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos);
     836         [ -  + ]:           2 :         if (!gjs_gi_argument_release_in_array(cx, transfer, &m_type_info,
     837                 :             :                                               original_out_arg))
     838                 :           0 :             return false;
     839                 :             : 
     840                 :           2 :         transfer =
     841         [ +  - ]:           2 :             state->call_completed() ? m_transfer : GI_TRANSFER_EVERYTHING;
     842                 :           2 :         return gjs_gi_argument_release_out_array(cx, transfer, &m_type_info,
     843                 :           2 :                                                  out_arg);
     844                 :             :     }
     845                 :             : };
     846                 :             : 
     847                 :             : struct ZeroTerminatedArrayIn : GenericIn, Nullable {
     848                 :          10 :     bool out(JSContext*, GjsFunctionCallState*, GIArgument*,
     849                 :             :              JS::MutableHandleValue) override {
     850                 :          10 :         return skip();
     851                 :             :     }
     852                 :             : 
     853                 :          10 :     bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg,
     854                 :             :                  GIArgument*) override {
     855                 :             :         GITransfer transfer =
     856         [ +  + ]:          10 :             state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING;
     857                 :             : 
     858                 :          10 :         return gjs_gi_argument_release_in_array(cx, transfer, &m_type_info,
     859                 :          10 :                                                 in_arg);
     860                 :             :     }
     861                 :             : 
     862                 :          14 :     GjsArgumentFlags flags() const override {
     863                 :          14 :         return Argument::flags() | Nullable::flags();
     864                 :             :     }
     865                 :             : };
     866                 :             : 
     867                 :             : struct FixedSizeArrayIn : GenericIn {
     868                 :           5 :     bool out(JSContext*, GjsFunctionCallState*, GIArgument*,
     869                 :             :              JS::MutableHandleValue) override {
     870                 :           5 :         return skip();
     871                 :             :     }
     872                 :             : 
     873                 :           5 :     bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg,
     874                 :             :                  GIArgument*) override {
     875                 :             :         GITransfer transfer =
     876         [ +  - ]:           5 :             state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING;
     877                 :             : 
     878                 :           5 :         int size = g_type_info_get_array_fixed_size(&m_type_info);
     879                 :           5 :         return gjs_gi_argument_release_in_array(cx, transfer, &m_type_info,
     880                 :           5 :                                                 size, in_arg);
     881                 :             :     }
     882                 :             : };
     883                 :             : 
     884                 :             : struct FixedSizeArrayInOut : GenericInOut {
     885                 :           1 :     bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument*,
     886                 :             :                  GIArgument* out_arg) override {
     887                 :             :         GITransfer transfer =
     888         [ +  - ]:           1 :             state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING;
     889                 :           1 :         GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos);
     890                 :           1 :         int size = g_type_info_get_array_fixed_size(&m_type_info);
     891         [ -  + ]:           1 :         if (!gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, size,
     892                 :             :                                               original_out_arg))
     893                 :           0 :             return false;
     894                 :             : 
     895                 :           1 :         transfer =
     896         [ +  - ]:           1 :             state->call_completed() ? m_transfer : GI_TRANSFER_EVERYTHING;
     897                 :           1 :         return gjs_gi_argument_release_out_array(cx, transfer, &m_type_info,
     898                 :           1 :                                                  size, out_arg);
     899                 :             :     }
     900                 :             : };
     901                 :             : 
     902                 :             : GJS_JSAPI_RETURN_CONVENTION
     903                 :           3 : bool NotIntrospectable::in(JSContext* cx, GjsFunctionCallState* state,
     904                 :             :                            GIArgument*, JS::HandleValue) {
     905                 :           3 :     const char* reason_string = "invalid introspection";
     906                 :             : 
     907   [ -  +  +  -  :           3 :     switch (m_reason) {
          +  -  -  -  -  
                      - ]
     908                 :           0 :         case CALLBACK_OUT:
     909                 :           0 :             reason_string = "callback out-argument";
     910                 :           0 :             break;
     911                 :           1 :         case DESTROY_NOTIFY_NO_CALLBACK:
     912                 :           1 :             reason_string = "DestroyNotify argument with no callback";
     913                 :           1 :             break;
     914                 :           1 :         case DESTROY_NOTIFY_NO_USER_DATA:
     915                 :           1 :             reason_string = "DestroyNotify argument with no user data";
     916                 :           1 :             break;
     917                 :           0 :         case INTERFACE_TRANSFER_CONTAINER:
     918                 :           0 :             reason_string = "type not supported for (transfer container)";
     919                 :           0 :             break;
     920                 :           1 :         case OUT_CALLER_ALLOCATES_NON_STRUCT:
     921                 :           1 :             reason_string = "type not supported for (out caller-allocates)";
     922                 :           1 :             break;
     923                 :           0 :         case UNREGISTERED_BOXED_WITH_TRANSFER:
     924                 :           0 :             reason_string =
     925                 :             :                 "boxed type with transfer not registered as a GType";
     926                 :           0 :             break;
     927                 :           0 :         case UNREGISTERED_UNION:
     928                 :           0 :             reason_string = "union type not registered as a GType";
     929                 :           0 :             break;
     930                 :           0 :         case UNSUPPORTED_TYPE:
     931                 :           0 :             reason_string = "type not supported by introspection";
     932                 :           0 :             break;
     933                 :           0 :         case LAST_REASON:
     934                 :             :             g_assert_not_reached();
     935                 :             :     }
     936                 :             : 
     937                 :           6 :     gjs_throw(cx,
     938                 :             :               "Function %s() cannot be called: argument '%s' with type %s is "
     939                 :             :               "not introspectable because it has a %s",
     940                 :           6 :               state->display_name().get(), m_arg_name,
     941                 :             :               g_type_tag_to_string(g_type_info_get_tag(&m_type_info)),
     942                 :             :               reason_string);
     943                 :           3 :     return false;
     944                 :             : }
     945                 :             : 
     946                 :             : GJS_JSAPI_RETURN_CONVENTION
     947                 :          71 : bool GenericIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
     948                 :             :                    JS::HandleValue value) {
     949                 :         142 :     return gjs_value_to_gi_argument(cx, value, &m_type_info, m_arg_name,
     950                 :          71 :                                     GJS_ARGUMENT_ARGUMENT, m_transfer, flags(),
     951                 :          71 :                                     arg);
     952                 :             : }
     953                 :             : 
     954                 :             : GJS_JSAPI_RETURN_CONVENTION
     955                 :          17 : bool GenericInOut::in(JSContext* cx, GjsFunctionCallState* state,
     956                 :             :                       GIArgument* arg, JS::HandleValue value) {
     957         [ -  + ]:          17 :     if (!GenericIn::in(cx, state, arg, value))
     958                 :           0 :         return false;
     959                 :             : 
     960                 :          17 :     return set_inout_parameter(state, arg);
     961                 :             : }
     962                 :             : 
     963                 :             : GJS_JSAPI_RETURN_CONVENTION
     964                 :         338 : bool ExplicitArrayIn::in(JSContext* cx, GjsFunctionCallState* state,
     965                 :             :                          GIArgument* arg, JS::HandleValue value) {
     966                 :             :     void* data;
     967                 :             :     size_t length;
     968                 :             : 
     969         [ +  + ]:         338 :     if (m_length_direction != GI_DIRECTION_INOUT &&
     970         [ -  + ]:         323 :         m_length_direction != GI_DIRECTION_IN) {
     971                 :           0 :         gjs_throw(cx, "Using different length argument direction for array %s"
     972                 :             :                   "is not supported for in arrays", m_arg_name);
     973                 :           0 :         return false;
     974                 :             :     }
     975                 :             : 
     976         [ +  + ]:         338 :     if (!gjs_array_to_explicit_array(cx, value, &m_type_info, m_arg_name,
     977                 :         338 :                                      GJS_ARGUMENT_ARGUMENT, m_transfer, flags(),
     978                 :             :                                      &data, &length))
     979                 :           5 :         return false;
     980                 :             : 
     981                 :         333 :     gjs_gi_argument_set_array_length(m_tag, &state->in_cvalue(m_length_pos),
     982                 :             :                                      length);
     983                 :         333 :     gjs_arg_set(arg, data);
     984                 :         333 :     return true;
     985                 :             : }
     986                 :             : 
     987                 :             : GJS_JSAPI_RETURN_CONVENTION
     988                 :          15 : bool ExplicitArrayInOut::in(JSContext* cx, GjsFunctionCallState* state,
     989                 :             :                             GIArgument* arg, JS::HandleValue value) {
     990         [ -  + ]:          15 :     if (!ExplicitArrayIn::in(cx, state, arg, value))
     991                 :           0 :         return false;
     992                 :             : 
     993                 :          15 :     uint8_t length_pos = m_length_pos;
     994                 :          15 :     uint8_t ix = m_arg_pos;
     995                 :             : 
     996         [ +  + ]:          15 :     if (!gjs_arg_get<void*>(arg)) {
     997                 :             :         // Special case where we were given JS null to also pass null for
     998                 :             :         // length, and not a pointer to an integer that derefs to 0.
     999                 :           9 :         gjs_arg_unset<void*>(&state->in_cvalue(length_pos));
    1000                 :           9 :         gjs_arg_unset<int>(&state->out_cvalue(length_pos));
    1001                 :           9 :         gjs_arg_unset<int>(&state->inout_original_cvalue(length_pos));
    1002                 :             : 
    1003                 :           9 :         gjs_arg_unset<void*>(&state->out_cvalue(ix));
    1004                 :           9 :         gjs_arg_unset<void*>(&state->inout_original_cvalue(ix));
    1005                 :             :     } else {
    1006         [ +  - ]:           6 :         if G_LIKELY (m_length_direction == GI_DIRECTION_INOUT) {
    1007                 :           6 :             state->out_cvalue(length_pos) =
    1008                 :           6 :                 state->inout_original_cvalue(length_pos) =
    1009                 :           6 :                     state->in_cvalue(length_pos);
    1010                 :           6 :             gjs_arg_set(&state->in_cvalue(length_pos),
    1011                 :           6 :                         &state->out_cvalue(length_pos));
    1012                 :             :         }
    1013                 :             : 
    1014                 :           6 :         state->out_cvalue(ix) = state->inout_original_cvalue(ix) = *arg;
    1015                 :           6 :         gjs_arg_set(arg, &state->out_cvalue(ix));
    1016                 :             :     }
    1017                 :             : 
    1018                 :          15 :     return true;
    1019                 :             : }
    1020                 :             : 
    1021                 :             : GJS_JSAPI_RETURN_CONVENTION
    1022                 :         248 : bool CallbackIn::in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg,
    1023                 :             :                     JS::HandleValue value) {
    1024                 :             :     GjsCallbackTrampoline* trampoline;
    1025                 :             :     void* closure;
    1026                 :             : 
    1027   [ +  +  +  +  :         248 :     if (value.isNull() && m_nullable) {
                   +  + ]
    1028                 :           8 :         closure = nullptr;
    1029                 :           8 :         trampoline = nullptr;
    1030                 :           8 :         m_ffi_closure = nullptr;
    1031                 :             :     } else {
    1032         [ +  + ]:         240 :         if (JS_TypeOfValue(cx, value) != JSTYPE_FUNCTION) {
    1033                 :           2 :             gjs_throw(cx, "Expected function for callback argument %s, got %s",
    1034                 :             :                       m_arg_name, JS::InformalValueTypeName(value));
    1035                 :           2 :             return false;
    1036                 :             :         }
    1037                 :             : 
    1038                 :         238 :         JS::RootedObject callable(cx, &value.toObject());
    1039                 :         238 :         bool is_object_method = !!state->instance_object;
    1040                 :         238 :         trampoline = GjsCallbackTrampoline::create(
    1041                 :         238 :             cx, callable, m_info, m_scope, is_object_method, false);
    1042         [ -  + ]:         238 :         if (!trampoline)
    1043                 :           0 :             return false;
    1044   [ +  +  -  + ]:         238 :         if (m_scope == GI_SCOPE_TYPE_NOTIFIED && is_object_method) {
    1045                 :           0 :             auto* priv = ObjectInstance::for_js(cx, state->instance_object);
    1046         [ #  # ]:           0 :             if (!priv) {
    1047                 :           0 :                 gjs_throw(cx, "Signal connected to wrong type of object");
    1048                 :           0 :                 return false;
    1049                 :             :             }
    1050                 :             : 
    1051         [ #  # ]:           0 :             if (!priv->associate_closure(cx, trampoline))
    1052                 :           0 :                 return false;
    1053                 :             :         }
    1054                 :         238 :         closure = trampoline->closure();
    1055                 :         238 :         m_ffi_closure = trampoline->get_ffi_closure();
    1056         [ +  - ]:         238 :     }
    1057                 :             : 
    1058         [ +  + ]:         246 :     if (has_callback_destroy()) {
    1059                 :          99 :         GDestroyNotify destroy_notify = nullptr;
    1060         [ +  + ]:          99 :         if (trampoline) {
    1061                 :             :             /* Adding another reference and a DestroyNotify that unsets it */
    1062                 :          95 :             g_closure_ref(trampoline);
    1063                 :          95 :             destroy_notify = [](void* data) {
    1064                 :          79 :                 g_assert(data);
    1065                 :          79 :                 g_closure_unref(static_cast<GClosure*>(data));
    1066                 :          79 :             };
    1067                 :             :         }
    1068                 :          99 :         gjs_arg_set(&state->in_cvalue(m_destroy_pos), destroy_notify);
    1069                 :             :     }
    1070         [ +  + ]:         246 :     if (has_callback_closure())
    1071                 :         222 :         gjs_arg_set(&state->in_cvalue(m_closure_pos), trampoline);
    1072                 :             : 
    1073   [ +  +  +  + ]:         246 :     if (trampoline && m_scope == GI_SCOPE_TYPE_ASYNC) {
    1074                 :             :         // Add an extra reference that will be cleared when garbage collecting
    1075                 :             :         // async calls
    1076                 :         111 :         g_closure_ref(trampoline);
    1077                 :             :     }
    1078                 :             : 
    1079                 :             :     bool keep_forever =
    1080         [ +  + ]:         393 :         !has_callback_destroy() && (
    1081                 :             : #if GI_CHECK_VERSION(1, 72, 0)
    1082         [ +  - ]:         147 :                                        m_scope == GI_SCOPE_TYPE_FOREVER ||
    1083                 :             : #endif
    1084         [ +  + ]:         147 :                                        m_scope == GI_SCOPE_TYPE_NOTIFIED);
    1085                 :             : 
    1086   [ +  +  +  + ]:         246 :     if (trampoline && keep_forever) {
    1087                 :           1 :         trampoline->mark_forever();
    1088                 :             :     }
    1089                 :         246 :     gjs_arg_set(arg, closure);
    1090                 :             : 
    1091                 :         246 :     return true;
    1092                 :             : }
    1093                 :             : 
    1094                 :             : GJS_JSAPI_RETURN_CONVENTION
    1095                 :         138 : bool GenericOut::in(JSContext*, GjsFunctionCallState* state, GIArgument* arg,
    1096                 :             :                     JS::HandleValue) {
    1097                 :             :     // Default value in case a broken C function doesn't fill in the pointer
    1098                 :         138 :     return set_out_parameter(state, arg);
    1099                 :             : }
    1100                 :             : 
    1101                 :             : GJS_JSAPI_RETURN_CONVENTION
    1102                 :           9 : bool CallerAllocatesOut::in(JSContext*, GjsFunctionCallState* state,
    1103                 :             :                             GIArgument* arg, JS::HandleValue) {
    1104                 :           9 :     void* blob = g_malloc0(m_allocates_size);
    1105                 :           9 :     gjs_arg_set(arg, blob);
    1106                 :           9 :     gjs_arg_set(&state->out_cvalue(m_arg_pos), blob);
    1107                 :           9 :     return true;
    1108                 :             : }
    1109                 :             : 
    1110                 :             : GJS_JSAPI_RETURN_CONVENTION
    1111                 :           7 : bool NullIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
    1112                 :             :                 JS::HandleValue) {
    1113                 :           7 :     return handle_nullable(cx, arg, m_arg_name);
    1114                 :             : }
    1115                 :             : 
    1116                 :             : GJS_JSAPI_RETURN_CONVENTION
    1117                 :         228 : bool BooleanIn::in(JSContext*, GjsFunctionCallState*, GIArgument* arg,
    1118                 :             :                    JS::HandleValue value) {
    1119                 :         228 :     gjs_arg_set(arg, JS::ToBoolean(value));
    1120                 :         228 :     return true;
    1121                 :             : }
    1122                 :             : 
    1123                 :             : template <typename T>
    1124                 :       25582 : GJS_JSAPI_RETURN_CONVENTION bool NumericIn<T>::in(JSContext* cx,
    1125                 :             :                                                   GjsFunctionCallState*,
    1126                 :             :                                                   GIArgument* arg,
    1127                 :             :                                                   JS::HandleValue value) {
    1128                 :       25582 :     bool out_of_range = false;
    1129                 :             : 
    1130         [ +  + ]:       25582 :     if (!gjs_arg_set_from_js_value<T>(cx, value, arg, &out_of_range)) {
    1131         [ +  + ]:          33 :         if (out_of_range) {
    1132                 :           8 :             gjs_throw(cx, "Argument %s: value is out of range for %s",
    1133                 :             :                       arg_name(), Gjs::static_type_name<T>());
    1134                 :             :         }
    1135                 :             : 
    1136                 :          33 :         return false;
    1137                 :             :     }
    1138                 :             : 
    1139                 :             :     gjs_debug_marshal(GJS_DEBUG_GFUNCTION, "%s set to value %s (type %s)",
    1140                 :             :                       GjsAutoChar{gjs_argument_display_name(
    1141                 :             :                                       arg_name(), GJS_ARGUMENT_ARGUMENT)}
    1142                 :             :                           .get(),
    1143                 :             :                       std::to_string(gjs_arg_get<T>(arg)).c_str(),
    1144                 :             :                       Gjs::static_type_name<T>());
    1145                 :             : 
    1146                 :       25549 :     return true;
    1147                 :             : }
    1148                 :             : 
    1149                 :             : GJS_JSAPI_RETURN_CONVENTION
    1150                 :           3 : bool UnicharIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
    1151                 :             :                    JS::HandleValue value) {
    1152         [ -  + ]:           3 :     if (!value.isString())
    1153                 :           0 :         return report_typeof_mismatch(cx, m_arg_name, value,
    1154                 :           0 :                                       ExpectedType::STRING);
    1155                 :             : 
    1156                 :           3 :     return gjs_unichar_from_string(cx, value, &gjs_arg_member<char32_t>(arg));
    1157                 :             : }
    1158                 :             : 
    1159                 :             : GJS_JSAPI_RETURN_CONVENTION
    1160                 :         469 : bool GTypeIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
    1161                 :             :                  JS::HandleValue value) {
    1162         [ -  + ]:         469 :     if (value.isNull())
    1163                 :           0 :         return report_invalid_null(cx, m_arg_name);
    1164         [ -  + ]:         469 :     if (!value.isObject())
    1165                 :           0 :         return report_typeof_mismatch(cx, m_arg_name, value,
    1166                 :           0 :                                       ExpectedType::OBJECT);
    1167                 :             : 
    1168                 :         469 :     JS::RootedObject gtype_obj(cx, &value.toObject());
    1169                 :         469 :     return gjs_gtype_get_actual_gtype(
    1170                 :         938 :         cx, gtype_obj, &gjs_arg_member<GType, GI_TYPE_TAG_GTYPE>(arg));
    1171                 :         469 : }
    1172                 :             : 
    1173                 :             : // Common code for most types that are pointers on the C side
    1174                 :       11990 : bool Nullable::handle_nullable(JSContext* cx, GIArgument* arg,
    1175                 :             :                                const char* arg_name) {
    1176         [ +  + ]:       11990 :     if (!m_nullable)
    1177                 :           2 :         return report_invalid_null(cx, arg_name);
    1178                 :       11988 :     gjs_arg_unset<void*>(arg);
    1179                 :       11988 :     return true;
    1180                 :             : }
    1181                 :             : 
    1182                 :             : template <GITypeTag TAG>
    1183                 :        4914 : GJS_JSAPI_RETURN_CONVENTION bool StringInTransferNone<TAG>::in(
    1184                 :             :     JSContext* cx, GjsFunctionCallState* state, GIArgument* arg,
    1185                 :             :     JS::HandleValue value) {
    1186         [ +  + ]:        4914 :     if (value.isNull())
    1187                 :          30 :         return NullableIn::in(cx, state, arg, value);
    1188                 :             : 
    1189         [ -  + ]:        4884 :     if (!value.isString())
    1190                 :           0 :         return report_typeof_mismatch(cx, m_arg_name, value,
    1191                 :           0 :                                       ExpectedType::STRING);
    1192                 :             : 
    1193                 :             :     if constexpr (TAG == GI_TYPE_TAG_FILENAME) {
    1194                 :         165 :         GjsAutoChar str;
    1195         [ -  + ]:         165 :         if (!gjs_string_to_filename(cx, value, &str))
    1196                 :           0 :             return false;
    1197                 :         165 :         gjs_arg_set(arg, str.release());
    1198                 :         165 :         return true;
    1199                 :         165 :     } else if constexpr (TAG == GI_TYPE_TAG_UTF8) {
    1200                 :        4719 :         JS::UniqueChars str = gjs_string_to_utf8(cx, value);
    1201         [ -  + ]:        4719 :         if (!str)
    1202                 :           0 :             return false;
    1203                 :        9438 :         gjs_arg_set(arg, g_strdup(str.get()));
    1204                 :        4719 :         return true;
    1205                 :        4719 :     } else {
    1206                 :             :         return invalid(cx, G_STRFUNC);
    1207                 :             :     }
    1208                 :             : }
    1209                 :             : 
    1210                 :             : GJS_JSAPI_RETURN_CONVENTION
    1211                 :          22 : bool EnumIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
    1212                 :             :                 JS::HandleValue value) {
    1213                 :             :     int64_t number;
    1214         [ -  + ]:          22 :     if (!Gjs::js_value_to_c(cx, value, &number))
    1215                 :           0 :         return false;
    1216                 :             : 
    1217                 :             :     // Unpack the values from their uint32_t bitfield. See note in
    1218                 :             :     // Enum::Enum().
    1219                 :             :     int64_t min, max;
    1220         [ +  + ]:          22 :     if (m_unsigned) {
    1221                 :           2 :         min = m_min;
    1222                 :           2 :         max = m_max;
    1223                 :             :     } else {
    1224                 :          20 :         min = static_cast<int32_t>(m_min);
    1225                 :          20 :         max = static_cast<int32_t>(m_max);
    1226                 :             :     }
    1227                 :             : 
    1228   [ +  -  -  + ]:          22 :     if (number > max || number < min) {
    1229                 :           0 :         gjs_throw(cx, "%" PRId64 " is not a valid value for enum argument %s",
    1230                 :             :                   number, m_arg_name);
    1231                 :           0 :         return false;
    1232                 :             :     }
    1233                 :             : 
    1234         [ +  + ]:          22 :     if (m_unsigned)
    1235                 :           2 :         gjs_arg_set<unsigned, GI_TYPE_TAG_INTERFACE>(arg, number);
    1236                 :             :     else
    1237                 :          20 :         gjs_arg_set<int, GI_TYPE_TAG_INTERFACE>(arg, number);
    1238                 :             : 
    1239                 :          22 :     return true;
    1240                 :             : }
    1241                 :             : 
    1242                 :             : GJS_JSAPI_RETURN_CONVENTION
    1243                 :         489 : bool FlagsIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
    1244                 :             :                  JS::HandleValue value) {
    1245                 :             :     int64_t number;
    1246         [ -  + ]:         489 :     if (!Gjs::js_value_to_c(cx, value, &number))
    1247                 :           0 :         return false;
    1248                 :             : 
    1249         [ -  + ]:         489 :     if ((uint64_t(number) & m_mask) != uint64_t(number)) {
    1250                 :           0 :         gjs_throw(cx,
    1251                 :             :                   "0x%" G_GINT64_MODIFIER
    1252                 :             :                   "x is not a valid value for flags argument %s",
    1253                 :             :                   number, m_arg_name);
    1254                 :           0 :         return false;
    1255                 :             :     }
    1256                 :             : 
    1257                 :             :     // We cast to unsigned because that's what makes sense, but then we
    1258                 :             :     // put it in the v_int slot because that's what we use to unmarshal
    1259                 :             :     // flags types at the moment.
    1260                 :         489 :     gjs_arg_set<int, GI_TYPE_TAG_INTERFACE>(arg, static_cast<unsigned>(number));
    1261                 :         489 :     return true;
    1262                 :             : }
    1263                 :             : 
    1264                 :             : GJS_JSAPI_RETURN_CONVENTION
    1265                 :           2 : bool ForeignStructInstanceIn::in(JSContext* cx, GjsFunctionCallState*,
    1266                 :             :                                  GIArgument* arg, JS::HandleValue value) {
    1267                 :           2 :     return gjs_struct_foreign_convert_to_gi_argument(
    1268                 :           2 :         cx, value, m_info, m_arg_name, GJS_ARGUMENT_ARGUMENT, m_transfer,
    1269                 :           4 :         flags(), arg);
    1270                 :             : }
    1271                 :             : 
    1272                 :             : GJS_JSAPI_RETURN_CONVENTION
    1273                 :         111 : bool GValueIn::in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg,
    1274                 :             :                   JS::HandleValue value) {
    1275         [ +  + ]:         111 :     if (value.isObject()) {
    1276                 :          87 :         JS::RootedObject obj(cx, &value.toObject());
    1277                 :             :         GType gtype;
    1278                 :             : 
    1279         [ -  + ]:          87 :         if (!gjs_gtype_get_actual_gtype(cx, obj, &gtype))
    1280                 :           0 :             return false;
    1281                 :             : 
    1282         [ +  + ]:          87 :         if (gtype == G_TYPE_VALUE) {
    1283                 :          60 :             gjs_arg_set(arg, BoxedBase::to_c_ptr<GValue>(cx, obj));
    1284                 :          60 :             state->ignore_release.insert(arg);
    1285                 :          60 :             return true;
    1286                 :             :         }
    1287         [ +  + ]:          87 :     }
    1288                 :             : 
    1289                 :          51 :     Gjs::AutoGValue gvalue;
    1290                 :             : 
    1291         [ -  + ]:          51 :     if (!gjs_value_to_g_value(cx, value, &gvalue))
    1292                 :           0 :         return false;
    1293                 :             : 
    1294                 :          51 :     gjs_arg_set(arg, g_boxed_copy(G_TYPE_VALUE, &gvalue));
    1295                 :             : 
    1296                 :          51 :     return true;
    1297                 :          51 : }
    1298                 :             : 
    1299                 :             : GJS_JSAPI_RETURN_CONVENTION
    1300                 :       58809 : bool BoxedInTransferNone::in(JSContext* cx, GjsFunctionCallState* state,
    1301                 :             :                              GIArgument* arg, JS::HandleValue value) {
    1302         [ +  + ]:       58809 :     if (value.isNull())
    1303                 :       11677 :         return NullableIn::in(cx, state, arg, value);
    1304                 :             : 
    1305                 :       47132 :     GType gtype = RegisteredType::gtype();
    1306                 :             : 
    1307         [ -  + ]:       47132 :     if (!value.isObject())
    1308                 :           0 :         return report_gtype_mismatch(cx, m_arg_name, value, gtype);
    1309                 :             : 
    1310                 :       47132 :     JS::RootedObject object(cx, &value.toObject());
    1311         [ +  + ]:       47132 :     if (gtype == G_TYPE_ERROR) {
    1312                 :          12 :         return ErrorBase::transfer_to_gi_argument(cx, object, arg,
    1313                 :          12 :                                                   GI_DIRECTION_IN, m_transfer);
    1314                 :             :     }
    1315                 :             : 
    1316                 :       94252 :     return BoxedBase::transfer_to_gi_argument(cx, object, arg, GI_DIRECTION_IN,
    1317                 :       94252 :                                               m_transfer, gtype, info());
    1318                 :       47132 : }
    1319                 :             : 
    1320                 :             : // Unions include ClutterEvent and GdkEvent, which occur fairly often in an
    1321                 :             : // interactive application, so they're worth a special case in a different
    1322                 :             : // virtual function.
    1323                 :             : GJS_JSAPI_RETURN_CONVENTION
    1324                 :           2 : bool UnionIn::in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg,
    1325                 :             :                  JS::HandleValue value) {
    1326         [ -  + ]:           2 :     if (value.isNull())
    1327                 :           0 :         return NullableIn::in(cx, state, arg, value);
    1328                 :             : 
    1329                 :           2 :     GType gtype = RegisteredType::gtype();
    1330                 :             : 
    1331         [ -  + ]:           2 :     if (!value.isObject())
    1332                 :           0 :         return report_gtype_mismatch(cx, m_arg_name, value, gtype);
    1333                 :             : 
    1334                 :           2 :     JS::RootedObject object(cx, &value.toObject());
    1335                 :           2 :     return UnionBase::transfer_to_gi_argument(cx, object, arg, GI_DIRECTION_IN,
    1336                 :           4 :                                               m_transfer, gtype);
    1337                 :           2 : }
    1338                 :             : 
    1339                 :             : GJS_JSAPI_RETURN_CONVENTION
    1340                 :       11552 : bool GClosureInTransferNone::in(JSContext* cx, GjsFunctionCallState* state,
    1341                 :             :                                 GIArgument* arg, JS::HandleValue value) {
    1342         [ -  + ]:       11552 :     if (value.isNull())
    1343                 :           0 :         return NullableIn::in(cx, state, arg, value);
    1344                 :             : 
    1345         [ -  + ]:       11552 :     if (!(JS_TypeOfValue(cx, value) == JSTYPE_FUNCTION))
    1346                 :           0 :         return report_typeof_mismatch(cx, m_arg_name, value,
    1347                 :           0 :                                       ExpectedType::FUNCTION);
    1348                 :             : 
    1349                 :       11552 :     JS::RootedObject callable(cx, &value.toObject());
    1350                 :       11552 :     GClosure* closure = Gjs::Closure::create_marshaled(cx, callable, "boxed");
    1351                 :       11552 :     gjs_arg_set(arg, closure);
    1352                 :       11552 :     g_closure_ref(closure);
    1353                 :       11552 :     g_closure_sink(closure);
    1354                 :             : 
    1355                 :       11552 :     return true;
    1356                 :       11552 : }
    1357                 :             : 
    1358                 :             : GJS_JSAPI_RETURN_CONVENTION
    1359                 :          72 : bool GBytesIn::in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg,
    1360                 :             :                   JS::HandleValue value) {
    1361         [ -  + ]:          72 :     if (value.isNull())
    1362                 :           0 :         return NullableIn::in(cx, state, arg, value);
    1363                 :             : 
    1364         [ -  + ]:          72 :     if (!value.isObject())
    1365                 :           0 :         return report_gtype_mismatch(cx, m_arg_name, value, G_TYPE_BYTES);
    1366                 :             : 
    1367                 :          72 :     JS::RootedObject object(cx, &value.toObject());
    1368         [ +  + ]:          72 :     if (JS_IsUint8Array(object)) {
    1369                 :          21 :         state->ignore_release.insert(arg);
    1370                 :          21 :         gjs_arg_set(arg, gjs_byte_array_get_bytes(object));
    1371                 :          21 :         return true;
    1372                 :             :     }
    1373                 :             : 
    1374                 :             :     // The bytearray path is taking an extra ref irrespective of transfer
    1375                 :             :     // ownership, so we need to do the same here.
    1376                 :         102 :     return BoxedBase::transfer_to_gi_argument(
    1377                 :          51 :         cx, object, arg, GI_DIRECTION_IN, GI_TRANSFER_EVERYTHING, G_TYPE_BYTES);
    1378                 :          72 : }
    1379                 :             : 
    1380                 :             : GJS_JSAPI_RETURN_CONVENTION
    1381                 :          35 : bool GBytesIn::release(JSContext* cx, GjsFunctionCallState* state,
    1382                 :             :                        GIArgument* in_arg, GIArgument* out_arg) {
    1383         [ -  + ]:          35 :     if (state->ignore_release.erase(in_arg))
    1384                 :           0 :         return BoxedIn::release(cx, state, in_arg, out_arg);
    1385                 :             : 
    1386                 :          35 :     return BoxedInTransferNone::release(cx, state, in_arg, out_arg);
    1387                 :             : }
    1388                 :             : 
    1389                 :             : GJS_JSAPI_RETURN_CONVENTION
    1390                 :           4 : bool InterfaceIn::in(JSContext* cx, GjsFunctionCallState* state,
    1391                 :             :                      GIArgument* arg, JS::HandleValue value) {
    1392         [ -  + ]:           4 :     if (value.isNull())
    1393                 :           0 :         return NullableIn::in(cx, state, arg, value);
    1394                 :             : 
    1395                 :           4 :     GType gtype = RegisteredType::gtype();
    1396                 :             : 
    1397         [ -  + ]:           4 :     if (!value.isObject())
    1398                 :           0 :         return report_gtype_mismatch(cx, m_arg_name, value, gtype);
    1399                 :             : 
    1400                 :           4 :     JS::RootedObject object(cx, &value.toObject());
    1401                 :             : 
    1402                 :             :     // Could be a GObject interface that's missing a prerequisite,
    1403                 :             :     // or could be a fundamental
    1404         [ +  - ]:           4 :     if (ObjectBase::typecheck(cx, object, nullptr, gtype,
    1405                 :             :                               GjsTypecheckNoThrow())) {
    1406                 :           8 :         return ObjectBase::transfer_to_gi_argument(
    1407                 :           8 :             cx, object, arg, GI_DIRECTION_IN, m_transfer, gtype);
    1408                 :             :     }
    1409                 :             : 
    1410                 :             :     // If this typecheck fails, then it's neither an object nor a
    1411                 :             :     // fundamental
    1412                 :           0 :     return FundamentalBase::transfer_to_gi_argument(
    1413                 :           0 :         cx, object, arg, GI_DIRECTION_IN, m_transfer, gtype);
    1414                 :           4 : }
    1415                 :             : 
    1416                 :             : GJS_JSAPI_RETURN_CONVENTION
    1417                 :        2197 : bool ObjectIn::in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg,
    1418                 :             :                   JS::HandleValue value) {
    1419         [ +  + ]:        2197 :     if (value.isNull())
    1420                 :         276 :         return NullableIn::in(cx, state, arg, value);
    1421                 :             : 
    1422                 :        1921 :     GType gtype = RegisteredType::gtype();
    1423                 :             : 
    1424         [ -  + ]:        1921 :     if (!value.isObject())
    1425                 :           0 :         return report_gtype_mismatch(cx, m_arg_name, value, gtype);
    1426                 :             : 
    1427                 :        1921 :     JS::RootedObject object(cx, &value.toObject());
    1428                 :        1921 :     return ObjectBase::transfer_to_gi_argument(cx, object, arg, GI_DIRECTION_IN,
    1429                 :        3842 :                                                m_transfer, gtype);
    1430                 :        1921 : }
    1431                 :             : 
    1432                 :             : GJS_JSAPI_RETURN_CONVENTION
    1433                 :           3 : bool FundamentalIn::in(JSContext* cx, GjsFunctionCallState* state,
    1434                 :             :                        GIArgument* arg, JS::HandleValue value) {
    1435         [ -  + ]:           3 :     if (value.isNull())
    1436                 :           0 :         return NullableIn::in(cx, state, arg, value);
    1437                 :             : 
    1438                 :           3 :     GType gtype = RegisteredType::gtype();
    1439                 :             : 
    1440         [ -  + ]:           3 :     if (!value.isObject())
    1441                 :           0 :         return report_gtype_mismatch(cx, m_arg_name, value, gtype);
    1442                 :             : 
    1443                 :           3 :     JS::RootedObject object(cx, &value.toObject());
    1444                 :           3 :     return FundamentalBase::transfer_to_gi_argument(
    1445                 :           6 :         cx, object, arg, GI_DIRECTION_IN, m_transfer, gtype);
    1446                 :           3 : }
    1447                 :             : 
    1448                 :             : GJS_JSAPI_RETURN_CONVENTION
    1449                 :          87 : bool GTypeStructInstanceIn::in(JSContext* cx, GjsFunctionCallState*,
    1450                 :             :                                GIArgument* arg, JS::HandleValue value) {
    1451                 :             :     // Instance parameter is never nullable
    1452         [ -  + ]:          87 :     if (!value.isObject())
    1453                 :           0 :         return report_typeof_mismatch(cx, m_arg_name, value,
    1454                 :           0 :                                       ExpectedType::OBJECT);
    1455                 :             : 
    1456                 :          87 :     JS::RootedObject obj(cx, &value.toObject());
    1457                 :             :     GType actual_gtype;
    1458         [ -  + ]:          87 :     if (!gjs_gtype_get_actual_gtype(cx, obj, &actual_gtype))
    1459                 :           0 :         return false;
    1460                 :             : 
    1461         [ -  + ]:          87 :     if (actual_gtype == G_TYPE_NONE) {
    1462                 :           0 :         gjs_throw(cx, "Invalid GType class passed for instance parameter");
    1463                 :           0 :         return false;
    1464                 :             :     }
    1465                 :             : 
    1466                 :             :     // We use peek here to simplify reference counting (we just ignore transfer
    1467                 :             :     // annotation, as GType classes are never really freed.) We know that the
    1468                 :             :     // GType class is referenced at least once when the JS constructor is
    1469                 :             :     // initialized.
    1470   [ +  -  -  +  :          87 :     if (g_type_is_a(actual_gtype, G_TYPE_INTERFACE))
                   -  + ]
    1471                 :           0 :         gjs_arg_set(arg, g_type_default_interface_peek(actual_gtype));
    1472                 :             :     else
    1473                 :          87 :         gjs_arg_set(arg, g_type_class_peek(actual_gtype));
    1474                 :             : 
    1475                 :          87 :     return true;
    1476                 :          87 : }
    1477                 :             : 
    1478                 :             : GJS_JSAPI_RETURN_CONVENTION
    1479                 :         161 : bool ParamInstanceIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
    1480                 :             :                          JS::HandleValue value) {
    1481                 :             :     // Instance parameter is never nullable
    1482         [ -  + ]:         161 :     if (!value.isObject())
    1483                 :           0 :         return report_typeof_mismatch(cx, m_arg_name, value,
    1484                 :           0 :                                       ExpectedType::OBJECT);
    1485                 :             : 
    1486                 :         161 :     JS::RootedObject obj(cx, &value.toObject());
    1487         [ -  + ]:         161 :     if (!gjs_typecheck_param(cx, obj, G_TYPE_PARAM, true))
    1488                 :           0 :         return false;
    1489                 :         161 :     gjs_arg_set(arg, gjs_g_param_from_param(cx, obj));
    1490                 :             : 
    1491         [ -  + ]:         161 :     if (m_transfer == GI_TRANSFER_EVERYTHING)
    1492                 :           0 :         g_param_spec_ref(gjs_arg_get<GParamSpec*>(arg));
    1493                 :             : 
    1494                 :         161 :     return true;
    1495                 :         161 : }
    1496                 :             : 
    1497                 :             : GJS_JSAPI_RETURN_CONVENTION
    1498                 :       21434 : bool GenericInOut::out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
    1499                 :             :                        JS::MutableHandleValue value) {
    1500                 :       21434 :     return gjs_value_from_gi_argument(cx, value, &m_type_info, arg, true);
    1501                 :             : }
    1502                 :             : 
    1503                 :             : GJS_JSAPI_RETURN_CONVENTION
    1504                 :          36 : bool ExplicitArrayInOut::out(JSContext* cx, GjsFunctionCallState* state,
    1505                 :             :                              GIArgument* arg, JS::MutableHandleValue value) {
    1506                 :             :     GIArgument* length_arg;
    1507                 :             : 
    1508         [ +  - ]:          36 :     if (m_length_direction != GI_DIRECTION_IN)
    1509                 :          36 :         length_arg = &(state->out_cvalue(m_length_pos));
    1510                 :             :     else
    1511                 :           0 :         length_arg = &(state->in_cvalue(m_length_pos));
    1512                 :             : 
    1513                 :          36 :     size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg);
    1514                 :             : 
    1515                 :          36 :     return gjs_value_from_explicit_array(cx, value, &m_type_info, m_transfer,
    1516                 :          36 :                                          arg, length);
    1517                 :             : }
    1518                 :             : 
    1519                 :             : GJS_JSAPI_RETURN_CONVENTION
    1520                 :          35 : bool GenericIn::release(JSContext* cx, GjsFunctionCallState* state,
    1521                 :             :                         GIArgument* in_arg, GIArgument*) {
    1522                 :             :     GITransfer transfer =
    1523         [ +  - ]:          35 :         state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING;
    1524                 :          35 :     return gjs_gi_argument_release_in_arg(cx, transfer, &m_type_info, in_arg);
    1525                 :             : }
    1526                 :             : 
    1527                 :             : GJS_JSAPI_RETURN_CONVENTION
    1528                 :       21408 : bool GenericOut::release(JSContext* cx, GjsFunctionCallState*,
    1529                 :             :                          GIArgument* in_arg [[maybe_unused]],
    1530                 :             :                          GIArgument* out_arg) {
    1531                 :       21408 :     return gjs_gi_argument_release(cx, m_transfer, &m_type_info, out_arg);
    1532                 :             : }
    1533                 :             : 
    1534                 :             : GJS_JSAPI_RETURN_CONVENTION
    1535                 :          14 : bool GenericInOut::release(JSContext* cx, GjsFunctionCallState* state,
    1536                 :             :                            GIArgument*, GIArgument* out_arg) {
    1537                 :             :     // For inout, transfer refers to what we get back from the function; for
    1538                 :             :     // the temporary C value we allocated, clearly we're responsible for
    1539                 :             :     // freeing it.
    1540                 :             : 
    1541                 :          14 :     GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos);
    1542         [ -  + ]:          14 :     if (!gjs_gi_argument_release_in_arg(cx, GI_TRANSFER_NOTHING, &m_type_info,
    1543                 :             :                                         original_out_arg))
    1544                 :           0 :         return false;
    1545                 :             : 
    1546                 :          14 :     return gjs_gi_argument_release(cx, m_transfer, &m_type_info, out_arg);
    1547                 :             : }
    1548                 :             : 
    1549                 :             : GJS_JSAPI_RETURN_CONVENTION
    1550                 :          21 : bool ExplicitArrayOut::release(JSContext* cx, GjsFunctionCallState* state,
    1551                 :             :                                GIArgument* in_arg [[maybe_unused]],
    1552                 :             :                                GIArgument* out_arg) {
    1553                 :          21 :     GIArgument* length_arg = &state->out_cvalue(m_length_pos);
    1554                 :          21 :     size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg);
    1555                 :             : 
    1556                 :          21 :     return gjs_gi_argument_release_out_array(cx, m_transfer, &m_type_info,
    1557                 :          21 :                                              length, out_arg);
    1558                 :             : }
    1559                 :             : 
    1560                 :             : GJS_JSAPI_RETURN_CONVENTION
    1561                 :         318 : bool ExplicitArrayIn::release(JSContext* cx, GjsFunctionCallState* state,
    1562                 :             :                               GIArgument* in_arg,
    1563                 :             :                               GIArgument* out_arg [[maybe_unused]]) {
    1564                 :         318 :     GIArgument* length_arg = &state->in_cvalue(m_length_pos);
    1565                 :         318 :     size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg);
    1566                 :             : 
    1567                 :             :     GITransfer transfer =
    1568         [ +  + ]:         318 :         state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING;
    1569                 :             : 
    1570                 :         318 :     return gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, length,
    1571                 :         318 :                                             in_arg);
    1572                 :             : }
    1573                 :             : 
    1574                 :             : GJS_JSAPI_RETURN_CONVENTION
    1575                 :          15 : bool ExplicitArrayInOut::release(JSContext* cx, GjsFunctionCallState* state,
    1576                 :             :                                  GIArgument* in_arg [[maybe_unused]],
    1577                 :             :                                  GIArgument* out_arg) {
    1578                 :          15 :     GIArgument* length_arg = &state->out_cvalue(m_length_pos);
    1579                 :          15 :     size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg);
    1580                 :             : 
    1581                 :             :     // For inout, transfer refers to what we get back from the function; for
    1582                 :             :     // the temporary C value we allocated, clearly we're responsible for
    1583                 :             :     // freeing it.
    1584                 :             : 
    1585                 :          15 :     GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos);
    1586                 :             :     // Due to https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/192
    1587                 :             :     // Here we've to guess what to do, but in general is "better" to leak than
    1588                 :             :     // crash, so let's assume that in/out transfer is matching.
    1589         [ +  + ]:          15 :     if (gjs_arg_get<void*>(original_out_arg) != gjs_arg_get<void*>(out_arg)) {
    1590                 :             :         GITransfer transfer =
    1591         [ +  - ]:           4 :             state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING;
    1592         [ -  + ]:           4 :         if (!gjs_gi_argument_release_in_array(cx, transfer, &m_type_info,
    1593                 :             :                                               length, original_out_arg))
    1594                 :           0 :             return false;
    1595                 :             :     }
    1596                 :             : 
    1597                 :             :     GITransfer transfer =
    1598         [ +  - ]:          15 :         state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING;
    1599                 :          15 :     return gjs_gi_argument_release_out_array(cx, transfer, &m_type_info, length,
    1600                 :          15 :                                              out_arg);
    1601                 :             : }
    1602                 :             : 
    1603                 :             : GJS_JSAPI_RETURN_CONVENTION
    1604                 :           6 : bool CallerAllocatesOut::release(JSContext*, GjsFunctionCallState*,
    1605                 :             :                                  GIArgument* in_arg,
    1606                 :             :                                  GIArgument* out_arg [[maybe_unused]]) {
    1607                 :           6 :     g_free(gjs_arg_steal<void*>(in_arg));
    1608                 :           6 :     return true;
    1609                 :             : }
    1610                 :             : 
    1611                 :             : GJS_JSAPI_RETURN_CONVENTION
    1612                 :           3 : bool BoxedCallerAllocatesOut::release(JSContext*, GjsFunctionCallState*,
    1613                 :             :                                       GIArgument* in_arg, GIArgument*) {
    1614                 :           3 :     g_boxed_free(m_gtype, gjs_arg_steal<void*>(in_arg));
    1615                 :           3 :     return true;
    1616                 :             : }
    1617                 :             : 
    1618                 :             : GJS_JSAPI_RETURN_CONVENTION
    1619                 :         246 : bool CallbackIn::release(JSContext*, GjsFunctionCallState*, GIArgument* in_arg,
    1620                 :             :                          GIArgument* out_arg [[maybe_unused]]) {
    1621                 :         246 :     ffi_closure *closure = m_ffi_closure;
    1622         [ +  + ]:         246 :     if (!closure)
    1623                 :           8 :         return true;
    1624                 :             : 
    1625                 :         238 :     g_closure_unref(static_cast<GClosure*>(closure->user_data));
    1626                 :             :     // CallbackTrampolines are refcounted because for notified/async closures
    1627                 :             :     // it is possible to destroy it while in call, and therefore we cannot
    1628                 :             :     // check its scope at this point
    1629                 :         238 :     gjs_arg_unset<void*>(in_arg);
    1630                 :         238 :     return true;
    1631                 :             : }
    1632                 :             : 
    1633                 :             : template <GITypeTag TAG>
    1634                 :        4913 : GJS_JSAPI_RETURN_CONVENTION bool StringInTransferNone<TAG>::release(
    1635                 :             :     JSContext*, GjsFunctionCallState*, GIArgument* in_arg,
    1636                 :             :     GIArgument* out_arg [[maybe_unused]]) {
    1637                 :        4913 :     g_free(gjs_arg_get<void*>(in_arg));
    1638                 :        4913 :     return true;
    1639                 :             : }
    1640                 :             : 
    1641                 :             : GJS_JSAPI_RETURN_CONVENTION
    1642                 :           2 : bool ForeignStructIn::release(JSContext* cx, GjsFunctionCallState* state,
    1643                 :             :                               GIArgument* in_arg,
    1644                 :             :                               GIArgument* out_arg [[maybe_unused]]) {
    1645                 :             :     GITransfer transfer =
    1646         [ +  - ]:           2 :         state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING;
    1647                 :             : 
    1648         [ +  - ]:           2 :     if (transfer == GI_TRANSFER_NOTHING)
    1649                 :           2 :         return gjs_struct_foreign_release_gi_argument(cx, m_transfer, m_info,
    1650                 :           2 :                                                       in_arg);
    1651                 :             : 
    1652                 :           0 :     return true;
    1653                 :             : }
    1654                 :             : 
    1655                 :             : GJS_JSAPI_RETURN_CONVENTION
    1656                 :       11675 : bool BoxedInTransferNone::release(JSContext*, GjsFunctionCallState*,
    1657                 :             :                                   GIArgument* in_arg,
    1658                 :             :                                   GIArgument* out_arg [[maybe_unused]]) {
    1659                 :       11675 :     GType gtype = RegisteredType::gtype();
    1660                 :       11675 :     g_assert(g_type_is_a(gtype, G_TYPE_BOXED));
    1661                 :             : 
    1662         [ -  + ]:       11675 :     if (!gjs_arg_get<void*>(in_arg))
    1663                 :           0 :         return true;
    1664                 :             : 
    1665                 :       11675 :     g_boxed_free(gtype, gjs_arg_get<void*>(in_arg));
    1666                 :       11675 :     return true;
    1667                 :             : }
    1668                 :             : 
    1669                 :             : GJS_JSAPI_RETURN_CONVENTION
    1670                 :         111 : bool GValueInTransferNone::release(JSContext* cx, GjsFunctionCallState* state,
    1671                 :             :                                    GIArgument* in_arg, GIArgument* out_arg) {
    1672         [ +  + ]:         111 :     if (state->ignore_release.erase(in_arg))
    1673                 :          60 :         return true;
    1674                 :             : 
    1675                 :          51 :     return BoxedInTransferNone::release(cx, state, in_arg, out_arg);
    1676                 :             : }
    1677                 :             : 
    1678                 :             : }  // namespace Arg
    1679                 :             : 
    1680                 :           0 : bool Argument::invalid(JSContext* cx, const char* func) const {
    1681         [ #  # ]:           0 :     gjs_throw(cx, "%s not implemented", func ? func : "Function");
    1682                 :           0 :     return false;
    1683                 :             : }
    1684                 :             : 
    1685                 :           0 : bool Argument::in(JSContext* cx, GjsFunctionCallState*, GIArgument*,
    1686                 :             :                   JS::HandleValue) {
    1687                 :           0 :     return invalid(cx, G_STRFUNC);
    1688                 :             : }
    1689                 :             : 
    1690                 :           0 : bool Argument::out(JSContext* cx, GjsFunctionCallState*, GIArgument*,
    1691                 :             :                    JS::MutableHandleValue) {
    1692                 :           0 :     return invalid(cx, G_STRFUNC);
    1693                 :             : }
    1694                 :             : 
    1695                 :           0 : bool Argument::release(JSContext*, GjsFunctionCallState*, GIArgument*,
    1696                 :             :                        GIArgument*) {
    1697                 :           0 :     return true;
    1698                 :             : }
    1699                 :             : 
    1700                 :             : // This is a trick to print out the sizes of the structs at compile time, in
    1701                 :             : // an error message:
    1702                 :             : // template <int s> struct Measure;
    1703                 :             : // Measure<sizeof(Arg::)> arg_size;
    1704                 :             : 
    1705                 :             : #ifdef GJS_DO_ARGUMENTS_SIZE_CHECK
    1706                 :             : template <typename T>
    1707                 :             : constexpr size_t argument_maximum_size() {
    1708                 :             :     if constexpr (std::is_same_v<T, Arg::NumericIn<int>>)
    1709                 :             :         return 24;
    1710                 :             :     if constexpr (std::is_same_v<T, Arg::ObjectIn> ||
    1711                 :             :                   std::is_same_v<T, Arg::BoxedIn>)
    1712                 :             :         return 40;
    1713                 :             :     else
    1714                 :             :         return 120;
    1715                 :             : }
    1716                 :             : #endif
    1717                 :             : 
    1718                 :             : template <typename T, Arg::Kind ArgKind, typename... Args>
    1719                 :       33258 : GjsAutoCppPointer<T> Argument::make(uint8_t index, const char* name,
    1720                 :             :                                     GITypeInfo* type_info, GITransfer transfer,
    1721                 :             :                                     GjsArgumentFlags flags, Args&&... args) {
    1722                 :             : #ifdef GJS_DO_ARGUMENTS_SIZE_CHECK
    1723                 :             :     static_assert(
    1724                 :             :         sizeof(T) <= argument_maximum_size<T>(),
    1725                 :             :         "Think very hard before increasing the size of Gjs::Arguments. "
    1726                 :             :         "One is allocated for every argument to every introspected function.");
    1727                 :             : #endif
    1728                 :       33258 :     auto arg = new T(args...);
    1729                 :             : 
    1730                 :             :     if constexpr (ArgKind == Arg::Kind::INSTANCE) {
    1731                 :        3475 :         g_assert(index == Argument::ABSENT &&
    1732                 :             :                  "index was ignored in INSTANCE parameter");
    1733                 :        3475 :         g_assert(name == nullptr && "name was ignored in INSTANCE parameter");
    1734                 :        3475 :         arg->set_instance_parameter();
    1735                 :             :     } else if constexpr (ArgKind == Arg::Kind::RETURN_VALUE) {
    1736                 :        8715 :         g_assert(index == Argument::ABSENT &&
    1737                 :             :                  "index was ignored in RETURN_VALUE parameter");
    1738                 :        8715 :         g_assert(name == nullptr &&
    1739                 :             :                  "name was ignored in RETURN_VALUE parameter");
    1740                 :        8715 :         arg->set_return_value();
    1741                 :             :     } else {
    1742                 :             :         if constexpr (std::is_base_of_v<Arg::Positioned, T>)
    1743                 :        1776 :             arg->set_arg_pos(index);
    1744                 :       21068 :         arg->m_arg_name = name;
    1745                 :             :     }
    1746                 :             : 
    1747                 :       33258 :     arg->m_skip_in = (flags & GjsArgumentFlags::SKIP_IN);
    1748                 :       33258 :     arg->m_skip_out = (flags & GjsArgumentFlags::SKIP_OUT);
    1749                 :             : 
    1750                 :             :     if constexpr (std::is_base_of_v<Arg::Nullable, T>)
    1751                 :       17973 :         arg->m_nullable = (flags & GjsArgumentFlags::MAY_BE_NULL);
    1752                 :             : 
    1753                 :             :     if constexpr (std::is_base_of_v<Arg::Transferable, T>)
    1754                 :       13662 :         arg->m_transfer = transfer;
    1755                 :             : 
    1756                 :             :     if constexpr (std::is_base_of_v<Arg::TypeInfo, T> &&
    1757                 :             :                   ArgKind != Arg::Kind::INSTANCE) {
    1758                 :        7081 :         arg->m_type_info = std::move(*type_info);
    1759                 :             :     }
    1760                 :             : 
    1761                 :       33258 :     return arg;
    1762                 :             : }
    1763                 :             : 
    1764                 :       11030 : bool ArgsCache::initialize(JSContext* cx, GICallableInfo* callable) {
    1765         [ -  + ]:       11030 :     if (!callable) {
    1766                 :           0 :         gjs_throw(cx, "Invalid callable provided");
    1767                 :           0 :         return false;
    1768                 :             :     }
    1769                 :             : 
    1770         [ -  + ]:       11030 :     if (m_args) {
    1771                 :           0 :         gjs_throw(cx, "Arguments cache already initialized!");
    1772                 :           0 :         return false;
    1773                 :             :     }
    1774                 :             : 
    1775                 :             :     GITypeInfo type_info;
    1776                 :       11030 :     g_callable_info_load_return_type(callable, &type_info);
    1777                 :             : 
    1778   [ +  +  +  + ]:       13601 :     m_has_return = g_type_info_get_tag(&type_info) != GI_TYPE_TAG_VOID ||
    1779                 :        2571 :                    g_type_info_is_pointer(&type_info);
    1780                 :       11030 :     m_is_method = !!g_callable_info_is_method(callable);
    1781                 :             : 
    1782                 :       11030 :     int size = g_callable_info_get_n_args(callable);
    1783         [ +  + ]:       11030 :     size += (m_is_method ? 1 : 0);
    1784         [ +  + ]:       11030 :     size += (m_has_return ? 1 : 0);
    1785                 :             : 
    1786         [ -  + ]:       11030 :     if (size > Argument::MAX_ARGS) {
    1787                 :           0 :         gjs_throw(cx,
    1788                 :             :                   "Too many arguments, only %u are supported, while %d are "
    1789                 :             :                   "provided!",
    1790                 :             :                   Argument::MAX_ARGS, size);
    1791                 :           0 :         return false;
    1792                 :             :     }
    1793                 :             : 
    1794   [ +  -  +  + ]:       44116 :     m_args = new ArgumentPtr[size]{};
    1795                 :       11030 :     return true;
    1796                 :             : }
    1797                 :             : 
    1798                 :             : template <typename T, Arg::Kind ArgKind, typename... Args>
    1799                 :       33258 : constexpr T* ArgsCache::set_argument(uint8_t index, const char* name,
    1800                 :             :                                      GITypeInfo* type_info, GITransfer transfer,
    1801                 :             :                                      GjsArgumentFlags flags, Args&&... args) {
    1802                 :       33258 :     GjsAutoCppPointer<T> arg = Argument::make<T, ArgKind>(
    1803                 :             :         index, name, type_info, transfer, flags, args...);
    1804                 :       33258 :     arg_get<ArgKind>(index) = arg.release();
    1805                 :       33258 :     return static_cast<T*>(arg_get<ArgKind>(index).get());
    1806                 :       33258 : }
    1807                 :             : 
    1808                 :             : template <typename T, Arg::Kind ArgKind, typename... Args>
    1809                 :        2256 : constexpr T* ArgsCache::set_argument(uint8_t index, const char* name,
    1810                 :             :                                      GITransfer transfer,
    1811                 :             :                                      GjsArgumentFlags flags, Args&&... args) {
    1812                 :        2256 :     return set_argument<T, ArgKind>(index, name, nullptr, transfer, flags,
    1813                 :        2256 :                                     args...);
    1814                 :             : }
    1815                 :             : 
    1816                 :             : template <typename T, Arg::Kind ArgKind, typename... Args>
    1817                 :             : constexpr T* ArgsCache::set_argument_auto(Args&&... args) {
    1818                 :             :     return set_argument<T, ArgKind>(std::forward<Args>(args)...);
    1819                 :             : }
    1820                 :             : 
    1821                 :             : template <typename T, Arg::Kind ArgKind, typename Tuple, typename... Args>
    1822                 :       22125 : constexpr T* ArgsCache::set_argument_auto(Tuple&& tuple, Args&&... args) {
    1823                 :             :     // TODO(3v1n0): Would be nice to have a simple way to check we're handling a
    1824                 :             :     // tuple
    1825                 :       22125 :     return std::apply(
    1826                 :       66375 :         [&](auto&&... largs) {
    1827                 :             :             return set_argument<T, ArgKind>(largs...,
    1828                 :       22125 :                                             std::forward<Args>(args)...);
    1829                 :             :         },
    1830                 :       22125 :         tuple);
    1831                 :             : }
    1832                 :             : 
    1833                 :             : template <typename T>
    1834                 :        8715 : constexpr T* ArgsCache::set_return(GITypeInfo* type_info, GITransfer transfer,
    1835                 :             :                                    GjsArgumentFlags flags) {
    1836                 :        8715 :     return set_argument<T, Arg::Kind::RETURN_VALUE>(Argument::ABSENT, nullptr,
    1837                 :        8715 :                                                     type_info, transfer, flags);
    1838                 :             : }
    1839                 :             : 
    1840                 :             : template <typename T>
    1841                 :         589 : constexpr T* ArgsCache::set_instance(GITransfer transfer,
    1842                 :             :                                      GjsArgumentFlags flags) {
    1843                 :         589 :     return set_argument<T, Arg::Kind::INSTANCE>(Argument::ABSENT, nullptr,
    1844                 :         589 :                                                 transfer, flags);
    1845                 :             : }
    1846                 :             : 
    1847                 :       35469 : GType ArgsCache::instance_type() const {
    1848         [ -  + ]:       35469 :     if (!m_is_method)
    1849                 :           0 :         return G_TYPE_NONE;
    1850                 :             : 
    1851                 :       35469 :     return instance()->as_instance()->gtype();
    1852                 :             : }
    1853                 :             : 
    1854                 :       64424 : GITypeTag ArgsCache::return_tag() const {
    1855                 :       64424 :     Argument* rval = return_value();
    1856         [ +  + ]:       64424 :     if (!rval)
    1857                 :       28750 :         return GI_TYPE_TAG_VOID;
    1858                 :             : 
    1859                 :       35674 :     return rval->return_tag();
    1860                 :             : }
    1861                 :             : 
    1862                 :       64424 : GITypeInfo* ArgsCache::return_type() const {
    1863                 :       64424 :     Argument* rval = return_value();
    1864         [ +  + ]:       64424 :     if (!rval)
    1865                 :       28750 :         return nullptr;
    1866                 :             : 
    1867                 :       35674 :     return const_cast<GITypeInfo*>(rval->return_type());
    1868                 :             : }
    1869                 :             : 
    1870                 :        1667 : constexpr void ArgsCache::set_skip_all(uint8_t index, const char* name) {
    1871                 :        1667 :     set_argument<Arg::SkipAll>(index, name, GI_TRANSFER_NOTHING,
    1872                 :             :                                GjsArgumentFlags::SKIP_ALL);
    1873                 :        1667 : }
    1874                 :             : 
    1875                 :             : template <Arg::Kind ArgKind>
    1876                 :        1063 : void ArgsCache::set_array_argument(GICallableInfo* callable, uint8_t gi_index,
    1877                 :             :                                    GITypeInfo* type_info, GIDirection direction,
    1878                 :             :                                    GIArgInfo* arg, GjsArgumentFlags flags,
    1879                 :             :                                    int length_pos) {
    1880                 :             :     Arg::ExplicitArray* array;
    1881                 :             :     GIArgInfo length_arg;
    1882                 :        1063 :     g_callable_info_load_arg(callable, length_pos, &length_arg);
    1883                 :             :     GITypeInfo length_type;
    1884                 :        1063 :     g_arg_info_load_type(&length_arg, &length_type);
    1885                 :             : 
    1886                 :             :     if constexpr (ArgKind == Arg::Kind::RETURN_VALUE) {
    1887                 :         142 :         GITransfer transfer = g_callable_info_get_caller_owns(callable);
    1888                 :         142 :         array = set_return<Arg::ReturnArray>(type_info, transfer,
    1889                 :             :                                              GjsArgumentFlags::NONE);
    1890                 :             :     } else {
    1891                 :         921 :         const char* arg_name = g_base_info_get_name(arg);
    1892                 :         921 :         GITransfer transfer = g_arg_info_get_ownership_transfer(arg);
    1893                 :         921 :         auto common_args =
    1894                 :             :             std::make_tuple(gi_index, arg_name, type_info, transfer, flags);
    1895                 :             : 
    1896         [ +  + ]:         921 :         if (direction == GI_DIRECTION_IN) {
    1897                 :         888 :             array = set_argument_auto<Arg::CArrayIn>(common_args);
    1898                 :         888 :             set_skip_all(length_pos, g_base_info_get_name(&length_arg));
    1899         [ +  + ]:          33 :         } else if (direction == GI_DIRECTION_INOUT) {
    1900                 :          13 :             array = set_argument_auto<Arg::CArrayInOut>(common_args);
    1901                 :          13 :             set_skip_all(length_pos, g_base_info_get_name(&length_arg));
    1902                 :             :         } else {
    1903                 :          20 :             array = set_argument_auto<Arg::CArrayOut>(common_args);
    1904                 :             :         }
    1905                 :             :     }
    1906                 :             : 
    1907         [ +  + ]:         921 :     if (ArgKind == Arg::Kind::RETURN_VALUE || direction == GI_DIRECTION_OUT) {
    1908                 :             :         // Even if we skip the length argument most of time, we need to
    1909                 :             :         // do some basic initialization here.
    1910                 :         162 :         set_argument<Arg::ArrayLengthOut>(
    1911                 :             :             length_pos, g_base_info_get_name(&length_arg), &length_type,
    1912                 :             :             GI_TRANSFER_NOTHING,
    1913                 :         182 :             static_cast<GjsArgumentFlags>(flags | GjsArgumentFlags::SKIP_ALL));
    1914                 :             :     }
    1915                 :             : 
    1916                 :        1063 :     array->set_array_length(length_pos, g_type_info_get_tag(&length_type),
    1917                 :             :                             g_arg_info_get_direction(&length_arg));
    1918                 :        1063 : }
    1919                 :             : 
    1920                 :       11030 : void ArgsCache::build_return(GICallableInfo* callable, bool* inc_counter_out) {
    1921                 :       11030 :     g_assert(inc_counter_out && "forgot out parameter");
    1922                 :             : 
    1923         [ +  + ]:       11030 :     if (!m_has_return) {
    1924                 :        2315 :         *inc_counter_out = false;
    1925                 :        6172 :         return;
    1926                 :             :     }
    1927                 :             : 
    1928                 :             :     GITypeInfo type_info;
    1929                 :        8715 :     g_callable_info_load_return_type(callable, &type_info);
    1930                 :        8715 :     GITransfer transfer = g_callable_info_get_caller_owns(callable);
    1931                 :        8715 :     GITypeTag tag = g_type_info_get_tag(&type_info);
    1932                 :             : 
    1933                 :        8715 :     *inc_counter_out = true;
    1934                 :        8715 :     GjsArgumentFlags flags = GjsArgumentFlags::SKIP_IN;
    1935                 :             : 
    1936         [ +  + ]:        8715 :     if (g_callable_info_may_return_null(callable))
    1937                 :         546 :         flags |= GjsArgumentFlags::MAY_BE_NULL;
    1938                 :             : 
    1939   [ +  +  +  +  :        8715 :     switch (tag) {
          +  +  +  +  +  
             +  +  +  +  
                      + ]
    1940                 :        1336 :         case GI_TYPE_TAG_BOOLEAN:
    1941                 :        1336 :             set_return<Arg::BooleanReturn>(&type_info, transfer, flags);
    1942                 :        1336 :             return;
    1943                 :             : 
    1944                 :           5 :         case GI_TYPE_TAG_INT8:
    1945                 :           5 :             set_return<Arg::NumericReturn<int8_t, GI_TYPE_TAG_INT8>>(
    1946                 :             :                 &type_info, transfer, flags);
    1947                 :           5 :             return;
    1948                 :             : 
    1949                 :           6 :         case GI_TYPE_TAG_INT16:
    1950                 :           6 :             set_return<Arg::NumericReturn<int16_t, GI_TYPE_TAG_INT16>>(
    1951                 :             :                 &type_info, transfer, flags);
    1952                 :           6 :             return;
    1953                 :             : 
    1954                 :          91 :         case GI_TYPE_TAG_INT32:
    1955                 :          91 :             set_return<Arg::NumericReturn<int32_t, GI_TYPE_TAG_INT32>>(
    1956                 :             :                 &type_info, transfer, flags);
    1957                 :          91 :             return;
    1958                 :             : 
    1959                 :           8 :         case GI_TYPE_TAG_UINT8:
    1960                 :           8 :             set_return<Arg::NumericReturn<uint8_t, GI_TYPE_TAG_UINT8>>(
    1961                 :             :                 &type_info, transfer, flags);
    1962                 :           8 :             return;
    1963                 :             : 
    1964                 :           5 :         case GI_TYPE_TAG_UINT16:
    1965                 :           5 :             set_return<Arg::NumericReturn<uint16_t, GI_TYPE_TAG_UINT16>>(
    1966                 :             :                 &type_info, transfer, flags);
    1967                 :           5 :             return;
    1968                 :             : 
    1969                 :         719 :         case GI_TYPE_TAG_UINT32:
    1970                 :         719 :             set_return<Arg::NumericReturn<uint32_t, GI_TYPE_TAG_UINT32>>(
    1971                 :             :                 &type_info, transfer, flags);
    1972                 :         719 :             return;
    1973                 :             : 
    1974                 :          51 :         case GI_TYPE_TAG_INT64:
    1975                 :          51 :             set_return<Arg::NumericReturn<int64_t, GI_TYPE_TAG_INT64>>(
    1976                 :             :                 &type_info, transfer, flags);
    1977                 :          51 :             return;
    1978                 :             : 
    1979                 :         167 :         case GI_TYPE_TAG_UINT64:
    1980                 :         167 :             set_return<Arg::NumericReturn<uint64_t, GI_TYPE_TAG_UINT64>>(
    1981                 :             :                 &type_info, transfer, flags);
    1982                 :         167 :             return;
    1983                 :             : 
    1984                 :           3 :         case GI_TYPE_TAG_FLOAT:
    1985                 :           3 :             set_return<Arg::NumericReturn<float, GI_TYPE_TAG_FLOAT>>(
    1986                 :             :                 &type_info, transfer, flags);
    1987                 :           3 :             return;
    1988                 :             : 
    1989                 :          29 :         case GI_TYPE_TAG_DOUBLE:
    1990                 :          29 :             set_return<Arg::NumericReturn<double, GI_TYPE_TAG_DOUBLE>>(
    1991                 :             :                 &type_info, transfer, flags);
    1992                 :          29 :             return;
    1993                 :             : 
    1994                 :        1295 :         case GI_TYPE_TAG_UTF8:
    1995         [ +  + ]:        1295 :             if (transfer == GI_TRANSFER_NOTHING) {
    1996                 :         219 :                 set_return<Arg::StringReturn<GI_TRANSFER_NOTHING>>(
    1997                 :             :                     &type_info, transfer, flags);
    1998                 :         219 :                 return;
    1999                 :             :             } else {
    2000                 :        1076 :                 set_return<Arg::StringReturn<GI_TRANSFER_EVERYTHING>>(
    2001                 :             :                     &type_info, transfer, flags);
    2002                 :        1076 :                 return;
    2003                 :             :             }
    2004                 :             : 
    2005                 :         350 :         case GI_TYPE_TAG_ARRAY: {
    2006                 :         350 :             int length_pos = g_type_info_get_array_length(&type_info);
    2007         [ +  + ]:         350 :             if (length_pos >= 0) {
    2008                 :         142 :                 set_array_argument<Arg::Kind::RETURN_VALUE>(
    2009                 :             :                     callable, 0, &type_info, GI_DIRECTION_OUT, nullptr, flags,
    2010                 :             :                     length_pos);
    2011                 :         142 :                 return;
    2012                 :             :             }
    2013                 :             : 
    2014                 :             :             [[fallthrough]];
    2015                 :             :         }
    2016                 :             : 
    2017                 :             :         default:
    2018                 :        4858 :             break;
    2019                 :             :     }
    2020                 :             : 
    2021                 :             :     // in() is ignored for the return value, but skip_in is not (it is used
    2022                 :             :     // in the failure release path)
    2023                 :        4858 :     set_return<Arg::GenericReturn>(&type_info, transfer, flags);
    2024                 :             : }
    2025                 :             : 
    2026                 :             : namespace Arg {
    2027                 :             : 
    2028                 :         230 : Enum::Enum(GIEnumInfo* enum_info) {
    2029                 :         230 :     int64_t min = std::numeric_limits<int64_t>::max();
    2030                 :         230 :     int64_t max = std::numeric_limits<int64_t>::min();
    2031                 :         230 :     int n = g_enum_info_get_n_values(enum_info);
    2032         [ +  + ]:        2941 :     for (int i = 0; i < n; i++) {
    2033                 :        2711 :         GjsAutoValueInfo value_info = g_enum_info_get_value(enum_info, i);
    2034                 :        2711 :         int64_t value = g_value_info_get_value(value_info);
    2035                 :             : 
    2036         [ +  + ]:        2711 :         if (value > max)
    2037                 :        2685 :             max = value;
    2038         [ +  + ]:        2711 :         if (value < min)
    2039                 :         240 :             min = value;
    2040                 :        2711 :     }
    2041                 :             : 
    2042                 :             :     // From the docs for g_value_info_get_value(): "This will always be
    2043                 :             :     // representable as a 32-bit signed or unsigned value. The use of gint64 as
    2044                 :             :     // the return type is to allow both."
    2045                 :             :     // We stuff them both into unsigned 32-bit fields, and use a flag to tell
    2046                 :             :     // whether we have to compare them as signed.
    2047                 :         230 :     m_min = static_cast<uint32_t>(min);
    2048                 :         230 :     m_max = static_cast<uint32_t>(max);
    2049                 :             : 
    2050   [ +  +  +  + ]:         230 :     m_unsigned = (min >= 0 && max > std::numeric_limits<int32_t>::max());
    2051                 :         230 : }
    2052                 :             : 
    2053                 :        1486 : Flags::Flags(GIEnumInfo* enum_info) {
    2054                 :        1486 :     uint64_t mask = 0;
    2055                 :        1486 :     int n = g_enum_info_get_n_values(enum_info);
    2056         [ +  + ]:       17263 :     for (int i = 0; i < n; i++) {
    2057                 :       15777 :         GjsAutoValueInfo value_info = g_enum_info_get_value(enum_info, i);
    2058                 :       15777 :         int64_t value = g_value_info_get_value(value_info);
    2059                 :             :         // From the docs for g_value_info_get_value(): "This will always be
    2060                 :             :         // representable as a 32-bit signed or unsigned value. The use of
    2061                 :             :         // gint64 as the return type is to allow both."
    2062                 :             :         // We stuff both into an unsigned, int-sized field, matching the
    2063                 :             :         // internal representation of flags in GLib (which uses guint).
    2064                 :       15777 :         mask |= static_cast<unsigned>(value);
    2065                 :       15777 :     }
    2066                 :             : 
    2067                 :        1486 :     m_mask = mask;
    2068                 :        1486 : }
    2069                 :             : 
    2070                 :             : }  // namespace Arg
    2071                 :             : 
    2072                 :             : namespace arg_cache {
    2073                 :        6506 : [[nodiscard]] static inline bool is_gdk_atom(GIBaseInfo* info) {
    2074         [ -  + ]:        6506 :     return strcmp("Atom", g_base_info_get_name(info)) == 0 &&
    2075         [ -  - ]:        6506 :            strcmp("Gdk", g_base_info_get_namespace(info)) == 0;
    2076                 :             : }
    2077                 :             : }  // namespace arg_cache
    2078                 :             : 
    2079                 :             : template <Arg::Kind ArgKind>
    2080                 :        8634 : void ArgsCache::build_interface_in_arg(uint8_t gi_index, GITypeInfo* type_info,
    2081                 :             :                                        GIBaseInfo* interface_info,
    2082                 :             :                                        GITransfer transfer, const char* name,
    2083                 :             :                                        GjsArgumentFlags flags) {
    2084                 :        8634 :     GIInfoType interface_type = g_base_info_get_type(interface_info);
    2085                 :             : 
    2086                 :        8634 :     auto base_args =
    2087                 :             :         std::make_tuple(gi_index, name, type_info, transfer, flags);
    2088                 :        8634 :     auto common_args =
    2089                 :        2886 :         std::tuple_cat(base_args, std::make_tuple(interface_info));
    2090                 :             : 
    2091                 :             :     // We do some transfer magic later, so let's ensure we don't mess up.
    2092                 :             :     // Should not happen in practice.
    2093         [ -  + ]:        8634 :     if (G_UNLIKELY(transfer == GI_TRANSFER_CONTAINER)) {
    2094                 :           0 :         set_argument_auto<Arg::NotIntrospectable>(base_args,
    2095                 :           0 :                                                   INTERFACE_TRANSFER_CONTAINER);
    2096                 :        8634 :         return;
    2097                 :             :     }
    2098                 :             : 
    2099   [ +  +  +  +  :        8634 :     switch (interface_type) {
                      - ]
    2100                 :         230 :         case GI_INFO_TYPE_ENUM:
    2101                 :         230 :             set_argument_auto<Arg::EnumIn, ArgKind>(common_args);
    2102                 :         230 :             return;
    2103                 :             : 
    2104                 :        1486 :         case GI_INFO_TYPE_FLAGS:
    2105                 :        1486 :             set_argument_auto<Arg::FlagsIn, ArgKind>(common_args);
    2106                 :        1486 :             return;
    2107                 :             : 
    2108                 :        3101 :         case GI_INFO_TYPE_STRUCT:
    2109         [ +  + ]:        3101 :             if (g_struct_info_is_foreign(interface_info)) {
    2110                 :             :                 if constexpr (ArgKind == Arg::Kind::INSTANCE)
    2111                 :           0 :                     set_argument_auto<Arg::ForeignStructInstanceIn, ArgKind>(
    2112                 :             :                         common_args);
    2113                 :             :                 else
    2114                 :          15 :                     set_argument_auto<Arg::ForeignStructIn, ArgKind>(
    2115                 :             :                         common_args);
    2116                 :          15 :                 return;
    2117                 :             :             }
    2118                 :             :             [[fallthrough]];
    2119                 :             :         case GI_INFO_TYPE_BOXED:
    2120                 :             :         case GI_INFO_TYPE_OBJECT:
    2121                 :             :         case GI_INFO_TYPE_INTERFACE:
    2122                 :             :         case GI_INFO_TYPE_UNION: {
    2123                 :        6903 :             GType gtype = g_registered_type_info_get_g_type(interface_info);
    2124                 :             : 
    2125   [ +  +  +  +  :        7228 :             if (interface_type == GI_INFO_TYPE_STRUCT && gtype == G_TYPE_NONE &&
             +  -  +  + ]
    2126                 :         325 :                 !g_struct_info_is_gtype_struct(interface_info)) {
    2127                 :             :                 if constexpr (ArgKind != Arg::Kind::INSTANCE) {
    2128                 :             :                     // This covers cases such as GTypeInstance
    2129                 :         318 :                     set_argument_auto<Arg::FallbackInterfaceIn, ArgKind>(
    2130                 :             :                         common_args);
    2131                 :         318 :                     return;
    2132                 :             :                 }
    2133                 :             :             }
    2134                 :             : 
    2135                 :             :             // Transfer handling is a bit complex here, because some of our in()
    2136                 :             :             // arguments know not to copy stuff if we don't need to.
    2137                 :             : 
    2138         [ +  + ]:        6585 :             if (gtype == G_TYPE_VALUE) {
    2139                 :             :                 if constexpr (ArgKind == Arg::Kind::INSTANCE)
    2140                 :          55 :                     set_argument_auto<Arg::BoxedIn, ArgKind>(common_args);
    2141         [ +  - ]:          24 :                 else if (transfer == GI_TRANSFER_NOTHING)
    2142                 :          24 :                     set_argument_auto<Arg::GValueInTransferNone, ArgKind>(
    2143                 :             :                         common_args);
    2144                 :             :                 else
    2145                 :           0 :                     set_argument_auto<Arg::GValueIn, ArgKind>(common_args);
    2146                 :          79 :                 return;
    2147                 :             :             }
    2148                 :             : 
    2149         [ -  + ]:        6506 :             if (arg_cache::is_gdk_atom(interface_info)) {
    2150                 :             :                 // Fall back to the generic marshaller
    2151                 :           0 :                 set_argument_auto<Arg::FallbackInterfaceIn, ArgKind>(
    2152                 :             :                     common_args);
    2153                 :           0 :                 return;
    2154                 :             :             }
    2155                 :             : 
    2156         [ +  + ]:        6506 :             if (gtype == G_TYPE_CLOSURE) {
    2157         [ +  - ]:         716 :                 if (transfer == GI_TRANSFER_NOTHING &&
    2158                 :             :                     ArgKind != Arg::Kind::INSTANCE)
    2159                 :         716 :                     set_argument_auto<Arg::GClosureInTransferNone, ArgKind>(
    2160                 :             :                         common_args);
    2161                 :             :                 else
    2162                 :           0 :                     set_argument_auto<Arg::GClosureIn, ArgKind>(common_args);
    2163                 :         716 :                 return;
    2164                 :             :             }
    2165                 :             : 
    2166         [ +  + ]:        5790 :             if (gtype == G_TYPE_BYTES) {
    2167         [ +  - ]:          78 :                 if (transfer == GI_TRANSFER_NOTHING &&
    2168                 :             :                     ArgKind != Arg::Kind::INSTANCE)
    2169                 :          78 :                     set_argument_auto<Arg::GBytesInTransferNone, ArgKind>(
    2170                 :             :                         common_args);
    2171                 :             :                 else
    2172                 :           2 :                     set_argument_auto<Arg::GBytesIn, ArgKind>(common_args);
    2173                 :          80 :                 return;
    2174                 :             :             }
    2175                 :             : 
    2176   [ +  +  +  +  :        5710 :             if (g_type_is_a(gtype, G_TYPE_OBJECT)) {
                   +  + ]
    2177                 :        3657 :                 set_argument_auto<Arg::ObjectIn, ArgKind>(common_args);
    2178                 :        3657 :                 return;
    2179                 :             :             }
    2180                 :             : 
    2181   [ +  +  -  +  :        2053 :             if (g_type_is_a(gtype, G_TYPE_PARAM)) {
                   +  + ]
    2182                 :         147 :                 set_argument_auto<Arg::FallbackInterfaceIn, ArgKind>(
    2183                 :             :                     common_args);
    2184                 :         147 :                 return;
    2185                 :             :             }
    2186                 :             : 
    2187         [ +  + ]:        1906 :             if (interface_type == GI_INFO_TYPE_UNION) {
    2188         [ -  + ]:           8 :                 if (gtype == G_TYPE_NONE) {
    2189                 :             :                     // Can't handle unions without a GType
    2190                 :           0 :                     set_argument_auto<Arg::NotIntrospectable>(
    2191                 :           0 :                         base_args, UNREGISTERED_UNION);
    2192                 :           0 :                     return;
    2193                 :             :                 }
    2194                 :             : 
    2195                 :           8 :                 set_argument_auto<Arg::UnionIn, ArgKind>(common_args);
    2196                 :           8 :                 return;
    2197                 :             :             }
    2198                 :             : 
    2199         [ +  + ]:        1898 :             if (G_TYPE_IS_INSTANTIATABLE(gtype)) {
    2200                 :           1 :                 set_argument_auto<Arg::FundamentalIn, ArgKind>(common_args);
    2201                 :           1 :                 return;
    2202                 :             :             }
    2203                 :             : 
    2204   [ +  -  +  +  :        1897 :             if (g_type_is_a(gtype, G_TYPE_INTERFACE)) {
                   +  + ]
    2205                 :           4 :                 set_argument_auto<Arg::InterfaceIn, ArgKind>(common_args);
    2206                 :           4 :                 return;
    2207                 :             :             }
    2208                 :             : 
    2209                 :             :             // generic boxed type
    2210         [ +  + ]:        1893 :             if (gtype == G_TYPE_NONE) {
    2211         [ -  + ]:           7 :                 if (transfer != GI_TRANSFER_NOTHING) {
    2212                 :             :                     // Can't transfer ownership of a structure type not
    2213                 :             :                     // registered as a boxed
    2214                 :           0 :                     set_argument_auto<Arg::NotIntrospectable>(
    2215                 :           0 :                         base_args, UNREGISTERED_BOXED_WITH_TRANSFER);
    2216                 :           0 :                     return;
    2217                 :             :                 }
    2218                 :             : 
    2219                 :           7 :                 set_argument_auto<Arg::UnregisteredBoxedIn, ArgKind>(
    2220                 :             :                     common_args);
    2221                 :           7 :                 return;
    2222                 :             :             }
    2223                 :        1886 :             set_argument_auto<Arg::BoxedIn, ArgKind>(common_args);
    2224                 :        1886 :             return;
    2225                 :             :         } break;
    2226                 :             : 
    2227                 :           0 :         case GI_INFO_TYPE_INVALID:
    2228                 :             :         case GI_INFO_TYPE_FUNCTION:
    2229                 :             :         case GI_INFO_TYPE_CALLBACK:
    2230                 :             :         case GI_INFO_TYPE_CONSTANT:
    2231                 :             :         case GI_INFO_TYPE_INVALID_0:
    2232                 :             :         case GI_INFO_TYPE_VALUE:
    2233                 :             :         case GI_INFO_TYPE_SIGNAL:
    2234                 :             :         case GI_INFO_TYPE_VFUNC:
    2235                 :             :         case GI_INFO_TYPE_PROPERTY:
    2236                 :             :         case GI_INFO_TYPE_FIELD:
    2237                 :             :         case GI_INFO_TYPE_ARG:
    2238                 :             :         case GI_INFO_TYPE_TYPE:
    2239                 :             :         case GI_INFO_TYPE_UNRESOLVED:
    2240                 :             :         default:
    2241                 :             :             // Don't know how to handle this interface type (should not happen
    2242                 :             :             // in practice, for typelibs emitted by g-ir-compiler)
    2243                 :           0 :             set_argument_auto<Arg::NotIntrospectable>(base_args,
    2244                 :           0 :                                                       UNSUPPORTED_TYPE);
    2245                 :             :     }
    2246                 :             : }
    2247                 :             : 
    2248                 :       16786 : void ArgsCache::build_normal_in_arg(uint8_t gi_index, GITypeInfo* type_info,
    2249                 :             :                                     GIArgInfo* arg, GjsArgumentFlags flags) {
    2250                 :             :     // "Normal" in arguments are those arguments that don't require special
    2251                 :             :     // processing, and don't touch other arguments.
    2252                 :             :     // Main categories are:
    2253                 :             :     // - void*
    2254                 :             :     // - small numbers (fit in 32bit)
    2255                 :             :     // - big numbers (need a double)
    2256                 :             :     // - strings
    2257                 :             :     // - enums/flags (different from numbers in the way they're exposed in GI)
    2258                 :             :     // - objects (GObjects, boxed, unions, etc.)
    2259                 :             :     // - hashes
    2260                 :             :     // - sequences (null-terminated arrays, lists, etc.)
    2261                 :             : 
    2262                 :       16786 :     const char* name = g_base_info_get_name(arg);
    2263                 :       16786 :     GITransfer transfer = g_arg_info_get_ownership_transfer(arg);
    2264                 :             :     auto common_args =
    2265                 :       16786 :         std::make_tuple(gi_index, name, type_info, transfer, flags);
    2266                 :       16786 :     GITypeTag tag = g_type_info_get_tag(type_info);
    2267                 :             : 
    2268   [ +  +  +  +  :       16786 :     switch (tag) {
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
    2269                 :         943 :         case GI_TYPE_TAG_VOID:
    2270                 :         943 :             set_argument_auto<Arg::NullIn>(common_args);
    2271                 :         943 :             break;
    2272                 :             : 
    2273                 :         382 :         case GI_TYPE_TAG_BOOLEAN:
    2274                 :         382 :             set_argument_auto<Arg::BooleanIn>(common_args);
    2275                 :         382 :             break;
    2276                 :             : 
    2277                 :         139 :         case GI_TYPE_TAG_INT8:
    2278                 :         139 :             set_argument_auto<Arg::NumericIn<int8_t>>(common_args);
    2279                 :        9287 :             return;
    2280                 :             : 
    2281                 :          69 :         case GI_TYPE_TAG_INT16:
    2282                 :          69 :             set_argument_auto<Arg::NumericIn<int16_t>>(common_args);
    2283                 :          69 :             return;
    2284                 :             : 
    2285                 :         988 :         case GI_TYPE_TAG_INT32:
    2286                 :         988 :             set_argument_auto<Arg::NumericIn<int32_t>>(common_args);
    2287                 :         988 :             return;
    2288                 :             : 
    2289                 :          69 :         case GI_TYPE_TAG_UINT8:
    2290                 :          69 :             set_argument_auto<Arg::NumericIn<uint8_t>>(common_args);
    2291                 :          69 :             return;
    2292                 :             : 
    2293                 :          74 :         case GI_TYPE_TAG_UINT16:
    2294                 :          74 :             set_argument_auto<Arg::NumericIn<uint16_t>>(common_args);
    2295                 :          74 :             return;
    2296                 :             : 
    2297                 :        1414 :         case GI_TYPE_TAG_UINT32:
    2298                 :        1414 :             set_argument_auto<Arg::NumericIn<uint32_t>>(common_args);
    2299                 :        1414 :             return;
    2300                 :             : 
    2301                 :         252 :         case GI_TYPE_TAG_INT64:
    2302                 :         252 :             set_argument_auto<Arg::NumericIn<int64_t>>(common_args);
    2303                 :         252 :             return;
    2304                 :             : 
    2305                 :         308 :         case GI_TYPE_TAG_UINT64:
    2306                 :         308 :             set_argument_auto<Arg::NumericIn<uint64_t>>(common_args);
    2307                 :         308 :             return;
    2308                 :             : 
    2309                 :           3 :         case GI_TYPE_TAG_FLOAT:
    2310                 :           3 :             set_argument_auto<Arg::NumericIn<float>>(common_args);
    2311                 :           3 :             return;
    2312                 :             : 
    2313                 :         223 :         case GI_TYPE_TAG_DOUBLE:
    2314                 :         223 :             set_argument_auto<Arg::NumericIn<double>>(common_args);
    2315                 :         223 :             return;
    2316                 :             : 
    2317                 :           1 :         case GI_TYPE_TAG_UNICHAR:
    2318                 :           1 :             set_argument_auto<Arg::UnicharIn>(common_args);
    2319                 :           1 :             break;
    2320                 :             : 
    2321                 :         195 :         case GI_TYPE_TAG_GTYPE:
    2322                 :         195 :             set_argument_auto<Arg::GTypeIn>(common_args);
    2323                 :         195 :             break;
    2324                 :             : 
    2325                 :         217 :         case GI_TYPE_TAG_FILENAME:
    2326         [ +  - ]:         217 :             if (transfer == GI_TRANSFER_NOTHING)
    2327                 :         217 :                 set_argument_auto<Arg::FilenameInTransferNone>(common_args);
    2328                 :             :             else
    2329                 :           0 :                 set_argument_auto<Arg::FilenameIn>(common_args);
    2330                 :         217 :             break;
    2331                 :             : 
    2332                 :        5653 :         case GI_TYPE_TAG_UTF8:
    2333         [ +  - ]:        5653 :             if (transfer == GI_TRANSFER_NOTHING)
    2334                 :        5653 :                 set_argument_auto<Arg::StringInTransferNone<GI_TYPE_TAG_UTF8>>(
    2335                 :             :                     common_args);
    2336                 :             :             else
    2337                 :           0 :                 set_argument_auto<Arg::StringIn>(common_args);
    2338                 :        5653 :             break;
    2339                 :             : 
    2340                 :        5748 :         case GI_TYPE_TAG_INTERFACE: {
    2341                 :             :             GjsAutoBaseInfo interface_info =
    2342                 :        5748 :                 g_type_info_get_interface(type_info);
    2343                 :        5748 :             build_interface_in_arg(gi_index, type_info, interface_info,
    2344                 :             :                                    transfer, name, flags);
    2345                 :        5748 :             return;
    2346                 :        5748 :         }
    2347                 :             : 
    2348                 :         108 :         case GI_TYPE_TAG_ARRAY:
    2349                 :             :         case GI_TYPE_TAG_GLIST:
    2350                 :             :         case GI_TYPE_TAG_GSLIST:
    2351                 :             :         case GI_TYPE_TAG_GHASH:
    2352                 :             :         case GI_TYPE_TAG_ERROR:
    2353                 :             :         default:
    2354                 :             :             // FIXME: Falling back to the generic marshaller
    2355                 :         108 :             set_argument_auto<Arg::FallbackIn>(common_args);
    2356                 :             :     }
    2357                 :             : }
    2358                 :             : 
    2359                 :         623 : void ArgsCache::build_normal_out_arg(uint8_t gi_index, GITypeInfo* type_info,
    2360                 :             :                                      GIArgInfo* arg, GjsArgumentFlags flags) {
    2361                 :         623 :     const char* name = g_base_info_get_name(arg);
    2362                 :         623 :     GITransfer transfer = g_arg_info_get_ownership_transfer(arg);
    2363                 :             :     auto common_args =
    2364                 :         623 :         std::make_tuple(gi_index, name, type_info, transfer, flags);
    2365                 :         623 :     GITypeTag tag = g_type_info_get_tag(type_info);
    2366                 :             : 
    2367   [ +  +  +  +  :         623 :     switch (tag) {
          +  +  +  +  +  
             +  +  +  + ]
    2368                 :          71 :         case GI_TYPE_TAG_BOOLEAN:
    2369                 :          71 :             set_argument_auto<Arg::BooleanOut>(common_args);
    2370                 :          71 :             break;
    2371                 :             : 
    2372                 :           5 :         case GI_TYPE_TAG_INT8:
    2373                 :           5 :             set_argument_auto<Arg::NumericOut<int8_t>>(common_args);
    2374                 :         188 :             return;
    2375                 :             : 
    2376                 :           4 :         case GI_TYPE_TAG_INT16:
    2377                 :           4 :             set_argument_auto<Arg::NumericOut<int16_t>>(common_args);
    2378                 :           4 :             return;
    2379                 :             : 
    2380                 :          47 :         case GI_TYPE_TAG_INT32:
    2381                 :          47 :             set_argument_auto<Arg::NumericOut<int32_t>>(common_args);
    2382                 :          47 :             return;
    2383                 :             : 
    2384                 :           1 :         case GI_TYPE_TAG_UINT8:
    2385                 :           1 :             set_argument_auto<Arg::NumericOut<uint8_t>>(common_args);
    2386                 :           1 :             return;
    2387                 :             : 
    2388                 :           2 :         case GI_TYPE_TAG_UINT16:
    2389                 :           2 :             set_argument_auto<Arg::NumericOut<uint16_t>>(common_args);
    2390                 :           2 :             return;
    2391                 :             : 
    2392                 :          12 :         case GI_TYPE_TAG_UINT32:
    2393                 :          12 :             set_argument_auto<Arg::NumericOut<uint32_t>>(common_args);
    2394                 :          12 :             return;
    2395                 :             : 
    2396                 :          13 :         case GI_TYPE_TAG_INT64:
    2397                 :          13 :             set_argument_auto<Arg::NumericOut<int64_t>>(common_args);
    2398                 :          13 :             return;
    2399                 :             : 
    2400                 :          15 :         case GI_TYPE_TAG_UINT64:
    2401                 :          15 :             set_argument_auto<Arg::NumericOut<uint64_t>>(common_args);
    2402                 :          15 :             return;
    2403                 :             : 
    2404                 :           7 :         case GI_TYPE_TAG_FLOAT:
    2405                 :           7 :             set_argument_auto<Arg::NumericOut<float>>(common_args);
    2406                 :           7 :             return;
    2407                 :             : 
    2408                 :          12 :         case GI_TYPE_TAG_DOUBLE:
    2409                 :          12 :             set_argument_auto<Arg::NumericOut<double>>(common_args);
    2410                 :          12 :             return;
    2411                 :             : 
    2412                 :          70 :         case GI_TYPE_TAG_UTF8:
    2413         [ +  + ]:          70 :             if (transfer == GI_TRANSFER_NOTHING) {
    2414                 :           4 :                 set_argument_auto<Arg::StringOut<GI_TRANSFER_NOTHING>>(
    2415                 :             :                     common_args);
    2416                 :             :             } else {
    2417                 :          66 :                 set_argument_auto<Arg::StringOut<GI_TRANSFER_EVERYTHING>>(
    2418                 :             :                     common_args);
    2419                 :             :             }
    2420                 :          70 :             return;
    2421                 :             : 
    2422                 :         364 :         default:
    2423                 :         364 :             set_argument_auto<Arg::FallbackOut>(common_args);
    2424                 :             :     }
    2425                 :             : }
    2426                 :             : 
    2427                 :          55 : void ArgsCache::build_normal_inout_arg(uint8_t gi_index, GITypeInfo* type_info,
    2428                 :             :                                        GIArgInfo* arg, GjsArgumentFlags flags) {
    2429                 :          55 :     const char* name = g_base_info_get_name(arg);
    2430                 :          55 :     GITransfer transfer = g_arg_info_get_ownership_transfer(arg);
    2431                 :             :     auto common_args =
    2432                 :          55 :         std::make_tuple(gi_index, name, type_info, transfer, flags);
    2433                 :          55 :     GITypeTag tag = g_type_info_get_tag(type_info);
    2434                 :             : 
    2435   [ +  +  +  +  :          55 :     switch (tag) {
          +  +  +  +  -  
                +  +  + ]
    2436                 :           2 :         case GI_TYPE_TAG_BOOLEAN:
    2437                 :           2 :             set_argument_auto<Arg::BooleanInOut>(common_args);
    2438                 :           2 :             break;
    2439                 :             : 
    2440                 :           2 :         case GI_TYPE_TAG_INT8:
    2441                 :           2 :             set_argument_auto<Arg::NumericInOut<int8_t>>(common_args);
    2442                 :          35 :             return;
    2443                 :             : 
    2444                 :           4 :         case GI_TYPE_TAG_INT16:
    2445                 :           4 :             set_argument_auto<Arg::NumericInOut<int16_t>>(common_args);
    2446                 :           4 :             return;
    2447                 :             : 
    2448                 :          15 :         case GI_TYPE_TAG_INT32:
    2449                 :          15 :             set_argument_auto<Arg::NumericInOut<int32_t>>(common_args);
    2450                 :          15 :             return;
    2451                 :             : 
    2452                 :           1 :         case GI_TYPE_TAG_UINT8:
    2453                 :           1 :             set_argument_auto<Arg::NumericInOut<uint8_t>>(common_args);
    2454                 :           1 :             return;
    2455                 :             : 
    2456                 :           2 :         case GI_TYPE_TAG_UINT16:
    2457                 :           2 :             set_argument_auto<Arg::NumericInOut<uint16_t>>(common_args);
    2458                 :           2 :             return;
    2459                 :             : 
    2460                 :           2 :         case GI_TYPE_TAG_UINT32:
    2461                 :           2 :             set_argument_auto<Arg::NumericInOut<uint32_t>>(common_args);
    2462                 :           2 :             return;
    2463                 :             : 
    2464                 :           4 :         case GI_TYPE_TAG_INT64:
    2465                 :           4 :             set_argument_auto<Arg::NumericInOut<int64_t>>(common_args);
    2466                 :           4 :             return;
    2467                 :             : 
    2468                 :           0 :         case GI_TYPE_TAG_UINT64:
    2469                 :           0 :             set_argument_auto<Arg::NumericInOut<uint64_t>>(common_args);
    2470                 :           0 :             return;
    2471                 :             : 
    2472                 :           4 :         case GI_TYPE_TAG_FLOAT:
    2473                 :           4 :             set_argument_auto<Arg::NumericInOut<float>>(common_args);
    2474                 :           4 :             return;
    2475                 :             : 
    2476                 :           1 :         case GI_TYPE_TAG_DOUBLE:
    2477                 :           1 :             set_argument_auto<Arg::NumericInOut<double>>(common_args);
    2478                 :           1 :             return;
    2479                 :             : 
    2480                 :          18 :         default:
    2481                 :          18 :             set_argument_auto<Arg::FallbackInOut>(common_args);
    2482                 :             :     }
    2483                 :             : }
    2484                 :             : 
    2485                 :       11030 : void ArgsCache::build_instance(GICallableInfo* callable) {
    2486         [ +  + ]:       11030 :     if (!m_is_method)
    2487                 :        7555 :         return;
    2488                 :             : 
    2489                 :        3475 :     GIBaseInfo* interface_info = g_base_info_get_container(callable);  // !owned
    2490                 :             : 
    2491                 :             :     GITransfer transfer =
    2492                 :        3475 :         g_callable_info_get_instance_ownership_transfer(callable);
    2493                 :             : 
    2494                 :             :     // These cases could be covered by the generic marshaller, except that
    2495                 :             :     // there's no way to get GITypeInfo for a method's instance parameter.
    2496                 :             :     // Instead, special-case the arguments here that would otherwise go through
    2497                 :             :     // the generic marshaller.
    2498                 :             :     // See: https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/334
    2499                 :        3475 :     GIInfoType info_type = g_base_info_get_type(interface_info);
    2500   [ +  +  +  +  :        4781 :     if (info_type == GI_INFO_TYPE_STRUCT &&
                   +  + ]
    2501                 :        1306 :         g_struct_info_is_gtype_struct(interface_info)) {
    2502                 :         461 :         set_instance<Arg::GTypeStructInstanceIn>(transfer);
    2503                 :         461 :         return;
    2504                 :             :     }
    2505         [ +  + ]:        3014 :     if (info_type == GI_INFO_TYPE_OBJECT) {
    2506                 :        1858 :         GType gtype = g_registered_type_info_get_g_type(interface_info);
    2507                 :             : 
    2508   [ +  +  -  +  :        1858 :         if (g_type_is_a(gtype, G_TYPE_PARAM)) {
                   +  + ]
    2509                 :         128 :             set_instance<Arg::ParamInstanceIn>(transfer);
    2510                 :         128 :             return;
    2511                 :             :         }
    2512                 :             :     }
    2513                 :             : 
    2514                 :        2886 :     build_interface_in_arg<Arg::Kind::INSTANCE>(
    2515                 :             :         Argument::ABSENT, nullptr, interface_info, transfer, nullptr,
    2516                 :             :         GjsArgumentFlags::NONE);
    2517                 :             : }
    2518                 :             : 
    2519                 :          11 : static constexpr bool type_tag_is_scalar(GITypeTag tag) {
    2520   [ +  -  +  -  :          11 :     return GI_TYPE_TAG_IS_NUMERIC(tag) || tag == GI_TYPE_TAG_BOOLEAN ||
             +  -  -  + ]
    2521                 :          11 :            tag == GI_TYPE_TAG_GTYPE;
    2522                 :             : }
    2523                 :             : 
    2524                 :       19238 : void ArgsCache::build_arg(uint8_t gi_index, GIDirection direction,
    2525                 :             :                           GIArgInfo* arg, GICallableInfo* callable,
    2526                 :             :                           bool* inc_counter_out) {
    2527                 :       19238 :     g_assert(inc_counter_out && "forgot out parameter");
    2528                 :             :     GITypeInfo type_info;
    2529                 :             : 
    2530                 :       19238 :     const char* arg_name = g_base_info_get_name(arg);
    2531                 :       19238 :     g_arg_info_load_type(arg, &type_info);
    2532                 :       19238 :     GITransfer transfer = g_arg_info_get_ownership_transfer(arg);
    2533                 :             : 
    2534                 :       19238 :     GjsArgumentFlags flags = GjsArgumentFlags::NONE;
    2535         [ +  + ]:       19238 :     if (g_arg_info_may_be_null(arg))
    2536                 :        4010 :         flags |= GjsArgumentFlags::MAY_BE_NULL;
    2537         [ +  + ]:       19238 :     if (g_arg_info_is_caller_allocates(arg))
    2538                 :          14 :         flags |= GjsArgumentFlags::CALLER_ALLOCATES;
    2539                 :             : 
    2540         [ +  + ]:       19238 :     if (direction == GI_DIRECTION_IN)
    2541                 :       18510 :         flags |= GjsArgumentFlags::SKIP_OUT;
    2542         [ +  + ]:         728 :     else if (direction == GI_DIRECTION_OUT)
    2543                 :         657 :         flags |= GjsArgumentFlags::SKIP_IN;
    2544                 :       19238 :     *inc_counter_out = true;
    2545                 :             : 
    2546                 :             :     auto common_args =
    2547                 :       19238 :         std::make_tuple(gi_index, arg_name, &type_info, transfer, flags);
    2548                 :             : 
    2549                 :       19238 :     GITypeTag type_tag = g_type_info_get_tag(&type_info);
    2550   [ +  +  +  + ]:       19895 :     if (direction == GI_DIRECTION_OUT &&
    2551         [ +  + ]:       19895 :         (flags & GjsArgumentFlags::CALLER_ALLOCATES)) {
    2552                 :          14 :         size_t size = 0;
    2553                 :             : 
    2554         [ +  + ]:          14 :         if (type_tag == GI_TYPE_TAG_ARRAY) {
    2555                 :           3 :             GIArrayType array_type = g_type_info_get_array_type(&type_info);
    2556                 :             : 
    2557         [ +  + ]:           3 :             switch (array_type) {
    2558                 :           2 :                 case GI_ARRAY_TYPE_C: {
    2559                 :           2 :                     GjsAutoTypeInfo param_info;
    2560                 :             :                     int n_elements =
    2561                 :           2 :                         g_type_info_get_array_fixed_size(&type_info);
    2562                 :             : 
    2563         [ -  + ]:           2 :                     if (n_elements <= 0)
    2564                 :           0 :                         break;
    2565                 :             : 
    2566                 :           2 :                     param_info = g_type_info_get_param_type(&type_info, 0);
    2567                 :           2 :                     GITypeTag param_tag = g_type_info_get_tag(param_info);
    2568                 :             : 
    2569                 :           2 :                     size = gjs_type_get_element_size(param_tag, param_info);
    2570                 :           2 :                     size *= n_elements;
    2571                 :           2 :                     break;
    2572                 :           2 :                 }
    2573                 :           1 :                 default:
    2574                 :           1 :                     break;
    2575                 :             :             }
    2576   [ +  -  +  +  :          22 :         } else if (!type_tag_is_scalar(type_tag) &&
                   +  + ]
    2577                 :          11 :                    !g_type_info_is_pointer(&type_info)) {
    2578                 :             :             // Scalar out parameters should not be annotated with
    2579                 :             :             // caller-allocates, which is for structured types that need to be
    2580                 :             :             // allocated in order for the function to fill them in.
    2581                 :          10 :             size = gjs_type_get_element_size(type_tag, &type_info);
    2582                 :             :         }
    2583                 :             : 
    2584         [ +  + ]:          14 :         if (!size) {
    2585                 :           2 :             set_argument_auto<Arg::NotIntrospectable>(
    2586                 :           2 :                 common_args, OUT_CALLER_ALLOCATES_NON_STRUCT);
    2587                 :           2 :             return;
    2588                 :             :         }
    2589                 :             : 
    2590         [ +  + ]:          12 :         if (type_tag == GI_TYPE_TAG_INTERFACE) {
    2591                 :             :             GjsAutoBaseInfo interface_info =
    2592                 :          10 :                 g_type_info_get_interface(&type_info);
    2593                 :          10 :             GType gtype = g_registered_type_info_get_g_type(interface_info);
    2594   [ +  -  +  +  :          10 :             if (g_type_is_a(gtype, G_TYPE_BOXED)) {
                   +  + ]
    2595                 :           6 :                 auto* gjs_arg = set_argument_auto<Arg::BoxedCallerAllocatesOut>(
    2596                 :             :                     common_args, gtype);
    2597                 :           6 :                 gjs_arg->m_allocates_size = size;
    2598                 :           6 :                 return;
    2599                 :             :             }
    2600         [ +  + ]:          10 :         }
    2601                 :             : 
    2602                 :           6 :         auto* gjs_arg = set_argument_auto<Arg::CallerAllocatesOut>(common_args);
    2603                 :           6 :         gjs_arg->m_allocates_size = size;
    2604                 :             : 
    2605                 :           6 :         return;
    2606                 :             :     }
    2607                 :             : 
    2608         [ +  + ]:       19224 :     if (type_tag == GI_TYPE_TAG_INTERFACE) {
    2609                 :        6804 :         GjsAutoBaseInfo interface_info = g_type_info_get_interface(&type_info);
    2610         [ +  + ]:        6804 :         if (interface_info.type() == GI_INFO_TYPE_CALLBACK) {
    2611         [ -  + ]:         714 :             if (direction != GI_DIRECTION_IN) {
    2612                 :             :                 // Can't do callbacks for out or inout
    2613                 :           0 :                 set_argument_auto<Arg::NotIntrospectable>(common_args,
    2614                 :           0 :                                                           CALLBACK_OUT);
    2615                 :           0 :                 return;
    2616                 :             :             }
    2617                 :             : 
    2618   [ +  +  +  + ]:         779 :             if (strcmp(interface_info.name(), "DestroyNotify") == 0 &&
    2619         [ +  - ]:          65 :                 strcmp(interface_info.ns(), "GLib") == 0) {
    2620                 :             :                 // We don't know (yet) what to do with GDestroyNotify appearing
    2621                 :             :                 // before a callback. If the callback comes later in the
    2622                 :             :                 // argument list, then the invalid argument will be
    2623                 :             :                 // overwritten with the 'skipped' one. If no callback follows,
    2624                 :             :                 // then this is probably an unsupported function, so the
    2625                 :             :                 // function invocation code will check this and throw.
    2626                 :          65 :                 set_argument_auto<Arg::NotIntrospectable>(
    2627                 :          65 :                     common_args, DESTROY_NOTIFY_NO_CALLBACK);
    2628                 :          65 :                 *inc_counter_out = false;
    2629                 :             :             } else {
    2630                 :         649 :                 auto* gjs_arg = set_argument_auto<Arg::CallbackIn>(
    2631                 :             :                     common_args, interface_info);
    2632                 :             : 
    2633                 :         649 :                 int destroy_pos = g_arg_info_get_destroy(arg);
    2634                 :         649 :                 int closure_pos = g_arg_info_get_closure(arg);
    2635                 :             : 
    2636         [ +  + ]:         649 :                 if (destroy_pos >= 0)
    2637                 :         149 :                     set_skip_all(destroy_pos);
    2638                 :             : 
    2639         [ +  + ]:         649 :                 if (closure_pos >= 0)
    2640                 :         617 :                     set_skip_all(closure_pos);
    2641                 :             : 
    2642   [ +  +  +  + ]:         649 :                 if (destroy_pos >= 0 && closure_pos < 0) {
    2643                 :           1 :                     set_argument_auto<Arg::NotIntrospectable>(
    2644                 :           1 :                         common_args, DESTROY_NOTIFY_NO_USER_DATA);
    2645                 :           1 :                     return;
    2646                 :             :                 }
    2647                 :             : 
    2648                 :         648 :                 gjs_arg->m_scope = g_arg_info_get_scope(arg);
    2649                 :         648 :                 gjs_arg->set_callback_destroy_pos(destroy_pos);
    2650                 :         648 :                 gjs_arg->set_callback_closure_pos(closure_pos);
    2651                 :             :             }
    2652                 :             : 
    2653                 :         713 :             return;
    2654                 :             :         }
    2655         [ +  + ]:        6804 :     }
    2656                 :             : 
    2657   [ +  +  +  +  :       19582 :     if (type_tag == GI_TYPE_TAG_ARRAY &&
                   +  + ]
    2658                 :        1072 :         g_type_info_get_array_type(&type_info) == GI_ARRAY_TYPE_C) {
    2659                 :        1057 :         int length_pos = g_type_info_get_array_length(&type_info);
    2660                 :             : 
    2661         [ +  + ]:        1057 :         if (length_pos >= 0) {
    2662                 :         921 :             Argument* cached_length = argument(length_pos);
    2663   [ +  +  +  + ]:         924 :             bool skip_length = cached_length && !(cached_length->skip_in() &&
    2664         [ +  + ]:           3 :                                                   cached_length->skip_out());
    2665                 :             : 
    2666                 :         921 :             set_array_argument(callable, gi_index, &type_info, direction, arg,
    2667                 :             :                                flags, length_pos);
    2668                 :             : 
    2669   [ +  +  +  + ]:         921 :             if (length_pos < gi_index && skip_length) {
    2670                 :             :                 // we already collected length_pos, remove it
    2671                 :         170 :                 *inc_counter_out = false;
    2672                 :             :             }
    2673                 :             : 
    2674                 :         921 :             return;
    2675         [ +  + ]:         136 :         } else if (g_type_info_is_zero_terminated(&type_info)) {
    2676         [ +  + ]:         124 :             if (direction == GI_DIRECTION_IN) {
    2677                 :         117 :                 set_argument_auto<Arg::ZeroTerminatedArrayIn>(common_args);
    2678                 :         117 :                 return;
    2679         [ +  + ]:           7 :             } else if (direction == GI_DIRECTION_INOUT) {
    2680                 :           2 :                 set_argument_auto<Arg::ZeroTerminatedArrayInOut>(common_args);
    2681                 :           2 :                 return;
    2682                 :             :             }
    2683         [ +  + ]:          12 :         } else if (g_type_info_get_array_fixed_size(&type_info) >= 0) {
    2684         [ +  + ]:          11 :             if (direction == GI_DIRECTION_IN) {
    2685                 :           5 :                 set_argument_auto<Arg::FixedSizeArrayIn>(common_args);
    2686                 :           5 :                 return;
    2687         [ +  + ]:           6 :             } else if (direction == GI_DIRECTION_INOUT) {
    2688                 :           1 :                 set_argument_auto<Arg::FixedSizeArrayInOut>(common_args);
    2689                 :           1 :                 return;
    2690                 :             :             }
    2691                 :             :         }
    2692                 :             :     }
    2693                 :             : 
    2694         [ +  + ]:       17464 :     if (direction == GI_DIRECTION_IN)
    2695                 :       16786 :         build_normal_in_arg(gi_index, &type_info, arg, flags);
    2696         [ +  + ]:         678 :     else if (direction == GI_DIRECTION_INOUT)
    2697                 :          55 :         build_normal_inout_arg(gi_index, &type_info, arg, flags);
    2698                 :             :     else
    2699                 :         623 :         build_normal_out_arg(gi_index, &type_info, arg, flags);
    2700                 :             : 
    2701                 :       17464 :     return;
    2702                 :             : }
    2703                 :             : 
    2704                 :             : }  // namespace Gjs
        

Generated by: LCOV version 2.0-1