d67cbf65cb8d99470df76c74ededb8cb6793d675
[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_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;
59     case GI_TYPE_TAG_INT:
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;
68 #else
69 #  error "Unexpected size for size_t: not 4 or 8"
70 #endif
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;
79 #else
80 #  error "Unexpected size for size_t: not 4 or 8"
81 #endif
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;
87 #else
88 #  error "Unexpected size for time_t: not 4 or 8"
89 #endif
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;
106     }
107
108   g_assert_not_reached ();
109
110   return NULL;
111 }
112
113 GArgument *
114 g_ir_ffi_convert_arguments(GICallableInfo *callable_info, void **args)
115 {
116   gint num_args, i;
117   GIArgInfo *arg_info;
118   GITypeInfo *arg_type;
119   GITypeTag tag;
120   GArgument *g_args;
121
122   num_args = g_callable_info_get_n_args (callable_info);
123   g_args = g_new0 (GArgument, num_args);
124
125   for (i = 0; i < num_args; i++)
126     {
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);
130
131       switch (tag)
132         {
133         case GI_TYPE_TAG_BOOLEAN:
134           g_args[i].v_boolean = *(gboolean *) args[i];
135           break;
136         case GI_TYPE_TAG_INT8:
137           g_args[i].v_int8 = *(gint8 *) args[i];
138           break;
139         case GI_TYPE_TAG_UINT8:
140           g_args[i].v_uint8 = *(guint8 *) args[i];
141           break;
142         case GI_TYPE_TAG_INT16:
143           g_args[i].v_int16 = *(gint16 *) args[i];
144           break;
145         case GI_TYPE_TAG_UINT16:
146           g_args[i].v_uint16 = *(guint16 *) args[i];
147           break;
148         case GI_TYPE_TAG_INT32:
149           g_args[i].v_int32 = *(gint32 *) args[i];
150           break;
151         case GI_TYPE_TAG_UINT32:
152           g_args[i].v_uint32 = *(guint32 *) args[i];
153           break;
154         case GI_TYPE_TAG_LONG:
155           g_args[i].v_long = *(glong *) args[i];
156           break;
157         case GI_TYPE_TAG_INT64:
158           g_args[i].v_int64 = *(gint64 *) args[i];
159           break;
160         case GI_TYPE_TAG_ULONG:
161           g_args[i].v_ulong = *(gulong *) args[i];
162           break;
163         case GI_TYPE_TAG_UINT64:
164           g_args[i].v_uint64 = *(guint64 *) args[i];
165           break;
166         case GI_TYPE_TAG_INT:
167           g_args[i].v_int = *(gint *) args[i];
168           break;
169         case GI_TYPE_TAG_SSIZE:
170           g_args[i].v_ssize = *(gssize *) args[i];
171           break;
172         case GI_TYPE_TAG_SIZE:
173           g_args[i].v_size = *(gsize *) args[i];
174           break;
175         case GI_TYPE_TAG_UINT:
176           g_args[i].v_uint = *(guint *) args[i];
177           break;
178         case GI_TYPE_TAG_FLOAT:
179           g_args[i].v_float = *(gfloat *) args[i];
180           break;
181         case GI_TYPE_TAG_DOUBLE:
182           g_args[i].v_double = *(gdouble *) args[i];
183           break;
184         case GI_TYPE_TAG_UTF8:
185           g_args[i].v_string = *(gchar **) args[i];
186           break;
187         case GI_TYPE_TAG_INTERFACE:
188           {
189             GIBaseInfo *interface;
190             GIInfoType interface_type;
191
192             interface = g_type_info_get_interface (arg_type);
193             interface_type = g_base_info_get_type (interface);
194
195             if (interface_type == GI_INFO_TYPE_OBJECT ||
196                 interface_type == GI_INFO_TYPE_INTERFACE)
197               {
198                 g_args[i].v_pointer = *(gpointer *) args[i];
199                 g_base_info_unref (interface);
200                 break;
201               }
202
203             else if (interface_type == GI_INFO_TYPE_ENUM ||
204                      interface_type == GI_INFO_TYPE_FLAGS)
205               {
206                 g_args[i].v_double = *(double *) args[i];
207                 g_base_info_unref (interface);
208                 break;
209               }
210             else if (interface_type == GI_INFO_TYPE_STRUCT)
211               {
212                 g_args[i].v_pointer = *(gpointer *) args[i];
213                 g_base_info_unref (interface);
214                 break;
215               }
216
217             g_base_info_unref (interface);
218           }
219         case GI_TYPE_TAG_GLIST:
220         case GI_TYPE_TAG_GSLIST:
221           g_args[i].v_pointer = *(gpointer *) args[i];
222           break;
223         default:
224           g_args[i].v_pointer = 0;
225         }
226
227       g_base_info_unref ((GIBaseInfo *) arg_info);
228       g_base_info_unref ((GIBaseInfo *) arg_type);
229     }
230   return g_args;
231 }
232
233 /**
234  * g_callable_info_get_ffi_arg_types:
235  * @callable_info: a callable info from a typelib
236  *
237  * Return value: an array of ffi_type*. The array itself
238  * should be freed using g_free() after use.
239  */
240 ffi_type **
241 g_callable_info_get_ffi_arg_types (GICallableInfo *callable_info)
242 {
243     ffi_type **arg_types;
244     gint n_args, i;
245     
246     g_return_val_if_fail (callable_info != NULL, NULL);
247
248     n_args = g_callable_info_get_n_args (callable_info);
249     
250     arg_types = (ffi_type **) g_new0 (ffi_type *, n_args + 1);
251     
252     for (i = 0; i < n_args; ++i)
253       {
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);
260       }
261     arg_types[n_args] = NULL;
262
263     return arg_types;
264 }
265
266 /**
267  * g_callable_info_get_ffi_return_type:
268  * @callable_info: a callable info from a typelib
269  *
270  * Fetches the ffi_type for a corresponding return value of
271  * a #GICallableInfo
272  * Return value: the ffi_type for the return value
273  */
274 ffi_type *
275 g_callable_info_get_ffi_return_type (GICallableInfo *callable_info)
276 {
277   GITypeInfo *return_type;
278   GITypeTag type_tag;
279
280   g_return_val_if_fail (callable_info != NULL, NULL);
281
282   return_type = g_callable_info_get_return_type (callable_info);
283   type_tag = g_type_info_get_tag (return_type);
284
285   g_base_info_unref((GIBaseInfo*)return_type);
286
287   return g_ir_ffi_get_ffi_type (type_tag);
288 }
289
290 /**
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
296  *
297  * Prepares a callback for ffi invocation.
298  *
299  * Note: this function requires the heap to be executable, which
300  *       might not function properly on systems with SELinux enabled.
301  *
302  * Return value: the ffi_closure or NULL on error.
303  * The return value should be freed by calling g_callable_info_prepare_closure().
304  */
305 ffi_closure *
306 g_callable_info_prepare_closure (GICallableInfo       *callable_info,
307                                  ffi_cif              *cif,
308                                  GIFFIClosureCallback  callback,
309                                  gpointer              user_data)
310 {
311   ffi_closure *closure;
312   ffi_status status;
313     
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);
317     
318   closure = mmap (NULL, sizeof (ffi_closure),
319                   PROT_EXEC | PROT_READ | PROT_WRITE,
320                   MAP_ANON | MAP_PRIVATE, -1, sysconf (_SC_PAGE_SIZE));
321   if (!closure)
322     {
323       g_warning("mmap failed: %s\n", strerror(errno));
324       return NULL;
325     }
326
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)
332     {
333       g_warning("ffi_prep_cif failed: %d\n", status);
334       munmap(closure, sizeof (closure));
335       return NULL;
336     }
337
338   status = ffi_prep_closure (closure, cif, callback, user_data);
339   if (status != FFI_OK)
340     {
341       g_warning ("ffi_prep_closure failed: %d\n", status);
342       munmap(closure, sizeof (closure));
343       return NULL;
344     }
345
346   if (mprotect(closure, sizeof (closure), PROT_READ | PROT_EXEC) == -1)
347     {
348       g_warning ("ffi_prep_closure failed: %s\n", strerror(errno));
349       munmap(closure, sizeof (closure));
350       return NULL;
351     }
352   
353   return closure;
354 }
355
356 /**
357  * g_callable_info_free_closure:
358  * @callable_info: a callable info from a typelib
359  * @closure: ffi closure
360  *
361  * Frees a ffi_closure returned from g_callable_info_prepare_closure()
362  */
363 void
364 g_callable_info_free_closure (GICallableInfo *callable_info,
365                               ffi_closure    *closure)
366 {
367   munmap(closure, sizeof (closure));
368 }