(root)/
glib-2.79.0/
girepository/
gicallableinfo.c
       1  /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
       2   * GObject introspection: Callable implementation
       3   *
       4   * Copyright (C) 2005 Matthias Clasen
       5   * Copyright (C) 2008,2009 Red Hat, Inc.
       6   *
       7   * SPDX-License-Identifier: LGPL-2.1-or-later
       8   *
       9   * This library is free software; you can redistribute it and/or
      10   * modify it under the terms of the GNU Lesser General Public
      11   * License as published by the Free Software Foundation; either
      12   * version 2 of the License, or (at your option) any later version.
      13   *
      14   * This library is distributed in the hope that it will be useful,
      15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17   * Lesser General Public License for more details.
      18   *
      19   * You should have received a copy of the GNU Lesser General Public
      20   * License along with this library; if not, write to the
      21   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      22   * Boston, MA 02111-1307, USA.
      23   */
      24  
      25  #include "config.h"
      26  
      27  #include <stdlib.h>
      28  
      29  #include <glib.h>
      30  
      31  #include <girepository/girepository.h>
      32  #include "gibaseinfo-private.h"
      33  #include "girepository-private.h"
      34  #include "gitypelib-internal.h"
      35  #include "girffi.h"
      36  #include "gicallableinfo.h"
      37  
      38  /* GICallableInfo functions */
      39  
      40  /**
      41   * GICallableInfo:
      42   *
      43   * `GICallableInfo` represents an entity which is callable.
      44   *
      45   * Examples of callable are:
      46   *
      47   *  - functions ([class@GIRepository.FunctionInfo])
      48   *  - virtual functions ([class@GIRepository.VFuncInfo])
      49   *  - callbacks ([class@GIRepository.CallbackInfo]).
      50   *
      51   * A callable has a list of arguments ([class@GIRepository.ArgInfo]), a return
      52   * type, direction and a flag which decides if it returns `NULL`.
      53   *
      54   * Since: 2.80
      55   */
      56  
      57  static guint32
      58  signature_offset (GICallableInfo *info)
      59  {
      60    GIRealInfo *rinfo = (GIRealInfo*)info;
      61    int sigoff = -1;
      62  
      63    switch (gi_base_info_get_info_type ((GIBaseInfo *) info))
      64      {
      65      case GI_INFO_TYPE_FUNCTION:
      66        sigoff = G_STRUCT_OFFSET (FunctionBlob, signature);
      67        break;
      68      case GI_INFO_TYPE_VFUNC:
      69        sigoff = G_STRUCT_OFFSET (VFuncBlob, signature);
      70        break;
      71      case GI_INFO_TYPE_CALLBACK:
      72        sigoff = G_STRUCT_OFFSET (CallbackBlob, signature);
      73        break;
      74      case GI_INFO_TYPE_SIGNAL:
      75        sigoff = G_STRUCT_OFFSET (SignalBlob, signature);
      76        break;
      77      default:
      78        g_assert_not_reached ();
      79      }
      80    if (sigoff >= 0)
      81      return *(guint32 *)&rinfo->typelib->data[rinfo->offset + sigoff];
      82    return 0;
      83  }
      84  
      85  /**
      86   * gi_callable_info_can_throw_gerror:
      87   * @info: a #GICallableInfo
      88   *
      89   * Whether the callable can throw a [type@GLib.Error]
      90   *
      91   * Returns: `TRUE` if this `GICallableInfo` can throw a [type@GLib.Error]
      92   * Since: 2.80
      93   */
      94  gboolean
      95  gi_callable_info_can_throw_gerror (GICallableInfo *info)
      96  {
      97    GIRealInfo *rinfo = (GIRealInfo*)info;
      98    SignatureBlob *signature;
      99  
     100    signature = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)];
     101    if (signature->throws)
     102      return TRUE;
     103  
     104    /* Functions and VFuncs store "throws" in their own blobs.
     105     * This info was additionally added to the SignatureBlob
     106     * to support the other callables. For Functions and VFuncs,
     107     * also check their legacy flag for compatibility.
     108     */
     109    switch (gi_base_info_get_info_type ((GIBaseInfo *) info)) {
     110    case GI_INFO_TYPE_FUNCTION:
     111      {
     112        FunctionBlob *blob;
     113        blob = (FunctionBlob *)&rinfo->typelib->data[rinfo->offset];
     114        return blob->throws;
     115      }
     116    case GI_INFO_TYPE_VFUNC:
     117      {
     118        VFuncBlob *blob;
     119        blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset];
     120        return blob->throws;
     121      }
     122    case GI_INFO_TYPE_CALLBACK:
     123    case GI_INFO_TYPE_SIGNAL:
     124      return FALSE;
     125    default:
     126      g_assert_not_reached ();
     127    }
     128  }
     129  
     130  /**
     131   * gi_callable_info_is_method:
     132   * @info: a #GICallableInfo
     133   *
     134   * Determines if the callable info is a method.
     135   *
     136   * For [class@GIRepository.VFuncInfo]s, [class@GIRepository.CallbackInfo]s, and
     137   * [class@GIRepository.SignalInfo]s, this is always true. Otherwise, this looks
     138   * at the `GI_FUNCTION_IS_METHOD` flag on the [class@GIRepository.FunctionInfo].
     139   *
     140   * Concretely, this function returns whether
     141   * [method@GIRepository.CallableInfo.get_n_args] matches the number of arguments
     142   * in the raw C method. For methods, there is one more C argument than is
     143   * exposed by introspection: the `self` or `this` object.
     144   *
     145   * Returns: `TRUE` if @info is a method, `FALSE` otherwise
     146   * Since: 2.80
     147   */
     148  gboolean
     149  gi_callable_info_is_method (GICallableInfo *info)
     150  {
     151    GIRealInfo *rinfo = (GIRealInfo*)info;
     152    switch (gi_base_info_get_info_type ((GIBaseInfo *) info)) {
     153    case GI_INFO_TYPE_FUNCTION:
     154      {
     155        FunctionBlob *blob;
     156        blob = (FunctionBlob *)&rinfo->typelib->data[rinfo->offset];
     157        return (!blob->constructor && !blob->is_static);
     158      }
     159    case GI_INFO_TYPE_VFUNC:
     160    case GI_INFO_TYPE_SIGNAL:
     161      return TRUE;
     162    case GI_INFO_TYPE_CALLBACK:
     163      return FALSE;
     164    default:
     165      g_assert_not_reached ();
     166    }
     167  }
     168  
     169  /**
     170   * gi_callable_info_get_return_type:
     171   * @info: a #GICallableInfo
     172   *
     173   * Obtain the return type of a callable item as a [class@GIRepository.TypeInfo].
     174   *
     175   * Returns: (transfer full): the [class@GIRepository.TypeInfo]. Free the struct
     176   *   by calling [method@GIRepository.BaseInfo.unref] when done.
     177   * Since: 2.80
     178   */
     179  GITypeInfo *
     180  gi_callable_info_get_return_type (GICallableInfo *info)
     181  {
     182    GIRealInfo *rinfo = (GIRealInfo *)info;
     183    guint32 offset;
     184  
     185    g_return_val_if_fail (info != NULL, NULL);
     186    g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), NULL);
     187  
     188    offset = signature_offset (info);
     189  
     190    return gi_type_info_new ((GIBaseInfo*)info, rinfo->typelib, offset);
     191  }
     192  
     193  /**
     194   * gi_callable_info_load_return_type:
     195   * @info: a #GICallableInfo
     196   * @type: (out caller-allocates): Initialized with return type of @info
     197   *
     198   * Obtain information about a return value of callable; this
     199   * function is a variant of [method@GIRepository.CallableInfo.get_return_type]
     200   * designed for stack allocation.
     201   *
     202   * The initialized @type must not be referenced after @info is deallocated.
     203   *
     204   * Since: 2.80
     205   */
     206  void
     207  gi_callable_info_load_return_type (GICallableInfo *info,
     208                                     GITypeInfo     *type)
     209  {
     210    GIRealInfo *rinfo = (GIRealInfo *)info;
     211    guint32 offset;
     212  
     213    g_return_if_fail (info != NULL);
     214    g_return_if_fail (GI_IS_CALLABLE_INFO (info));
     215  
     216    offset = signature_offset (info);
     217  
     218    gi_type_info_init ((GIBaseInfo *) type, (GIBaseInfo*)info, rinfo->typelib, offset);
     219  }
     220  
     221  /**
     222   * gi_callable_info_may_return_null:
     223   * @info: a #GICallableInfo
     224   *
     225   * See if a callable could return `NULL`.
     226   *
     227   * Returns: `TRUE` if callable could return `NULL`
     228   * Since: 2.80
     229   */
     230  gboolean
     231  gi_callable_info_may_return_null (GICallableInfo *info)
     232  {
     233    GIRealInfo *rinfo = (GIRealInfo *)info;
     234    SignatureBlob *blob;
     235  
     236    g_return_val_if_fail (info != NULL, FALSE);
     237    g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), FALSE);
     238  
     239    blob = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)];
     240  
     241    return blob->may_return_null;
     242  }
     243  
     244  /**
     245   * gi_callable_info_skip_return:
     246   * @info: a #GICallableInfo
     247   *
     248   * See if a callable’s return value is only useful in C.
     249   *
     250   * Returns: `TRUE` if return value is only useful in C.
     251   * Since: 2.80
     252   */
     253  gboolean
     254  gi_callable_info_skip_return (GICallableInfo *info)
     255  {
     256    GIRealInfo *rinfo = (GIRealInfo *)info;
     257    SignatureBlob *blob;
     258  
     259    g_return_val_if_fail (info != NULL, FALSE);
     260    g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), FALSE);
     261  
     262    blob = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)];
     263  
     264    return blob->skip_return;
     265  }
     266  
     267  /**
     268   * gi_callable_info_get_caller_owns:
     269   * @info: a #GICallableInfo
     270   *
     271   * See whether the caller owns the return value of this callable.
     272   *
     273   * [type@GIRepository.Transfer] contains a list of possible transfer values.
     274   *
     275   * Returns: the transfer mode for the return value of the callable
     276   * Since: 2.80
     277   */
     278  GITransfer
     279  gi_callable_info_get_caller_owns (GICallableInfo *info)
     280  {
     281    GIRealInfo *rinfo = (GIRealInfo*) info;
     282    SignatureBlob *blob;
     283  
     284    g_return_val_if_fail (info != NULL, -1);
     285    g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), -1);
     286  
     287    blob = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)];
     288  
     289    if (blob->caller_owns_return_value)
     290      return GI_TRANSFER_EVERYTHING;
     291    else if (blob->caller_owns_return_container)
     292      return GI_TRANSFER_CONTAINER;
     293    else
     294      return GI_TRANSFER_NOTHING;
     295  }
     296  
     297  /**
     298   * gi_callable_info_get_instance_ownership_transfer:
     299   * @info: a #GICallableInfo
     300   *
     301   * Obtains the ownership transfer for the instance argument.
     302   *
     303   * [type@GIRepository.Transfer] contains a list of possible transfer values.
     304   *
     305   * Returns: the transfer mode of the instance argument
     306   * Since: 2.80
     307   */
     308  GITransfer
     309  gi_callable_info_get_instance_ownership_transfer (GICallableInfo *info)
     310  {
     311    GIRealInfo *rinfo = (GIRealInfo*) info;
     312    SignatureBlob *blob;
     313  
     314    g_return_val_if_fail (info != NULL, -1);
     315    g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), -1);
     316  
     317    blob = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)];
     318  
     319    if (blob->instance_transfer_ownership)
     320      return GI_TRANSFER_EVERYTHING;
     321    else
     322      return GI_TRANSFER_NOTHING;
     323  }
     324  
     325  /**
     326   * gi_callable_info_get_n_args:
     327   * @info: a #GICallableInfo
     328   *
     329   * Obtain the number of arguments (both ‘in’ and ‘out’) for this callable.
     330   *
     331   * Returns: The number of arguments this callable expects.
     332   * Since: 2.80
     333   */
     334  guint
     335  gi_callable_info_get_n_args (GICallableInfo *info)
     336  {
     337    GIRealInfo *rinfo = (GIRealInfo *)info;
     338    gint offset;
     339    SignatureBlob *blob;
     340  
     341    g_return_val_if_fail (info != NULL, -1);
     342    g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), -1);
     343  
     344    offset = signature_offset (info);
     345    blob = (SignatureBlob *)&rinfo->typelib->data[offset];
     346  
     347    return blob->n_arguments;
     348  }
     349  
     350  /**
     351   * gi_callable_info_get_arg:
     352   * @info: a #GICallableInfo
     353   * @n: the argument index to fetch
     354   *
     355   * Obtain information about a particular argument of this callable.
     356   *
     357   * Returns: (transfer full): the [class@GIRepository.ArgInfo]. Free it with
     358   *   [method@GIRepository.BaseInfo.unref] when done.
     359   * Since: 2.80
     360   */
     361  GIArgInfo *
     362  gi_callable_info_get_arg (GICallableInfo *info,
     363                            guint           n)
     364  {
     365    GIRealInfo *rinfo = (GIRealInfo *)info;
     366    Header *header;
     367    gint offset;
     368  
     369    g_return_val_if_fail (info != NULL, NULL);
     370    g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), NULL);
     371  
     372    offset = signature_offset (info);
     373    header = (Header *)rinfo->typelib->data;
     374  
     375    return (GIArgInfo *) gi_info_new (GI_INFO_TYPE_ARG, (GIBaseInfo*)info, rinfo->typelib,
     376                                      offset + header->signature_blob_size + n * header->arg_blob_size);
     377  }
     378  
     379  /**
     380   * gi_callable_info_load_arg:
     381   * @info: a #GICallableInfo
     382   * @n: the argument index to fetch
     383   * @arg: (out caller-allocates): Initialize with argument number @n
     384   *
     385   * Obtain information about a particular argument of this callable; this
     386   * function is a variant of [method@GIRepository.CallableInfo.get_arg] designed
     387   * for stack allocation.
     388   *
     389   * The initialized @arg must not be referenced after @info is deallocated.
     390   *
     391   * Since: 2.80
     392   */
     393  void
     394  gi_callable_info_load_arg (GICallableInfo *info,
     395                             guint           n,
     396                             GIArgInfo      *arg)
     397  {
     398    GIRealInfo *rinfo = (GIRealInfo *)info;
     399    Header *header;
     400    gint offset;
     401  
     402    g_return_if_fail (info != NULL);
     403    g_return_if_fail (GI_IS_CALLABLE_INFO (info));
     404  
     405    offset = signature_offset (info);
     406    header = (Header *)rinfo->typelib->data;
     407  
     408    gi_info_init ((GIRealInfo*)arg, GI_INFO_TYPE_ARG, rinfo->repository, (GIBaseInfo*)info, rinfo->typelib,
     409                  offset + header->signature_blob_size + n * header->arg_blob_size);
     410  }
     411  
     412  /**
     413   * gi_callable_info_get_return_attribute:
     414   * @info: a #GICallableInfo
     415   * @name: a freeform string naming an attribute
     416   *
     417   * Retrieve an arbitrary attribute associated with the return value.
     418   *
     419   * Returns: (nullable): The value of the attribute, or `NULL` if no such
     420   *   attribute exists
     421   * Since: 2.80
     422   */
     423  const gchar *
     424  gi_callable_info_get_return_attribute (GICallableInfo *info,
     425                                         const gchar    *name)
     426  {
     427    GIAttributeIter iter = { 0, };
     428    const char *curname, *curvalue;
     429    while (gi_callable_info_iterate_return_attributes (info, &iter, &curname, &curvalue))
     430      {
     431        if (g_strcmp0 (name, curname) == 0)
     432          return (const gchar*) curvalue;
     433      }
     434  
     435    return NULL;
     436  }
     437  
     438  /**
     439   * gi_callable_info_iterate_return_attributes:
     440   * @info: a #GICallableInfo
     441   * @iterator: (inout): a [type@GIRepository.AttributeIter] structure, must be
     442   *   initialized; see below
     443   * @name: (out) (transfer none): Returned name, must not be freed
     444   * @value: (out) (transfer none): Returned name, must not be freed
     445   *
     446   * Iterate over all attributes associated with the return value.
     447   *
     448   * The iterator structure is typically stack allocated, and must have its
     449   * first member initialized to `NULL`.
     450   *
     451   * Both the @name and @value should be treated as constants
     452   * and must not be freed.
     453   *
     454   * See [method@GIRepository.BaseInfo.iterate_attributes] for an example of how
     455   * to use a similar API.
     456   *
     457   * Returns: `TRUE` if there are more attributes
     458   * Since: 2.80
     459   */
     460  gboolean
     461  gi_callable_info_iterate_return_attributes (GICallableInfo   *info,
     462                                              GIAttributeIter  *iterator,
     463                                              const char      **name,
     464                                              const char      **value)
     465  {
     466    GIRealInfo *rinfo = (GIRealInfo *)info;
     467    Header *header = (Header *)rinfo->typelib->data;
     468    AttributeBlob *next, *after;
     469    guint32 blob_offset;
     470  
     471    after = (AttributeBlob *) &rinfo->typelib->data[header->attributes +
     472                                                    header->n_attributes * header->attribute_blob_size];
     473  
     474    blob_offset = signature_offset (info);
     475  
     476    if (iterator->data != NULL)
     477      next = (AttributeBlob *) iterator->data;
     478    else
     479      next = _attribute_blob_find_first ((GIBaseInfo *) info, blob_offset);
     480  
     481    if (next == NULL || next->offset != blob_offset || next >= after)
     482      return FALSE;
     483  
     484    *name = gi_typelib_get_string (rinfo->typelib, next->name);
     485    *value = gi_typelib_get_string (rinfo->typelib, next->value);
     486    iterator->data = next + 1;
     487  
     488    return TRUE;
     489  }
     490  
     491  /**
     492   * gi_type_tag_extract_ffi_return_value:
     493   * @return_tag: [type@GIRepository.TypeTag] of the return value
     494   * @interface_type: [type@GIRepository.InfoType] of the underlying interface type
     495   * @ffi_value: pointer to [type@GIRepository.FFIReturnValue] union containing
     496   *   the return value from `ffi_call()`
     497   * @arg: (out caller-allocates): pointer to an allocated
     498   *   [class@GIRepository.Argument]
     499   *
     500   * Extract the correct bits from an `ffi_arg` return value into
     501   * [class@GIRepository.Argument].
     502   *
     503   * See: https://bugzilla.gnome.org/show_bug.cgi?id=665152
     504   *
     505   * Also see [`ffi_call()`](man:ffi_call(3)): the storage requirements for return
     506   * values are ‘special’.
     507   *
     508   * The @interface_type argument only applies if @return_tag is
     509   * `GI_TYPE_TAG_INTERFACE`. Otherwise it is ignored.
     510   *
     511   * Since: 2.80
     512   */
     513  void
     514  gi_type_tag_extract_ffi_return_value (GITypeTag         return_tag,
     515                                        GIInfoType        interface_type,
     516                                        GIFFIReturnValue *ffi_value,
     517                                        GIArgument       *arg)
     518  {
     519      switch (return_tag) {
     520      case GI_TYPE_TAG_INT8:
     521          arg->v_int8 = (gint8) ffi_value->v_long;
     522          break;
     523      case GI_TYPE_TAG_UINT8:
     524          arg->v_uint8 = (guint8) ffi_value->v_ulong;
     525          break;
     526      case GI_TYPE_TAG_INT16:
     527          arg->v_int16 = (gint16) ffi_value->v_long;
     528          break;
     529      case GI_TYPE_TAG_UINT16:
     530          arg->v_uint16 = (guint16) ffi_value->v_ulong;
     531          break;
     532      case GI_TYPE_TAG_INT32:
     533          arg->v_int32 = (gint32) ffi_value->v_long;
     534          break;
     535      case GI_TYPE_TAG_UINT32:
     536      case GI_TYPE_TAG_BOOLEAN:
     537      case GI_TYPE_TAG_UNICHAR:
     538          arg->v_uint32 = (guint32) ffi_value->v_ulong;
     539          break;
     540      case GI_TYPE_TAG_INT64:
     541          arg->v_int64 = (gint64) ffi_value->v_int64;
     542          break;
     543      case GI_TYPE_TAG_UINT64:
     544          arg->v_uint64 = (guint64) ffi_value->v_uint64;
     545          break;
     546      case GI_TYPE_TAG_FLOAT:
     547          arg->v_float = ffi_value->v_float;
     548          break;
     549      case GI_TYPE_TAG_DOUBLE:
     550          arg->v_double = ffi_value->v_double;
     551          break;
     552      case GI_TYPE_TAG_INTERFACE:
     553          switch(interface_type) {
     554          case GI_INFO_TYPE_ENUM:
     555          case GI_INFO_TYPE_FLAGS:
     556              arg->v_int32 = (gint32) ffi_value->v_long;
     557              break;
     558          default:
     559              arg->v_pointer = (gpointer) ffi_value->v_pointer;
     560              break;
     561          }
     562          break;
     563      default:
     564          arg->v_pointer = (gpointer) ffi_value->v_pointer;
     565          break;
     566      }
     567  }
     568  
     569  /**
     570   * gi_type_info_extract_ffi_return_value:
     571   * @return_info: [type@GIRepository.TypeInfo] describing the return type
     572   * @ffi_value: pointer to [type@GIRepository.FFIReturnValue] union containing
     573   *   the return value from `ffi_call()`
     574   * @arg: (out caller-allocates): pointer to an allocated
     575   *   [class@GIRepository.Argument]
     576   *
     577   * Extract the correct bits from an `ffi_arg` return value into
     578   * [class@GIRepository.Argument].
     579   *
     580   * See: https://bugzilla.gnome.org/show_bug.cgi?id=665152
     581   *
     582   * Also see [`ffi_call()`](man:ffi_call(3)): the storage requirements for return
     583   * values are ‘special’.
     584   *
     585   * Since: 2.80
     586   */
     587  void
     588  gi_type_info_extract_ffi_return_value (GITypeInfo       *return_info,
     589                                         GIFFIReturnValue *ffi_value,
     590                                         GIArgument       *arg)
     591  {
     592    GITypeTag return_tag = gi_type_info_get_tag (return_info);
     593    GIInfoType interface_type = GI_INFO_TYPE_INVALID;
     594  
     595    if (return_tag == GI_TYPE_TAG_INTERFACE)
     596      {
     597        GIBaseInfo *interface_info = gi_type_info_get_interface (return_info);
     598        interface_type = gi_base_info_get_info_type (interface_info);
     599        gi_base_info_unref (interface_info);
     600      }
     601  
     602    gi_type_tag_extract_ffi_return_value (return_tag, interface_type,
     603                                          ffi_value, arg);
     604  }
     605  
     606  /**
     607   * gi_callable_info_invoke:
     608   * @info: a #GICallableInfo
     609   * @function: function pointer to call
     610   * @in_args: (array length=n_in_args): array of ‘in’ arguments
     611   * @n_in_args: number of arguments in @in_args
     612   * @out_args: (array length=n_out_args): array of ‘out’ arguments allocated by
     613   *   the caller, to be populated with outputted values
     614   * @n_out_args: number of arguments in @out_args
     615   * @return_value: (out caller-allocates) (not optional) (nullable): return
     616   *   location for the return value from the callable; `NULL` may be returned if
     617   *   the callable returns that
     618   * @is_method: `TRUE` if @info is a method
     619   * @throws: `TRUE` if @info may throw a [type@GLib.Error]
     620   * @error: return location for a [type@GLib.Error], or `NULL`
     621   *
     622   * Invoke the given `GICallableInfo` by calling the given @function pointer.
     623   *
     624   * The set of arguments passed to @function will be constructed according to the
     625   * introspected type of the `GICallableInfo`, using @in_args, @out_args,
     626   * @is_method, @throws and @error.
     627   *
     628   * Returns: `TRUE` if the callable was executed successfully and didn’t throw
     629   *   a [type@GLib.Error]; `FALSE` if @error is set
     630   * Since: 2.80
     631   */
     632  gboolean
     633  gi_callable_info_invoke (GICallableInfo    *info,
     634                           gpointer           function,
     635                           const GIArgument  *in_args,
     636                           gsize              n_in_args,
     637                           const GIArgument  *out_args,
     638                           gsize              n_out_args,
     639                           GIArgument        *return_value,
     640                           gboolean           is_method,
     641                           gboolean           throws,
     642                           GError           **error)
     643  {
     644    ffi_cif cif;
     645    ffi_type *rtype;
     646    ffi_type **atypes;
     647    GITypeInfo *tinfo;
     648    GITypeInfo *rinfo;
     649    GITypeTag rtag;
     650    GIArgInfo *ainfo;
     651    gsize n_args, n_invoke_args, in_pos, out_pos, i;
     652    gpointer *args;
     653    gboolean success = FALSE;
     654    GError *local_error = NULL;
     655    gpointer error_address = &local_error;
     656    GIFFIReturnValue ffi_return_value;
     657    gpointer return_value_p; /* Will point inside the union return_value */
     658  
     659    rinfo = gi_callable_info_get_return_type ((GICallableInfo *)info);
     660    rtype = gi_type_info_get_ffi_type (rinfo);
     661    rtag = gi_type_info_get_tag(rinfo);
     662  
     663    in_pos = 0;
     664    out_pos = 0;
     665  
     666    n_args = gi_callable_info_get_n_args ((GICallableInfo *)info);
     667    if (is_method)
     668      {
     669        if (n_in_args == 0)
     670          {
     671            g_set_error (error,
     672                         GI_INVOKE_ERROR,
     673                         GI_INVOKE_ERROR_ARGUMENT_MISMATCH,
     674                         "Too few \"in\" arguments (handling this)");
     675            goto out;
     676          }
     677        n_invoke_args = n_args+1;
     678        in_pos++;
     679      }
     680    else
     681      n_invoke_args = n_args;
     682  
     683    if (throws)
     684      /* Add an argument for the GError */
     685      n_invoke_args ++;
     686  
     687    atypes = g_alloca (sizeof (ffi_type*) * n_invoke_args);
     688    args = g_alloca (sizeof (gpointer) * n_invoke_args);
     689  
     690    if (is_method)
     691      {
     692        atypes[0] = &ffi_type_pointer;
     693        args[0] = (gpointer) &in_args[0];
     694      }
     695    for (i = 0; i < n_args; i++)
     696      {
     697        int offset = (is_method ? 1 : 0);
     698        ainfo = gi_callable_info_get_arg ((GICallableInfo *)info, i);
     699        switch (gi_arg_info_get_direction (ainfo))
     700          {
     701          case GI_DIRECTION_IN:
     702            tinfo = gi_arg_info_get_type_info (ainfo);
     703            atypes[i+offset] = gi_type_info_get_ffi_type (tinfo);
     704            gi_base_info_unref ((GIBaseInfo *)ainfo);
     705            gi_base_info_unref ((GIBaseInfo *)tinfo);
     706  
     707            if (in_pos >= n_in_args)
     708              {
     709                g_set_error (error,
     710                             GI_INVOKE_ERROR,
     711                             GI_INVOKE_ERROR_ARGUMENT_MISMATCH,
     712                             "Too few \"in\" arguments (handling in)");
     713                goto out;
     714              }
     715  
     716            args[i+offset] = (gpointer)&in_args[in_pos];
     717            in_pos++;
     718  
     719            break;
     720          case GI_DIRECTION_OUT:
     721            atypes[i+offset] = &ffi_type_pointer;
     722            gi_base_info_unref ((GIBaseInfo *)ainfo);
     723  
     724            if (out_pos >= n_out_args)
     725              {
     726                g_set_error (error,
     727                             GI_INVOKE_ERROR,
     728                             GI_INVOKE_ERROR_ARGUMENT_MISMATCH,
     729                             "Too few \"out\" arguments (handling out)");
     730                goto out;
     731              }
     732  
     733            args[i+offset] = (gpointer)&out_args[out_pos];
     734            out_pos++;
     735            break;
     736          case GI_DIRECTION_INOUT:
     737            atypes[i+offset] = &ffi_type_pointer;
     738            gi_base_info_unref ((GIBaseInfo *)ainfo);
     739  
     740            if (in_pos >= n_in_args)
     741              {
     742                g_set_error (error,
     743                             GI_INVOKE_ERROR,
     744                             GI_INVOKE_ERROR_ARGUMENT_MISMATCH,
     745                             "Too few \"in\" arguments (handling inout)");
     746                goto out;
     747              }
     748  
     749            if (out_pos >= n_out_args)
     750              {
     751                g_set_error (error,
     752                             GI_INVOKE_ERROR,
     753                             GI_INVOKE_ERROR_ARGUMENT_MISMATCH,
     754                             "Too few \"out\" arguments (handling inout)");
     755                goto out;
     756              }
     757  
     758            args[i+offset] = (gpointer)&in_args[in_pos];
     759            in_pos++;
     760            out_pos++;
     761            break;
     762          default:
     763            gi_base_info_unref ((GIBaseInfo *)ainfo);
     764            g_assert_not_reached ();
     765          }
     766      }
     767  
     768    if (throws)
     769      {
     770        args[n_invoke_args - 1] = &error_address;
     771        atypes[n_invoke_args - 1] = &ffi_type_pointer;
     772      }
     773  
     774    if (in_pos < n_in_args)
     775      {
     776        g_set_error (error,
     777                     GI_INVOKE_ERROR,
     778                     GI_INVOKE_ERROR_ARGUMENT_MISMATCH,
     779                     "Too many \"in\" arguments (at end)");
     780        goto out;
     781      }
     782    if (out_pos < n_out_args)
     783      {
     784        g_set_error (error,
     785                     GI_INVOKE_ERROR,
     786                     GI_INVOKE_ERROR_ARGUMENT_MISMATCH,
     787                     "Too many \"out\" arguments (at end)");
     788        goto out;
     789      }
     790  
     791    if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) != FFI_OK)
     792      goto out;
     793  
     794    g_return_val_if_fail (return_value, FALSE);
     795    /* See comment for GIFFIReturnValue above */
     796    switch (rtag)
     797      {
     798      case GI_TYPE_TAG_FLOAT:
     799        return_value_p = &ffi_return_value.v_float;
     800        break;
     801      case GI_TYPE_TAG_DOUBLE:
     802        return_value_p = &ffi_return_value.v_double;
     803        break;
     804      case GI_TYPE_TAG_INT64:
     805      case GI_TYPE_TAG_UINT64:
     806        return_value_p = &ffi_return_value.v_uint64;
     807        break;
     808      default:
     809        return_value_p = &ffi_return_value.v_long;
     810      }
     811    ffi_call (&cif, function, return_value_p, args);
     812  
     813    if (local_error)
     814      {
     815        g_propagate_error (error, local_error);
     816        success = FALSE;
     817      }
     818    else
     819      {
     820        gi_type_info_extract_ffi_return_value (rinfo, &ffi_return_value, return_value);
     821        success = TRUE;
     822      }
     823   out:
     824    gi_base_info_unref ((GIBaseInfo *)rinfo);
     825    return success;
     826  }
     827  
     828  void
     829  gi_callable_info_class_init (gpointer g_class,
     830                               gpointer class_data)
     831  {
     832    GIBaseInfoClass *info_class = g_class;
     833  
     834    info_class->info_type = GI_INFO_TYPE_CALLABLE;
     835  }