1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 * GObject introspection: Compute structure offsets
4 * Copyright (C) 2008 Red Hat, Inc.
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.
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)
33 ENUM_1 = 1 /* compiler could use int8, uint8, int16, uint16, int32, uint32 */
37 ENUM_2 = 128 /* compiler could use uint8, int16, uint16, int32, uint32 */
41 ENUM_3 = 257 /* compiler could use int16, uint16, int32, uint32 */
45 ENUM_4 = G_MAXSHORT + 1 /* compiler could use uint16, int32, uint32 */
49 ENUM_5 = G_MAXUSHORT + 1 /* compiler could use int32, uint32 */
53 ENUM_6 = ((guint)G_MAXINT) + 1 /* compiler could use uint32 */
57 ENUM_7 = -1 /* compiler could use int8, int16, int32 */
61 ENUM_8 = -129 /* compiler could use int16, int32 */
65 ENUM_9 = G_MINSHORT - 1 /* compiler could use int32 */
69 compute_enum_storage_type (GIrNodeEnum *enum_node)
77 if (enum_node->storage_type != GI_TYPE_TAG_VOID) /* already done */
80 for (l = enum_node->values; l; l = l->next)
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;
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);
98 width = sizeof(Enum9);
102 if (max_value <= 127)
104 width = sizeof (Enum1);
105 signed_type = (gint64)(Enum1)(-1) < 0;
107 else if (max_value <= 255)
109 width = sizeof (Enum2);
110 signed_type = (gint64)(Enum2)(-1) < 0;
112 else if (max_value <= G_MAXSHORT)
114 width = sizeof (Enum3);
115 signed_type = (gint64)(Enum3)(-1) < 0;
117 else if (max_value <= G_MAXUSHORT)
119 width = sizeof (Enum4);
120 signed_type = (gint64)(Enum4)(-1) < 0;
122 else if (max_value <= G_MAXINT)
124 width = sizeof (Enum5);
125 signed_type = (gint64)(Enum5)(-1) < 0;
129 width = sizeof (Enum6);
130 signed_type = (gint64)(Enum6)(-1) < 0;
135 enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT8 : GI_TYPE_TAG_UINT8;
137 enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT16 : GI_TYPE_TAG_UINT16;
139 enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT32 : GI_TYPE_TAG_UINT32;
141 enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT64 : GI_TYPE_TAG_UINT64;
143 g_error ("Unexpected enum width %d", width);
147 get_enum_size_alignment (GIrNodeEnum *enum_node,
153 compute_enum_storage_type (enum_node);
155 switch (enum_node->storage_type)
157 case GI_TYPE_TAG_INT8:
158 case GI_TYPE_TAG_UINT8:
159 type_ffi = &ffi_type_uint8;
161 case GI_TYPE_TAG_INT16:
162 case GI_TYPE_TAG_UINT16:
163 type_ffi = &ffi_type_uint16;
165 case GI_TYPE_TAG_INT32:
166 case GI_TYPE_TAG_UINT32:
167 type_ffi = &ffi_type_uint32;
169 case GI_TYPE_TAG_INT64:
170 case GI_TYPE_TAG_UINT64:
171 type_ffi = &ffi_type_uint64;
174 g_error ("Unexpected enum storage type %s",
175 g_type_tag_to_string (enum_node->storage_type));
178 *size = type_ffi->size;
179 *alignment = type_ffi->alignment;
185 get_interface_size_alignment (GIrTypelibBuild *build,
193 iface = _g_ir_find_node (build, ((GIrNode*)type)->module, type->interface);
196 _g_ir_module_fatal (build, 0, "Can't resolve type '%s' for %s", type->interface, who);
202 _g_ir_node_compute_offsets (build, iface);
206 case G_IR_NODE_BOXED:
208 GIrNodeBoxed *boxed = (GIrNodeBoxed *)iface;
210 *alignment = boxed->alignment;
213 case G_IR_NODE_STRUCT:
215 GIrNodeStruct *struct_ = (GIrNodeStruct *)iface;
216 *size = struct_->size;
217 *alignment = struct_->alignment;
220 case G_IR_NODE_OBJECT:
221 case G_IR_NODE_INTERFACE:
223 GIrNodeInterface *interface = (GIrNodeInterface *)iface;
224 *size = interface->size;
225 *alignment = interface->alignment;
228 case G_IR_NODE_UNION:
230 GIrNodeUnion *union_ = (GIrNodeUnion *)iface;
231 *size = union_->size;
232 *alignment = union_->alignment;
236 case G_IR_NODE_FLAGS:
238 return get_enum_size_alignment ((GIrNodeEnum *)iface,
241 case G_IR_NODE_CALLBACK:
243 *size = ffi_type_pointer.size;
244 *alignment = ffi_type_pointer.alignment;
249 g_warning ("%s has is not a pointer and is of type %s",
251 _g_ir_node_type_to_string (iface->type));
258 return *alignment > 0;
262 get_type_size_alignment (GIrTypelibBuild *build,
270 if (type->is_pointer)
272 type_ffi = &ffi_type_pointer;
274 else if (type->tag == GI_TYPE_TAG_ARRAY)
276 gint elt_size, elt_alignment;
279 || !get_type_size_alignment(build, type->parameter_type1,
280 &elt_size, &elt_alignment, who))
287 *size = type->size * elt_size;
288 *alignment = elt_alignment;
294 if (type->tag == GI_TYPE_TAG_INTERFACE)
296 return get_interface_size_alignment (build, type, size, alignment, who);
300 type_ffi = gi_type_tag_get_ffi_type (type->tag, type->is_pointer);
302 if (type_ffi == &ffi_type_void)
304 g_warning ("%s has void type", who);
309 else if (type_ffi == &ffi_type_pointer)
311 g_warning ("%s has is not a pointer and is of type %s",
313 g_type_tag_to_string (type->tag));
322 *size = type_ffi->size;
323 *alignment = type_ffi->alignment;
329 get_field_size_alignment (GIrTypelibBuild *build,
331 GIrNode *parent_node,
335 GIrModule *module = build->module;
339 who = g_strdup_printf ("field %s.%s.%s", module->name, parent_node->name, ((GIrNode *)field)->name);
343 *size = ffi_type_pointer.size;
344 *alignment = ffi_type_pointer.alignment;
348 success = get_type_size_alignment (build, field->type, size, alignment, who);
354 #define GI_ALIGN(n, align) (((n) + (align) - 1) & ~((align) - 1))
357 compute_struct_field_offsets (GIrTypelibBuild *build,
366 gboolean have_error = FALSE;
368 *alignment_out = -2; /* mark to detect recursion */
370 for (l = members; l; l = l->next)
372 GIrNode *member = (GIrNode *)l->data;
374 if (member->type == G_IR_NODE_FIELD)
376 GIrNodeField *field = (GIrNodeField *)member;
381 int member_alignment;
383 if (get_field_size_alignment (build, field, node,
384 &member_size, &member_alignment))
386 size = GI_ALIGN (size, member_alignment);
387 alignment = MAX (alignment, member_alignment);
388 field->offset = size;
398 else if (member->type == G_IR_NODE_CALLBACK)
400 size = GI_ALIGN (size, ffi_type_pointer.alignment);
401 alignment = MAX (alignment, ffi_type_pointer.alignment);
402 size += ffi_type_pointer.size;
406 /* Structs are tail-padded out to a multiple of their alignment */
407 size = GI_ALIGN (size, alignment);
412 *alignment_out = alignment;
424 compute_union_field_offsets (GIrTypelibBuild *build,
433 gboolean have_error = FALSE;
435 *alignment_out = -2; /* mark to detect recursion */
437 for (l = members; l; l = l->next)
439 GIrNode *member = (GIrNode *)l->data;
441 if (member->type == G_IR_NODE_FIELD)
443 GIrNodeField *field = (GIrNodeField *)member;
448 int member_alignment;
450 if (get_field_size_alignment (build,field, node,
451 &member_size, &member_alignment))
453 size = MAX (size, member_size);
454 alignment = MAX (alignment, member_alignment);
462 /* Unions are tail-padded out to a multiple of their alignment */
463 size = GI_ALIGN (size, alignment);
468 *alignment_out = alignment;
480 check_needs_computation (GIrTypelibBuild *build,
484 GIrModule *module = build->module;
486 * 0: Not yet computed
487 * >0: Previously succeeded
488 * -1: Previously failed
493 g_warning ("Recursion encountered when computing the size of %s.%s",
494 module->name, node->name);
497 return alignment == 0;
501 * _g_ir_node_compute_offsets:
502 * @build: Current typelib build
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.
510 _g_ir_node_compute_offsets (GIrTypelibBuild *build,
513 gboolean appended_stack;
516 appended_stack = node != (GIrNode*)build->stack->data;
518 appended_stack = TRUE;
520 build->stack = g_list_prepend (build->stack, node);
524 case G_IR_NODE_BOXED:
526 GIrNodeBoxed *boxed = (GIrNodeBoxed *)node;
528 if (!check_needs_computation (build, node, boxed->alignment))
531 compute_struct_field_offsets (build, node, boxed->members,
532 &boxed->size, &boxed->alignment);
535 case G_IR_NODE_STRUCT:
537 GIrNodeStruct *struct_ = (GIrNodeStruct *)node;
539 if (!check_needs_computation (build, node, struct_->alignment))
542 compute_struct_field_offsets (build, node, struct_->members,
543 &struct_->size, &struct_->alignment);
546 case G_IR_NODE_OBJECT:
547 case G_IR_NODE_INTERFACE:
549 GIrNodeInterface *iface = (GIrNodeInterface *)node;
551 if (!check_needs_computation (build, node, iface->alignment))
554 compute_struct_field_offsets (build, node, iface->members,
555 &iface->size, &iface->alignment);
558 case G_IR_NODE_UNION:
560 GIrNodeUnion *union_ = (GIrNodeUnion *)node;
562 if (!check_needs_computation (build, node, union_->alignment))
565 compute_union_field_offsets (build, (GIrNode*)union_, union_->members,
566 &union_->size, &union_->alignment);
570 case G_IR_NODE_FLAGS:
572 GIrNodeEnum *enum_ = (GIrNodeEnum *)node;
574 if (enum_->storage_type != GI_TYPE_TAG_VOID) /* already done */
577 compute_enum_storage_type (enum_);
586 build->stack = g_list_delete_link (build->stack, build->stack);