Initial packaging for Tizen
[profile/ivi/gobject-introspection.git] / girepository / giroffsets.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2  * GObject introspection: Compute structure offsets
3  *
4  * Copyright (C) 2008 Red Hat, Inc.
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 "girffi.h"
23 #include "girnode.h"
24 #include <string.h>
25
26 /* The C standard specifies that an enumeration can be any char or any signed
27  * or unsigned integer type capable of representing all the values of the
28  * enumeration. We use test enumerations to figure out what choices the
29  * compiler makes. (Ignoring > 32 bit enumerations)
30  */
31
32 typedef enum {
33   ENUM_1 = 1 /* compiler could use int8, uint8, int16, uint16, int32, uint32 */
34 } Enum1;
35
36 typedef enum {
37   ENUM_2 = 128 /* compiler could use uint8, int16, uint16, int32, uint32 */
38 } Enum2;
39
40 typedef enum {
41   ENUM_3 = 257 /* compiler could use int16, uint16, int32, uint32 */
42 } Enum3;
43
44 typedef enum {
45   ENUM_4 = G_MAXSHORT + 1 /* compiler could use uint16, int32, uint32 */
46 } Enum4;
47
48 typedef enum {
49   ENUM_5 = G_MAXUSHORT + 1 /* compiler could use int32, uint32 */
50 } Enum5;
51
52 typedef enum {
53   ENUM_6 = ((guint)G_MAXINT) + 1 /* compiler could use uint32 */
54 } Enum6;
55
56 typedef enum {
57   ENUM_7 = -1 /* compiler could use int8, int16, int32 */
58 } Enum7;
59
60 typedef enum {
61   ENUM_8 = -129 /* compiler could use int16, int32 */
62 } Enum8;
63
64 typedef enum {
65   ENUM_9 = G_MINSHORT - 1 /* compiler could use int32 */
66 } Enum9;
67
68 static void
69 compute_enum_storage_type (GIrNodeEnum *enum_node)
70 {
71   GList *l;
72   gint64 max_value = 0;
73   gint64 min_value = 0;
74   int width;
75   gboolean signed_type;
76
77   if (enum_node->storage_type != GI_TYPE_TAG_VOID) /* already done */
78     return;
79
80   for (l = enum_node->values; l; l = l->next)
81     {
82       GIrNodeValue *value = l->data;
83       if (value->value > max_value)
84         max_value = value->value;
85       if (value->value < min_value)
86         min_value = value->value;
87     }
88
89   if (min_value < 0)
90     {
91       signed_type = TRUE;
92
93       if (min_value > -128 && max_value <= 127)
94         width = sizeof(Enum7);
95       else if (min_value >= G_MINSHORT && max_value <= G_MAXSHORT)
96         width = sizeof(Enum8);
97       else
98         width = sizeof(Enum9);
99     }
100   else
101     {
102       if (max_value <= 127)
103         {
104           width = sizeof (Enum1);
105           signed_type = (gint64)(Enum1)(-1) < 0;
106         }
107       else if (max_value <= 255)
108         {
109           width = sizeof (Enum2);
110           signed_type = (gint64)(Enum2)(-1) < 0;
111         }
112       else if (max_value <= G_MAXSHORT)
113         {
114           width = sizeof (Enum3);
115           signed_type = (gint64)(Enum3)(-1) < 0;
116         }
117       else if (max_value <= G_MAXUSHORT)
118         {
119           width = sizeof (Enum4);
120           signed_type = (gint64)(Enum4)(-1) < 0;
121         }
122       else if (max_value <= G_MAXINT)
123         {
124           width = sizeof (Enum5);
125           signed_type = (gint64)(Enum5)(-1) < 0;
126         }
127       else
128         {
129           width = sizeof (Enum6);
130           signed_type = (gint64)(Enum6)(-1) < 0;
131         }
132     }
133
134   if (width == 1)
135     enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT8 : GI_TYPE_TAG_UINT8;
136   else if (width == 2)
137     enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT16 : GI_TYPE_TAG_UINT16;
138   else if (width == 4)
139     enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT32 : GI_TYPE_TAG_UINT32;
140   else if (width == 8)
141     enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT64 : GI_TYPE_TAG_UINT64;
142   else
143     g_error ("Unexpected enum width %d", width);
144 }
145
146 static gboolean
147 get_enum_size_alignment (GIrNodeEnum *enum_node,
148                          gint        *size,
149                          gint        *alignment)
150 {
151   ffi_type *type_ffi;
152
153   compute_enum_storage_type (enum_node);
154
155   switch (enum_node->storage_type)
156     {
157     case GI_TYPE_TAG_INT8:
158     case GI_TYPE_TAG_UINT8:
159       type_ffi = &ffi_type_uint8;
160       break;
161     case GI_TYPE_TAG_INT16:
162     case GI_TYPE_TAG_UINT16:
163       type_ffi = &ffi_type_uint16;
164       break;
165     case GI_TYPE_TAG_INT32:
166     case GI_TYPE_TAG_UINT32:
167       type_ffi = &ffi_type_uint32;
168       break;
169     case GI_TYPE_TAG_INT64:
170     case GI_TYPE_TAG_UINT64:
171       type_ffi = &ffi_type_uint64;
172       break;
173     default:
174       g_error ("Unexpected enum storage type %s",
175                g_type_tag_to_string (enum_node->storage_type));
176     }
177
178   *size = type_ffi->size;
179   *alignment = type_ffi->alignment;
180
181   return TRUE;
182 }
183
184 static gboolean
185 get_interface_size_alignment (GIrTypelibBuild   *build,
186                               GIrNodeType *type,
187                               gint        *size,
188                               gint        *alignment,
189                               const char  *who)
190 {
191   GIrNode *iface;
192
193   iface = _g_ir_find_node (build, ((GIrNode*)type)->module, type->interface);
194   if (!iface)
195     {
196       _g_ir_module_fatal (build, 0, "Can't resolve type '%s' for %s", type->interface, who);
197       *size = -1;
198       *alignment = -1;
199       return FALSE;
200     }
201
202   _g_ir_node_compute_offsets (build, iface);
203
204   switch (iface->type)
205     {
206     case G_IR_NODE_BOXED:
207       {
208         GIrNodeBoxed *boxed = (GIrNodeBoxed *)iface;
209         *size = boxed->size;
210         *alignment = boxed->alignment;
211         break;
212       }
213     case G_IR_NODE_STRUCT:
214       {
215         GIrNodeStruct *struct_ = (GIrNodeStruct *)iface;
216         *size = struct_->size;
217         *alignment = struct_->alignment;
218         break;
219       }
220     case G_IR_NODE_OBJECT:
221     case G_IR_NODE_INTERFACE:
222       {
223         GIrNodeInterface *interface = (GIrNodeInterface *)iface;
224         *size = interface->size;
225         *alignment = interface->alignment;
226         break;
227       }
228     case G_IR_NODE_UNION:
229       {
230         GIrNodeUnion *union_ = (GIrNodeUnion *)iface;
231         *size = union_->size;
232         *alignment = union_->alignment;
233         break;
234       }
235     case G_IR_NODE_ENUM:
236     case G_IR_NODE_FLAGS:
237       {
238         return get_enum_size_alignment ((GIrNodeEnum *)iface,
239                                         size, alignment);
240       }
241     case G_IR_NODE_CALLBACK:
242       {
243         *size = ffi_type_pointer.size;
244         *alignment = ffi_type_pointer.alignment;
245         break;
246       }
247     default:
248       {
249         g_warning ("%s has is not a pointer and is of type %s",
250                    who,
251                    _g_ir_node_type_to_string (iface->type));
252         *size = -1;
253         *alignment = -1;
254         break;
255       }
256     }
257
258   return *alignment > 0;
259 }
260
261 static gboolean
262 get_type_size_alignment (GIrTypelibBuild   *build,
263                          GIrNodeType *type,
264                          gint        *size,
265                          gint        *alignment,
266                          const char  *who)
267 {
268   ffi_type *type_ffi;
269
270   if (type->is_pointer)
271     {
272       type_ffi = &ffi_type_pointer;
273     }
274   else if (type->tag == GI_TYPE_TAG_ARRAY)
275     {
276       gint elt_size, elt_alignment;
277
278       if (!type->has_size
279           || !get_type_size_alignment(build, type->parameter_type1,
280                                       &elt_size, &elt_alignment, who))
281         {
282           *size = -1;
283           *alignment = -1;
284           return FALSE;
285         }
286
287       *size = type->size * elt_size;
288       *alignment = elt_alignment;
289
290       return TRUE;
291     }
292   else
293     {
294       if (type->tag == GI_TYPE_TAG_INTERFACE)
295         {
296           return get_interface_size_alignment (build, type, size, alignment, who);
297         }
298       else
299         {
300           type_ffi = gi_type_tag_get_ffi_type (type->tag, type->is_pointer);
301
302           if (type_ffi == &ffi_type_void)
303             {
304               g_warning ("%s has void type", who);
305               *size = -1;
306               *alignment = -1;
307               return FALSE;
308             }
309           else if (type_ffi == &ffi_type_pointer)
310             {
311               g_warning ("%s has is not a pointer and is of type %s",
312                          who,
313                          g_type_tag_to_string (type->tag));
314               *size = -1;
315               *alignment = -1;
316               return FALSE;
317             }
318         }
319     }
320
321   g_assert (type_ffi);
322   *size = type_ffi->size;
323   *alignment = type_ffi->alignment;
324
325   return TRUE;
326 }
327
328 static gboolean
329 get_field_size_alignment (GIrTypelibBuild    *build,
330                           GIrNodeField *field,
331                           GIrNode      *parent_node,
332                           gint         *size,
333                           gint         *alignment)
334 {
335   GIrModule *module = build->module;
336   gchar *who;
337   gboolean success;
338
339   who = g_strdup_printf ("field %s.%s.%s", module->name, parent_node->name, ((GIrNode *)field)->name);
340
341   if (field->callback)
342     {
343       *size = ffi_type_pointer.size;
344       *alignment = ffi_type_pointer.alignment;
345       success = TRUE;
346     }
347   else
348     success = get_type_size_alignment (build, field->type, size, alignment, who);
349   g_free (who);
350
351   return success;
352 }
353
354 #define GI_ALIGN(n, align) (((n) + (align) - 1) & ~((align) - 1))
355
356 static gboolean
357 compute_struct_field_offsets (GIrTypelibBuild   *build,
358                               GIrNode     *node,
359                               GList       *members,
360                               gint        *size_out,
361                               gint        *alignment_out)
362 {
363   int size = 0;
364   int alignment = 1;
365   GList *l;
366   gboolean have_error = FALSE;
367
368   *alignment_out = -2; /* mark to detect recursion */
369
370   for (l = members; l; l = l->next)
371     {
372       GIrNode *member = (GIrNode *)l->data;
373
374       if (member->type == G_IR_NODE_FIELD)
375         {
376           GIrNodeField *field = (GIrNodeField *)member;
377
378           if (!have_error)
379             {
380               int member_size;
381               int member_alignment;
382
383               if (get_field_size_alignment (build, field, node,
384                                             &member_size, &member_alignment))
385                 {
386                   size = GI_ALIGN (size, member_alignment);
387                   alignment = MAX (alignment, member_alignment);
388                   field->offset = size;
389                   size += member_size;
390                 }
391               else
392                 have_error = TRUE;
393             }
394
395           if (have_error)
396             field->offset = -1;
397         }
398       else if (member->type == G_IR_NODE_CALLBACK)
399         {
400           size = GI_ALIGN (size, ffi_type_pointer.alignment);
401           alignment = MAX (alignment, ffi_type_pointer.alignment);
402           size += ffi_type_pointer.size;
403         }
404     }
405
406   /* Structs are tail-padded out to a multiple of their alignment */
407   size = GI_ALIGN (size, alignment);
408
409   if (!have_error)
410     {
411       *size_out = size;
412       *alignment_out = alignment;
413     }
414   else
415     {
416       *size_out = -1;
417       *alignment_out = -1;
418     }
419
420   return !have_error;
421 }
422
423 static gboolean
424 compute_union_field_offsets (GIrTypelibBuild *build,
425                              GIrNode     *node,
426                              GList       *members,
427                              gint        *size_out,
428                              gint        *alignment_out)
429 {
430   int size = 0;
431   int alignment = 1;
432   GList *l;
433   gboolean have_error = FALSE;
434
435   *alignment_out = -2; /* mark to detect recursion */
436
437   for (l = members; l; l = l->next)
438     {
439       GIrNode *member = (GIrNode *)l->data;
440
441       if (member->type == G_IR_NODE_FIELD)
442         {
443           GIrNodeField *field = (GIrNodeField *)member;
444
445           if (!have_error)
446             {
447               int member_size;
448               int member_alignment;
449
450               if (get_field_size_alignment (build,field, node,
451                                             &member_size, &member_alignment))
452                 {
453                   size = MAX (size, member_size);
454                   alignment = MAX (alignment, member_alignment);
455                 }
456               else
457                 have_error = TRUE;
458             }
459         }
460     }
461
462   /* Unions are tail-padded out to a multiple of their alignment */
463   size = GI_ALIGN (size, alignment);
464
465   if (!have_error)
466     {
467       *size_out = size;
468       *alignment_out = alignment;
469     }
470   else
471     {
472       *size_out = -1;
473       *alignment_out = -1;
474     }
475
476   return !have_error;
477 }
478
479 static gboolean
480 check_needs_computation (GIrTypelibBuild *build,
481                          GIrNode   *node,
482                          gint       alignment)
483 {
484   GIrModule *module = build->module;
485   /*
486    *  0: Not yet computed
487    * >0: Previously succeeded
488    * -1: Previously failed
489    * -2: In progress
490    */
491   if (alignment == -2)
492     {
493       g_warning ("Recursion encountered when computing the size of %s.%s",
494                  module->name, node->name);
495     }
496
497   return alignment == 0;
498 }
499
500 /**
501  * _g_ir_node_compute_offsets:
502  * @build: Current typelib build
503  * @node: a #GIrNode
504  *
505  * If a node is a a structure or union, makes sure that the field
506  * offsets have been computed, and also computes the overall size and
507  * alignment for the type.
508  */
509 void
510 _g_ir_node_compute_offsets (GIrTypelibBuild *build,
511                             GIrNode         *node)
512 {
513   gboolean appended_stack;
514
515   if (build->stack)
516     appended_stack = node != (GIrNode*)build->stack->data; 
517   else
518     appended_stack = TRUE;
519   if (appended_stack)
520     build->stack = g_list_prepend (build->stack, node);
521
522   switch (node->type)
523     {
524     case G_IR_NODE_BOXED:
525       {
526         GIrNodeBoxed *boxed = (GIrNodeBoxed *)node;
527
528         if (!check_needs_computation (build, node, boxed->alignment))
529           return;
530
531         compute_struct_field_offsets (build, node, boxed->members,
532                                       &boxed->size, &boxed->alignment);
533         break;
534       }
535     case G_IR_NODE_STRUCT:
536       {
537         GIrNodeStruct *struct_ = (GIrNodeStruct *)node;
538
539         if (!check_needs_computation (build, node, struct_->alignment))
540           return;
541
542         compute_struct_field_offsets (build, node, struct_->members,
543                                       &struct_->size, &struct_->alignment);
544         break;
545       }
546     case G_IR_NODE_OBJECT:
547     case G_IR_NODE_INTERFACE:
548       {
549         GIrNodeInterface *iface = (GIrNodeInterface *)node;
550
551         if (!check_needs_computation (build, node, iface->alignment))
552           return;
553
554         compute_struct_field_offsets (build, node, iface->members,
555                                       &iface->size, &iface->alignment);
556         break;
557       }
558     case G_IR_NODE_UNION:
559       {
560         GIrNodeUnion *union_ = (GIrNodeUnion *)node;
561
562         if (!check_needs_computation (build, node, union_->alignment))
563           return;
564
565         compute_union_field_offsets (build, (GIrNode*)union_, union_->members,
566                                      &union_->size, &union_->alignment);
567         break;
568       }
569     case G_IR_NODE_ENUM:
570     case G_IR_NODE_FLAGS:
571       {
572         GIrNodeEnum *enum_ = (GIrNodeEnum *)node;
573
574         if (enum_->storage_type != GI_TYPE_TAG_VOID) /* already done */
575           return;
576
577         compute_enum_storage_type (enum_);
578
579         break;
580       }
581     default:
582       break;
583     }
584   
585   if (appended_stack)
586     build->stack = g_list_delete_link (build->stack, build->stack);
587 }