(root)/
glib-2.79.0/
girepository/
girffi.c
       1  /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
       2   * GObject introspection: Helper functions for ffi integration
       3   *
       4   * Copyright (C) 2008 Red Hat, Inc
       5   * Copyright (C) 2005 Matthias Clasen
       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 <sys/types.h>
      28  
      29  #include <errno.h>
      30  #include <string.h>
      31  #ifdef HAVE_UNISTD_H
      32  #include <unistd.h>
      33  #endif
      34  #include "girffi.h"
      35  #include "girepository.h"
      36  #include "girepository-private.h"
      37  
      38  static ffi_type *
      39  gi_type_tag_get_ffi_type_internal (GITypeTag   tag,
      40                                     gboolean    is_pointer,
      41  				   gboolean    is_enum)
      42  {
      43    switch (tag)
      44      {
      45      case GI_TYPE_TAG_BOOLEAN:
      46        return &ffi_type_uint;
      47      case GI_TYPE_TAG_INT8:
      48        return &ffi_type_sint8;
      49      case GI_TYPE_TAG_UINT8:
      50        return &ffi_type_uint8;
      51      case GI_TYPE_TAG_INT16:
      52        return &ffi_type_sint16;
      53      case GI_TYPE_TAG_UINT16:
      54        return &ffi_type_uint16;
      55      case GI_TYPE_TAG_INT32:
      56        return &ffi_type_sint32;
      57      case GI_TYPE_TAG_UINT32:
      58      case GI_TYPE_TAG_UNICHAR:
      59        return &ffi_type_uint32;
      60      case GI_TYPE_TAG_INT64:
      61        return &ffi_type_sint64;
      62      case GI_TYPE_TAG_UINT64:
      63        return &ffi_type_uint64;
      64      case GI_TYPE_TAG_GTYPE:
      65  #if GLIB_SIZEOF_SIZE_T == 4
      66        return &ffi_type_uint32;
      67  #elif GLIB_SIZEOF_SIZE_T == 8
      68        return &ffi_type_uint64;
      69  #else
      70  #  error "Unexpected size for size_t: not 4 or 8"
      71  #endif
      72      case GI_TYPE_TAG_FLOAT:
      73        return &ffi_type_float;
      74      case GI_TYPE_TAG_DOUBLE:
      75        return &ffi_type_double;
      76      case GI_TYPE_TAG_UTF8:
      77      case GI_TYPE_TAG_FILENAME:
      78      case GI_TYPE_TAG_ARRAY:
      79      case GI_TYPE_TAG_GLIST:
      80      case GI_TYPE_TAG_GSLIST:
      81      case GI_TYPE_TAG_GHASH:
      82      case GI_TYPE_TAG_ERROR:
      83        return &ffi_type_pointer;
      84      case GI_TYPE_TAG_INTERFACE:
      85        {
      86  	/* We need to handle enums specially:
      87  	 * https://bugzilla.gnome.org/show_bug.cgi?id=665150
      88  	 */
      89          if (!is_enum)
      90            return &ffi_type_pointer;
      91  	else
      92  	  return &ffi_type_sint32;
      93        }
      94      case GI_TYPE_TAG_VOID:
      95        if (is_pointer)
      96          return &ffi_type_pointer;
      97        else
      98          return &ffi_type_void;
      99      default:
     100        break;
     101      }
     102  
     103    g_assert_not_reached ();
     104  
     105    return NULL;
     106  }
     107  
     108  /**
     109   * gi_type_tag_get_ffi_type:
     110   * @type_tag: a #GITypeTag
     111   * @is_pointer: whether this is a pointer type
     112   *
     113   * Get the `ffi_type` corresponding to @type_tag.
     114   *
     115   * Returns: (transfer none): an `ffi_type` corresponding to the platform default
     116   *   C ABI for @tag and @is_pointer.
     117   * Since: 2.80
     118   */
     119  ffi_type *
     120  gi_type_tag_get_ffi_type (GITypeTag   type_tag,
     121  			  gboolean    is_pointer)
     122  {
     123    return gi_type_tag_get_ffi_type_internal (type_tag, is_pointer, FALSE);
     124  }
     125  
     126  /**
     127   * gi_type_info_get_ffi_type:
     128   * @info: a #GITypeInfo
     129   *
     130   * Get the `ffi_type` corresponding to @info.
     131   *
     132   * Returns: (transfer none): a `ffi_type` corresponding to the platform default
     133   *   C ABI for @info.
     134   * Since: 2.80
     135   */
     136  ffi_type *
     137  gi_type_info_get_ffi_type (GITypeInfo *info)
     138  {
     139    gboolean is_enum = FALSE;
     140    GIBaseInfo *iinfo;
     141  
     142    if (gi_type_info_get_tag (info) == GI_TYPE_TAG_INTERFACE)
     143      {
     144        iinfo = gi_type_info_get_interface (info);
     145        switch (gi_base_info_get_info_type (iinfo))
     146          {
     147          case GI_INFO_TYPE_ENUM:
     148          case GI_INFO_TYPE_FLAGS:
     149            is_enum = TRUE;
     150            break;
     151          default:
     152            break;
     153          }
     154        gi_base_info_unref (iinfo);
     155      }
     156  
     157    return gi_type_tag_get_ffi_type_internal (gi_type_info_get_tag (info), gi_type_info_is_pointer (info), is_enum);
     158  }
     159  
     160  /**
     161   * gi_callable_info_get_ffi_arg_types:
     162   * @callable_info: a callable info from a typelib
     163   * @n_args_p: (out) (optional): the number of arguments returned
     164   *
     165   * Get the `ffi_type`s for the arguments of @callable_info.
     166   *
     167   * Returns: (transfer container) (array length=n_args_p): an array of
     168   *   `ffi_type*`. The array itself should be freed using [func@GLib.free] after
     169   *   use.
     170   * Since: 2.80
     171   */
     172  static ffi_type **
     173  gi_callable_info_get_ffi_arg_types (GICallableInfo *callable_info,
     174                                      int            *n_args_p)
     175  {
     176      ffi_type **arg_types;
     177      gboolean is_method, throws;
     178      gint n_args, n_invoke_args, i, offset;
     179  
     180      g_return_val_if_fail (callable_info != NULL, NULL);
     181  
     182      n_args = gi_callable_info_get_n_args (callable_info);
     183      is_method = gi_callable_info_is_method (callable_info);
     184      throws = gi_callable_info_can_throw_gerror (callable_info);
     185      offset = is_method ? 1 : 0;
     186  
     187      n_invoke_args = n_args;
     188  
     189      if (is_method)
     190        n_invoke_args++;
     191      if (throws)
     192        n_invoke_args++;
     193  
     194      if (n_args_p)
     195        *n_args_p = n_invoke_args;
     196  
     197      arg_types = (ffi_type **) g_new0 (ffi_type *, n_invoke_args + 1);
     198  
     199      if (is_method)
     200        arg_types[0] = &ffi_type_pointer;
     201      if (throws)
     202        arg_types[n_invoke_args - 1] = &ffi_type_pointer;
     203  
     204      for (i = 0; i < n_args; ++i)
     205        {
     206          GIArgInfo arg_info;
     207          GITypeInfo arg_type;
     208  
     209          gi_callable_info_load_arg (callable_info, i, &arg_info);
     210          gi_arg_info_load_type (&arg_info, &arg_type);
     211          switch (gi_arg_info_get_direction (&arg_info))
     212            {
     213              case GI_DIRECTION_IN:
     214                arg_types[i + offset] = gi_type_info_get_ffi_type (&arg_type);
     215                break;
     216              case GI_DIRECTION_OUT:
     217              case GI_DIRECTION_INOUT:
     218                arg_types[i + offset] = &ffi_type_pointer;
     219                break;
     220              default:
     221                g_assert_not_reached ();
     222            }
     223        }
     224  
     225      arg_types[n_invoke_args] = NULL;
     226  
     227      return arg_types;
     228  }
     229  
     230  /**
     231   * gi_callable_info_get_ffi_return_type:
     232   * @callable_info: a callable info from a typelib
     233   *
     234   * Fetches the `ffi_type` for a corresponding return value of
     235   * a [class@GIRepository.CallableInfo].
     236   *
     237   * Returns: (transfer none): the `ffi_type` for the return value
     238   * Since: 2.80
     239   */
     240  static ffi_type *
     241  gi_callable_info_get_ffi_return_type (GICallableInfo *callable_info)
     242  {
     243    GITypeInfo *return_type;
     244    ffi_type *return_ffi_type;
     245  
     246    g_return_val_if_fail (callable_info != NULL, NULL);
     247  
     248    return_type = gi_callable_info_get_return_type (callable_info);
     249    return_ffi_type = gi_type_info_get_ffi_type (return_type);
     250    gi_base_info_unref((GIBaseInfo*)return_type);
     251  
     252    return return_ffi_type;
     253  }
     254  
     255  /**
     256   * gi_function_info_prep_invoker:
     257   * @info: A #GIFunctionInfo
     258   * @invoker: (out caller-allocates): Output invoker structure
     259   * @error: A #GError
     260   *
     261   * Initialize the caller-allocated @invoker structure with a cache
     262   * of information needed to invoke the C function corresponding to
     263   * @info with the platform’s default ABI.
     264   *
     265   * A primary intent of this function is that a dynamic structure allocated
     266   * by a language binding could contain a [type@GIRepository.FunctionInvoker]
     267   * structure inside the binding’s function mapping.
     268   *
     269   * Returns: `TRUE` on success, `FALSE` otherwise with @error set.
     270   * Since: 2.80
     271   */
     272  gboolean
     273  gi_function_info_prep_invoker (GIFunctionInfo     *info,
     274                                 GIFunctionInvoker  *invoker,
     275                                 GError            **error)
     276  {
     277    const char *symbol;
     278    gpointer addr;
     279  
     280    g_return_val_if_fail (info != NULL, FALSE);
     281    g_return_val_if_fail (invoker != NULL, FALSE);
     282  
     283    symbol = gi_function_info_get_symbol ((GIFunctionInfo*) info);
     284  
     285    if (!gi_typelib_symbol (gi_base_info_get_typelib ((GIBaseInfo *) info),
     286                            symbol, &addr))
     287      {
     288        g_set_error (error,
     289                     GI_INVOKE_ERROR,
     290                     GI_INVOKE_ERROR_SYMBOL_NOT_FOUND,
     291                     "Could not locate %s: %s", symbol, g_module_error ());
     292  
     293        return FALSE;
     294      }
     295  
     296    return gi_function_invoker_new_for_address (addr, (GICallableInfo *) info, invoker, error);
     297  }
     298  
     299  /**
     300   * gi_function_invoker_new_for_address:
     301   * @addr: The address
     302   * @info: A #GICallableInfo
     303   * @invoker: (out caller-allocates): Output invoker structure
     304   * @error: A #GError
     305   *
     306   * Initialize the caller-allocated @invoker structure with a cache
     307   * of information needed to invoke the C function corresponding to
     308   * @info with the platform’s default ABI.
     309   *
     310   * A primary intent of this function is that a dynamic structure allocated
     311   * by a language binding could contain a [type@GIRepository.FunctionInvoker]
     312   * structure inside the binding’s function mapping.
     313   *
     314   * Returns: `TRUE` on success, `FALSE` otherwise with @error set.
     315   * Since: 2.80
     316   */
     317  gboolean
     318  gi_function_invoker_new_for_address (gpointer            addr,
     319                                       GICallableInfo     *info,
     320                                       GIFunctionInvoker  *invoker,
     321                                       GError            **error)
     322  {
     323    ffi_type **atypes;
     324    gint n_args;
     325  
     326    g_return_val_if_fail (info != NULL, FALSE);
     327    g_return_val_if_fail (invoker != NULL, FALSE);
     328  
     329    invoker->native_address = addr;
     330  
     331    atypes = gi_callable_info_get_ffi_arg_types (info, &n_args);
     332  
     333    return ffi_prep_cif (&(invoker->cif), FFI_DEFAULT_ABI, n_args,
     334                         gi_callable_info_get_ffi_return_type (info),
     335                         atypes) == FFI_OK;
     336  }
     337  
     338  /**
     339   * gi_function_invoker_destroy:
     340   * @invoker: (transfer none): A #GIFunctionInvoker
     341   *
     342   * Release all resources allocated for the internals of @invoker.
     343   *
     344   * Callers are responsible for freeing any resources allocated for the structure
     345   * itself however.
     346   *
     347   * Since: 2.80
     348   */
     349  void
     350  gi_function_invoker_destroy (GIFunctionInvoker *invoker)
     351  {
     352    g_free (invoker->cif.arg_types);
     353  }
     354  
     355  typedef struct {
     356    ffi_closure ffi_closure;
     357    gpointer writable_self;
     358    gpointer native_address;
     359  } GIClosureWrapper;
     360  
     361  /**
     362   * gi_callable_info_create_closure:
     363   * @callable_info: a callable info from a typelib
     364   * @cif: a `ffi_cif` structure
     365   * @callback: the ffi callback
     366   * @user_data: data to be passed into the callback
     367   *
     368   * Prepares a callback for ffi invocation.
     369   *
     370   * Returns: (transfer full) (nullable): the `ffi_closure`, or `NULL` on error.
     371   *   The return value should be freed by calling
     372   *   [method@GIRepository.CallableInfo.destroy_closure].
     373   * Since: 2.80
     374   */
     375  ffi_closure *
     376  gi_callable_info_create_closure (GICallableInfo       *callable_info,
     377                                   ffi_cif              *cif,
     378                                   GIFFIClosureCallback  callback,
     379                                   gpointer              user_data)
     380  {
     381    gpointer exec_ptr;
     382    int n_args;
     383    ffi_type **atypes;
     384    GIClosureWrapper *closure;
     385    ffi_status status;
     386  
     387    g_return_val_if_fail (callable_info != NULL, FALSE);
     388    g_return_val_if_fail (cif != NULL, FALSE);
     389    g_return_val_if_fail (callback != NULL, FALSE);
     390  
     391    closure = ffi_closure_alloc (sizeof (GIClosureWrapper), &exec_ptr);
     392    if (!closure)
     393      {
     394        g_warning ("could not allocate closure\n");
     395        return NULL;
     396      }
     397    closure->writable_self = closure;
     398    closure->native_address = exec_ptr;
     399  
     400  
     401    atypes = gi_callable_info_get_ffi_arg_types (callable_info, &n_args);
     402    status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, n_args,
     403                           gi_callable_info_get_ffi_return_type (callable_info),
     404                           atypes);
     405    if (status != FFI_OK)
     406      {
     407        g_warning ("ffi_prep_cif failed: %d\n", status);
     408        ffi_closure_free (closure);
     409        return NULL;
     410      }
     411  
     412    status = ffi_prep_closure_loc (&closure->ffi_closure, cif, callback, user_data, exec_ptr);
     413    if (status != FFI_OK)
     414      {
     415        g_warning ("ffi_prep_closure failed: %d\n", status);
     416        ffi_closure_free (closure);
     417        return NULL;
     418      }
     419  
     420    return &closure->ffi_closure;
     421  }
     422  
     423  /**
     424   * gi_callable_info_get_closure_native_address:
     425   * @callable_info: a callable info from a typelib
     426   * @closure: ffi closure
     427   *
     428   * Gets callable code from `ffi_closure` prepared by
     429   * [method@GIRepository.CallableInfo.create_closure].
     430   *
     431   * Returns: (transfer none): native address
     432   * Since: 2.80
     433   */
     434  gpointer *
     435  gi_callable_info_get_closure_native_address (GICallableInfo *callable_info,
     436                                               ffi_closure    *closure)
     437  {
     438    GIClosureWrapper *wrapper = (GIClosureWrapper *)closure;
     439    return wrapper->native_address;
     440  }
     441  
     442  /**
     443   * gi_callable_info_destroy_closure:
     444   * @callable_info: a callable info from a typelib
     445   * @closure: (transfer full): ffi closure
     446   *
     447   * Frees a `ffi_closure` returned from
     448   * [method@GIRepository.CallableInfo.create_closure].
     449   *
     450   * Since: 2.80
     451   */
     452  void
     453  gi_callable_info_destroy_closure (GICallableInfo *callable_info,
     454                                    ffi_closure    *closure)
     455  {
     456    GIClosureWrapper *wrapper = (GIClosureWrapper *)closure;
     457  
     458    g_free (wrapper->ffi_closure.cif->arg_types);
     459    ffi_closure_free (wrapper->writable_self);
     460  }