1 /* GObject introspection: Helper functions for ffi integration
3 * Copyright (C) 2008 Red Hat, Inc
4 * Copyright (C) 2005 Matthias Clasen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 #include <sys/types.h>
30 #include "girepository.h"
33 g_ir_ffi_get_ffi_type (GITypeTag tag)
37 case GI_TYPE_TAG_BOOLEAN:
38 return &ffi_type_uint;
39 case GI_TYPE_TAG_INT8:
40 return &ffi_type_sint8;
41 case GI_TYPE_TAG_UINT8:
42 return &ffi_type_uint8;
43 case GI_TYPE_TAG_INT16:
44 return &ffi_type_sint16;
45 case GI_TYPE_TAG_UINT16:
46 return &ffi_type_uint16;
47 case GI_TYPE_TAG_INT32:
48 return &ffi_type_sint32;
49 case GI_TYPE_TAG_UINT32:
50 return &ffi_type_uint32;
51 case GI_TYPE_TAG_INT64:
52 return &ffi_type_sint64;
53 case GI_TYPE_TAG_UINT64:
54 return &ffi_type_uint64;
55 case GI_TYPE_TAG_SHORT:
56 return &ffi_type_sshort;
57 case GI_TYPE_TAG_USHORT:
58 return &ffi_type_ushort;
60 return &ffi_type_sint;
61 case GI_TYPE_TAG_UINT:
62 return &ffi_type_uint;
63 case GI_TYPE_TAG_SSIZE:
64 #if GLIB_SIZEOF_SIZE_T == 4
65 return &ffi_type_sint32;
66 #elif GLIB_SIZEOF_SIZE_T == 8
67 return &ffi_type_sint64;
69 # error "Unexpected size for size_t: not 4 or 8"
71 case GI_TYPE_TAG_LONG:
72 return &ffi_type_slong;
73 case GI_TYPE_TAG_SIZE:
74 case GI_TYPE_TAG_GTYPE:
75 #if GLIB_SIZEOF_SIZE_T == 4
76 return &ffi_type_uint32;
77 #elif GLIB_SIZEOF_SIZE_T == 8
78 return &ffi_type_uint64;
80 # error "Unexpected size for size_t: not 4 or 8"
82 case GI_TYPE_TAG_TIME_T:
83 #if SIZEOF_TIME_T == 4
84 return &ffi_type_sint32;
85 #elif SIZEOF_TIME_T == 8
86 return &ffi_type_sint64;
88 # error "Unexpected size for time_t: not 4 or 8"
90 case GI_TYPE_TAG_ULONG:
91 return &ffi_type_ulong;
92 case GI_TYPE_TAG_FLOAT:
93 return &ffi_type_float;
94 case GI_TYPE_TAG_DOUBLE:
95 return &ffi_type_double;
96 case GI_TYPE_TAG_UTF8:
97 case GI_TYPE_TAG_FILENAME:
98 case GI_TYPE_TAG_ARRAY:
99 case GI_TYPE_TAG_INTERFACE:
100 case GI_TYPE_TAG_GLIST:
101 case GI_TYPE_TAG_GSLIST:
102 case GI_TYPE_TAG_GHASH:
103 case GI_TYPE_TAG_ERROR:
104 case GI_TYPE_TAG_VOID:
105 return &ffi_type_pointer;
108 g_assert_not_reached ();
114 g_ir_ffi_convert_arguments(GICallableInfo *callable_info, void **args)
118 GITypeInfo *arg_type;
122 num_args = g_callable_info_get_n_args (callable_info);
123 g_args = g_new0 (GArgument, num_args);
125 for (i = 0; i < num_args; i++)
127 arg_info = g_callable_info_get_arg (callable_info, i);
128 arg_type = g_arg_info_get_type (arg_info);
129 tag = g_type_info_get_tag (arg_type);
133 case GI_TYPE_TAG_BOOLEAN:
134 g_args[i].v_boolean = *(gboolean *) args[i];
136 case GI_TYPE_TAG_INT8:
137 g_args[i].v_int8 = *(gint8 *) args[i];
139 case GI_TYPE_TAG_UINT8:
140 g_args[i].v_uint8 = *(guint8 *) args[i];
142 case GI_TYPE_TAG_INT16:
143 g_args[i].v_int16 = *(gint16 *) args[i];
145 case GI_TYPE_TAG_UINT16:
146 g_args[i].v_uint16 = *(guint16 *) args[i];
148 case GI_TYPE_TAG_INT32:
149 g_args[i].v_int32 = *(gint32 *) args[i];
151 case GI_TYPE_TAG_UINT32:
152 g_args[i].v_uint32 = *(guint32 *) args[i];
154 case GI_TYPE_TAG_LONG:
155 g_args[i].v_long = *(glong *) args[i];
157 case GI_TYPE_TAG_INT64:
158 g_args[i].v_int64 = *(gint64 *) args[i];
160 case GI_TYPE_TAG_ULONG:
161 g_args[i].v_ulong = *(gulong *) args[i];
163 case GI_TYPE_TAG_UINT64:
164 g_args[i].v_uint64 = *(guint64 *) args[i];
166 case GI_TYPE_TAG_INT:
167 g_args[i].v_int = *(gint *) args[i];
169 case GI_TYPE_TAG_SSIZE:
170 g_args[i].v_ssize = *(gssize *) args[i];
172 case GI_TYPE_TAG_SIZE:
173 g_args[i].v_size = *(gsize *) args[i];
175 case GI_TYPE_TAG_UINT:
176 g_args[i].v_uint = *(guint *) args[i];
178 case GI_TYPE_TAG_FLOAT:
179 g_args[i].v_float = *(gfloat *) args[i];
181 case GI_TYPE_TAG_DOUBLE:
182 g_args[i].v_double = *(gdouble *) args[i];
184 case GI_TYPE_TAG_UTF8:
185 g_args[i].v_string = *(gchar **) args[i];
187 case GI_TYPE_TAG_INTERFACE:
189 GIBaseInfo *interface;
190 GIInfoType interface_type;
192 interface = g_type_info_get_interface (arg_type);
193 interface_type = g_base_info_get_type (interface);
195 if (interface_type == GI_INFO_TYPE_OBJECT ||
196 interface_type == GI_INFO_TYPE_INTERFACE)
198 g_args[i].v_pointer = *(gpointer *) args[i];
199 g_base_info_unref (interface);
203 else if (interface_type == GI_INFO_TYPE_ENUM ||
204 interface_type == GI_INFO_TYPE_FLAGS)
206 g_args[i].v_double = *(double *) args[i];
207 g_base_info_unref (interface);
210 else if (interface_type == GI_INFO_TYPE_STRUCT)
212 g_args[i].v_pointer = *(gpointer *) args[i];
213 g_base_info_unref (interface);
217 g_base_info_unref (interface);
219 case GI_TYPE_TAG_GLIST:
220 case GI_TYPE_TAG_GSLIST:
221 g_args[i].v_pointer = *(gpointer *) args[i];
224 g_args[i].v_pointer = 0;
227 g_base_info_unref ((GIBaseInfo *) arg_info);
228 g_base_info_unref ((GIBaseInfo *) arg_type);
234 * g_callable_info_get_ffi_arg_types:
235 * @callable_info: a callable info from a typelib
237 * Return value: an array of ffi_type*. The array itself
238 * should be freed using g_free() after use.
241 g_callable_info_get_ffi_arg_types (GICallableInfo *callable_info)
243 ffi_type **arg_types;
246 g_return_val_if_fail (callable_info != NULL, NULL);
248 n_args = g_callable_info_get_n_args (callable_info);
250 arg_types = (ffi_type **) g_new0 (ffi_type *, n_args + 1);
252 for (i = 0; i < n_args; ++i)
254 GIArgInfo *arg_info = g_callable_info_get_arg (callable_info, i);
255 GITypeInfo *arg_type = g_arg_info_get_type (arg_info);
256 GITypeTag type_tag = g_type_info_get_tag (arg_type);
257 arg_types[i] = g_ir_ffi_get_ffi_type (type_tag);
258 g_base_info_unref ((GIBaseInfo *)arg_info);
259 g_base_info_unref ((GIBaseInfo *)arg_type);
261 arg_types[n_args] = NULL;
267 * g_callable_info_get_ffi_return_type:
268 * @callable_info: a callable info from a typelib
270 * Fetches the ffi_type for a corresponding return value of
272 * Return value: the ffi_type for the return value
275 g_callable_info_get_ffi_return_type (GICallableInfo *callable_info)
277 GITypeInfo *return_type;
280 g_return_val_if_fail (callable_info != NULL, NULL);
282 return_type = g_callable_info_get_return_type (callable_info);
283 type_tag = g_type_info_get_tag (return_type);
285 g_base_info_unref((GIBaseInfo*)return_type);
287 return g_ir_ffi_get_ffi_type (type_tag);
291 * g_callable_info_prepare_closure:
292 * @callable_info: a callable info from a typelib
293 * @cif: a ffi_cif structure
294 * @callback: the ffi callback
295 * @user_data: data to be passed into the callback
297 * Prepares a callback for ffi invocation.
299 * Note: this function requires the heap to be executable, which
300 * might not function properly on systems with SELinux enabled.
302 * Return value: the ffi_closure or NULL on error.
303 * The return value should be freed by calling g_callable_info_prepare_closure().
306 g_callable_info_prepare_closure (GICallableInfo *callable_info,
308 GIFFIClosureCallback callback,
311 ffi_closure *closure;
314 g_return_val_if_fail (callable_info != NULL, FALSE);
315 g_return_val_if_fail (cif != NULL, FALSE);
316 g_return_val_if_fail (callback != NULL, FALSE);
318 closure = mmap (NULL, sizeof (ffi_closure),
319 PROT_EXEC | PROT_READ | PROT_WRITE,
320 MAP_ANON | MAP_PRIVATE, -1, sysconf (_SC_PAGE_SIZE));
323 g_warning("mmap failed: %s\n", strerror(errno));
327 status = ffi_prep_cif (cif, FFI_DEFAULT_ABI,
328 g_callable_info_get_n_args (callable_info),
329 g_callable_info_get_ffi_return_type (callable_info),
330 g_callable_info_get_ffi_arg_types (callable_info));
331 if (status != FFI_OK)
333 g_warning("ffi_prep_cif failed: %d\n", status);
334 munmap(closure, sizeof (closure));
338 status = ffi_prep_closure (closure, cif, callback, user_data);
339 if (status != FFI_OK)
341 g_warning ("ffi_prep_closure failed: %d\n", status);
342 munmap(closure, sizeof (closure));
346 if (mprotect(closure, sizeof (closure), PROT_READ | PROT_EXEC) == -1)
348 g_warning ("ffi_prep_closure failed: %s\n", strerror(errno));
349 munmap(closure, sizeof (closure));
357 * g_callable_info_free_closure:
358 * @callable_info: a callable info from a typelib
359 * @closure: ffi closure
361 * Frees a ffi_closure returned from g_callable_info_prepare_closure()
364 g_callable_info_free_closure (GICallableInfo *callable_info,
365 ffi_closure *closure)
367 munmap(closure, sizeof (closure));