c057afaf7b8c4235f5895ae53e71538e8b83d4e7
[gnome.gobject-introspection] / girepository / girffi.c
1 /* GObject introspection: Helper functions for ffi integration
2  *
3  * Copyright (C) 2008 Red Hat, Inc
4  * Copyright (C) 2005 Matthias Clasen
5  *
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.
10  *
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.
15  *
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.
20  */
21
22 #include <sys/types.h>
23 #include <sys/mman.h>
24
25 #include <config.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include "girffi.h"
30 #include "girepository.h"
31
32 ffi_type *
33 g_ir_ffi_get_ffi_type (GITypeTag tag)
34 {
35   switch (tag)
36     {
37     case GI_TYPE_TAG_VOID:
38       return &ffi_type_void;
39     case GI_TYPE_TAG_BOOLEAN:
40       return &ffi_type_uint;
41     case GI_TYPE_TAG_INT8:
42       return &ffi_type_sint8;
43     case GI_TYPE_TAG_UINT8:
44       return &ffi_type_uint8;
45     case GI_TYPE_TAG_INT16:
46       return &ffi_type_sint16;
47     case GI_TYPE_TAG_UINT16:
48       return &ffi_type_uint16;
49     case GI_TYPE_TAG_INT32:
50       return &ffi_type_sint32;
51     case GI_TYPE_TAG_UINT32:
52       return &ffi_type_uint32;
53     case GI_TYPE_TAG_INT64:
54       return &ffi_type_sint64;
55     case GI_TYPE_TAG_UINT64:
56       return &ffi_type_uint64;
57     case GI_TYPE_TAG_SHORT:
58       return &ffi_type_sshort;
59     case GI_TYPE_TAG_USHORT:
60       return &ffi_type_ushort;
61     case GI_TYPE_TAG_INT:
62       return &ffi_type_sint;
63     case GI_TYPE_TAG_UINT:
64       return &ffi_type_uint;
65     case GI_TYPE_TAG_SSIZE:
66 #if GLIB_SIZEOF_SIZE_T == 4
67       return &ffi_type_sint32;
68 #elif GLIB_SIZEOF_SIZE_T == 8
69       return &ffi_type_sint64;
70 #else
71 #  error "Unexpected size for size_t: not 4 or 8"
72 #endif
73     case GI_TYPE_TAG_LONG:
74       return &ffi_type_slong;
75     case GI_TYPE_TAG_SIZE:
76     case GI_TYPE_TAG_GTYPE:
77 #if GLIB_SIZEOF_SIZE_T == 4
78       return &ffi_type_uint32;
79 #elif GLIB_SIZEOF_SIZE_T == 8
80       return &ffi_type_uint64;
81 #else
82 #  error "Unexpected size for size_t: not 4 or 8"
83 #endif
84     case GI_TYPE_TAG_TIME_T:
85 #if SIZEOF_TIME_T == 4
86       return &ffi_type_sint32;
87 #elif SIZEOF_TIME_T == 8
88       return &ffi_type_sint64;
89 #else
90 #  error "Unexpected size for time_t: not 4 or 8"
91 #endif
92     case GI_TYPE_TAG_ULONG:
93       return &ffi_type_ulong;
94     case GI_TYPE_TAG_FLOAT:
95       return &ffi_type_float;
96     case GI_TYPE_TAG_DOUBLE:
97       return &ffi_type_double;
98     case GI_TYPE_TAG_UTF8:
99     case GI_TYPE_TAG_FILENAME:
100     case GI_TYPE_TAG_ARRAY:
101     case GI_TYPE_TAG_INTERFACE:
102     case GI_TYPE_TAG_GLIST:
103     case GI_TYPE_TAG_GSLIST:
104     case GI_TYPE_TAG_GHASH:
105     case GI_TYPE_TAG_ERROR:
106       return &ffi_type_pointer;
107     }
108
109   g_assert_not_reached ();
110
111   return NULL;
112 }
113
114 GArgument *
115 g_ir_ffi_convert_arguments(GICallableInfo *callable_info, void **args)
116 {
117   gint num_args, i;
118   GIArgInfo *arg_info;
119   GITypeInfo *arg_type;
120   GITypeTag tag;
121   GArgument *g_args;
122
123   num_args = g_callable_info_get_n_args (callable_info);
124   g_args = g_new0 (GArgument, num_args);
125
126   for (i = 0; i < num_args; i++)
127     {
128       arg_info = g_callable_info_get_arg (callable_info, i);
129       arg_type = g_arg_info_get_type (arg_info);
130       tag = g_type_info_get_tag (arg_type);
131
132       switch (tag)
133         {
134         case GI_TYPE_TAG_BOOLEAN:
135           g_args[i].v_boolean = *(gboolean *) args[i];
136           break;
137         case GI_TYPE_TAG_INT8:
138           g_args[i].v_int8 = *(gint8 *) args[i];
139           break;
140         case GI_TYPE_TAG_UINT8:
141           g_args[i].v_uint8 = *(guint8 *) args[i];
142           break;
143         case GI_TYPE_TAG_INT16:
144           g_args[i].v_int16 = *(gint16 *) args[i];
145           break;
146         case GI_TYPE_TAG_UINT16:
147           g_args[i].v_uint16 = *(guint16 *) args[i];
148           break;
149         case GI_TYPE_TAG_INT32:
150           g_args[i].v_int32 = *(gint32 *) args[i];
151           break;
152         case GI_TYPE_TAG_UINT32:
153           g_args[i].v_uint32 = *(guint32 *) args[i];
154           break;
155         case GI_TYPE_TAG_LONG:
156           g_args[i].v_long = *(glong *) args[i];
157           break;
158         case GI_TYPE_TAG_INT64:
159           g_args[i].v_int64 = *(gint64 *) args[i];
160           break;
161         case GI_TYPE_TAG_ULONG:
162           g_args[i].v_ulong = *(gulong *) args[i];
163           break;
164         case GI_TYPE_TAG_UINT64:
165           g_args[i].v_uint64 = *(guint64 *) args[i];
166           break;
167         case GI_TYPE_TAG_INT:
168           g_args[i].v_int = *(gint *) args[i];
169           break;
170         case GI_TYPE_TAG_SSIZE:
171           g_args[i].v_ssize = *(gssize *) args[i];
172           break;
173         case GI_TYPE_TAG_SIZE:
174           g_args[i].v_size = *(gsize *) args[i];
175           break;
176         case GI_TYPE_TAG_UINT:
177           g_args[i].v_uint = *(guint *) args[i];
178           break;
179         case GI_TYPE_TAG_FLOAT:
180           g_args[i].v_float = *(gfloat *) args[i];
181           break;
182         case GI_TYPE_TAG_DOUBLE:
183           g_args[i].v_double = *(gdouble *) args[i];
184           break;
185         case GI_TYPE_TAG_UTF8:
186           g_args[i].v_string = *(gchar **) args[i];
187           break;
188         case GI_TYPE_TAG_INTERFACE:
189           {
190             GIBaseInfo *interface;
191             GIInfoType interface_type;
192
193             interface = g_type_info_get_interface (arg_type);
194             interface_type = g_base_info_get_type (interface);
195
196             if (interface_type == GI_INFO_TYPE_OBJECT ||
197                 interface_type == GI_INFO_TYPE_INTERFACE)
198               {
199                 g_args[i].v_pointer = *(gpointer *) args[i];
200                 g_base_info_unref (interface);
201                 break;
202               }
203
204             else if (interface_type == GI_INFO_TYPE_ENUM ||
205                      interface_type == GI_INFO_TYPE_FLAGS)
206               {
207                 g_args[i].v_double = *(double *) args[i];
208                 g_base_info_unref (interface);
209                 break;
210               }
211             else if (interface_type == GI_INFO_TYPE_STRUCT)
212               {
213                 g_args[i].v_pointer = *(gpointer *) args[i];
214                 g_base_info_unref (interface);
215                 break;
216               }
217
218             g_base_info_unref (interface);
219           }
220         case GI_TYPE_TAG_GLIST:
221         case GI_TYPE_TAG_GSLIST:
222           g_args[i].v_pointer = *(gpointer *) args[i];
223           break;
224         default:
225           g_args[i].v_pointer = 0;
226         }
227
228       g_base_info_unref ((GIBaseInfo *) arg_info);
229       g_base_info_unref ((GIBaseInfo *) arg_type);
230     }
231   return g_args;
232 }
233
234 /**
235  * g_callable_info_get_ffi_arg_types:
236  * @callable_info: a callable info from a typelib
237  *
238  * Return value: an array of ffi_type*. The array itself
239  * should be freed using g_free() after use.
240  */
241 ffi_type **
242 g_callable_info_get_ffi_arg_types (GICallableInfo *callable_info)
243 {
244     ffi_type **arg_types;
245     gint n_args, i;
246     
247     g_return_val_if_fail (callable_info != NULL, NULL);
248
249     n_args = g_callable_info_get_n_args (callable_info);
250     
251     arg_types = (ffi_type **) g_new0 (ffi_type *, n_args + 1);
252     
253     for (i = 0; i < n_args; ++i)
254       {
255         GIArgInfo *arg_info = g_callable_info_get_arg (callable_info, i);
256         GITypeInfo *arg_type = g_arg_info_get_type (arg_info);
257         GITypeTag type_tag = g_type_info_get_tag (arg_type);
258         arg_types[i] = g_ir_ffi_get_ffi_type (type_tag);
259         g_base_info_unref ((GIBaseInfo *)arg_info);
260         g_base_info_unref ((GIBaseInfo *)arg_type);
261       }
262     arg_types[n_args] = NULL;
263
264     return arg_types;
265 }
266
267 /**
268  * g_callable_info_get_ffi_return_type:
269  * @callable_info: a callable info from a typelib
270  *
271  * Fetches the ffi_type for a corresponding return value of
272  * a #GICallableInfo
273  * Return value: the ffi_type for the return value
274  */
275 ffi_type *
276 g_callable_info_get_ffi_return_type (GICallableInfo *callable_info)
277 {
278   GITypeInfo *return_type;
279   GITypeTag type_tag;
280
281   g_return_val_if_fail (callable_info != NULL, NULL);
282
283   return_type = g_callable_info_get_return_type (callable_info);
284   type_tag = g_type_info_get_tag (return_type);
285
286   g_base_info_unref((GIBaseInfo*)return_type);
287
288   return g_ir_ffi_get_ffi_type (type_tag);
289 }
290
291 /**
292  * g_callable_info_prepare_closure:
293  * @callable_info: a callable info from a typelib
294  * @cif: a ffi_cif structure
295  * @callback: the ffi callback
296  * @user_data: data to be passed into the callback
297  *
298  * Prepares a callback for ffi invocation.
299  *
300  * Note: this function requires the heap to be executable, which
301  *       might not function properly on systems with SELinux enabled.
302  *
303  * Return value: the ffi_closure or NULL on error.
304  * The return value should be freed by calling g_callable_info_prepare_closure().
305  */
306 ffi_closure *
307 g_callable_info_prepare_closure (GICallableInfo       *callable_info,
308                                  ffi_cif              *cif,
309                                  GIFFIClosureCallback  callback,
310                                  gpointer              user_data)
311 {
312   ffi_closure *closure;
313   ffi_status status;
314     
315   g_return_val_if_fail (callable_info != NULL, FALSE);
316   g_return_val_if_fail (cif != NULL, FALSE);
317   g_return_val_if_fail (callback != NULL, FALSE);
318     
319   closure = mmap (NULL, sizeof (ffi_closure),
320                   PROT_EXEC | PROT_READ | PROT_WRITE,
321                   MAP_ANON | MAP_PRIVATE, -1, sysconf (_SC_PAGE_SIZE));
322   if (!closure)
323     {
324       g_warning("mmap failed: %s\n", strerror(errno));
325       return NULL;
326     }
327
328   status = ffi_prep_cif (cif, FFI_DEFAULT_ABI,
329                          g_callable_info_get_n_args (callable_info),
330                          g_callable_info_get_ffi_return_type (callable_info),
331                          g_callable_info_get_ffi_arg_types (callable_info));
332   if (status != FFI_OK)
333     {
334       g_warning("ffi_prep_cif failed: %d\n", status);
335       munmap(closure, sizeof (closure));
336       return NULL;
337     }
338
339   status = ffi_prep_closure (closure, cif, callback, user_data);
340   if (status != FFI_OK)
341     {
342       g_warning ("ffi_prep_closure failed: %d\n", status);
343       munmap(closure, sizeof (closure));
344       return NULL;
345     }
346
347   if (mprotect(closure, sizeof (closure), PROT_READ | PROT_EXEC) == -1)
348     {
349       g_warning ("ffi_prep_closure failed: %s\n", strerror(errno));
350       munmap(closure, sizeof (closure));
351       return NULL;
352     }
353   
354   return closure;
355 }
356
357 /**
358  * g_callable_info_free_closure:
359  * @callable_info: a callable info from a typelib
360  * @closure: ffi closure
361  *
362  * Frees a ffi_closure returned from g_callable_info_prepare_closure()
363  */
364 void
365 g_callable_info_free_closure (GICallableInfo *callable_info,
366                               ffi_closure    *closure)
367 {
368   munmap(closure, sizeof (closure));
369 }