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 }