summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--girepository/gicallableinfo.c172
-rw-r--r--girepository/gifunctioninfo.c167
-rw-r--r--girepository/girepository-private.h11
-rw-r--r--girepository/givfuncinfo.c119
-rw-r--r--girepository/givfuncinfo.h11
5 files changed, 323 insertions, 157 deletions
diff --git a/girepository/gicallableinfo.c b/girepository/gicallableinfo.c
index 6b79e62c..1d439683 100644
--- a/girepository/gicallableinfo.c
+++ b/girepository/gicallableinfo.c
@@ -26,6 +26,7 @@
#include <girepository.h>
#include "girepository-private.h"
#include "gitypelib-internal.h"
+#include "girffi.h"
/* GICallableInfo functions */
@@ -335,3 +336,174 @@ g_callable_info_iterate_return_attributes (GICallableInfo *info,
return TRUE;
}
+
+gboolean
+_g_callable_info_invoke (GIFunctionInfo *info,
+ gpointer function,
+ const GIArgument *in_args,
+ int n_in_args,
+ const GIArgument *out_args,
+ int n_out_args,
+ GIArgument *return_value,
+ gboolean is_method,
+ gboolean throws,
+ GError **error)
+{
+ ffi_cif cif;
+ ffi_type *rtype;
+ ffi_type **atypes;
+ GITypeInfo *tinfo;
+ GIArgInfo *ainfo;
+ gint n_args, n_invoke_args, in_pos, out_pos, i;
+ gpointer *args;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
+ gpointer error_address = &local_error;
+
+ tinfo = g_callable_info_get_return_type ((GICallableInfo *)info);
+ rtype = g_type_info_get_ffi_type (tinfo);
+ g_base_info_unref ((GIBaseInfo *)tinfo);
+
+ in_pos = 0;
+ out_pos = 0;
+
+ n_args = g_callable_info_get_n_args ((GICallableInfo *)info);
+ if (is_method)
+ {
+ if (n_in_args == 0)
+ {
+ g_set_error (error,
+ G_INVOKE_ERROR,
+ G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+ "Too few \"in\" arguments (handling this)");
+ goto out;
+ }
+ n_invoke_args = n_args+1;
+ in_pos++;
+ }
+ else
+ n_invoke_args = n_args;
+
+ if (throws)
+ /* Add an argument for the GError */
+ n_invoke_args ++;
+
+ atypes = g_alloca (sizeof (ffi_type*) * n_invoke_args);
+ args = g_alloca (sizeof (gpointer) * n_invoke_args);
+
+ if (is_method)
+ {
+ atypes[0] = &ffi_type_pointer;
+ args[0] = (gpointer) &in_args[0];
+ }
+ for (i = 0; i < n_args; i++)
+ {
+ int offset = (is_method ? 1 : 0);
+ ainfo = g_callable_info_get_arg ((GICallableInfo *)info, i);
+ switch (g_arg_info_get_direction (ainfo))
+ {
+ case GI_DIRECTION_IN:
+ tinfo = g_arg_info_get_type (ainfo);
+ atypes[i+offset] = g_type_info_get_ffi_type (tinfo);
+ g_base_info_unref ((GIBaseInfo *)tinfo);
+
+ if (in_pos >= n_in_args)
+ {
+ g_set_error (error,
+ G_INVOKE_ERROR,
+ G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+ "Too few \"in\" arguments (handling in)");
+ goto out;
+ }
+
+ args[i+offset] = (gpointer)&in_args[in_pos];
+ in_pos++;
+
+ break;
+ case GI_DIRECTION_OUT:
+ atypes[i+offset] = &ffi_type_pointer;
+
+ if (out_pos >= n_out_args)
+ {
+ g_set_error (error,
+ G_INVOKE_ERROR,
+ G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+ "Too few \"out\" arguments (handling out)");
+ goto out;
+ }
+
+ args[i+offset] = (gpointer)&out_args[out_pos];
+ out_pos++;
+ break;
+ case GI_DIRECTION_INOUT:
+ atypes[i+offset] = &ffi_type_pointer;
+
+ if (in_pos >= n_in_args)
+ {
+ g_set_error (error,
+ G_INVOKE_ERROR,
+ G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+ "Too few \"in\" arguments (handling inout)");
+ goto out;
+ }
+
+ if (out_pos >= n_out_args)
+ {
+ g_set_error (error,
+ G_INVOKE_ERROR,
+ G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+ "Too few \"out\" arguments (handling inout)");
+ goto out;
+ }
+
+ args[i+offset] = (gpointer)&in_args[in_pos];
+ in_pos++;
+ out_pos++;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ g_base_info_unref ((GIBaseInfo *)ainfo);
+ }
+
+ if (throws)
+ {
+ args[n_invoke_args - 1] = &error_address;
+ atypes[n_invoke_args - 1] = &ffi_type_pointer;
+ }
+
+ if (in_pos < n_in_args)
+ {
+ g_set_error (error,
+ G_INVOKE_ERROR,
+ G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+ "Too many \"in\" arguments (at end)");
+ goto out;
+ }
+ if (out_pos < n_out_args)
+ {
+ g_set_error (error,
+ G_INVOKE_ERROR,
+ G_INVOKE_ERROR_ARGUMENT_MISMATCH,
+ "Too many \"out\" arguments (at end)");
+ goto out;
+ }
+
+ if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) != FFI_OK)
+ goto out;
+
+ g_return_val_if_fail (return_value, FALSE);
+ ffi_call (&cif, function, return_value, args);
+
+ if (local_error)
+ {
+ g_propagate_error (error, local_error);
+ success = FALSE;
+ }
+ else
+ {
+ success = TRUE;
+ }
+ out:
+ return success;
+}
diff --git a/girepository/gifunctioninfo.c b/girepository/gifunctioninfo.c
index 2f8920de..2544cc3f 100644
--- a/girepository/gifunctioninfo.c
+++ b/girepository/gifunctioninfo.c
@@ -26,7 +26,6 @@
#include <girepository.h>
#include "girepository-private.h"
#include "gitypelib-internal.h"
-#include "girffi.h"
/**
* SECTION:gifunctioninfo
@@ -249,20 +248,10 @@ g_function_info_invoke (GIFunctionInfo *info,
GIArgument *return_value,
GError **error)
{
- ffi_cif cif;
- ffi_type *rtype;
- ffi_type **atypes;
const gchar *symbol;
gpointer func;
- GITypeInfo *tinfo;
- GIArgInfo *ainfo;
gboolean is_method;
gboolean throws;
- gint n_args, n_invoke_args, in_pos, out_pos, i;
- gpointer *args;
- gboolean success = FALSE;
- GError *local_error = NULL;
- gpointer error_address = &local_error;
symbol = g_function_info_get_symbol (info);
@@ -281,150 +270,14 @@ g_function_info_invoke (GIFunctionInfo *info,
&& (g_function_info_get_flags (info) & GI_FUNCTION_IS_CONSTRUCTOR) == 0;
throws = g_function_info_get_flags (info) & GI_FUNCTION_THROWS;
- tinfo = g_callable_info_get_return_type ((GICallableInfo *)info);
- rtype = g_type_info_get_ffi_type (tinfo);
- g_base_info_unref ((GIBaseInfo *)tinfo);
-
- in_pos = 0;
- out_pos = 0;
-
- n_args = g_callable_info_get_n_args ((GICallableInfo *)info);
- if (is_method)
- {
- if (n_in_args == 0)
- {
- g_set_error (error,
- G_INVOKE_ERROR,
- G_INVOKE_ERROR_ARGUMENT_MISMATCH,
- "Too few \"in\" arguments (handling this)");
- goto out;
- }
- n_invoke_args = n_args+1;
- in_pos++;
- }
- else
- n_invoke_args = n_args;
-
- if (throws)
- /* Add an argument for the GError */
- n_invoke_args ++;
-
- atypes = g_alloca (sizeof (ffi_type*) * n_invoke_args);
- args = g_alloca (sizeof (gpointer) * n_invoke_args);
-
- if (is_method)
- {
- atypes[0] = &ffi_type_pointer;
- args[0] = (gpointer) &in_args[0];
- }
- for (i = 0; i < n_args; i++)
- {
- int offset = (is_method ? 1 : 0);
- ainfo = g_callable_info_get_arg ((GICallableInfo *)info, i);
- switch (g_arg_info_get_direction (ainfo))
- {
- case GI_DIRECTION_IN:
- tinfo = g_arg_info_get_type (ainfo);
- atypes[i+offset] = g_type_info_get_ffi_type (tinfo);
- g_base_info_unref ((GIBaseInfo *)tinfo);
-
- if (in_pos >= n_in_args)
- {
- g_set_error (error,
- G_INVOKE_ERROR,
- G_INVOKE_ERROR_ARGUMENT_MISMATCH,
- "Too few \"in\" arguments (handling in)");
- goto out;
- }
-
- args[i+offset] = (gpointer)&in_args[in_pos];
- in_pos++;
-
- break;
- case GI_DIRECTION_OUT:
- atypes[i+offset] = &ffi_type_pointer;
-
- if (out_pos >= n_out_args)
- {
- g_set_error (error,
- G_INVOKE_ERROR,
- G_INVOKE_ERROR_ARGUMENT_MISMATCH,
- "Too few \"out\" arguments (handling out)");
- goto out;
- }
-
- args[i+offset] = (gpointer)&out_args[out_pos];
- out_pos++;
- break;
- case GI_DIRECTION_INOUT:
- atypes[i+offset] = &ffi_type_pointer;
-
- if (in_pos >= n_in_args)
- {
- g_set_error (error,
- G_INVOKE_ERROR,
- G_INVOKE_ERROR_ARGUMENT_MISMATCH,
- "Too few \"in\" arguments (handling inout)");
- goto out;
- }
-
- if (out_pos >= n_out_args)
- {
- g_set_error (error,
- G_INVOKE_ERROR,
- G_INVOKE_ERROR_ARGUMENT_MISMATCH,
- "Too few \"out\" arguments (handling inout)");
- goto out;
- }
-
- args[i+offset] = (gpointer)&in_args[in_pos];
- in_pos++;
- out_pos++;
- break;
- default:
- g_assert_not_reached ();
- }
- g_base_info_unref ((GIBaseInfo *)ainfo);
- }
-
- if (throws)
- {
- args[n_invoke_args - 1] = &error_address;
- atypes[n_invoke_args - 1] = &ffi_type_pointer;
- }
-
- if (in_pos < n_in_args)
- {
- g_set_error (error,
- G_INVOKE_ERROR,
- G_INVOKE_ERROR_ARGUMENT_MISMATCH,
- "Too many \"in\" arguments (at end)");
- goto out;
- }
- if (out_pos < n_out_args)
- {
- g_set_error (error,
- G_INVOKE_ERROR,
- G_INVOKE_ERROR_ARGUMENT_MISMATCH,
- "Too many \"out\" arguments (at end)");
- goto out;
- }
-
- if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) != FFI_OK)
- goto out;
-
- g_return_val_if_fail (return_value, FALSE);
- ffi_call (&cif, func, return_value, args);
-
- if (local_error)
- {
- g_propagate_error (error, local_error);
- success = FALSE;
- }
- else
- {
- success = TRUE;
- }
- out:
- return success;
+ return _g_callable_info_invoke ((GICallableInfo*) info,
+ func,
+ in_args,
+ n_in_args,
+ out_args,
+ n_out_args,
+ return_value,
+ is_method,
+ throws,
+ error);
}
diff --git a/girepository/girepository-private.h b/girepository/girepository-private.h
index 897c52c4..52d65b2b 100644
--- a/girepository/girepository-private.h
+++ b/girepository/girepository-private.h
@@ -108,6 +108,17 @@ GIVFuncInfo * _g_base_info_find_vfunc (GIRealInfo *rinfo,
gint n_vfuncs,
const gchar *name);
+gboolean _g_callable_info_invoke (GICallableInfo *info,
+ gpointer function,
+ const GIArgument *in_args,
+ int n_in_args,
+ const GIArgument *out_args,
+ int n_out_args,
+ GIArgument *return_value,
+ gboolean is_method,
+ gboolean throws,
+ GError **error);
+
extern ffi_status ffi_prep_closure_loc (ffi_closure *,
ffi_cif *,
void (*fun)(ffi_cif *, void *, void **, void *),
diff --git a/girepository/givfuncinfo.c b/girepository/givfuncinfo.c
index 98ac9453..332655a0 100644
--- a/girepository/givfuncinfo.c
+++ b/girepository/givfuncinfo.c
@@ -196,3 +196,122 @@ g_vfunc_info_get_invoker (GIVFuncInfo *info)
g_assert_not_reached ();
}
+/**
+ * g_vfunc_info_get_address:
+ * @info: a #GIVFuncInfo
+ * @implementor_gtype: #GType implementing this virtual function
+ * @error: return location for a #GError
+ *
+ * This method will look up where inside the type struct of @implementor_gtype
+ * is the implementation for @info.
+ *
+ * Returns: address to a function or %NULL if an error happened
+ */
+gpointer
+g_vfunc_info_get_address (GIVFuncInfo *vfunc_info,
+ GType implementor_gtype,
+ GError **error)
+{
+ GIObjectInfo *object_info;
+ GIStructInfo *struct_info;
+ GIFieldInfo *field_info = NULL;
+ int length, i, offset;
+ gpointer implementor_vtable, func;
+
+ object_info = (GIObjectInfo *) g_base_info_get_container (vfunc_info);
+ struct_info = g_object_info_get_class_struct (object_info);
+
+ length = g_struct_info_get_n_fields (struct_info);
+ for (i = 0; i < length; i++)
+ {
+ field_info = g_struct_info_get_field (struct_info, i);
+
+ if (strcmp (g_base_info_get_name ( (GIBaseInfo*) field_info),
+ g_base_info_get_name ( (GIBaseInfo*) vfunc_info)) != 0) {
+ g_base_info_unref (field_info);
+ field_info = NULL;
+ continue;
+ }
+
+ break;
+ }
+
+ if (field_info == NULL)
+ {
+ g_set_error (error,
+ G_INVOKE_ERROR,
+ G_INVOKE_ERROR_SYMBOL_NOT_FOUND,
+ "Couldn't find struct field for this vfunc");
+ return NULL;
+ }
+
+ implementor_vtable = g_type_class_ref (implementor_gtype);
+ offset = g_field_info_get_offset (field_info);
+ func = *(gpointer*) G_STRUCT_MEMBER_P (implementor_vtable, offset);
+ g_type_class_unref (implementor_vtable);
+
+ if (func == NULL)
+ {
+ g_set_error (error,
+ G_INVOKE_ERROR,
+ G_INVOKE_ERROR_SYMBOL_NOT_FOUND,
+ "Class %s doesn't implement %s",
+ g_type_name (implementor_gtype),
+ g_base_info_get_name ( (GIBaseInfo*) vfunc_info));
+ return NULL;
+ }
+
+ return func;
+}
+
+/**
+ * g_vfunc_info_invoke: (skip)
+ * @info: a #GIVFuncInfo describing the virtual function to invoke
+ * @implementor: #GType of the type that implements this virtual function
+ * @in_args: an array of #GIArgument<!-- -->s, one for each in
+ * parameter of @info. If there are no in parameter, @in_args
+ * can be %NULL
+ * @n_in_args: the length of the @in_args array
+ * @out_args: an array of #GIArgument<!-- -->s, one for each out
+ * parameter of @info. If there are no out parameters, @out_args
+ * may be %NULL
+ * @n_out_args: the length of the @out_args array
+ * @return_value: return location for the return value of the
+ * function. If the function returns void, @return_value may be
+ * %NULL
+ * @error: return location for detailed error information, or %NULL
+ *
+ * Invokes the function described in @info with the given
+ * arguments. Note that inout parameters must appear in both
+ * argument lists.
+ *
+ * Returns: %TRUE if the function has been invoked, %FALSE if an
+ * error occurred.
+ */
+gboolean
+g_vfunc_info_invoke (GIVFuncInfo *info,
+ GType implementor,
+ const GIArgument *in_args,
+ int n_in_args,
+ const GIArgument *out_args,
+ int n_out_args,
+ GIArgument *return_value,
+ GError **error)
+{
+ gpointer func;
+
+ func = g_vfunc_info_get_address (info, implementor, error);
+ if (*error != NULL)
+ return FALSE;
+
+ return _g_callable_info_invoke ((GICallableInfo*) info,
+ func,
+ in_args,
+ n_in_args,
+ out_args,
+ n_out_args,
+ return_value,
+ TRUE,
+ FALSE,
+ error);
+}
diff --git a/girepository/givfuncinfo.h b/girepository/givfuncinfo.h
index 6629cad8..3c556cbe 100644
--- a/girepository/givfuncinfo.h
+++ b/girepository/givfuncinfo.h
@@ -37,6 +37,17 @@ GIVFuncInfoFlags g_vfunc_info_get_flags (GIVFuncInfo *info);
gint g_vfunc_info_get_offset (GIVFuncInfo *info);
GISignalInfo * g_vfunc_info_get_signal (GIVFuncInfo *info);
GIFunctionInfo * g_vfunc_info_get_invoker (GIVFuncInfo *info);
+gpointer g_vfunc_info_get_address (GIVFuncInfo *info,
+ GType implementor_gtype,
+ GError **error);
+gboolean g_vfunc_info_invoke (GIVFuncInfo *info,
+ GType implementor,
+ const GIArgument *in_args,
+ int n_in_args,
+ const GIArgument *out_args,
+ int n_out_args,
+ GIArgument *return_value,
+ GError **error);
G_END_DECLS