mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-24 13:06:14 +01:00
Bug 560252 - Compute field offsets before writing typelib
girnode.h: Store the total size and alignment for GIrNodeStruct/Boxed/Union. giroffset.c: New file implementing computation of structure field offsets. girnode.c: Compute structure field offsets before writing types into the typelib. docs/typelib-format.txt: Document that a field offset of 0xFFFF means "unknown". Also fix description of the discriminator_offset field for unions. svn path=/trunk/; revision=876
This commit is contained in:
parent
6d9212674a
commit
31a7f413d6
@ -25,6 +25,7 @@ libgirepository_parser_la_SOURCES = \
|
||||
girmodule.h \
|
||||
girnode.c \
|
||||
girnode.h \
|
||||
giroffsets.c \
|
||||
girparser.c \
|
||||
girparser.h
|
||||
libgirepository_parser_la_CFLAGS = $(GIREPO_CFLAGS)
|
||||
|
@ -1354,6 +1354,8 @@ g_ir_node_build_typelib (GIrNode *node,
|
||||
node->name ? " " : "",
|
||||
g_ir_node_type_to_string (node->type));
|
||||
|
||||
g_ir_node_compute_offsets (node, module, modules);
|
||||
|
||||
switch (node->type)
|
||||
{
|
||||
case G_IR_NODE_TYPE:
|
||||
@ -1525,7 +1527,10 @@ g_ir_node_build_typelib (GIrNode *node,
|
||||
blob->writable = field->writable;
|
||||
blob->reserved = 0;
|
||||
blob->bits = 0;
|
||||
blob->struct_offset = field->offset;
|
||||
if (field->offset >= 0)
|
||||
blob->struct_offset = field->offset;
|
||||
else
|
||||
blob->struct_offset = 0xFFFF; /* mark as unknown */
|
||||
|
||||
g_ir_node_build_typelib ((GIrNode *)field->type,
|
||||
module, modules, strings, types,
|
||||
|
16
girnode.h
16
girnode.h
@ -271,6 +271,9 @@ struct _GIrNodeBoxed
|
||||
|
||||
gchar *gtype_name;
|
||||
gchar *gtype_init;
|
||||
|
||||
gint alignment;
|
||||
gint size;
|
||||
|
||||
GList *members;
|
||||
};
|
||||
@ -284,6 +287,9 @@ struct _GIrNodeStruct
|
||||
|
||||
gchar *gtype_name;
|
||||
gchar *gtype_init;
|
||||
|
||||
gint alignment;
|
||||
gint size;
|
||||
|
||||
GList *members;
|
||||
};
|
||||
@ -300,6 +306,9 @@ struct _GIrNodeUnion
|
||||
gchar *gtype_name;
|
||||
gchar *gtype_init;
|
||||
|
||||
gint alignment;
|
||||
gint size;
|
||||
|
||||
gint discriminator_offset;
|
||||
GIrNodeType *discriminator_type;
|
||||
};
|
||||
@ -348,6 +357,13 @@ gboolean g_ir_find_node (GIrModule *module,
|
||||
GIrNode **node_out,
|
||||
GIrModule **module_out);
|
||||
|
||||
/* In giroffsets.c */
|
||||
|
||||
void g_ir_node_compute_offsets (GIrNode *node,
|
||||
GIrModule *module,
|
||||
GList *modules);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_IR_NODE_H__ */
|
||||
|
413
giroffsets.c
Normal file
413
giroffsets.c
Normal file
@ -0,0 +1,413 @@
|
||||
/* GObject introspection: Compute structure offsets
|
||||
*
|
||||
* Copyright (C) 2008 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "girffi.h"
|
||||
#include "girnode.h"
|
||||
|
||||
/* The C standard specifies that an enumeration can be any char or any signed
|
||||
* or unsigned integer type capable of resresenting all the values of the
|
||||
* enumeration. We use test enumerations to figure out what choices the
|
||||
* compiler makes.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
ENUM_1 = 1 /* compiler could use int8, uint8, int16, uint16, int32, uint32 */
|
||||
} Enum1;
|
||||
|
||||
typedef enum {
|
||||
ENUM_2 = 128 /* compiler could use uint8, int16, uint16, int32, uint32 */
|
||||
} Enum2;
|
||||
|
||||
typedef enum {
|
||||
ENUM_3 = 257 /* compiler could use int16, uint16, int32, uint32 */
|
||||
} Enum3;
|
||||
|
||||
typedef enum {
|
||||
ENUM_4 = G_MAXSHORT + 1 /* compiler could use uint16, int32, uint32 */
|
||||
} Enum4;
|
||||
|
||||
typedef enum {
|
||||
ENUM_5 = G_MAXUSHORT + 1 /* compiler could use int32, uint32 */
|
||||
} Enum5;
|
||||
|
||||
typedef enum {
|
||||
ENUM_6 = ((guint)G_MAXINT) + 1 /* compiler could use uint32 */
|
||||
} Enum6;
|
||||
|
||||
/* GIrNodeValue has guint32 values, so if it matters to the ABI whether
|
||||
* constant values are signed, we are in trouble. And we don't handle
|
||||
* enums with > 32 bit values. */
|
||||
|
||||
#if 0
|
||||
typedef enum {
|
||||
ENUM_7 = -1 /* compiler could use int8, int16, int32 */
|
||||
} Enum7;
|
||||
|
||||
/* etc... */
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
get_enum_size_alignment (GIrNodeEnum *enum_node,
|
||||
gint *size,
|
||||
gint *alignment)
|
||||
{
|
||||
GList *l;
|
||||
guint32 max_value = 0;
|
||||
int width;
|
||||
ffi_type *type_ffi;
|
||||
|
||||
for (l = enum_node->values; l; l = l->next)
|
||||
{
|
||||
GIrNodeValue *value = l->data;
|
||||
if (value->value > max_value)
|
||||
max_value = value->value;
|
||||
}
|
||||
|
||||
if (max_value < 128)
|
||||
width = sizeof (Enum1);
|
||||
else if (max_value < 256)
|
||||
width = sizeof (Enum2);
|
||||
else if (max_value < G_MAXSHORT)
|
||||
width = sizeof (Enum3);
|
||||
else if (max_value < G_MAXUSHORT)
|
||||
width = sizeof (Enum4);
|
||||
else if (max_value < G_MAXINT)
|
||||
width = sizeof (Enum5);
|
||||
else
|
||||
width = sizeof (Enum6);
|
||||
|
||||
if (width == 1)
|
||||
type_ffi = &ffi_type_sint8;
|
||||
else if (width == 2)
|
||||
type_ffi = &ffi_type_sint16;
|
||||
else if (width == 4)
|
||||
type_ffi = &ffi_type_sint32;
|
||||
else if (width == 8)
|
||||
type_ffi = &ffi_type_sint64;
|
||||
else
|
||||
g_error ("Unexpected enum width %d", width);
|
||||
|
||||
*size = type_ffi->size;
|
||||
*alignment = type_ffi->alignment;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_interface_size_alignment (GIrNodeType *type,
|
||||
GIrModule *module,
|
||||
GList *modules,
|
||||
gint *size,
|
||||
gint *alignment)
|
||||
{
|
||||
GIrNode *iface;
|
||||
GIrModule *iface_module;
|
||||
|
||||
if (!g_ir_find_node (module, modules, type->interface, &iface, &iface_module))
|
||||
{
|
||||
g_warning ("Type for type name '%s' not found", type->interface);
|
||||
*size = -1;
|
||||
*alignment = -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_ir_node_compute_offsets (iface, iface_module,
|
||||
iface_module == module ? modules : NULL);
|
||||
|
||||
switch (iface->type)
|
||||
{
|
||||
case G_IR_NODE_BOXED:
|
||||
{
|
||||
GIrNodeBoxed *boxed = (GIrNodeBoxed *)iface;
|
||||
*size = boxed->size;
|
||||
*alignment = boxed->alignment;
|
||||
break;
|
||||
}
|
||||
case G_IR_NODE_STRUCT:
|
||||
{
|
||||
GIrNodeStruct *struct_ = (GIrNodeStruct *)iface;
|
||||
*size = struct_->size;
|
||||
*alignment = struct_->alignment;
|
||||
break;
|
||||
}
|
||||
case G_IR_NODE_UNION:
|
||||
{
|
||||
GIrNodeUnion *union_ = (GIrNodeUnion *)iface;
|
||||
*size = union_->size;
|
||||
*alignment = union_->alignment;
|
||||
break;
|
||||
}
|
||||
case G_IR_NODE_ENUM:
|
||||
case G_IR_NODE_FLAGS:
|
||||
{
|
||||
return get_enum_size_alignment ((GIrNodeEnum *)iface,
|
||||
size, alignment);
|
||||
}
|
||||
case G_IR_NODE_CALLBACK:
|
||||
{
|
||||
*size = ffi_type_pointer.size;
|
||||
*alignment = ffi_type_pointer.alignment;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
g_warning ("Unexpected non-pointer field of type %s in structure",
|
||||
g_ir_node_type_to_string (iface->type));
|
||||
*size = -1;
|
||||
*alignment = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return *alignment != -1;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_field_size_alignment (GIrNodeField *field,
|
||||
GIrModule *module,
|
||||
GList *modules,
|
||||
gint *size,
|
||||
gint *alignment)
|
||||
{
|
||||
GIrNodeType *type = field->type;
|
||||
ffi_type *type_ffi;
|
||||
|
||||
if (type->is_pointer)
|
||||
{
|
||||
type_ffi = &ffi_type_pointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type->tag == GI_TYPE_TAG_INTERFACE)
|
||||
{
|
||||
return get_interface_size_alignment (type,
|
||||
module, modules,
|
||||
size, alignment);
|
||||
}
|
||||
else
|
||||
{
|
||||
type_ffi = g_ir_ffi_get_ffi_type (type->tag);
|
||||
|
||||
if (type_ffi == &ffi_type_void)
|
||||
{
|
||||
g_warning ("field '%s' has void type", ((GIrNode *)field)->name);
|
||||
*size = -1;
|
||||
*alignment = -1;
|
||||
return FALSE;
|
||||
}
|
||||
else if (type_ffi == &ffi_type_pointer)
|
||||
{
|
||||
g_warning ("non-pointer field '%s' has unhandled type %s",
|
||||
((GIrNode *)field)->name,
|
||||
g_type_tag_to_string (type->tag));
|
||||
*size = -1;
|
||||
*alignment = -1;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_assert (type_ffi);
|
||||
*size = type_ffi->size;
|
||||
*alignment = type_ffi->alignment;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define ALIGN(n, align) (((n) + (align) - 1) & ~((align) - 1))
|
||||
|
||||
static gboolean
|
||||
compute_struct_field_offsets (GList *members,
|
||||
GIrModule *module,
|
||||
GList *modules,
|
||||
gint *size_out,
|
||||
gint *alignment_out)
|
||||
{
|
||||
int size = 0;
|
||||
int alignment = 1;
|
||||
GList *l;
|
||||
gboolean have_error = FALSE;
|
||||
|
||||
for (l = members; l; l = l->next)
|
||||
{
|
||||
GIrNode *member = (GIrNode *)l->data;
|
||||
|
||||
if (member->type == G_IR_NODE_FIELD)
|
||||
{
|
||||
GIrNodeField *field = (GIrNodeField *)member;
|
||||
|
||||
if (!have_error)
|
||||
{
|
||||
int member_size;
|
||||
int member_alignment;
|
||||
|
||||
if (get_field_size_alignment (field,
|
||||
module, modules,
|
||||
&member_size, &member_alignment))
|
||||
{
|
||||
size = ALIGN (size, member_alignment);
|
||||
alignment = MAX (alignment, member_alignment);
|
||||
field->offset = size;
|
||||
size += member_size;
|
||||
}
|
||||
else
|
||||
have_error = TRUE;
|
||||
}
|
||||
|
||||
if (have_error)
|
||||
field->offset = -1;
|
||||
}
|
||||
else if (member->type == G_IR_NODE_CALLBACK)
|
||||
{
|
||||
size = ffi_type_pointer.size;
|
||||
alignment = ffi_type_pointer.alignment;
|
||||
}
|
||||
}
|
||||
|
||||
/* Structs are tail-padded out to a multiple of their alignment */
|
||||
size = ALIGN (size, alignment);
|
||||
|
||||
if (!have_error)
|
||||
{
|
||||
*size_out = size;
|
||||
*alignment_out = alignment;
|
||||
}
|
||||
else
|
||||
{
|
||||
*size_out = -1;
|
||||
*alignment_out = -1;
|
||||
}
|
||||
|
||||
return !have_error;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
compute_union_field_offsets (GList *members,
|
||||
GIrModule *module,
|
||||
GList *modules,
|
||||
gint *size_out,
|
||||
gint *alignment_out)
|
||||
{
|
||||
int size = 0;
|
||||
int alignment = 1;
|
||||
GList *l;
|
||||
gboolean have_error = FALSE;
|
||||
|
||||
for (l = members; l; l = l->next)
|
||||
{
|
||||
GIrNode *member = (GIrNode *)l->data;
|
||||
|
||||
if (member->type == G_IR_NODE_FIELD)
|
||||
{
|
||||
GIrNodeField *field = (GIrNodeField *)member;
|
||||
|
||||
if (!have_error)
|
||||
{
|
||||
int member_size;
|
||||
int member_alignment;
|
||||
|
||||
if (get_field_size_alignment (field,
|
||||
module, modules,
|
||||
&member_size, &member_alignment))
|
||||
{
|
||||
size = MAX (size, member_size);
|
||||
alignment = MAX (alignment, member_alignment);
|
||||
}
|
||||
else
|
||||
have_error = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unions are tail-padded out to a multiple of their alignment */
|
||||
size = ALIGN (size, alignment);
|
||||
|
||||
if (!have_error)
|
||||
{
|
||||
*size_out = size;
|
||||
*alignment_out = alignment;
|
||||
}
|
||||
else
|
||||
{
|
||||
*size_out = -1;
|
||||
*alignment_out = -1;
|
||||
}
|
||||
|
||||
return !have_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_ir_node_compute_offsets:
|
||||
* @node: a #GIrNode
|
||||
* @module: Current module being processed
|
||||
* @moudles: all currently loaded modules
|
||||
*
|
||||
* If a node is a a structure or union, makes sure that the field
|
||||
* offsets have been computed, and also computes the overall size and
|
||||
* alignment for the type.
|
||||
*/
|
||||
void
|
||||
g_ir_node_compute_offsets (GIrNode *node,
|
||||
GIrModule *module,
|
||||
GList *modules)
|
||||
{
|
||||
switch (node->type)
|
||||
{
|
||||
case G_IR_NODE_BOXED:
|
||||
{
|
||||
GIrNodeBoxed *boxed = (GIrNodeBoxed *)node;
|
||||
|
||||
if (boxed->alignment != 0) /* Already done */
|
||||
return;
|
||||
|
||||
compute_struct_field_offsets (boxed->members,
|
||||
module, modules,
|
||||
&boxed->size, &boxed->alignment);
|
||||
break;
|
||||
}
|
||||
case G_IR_NODE_STRUCT:
|
||||
{
|
||||
GIrNodeStruct *struct_ = (GIrNodeStruct *)node;
|
||||
|
||||
if (struct_->alignment != 0)
|
||||
return;
|
||||
|
||||
compute_struct_field_offsets (struct_->members,
|
||||
module, modules,
|
||||
&struct_->size, &struct_->alignment);
|
||||
break;
|
||||
}
|
||||
case G_IR_NODE_UNION:
|
||||
{
|
||||
GIrNodeUnion *union_ = (GIrNodeUnion *)node;
|
||||
|
||||
if (union_->alignment != 0)
|
||||
return;
|
||||
|
||||
compute_union_field_offsets (union_->members,
|
||||
module, modules,
|
||||
&union_->size, &union_->alignment);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Nothing to do */
|
||||
return;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user