gobject-introspection r876 - in trunk: . docs girepository



Author: otaylor
Date: Tue Nov 11 05:10:36 2008
New Revision: 876
URL: http://svn.gnome.org/viewvc/gobject-introspection?rev=876&view=rev

Log:
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.

Added:
   trunk/girepository/giroffsets.c
Modified:
   trunk/ChangeLog
   trunk/docs/typelib-format.txt
   trunk/girepository/Makefile.am
   trunk/girepository/girnode.c
   trunk/girepository/girnode.h

Modified: trunk/docs/typelib-format.txt
==============================================================================
--- trunk/docs/typelib-format.txt	(original)
+++ trunk/docs/typelib-format.txt	Tue Nov 11 05:10:36 2008
@@ -735,7 +735,8 @@
 	  interface to which this virtual function belongs.
 
 struct_offset:
-          The offset of the function pointer in the class struct.
+          The offset of the function pointer in the class struct. The value
+	  0xFFFF indicates that the struct offset is unknown.
 
 signature: 
           Offset of the SignatureBlob describing the parameter types and the 
@@ -767,7 +768,8 @@
           uses, otherwise 0.
 
 struct_offset:
-          The offset of the field in the struct.
+          The offset of the field in the struct. The value 0xFFFF indicates
+	  that the struct offset is unknown.
 
 type:     The type of the field.
 
@@ -1071,8 +1073,10 @@
 n_fields: Length of the arrays
 
 discriminator_offset: 
-          Offset from the beginning of the blob where the
-	  discriminator of a discriminated union is located
+          Offset from the beginning of the union where the
+	  discriminator of a discriminated union is located.
+	  The value 0xFFFF indicates that the discriminator offset
+	  is unknown.
 
 discriminator_type: 
           Type of the discriminator 

Modified: trunk/girepository/Makefile.am
==============================================================================
--- trunk/girepository/Makefile.am	(original)
+++ trunk/girepository/Makefile.am	Tue Nov 11 05:10:36 2008
@@ -25,6 +25,7 @@
 	girmodule.h				\
 	girnode.c				\
 	girnode.h				\
+	giroffsets.c				\
 	girparser.c				\
 	girparser.h
 libgirepository_parser_la_CFLAGS = $(GIREPO_CFLAGS)

Modified: trunk/girepository/girnode.c
==============================================================================
--- trunk/girepository/girnode.c	(original)
+++ trunk/girepository/girnode.c	Tue Nov 11 05:10:36 2008
@@ -1354,6 +1354,8 @@
 	   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 @@
 	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,

Modified: trunk/girepository/girnode.h
==============================================================================
--- trunk/girepository/girnode.h	(original)
+++ trunk/girepository/girnode.h	Tue Nov 11 05:10:36 2008
@@ -271,6 +271,9 @@
 
   gchar *gtype_name;
   gchar *gtype_init;
+
+  gint alignment;
+  gint size;
   
   GList *members;
 };
@@ -284,6 +287,9 @@
 
   gchar *gtype_name;
   gchar *gtype_init;
+
+  gint alignment;
+  gint size;
   
   GList *members;
 };
@@ -300,6 +306,9 @@
   gchar *gtype_name;
   gchar *gtype_init;
 
+  gint alignment;
+  gint size;
+
   gint discriminator_offset;
   GIrNodeType *discriminator_type;
 };
@@ -348,6 +357,13 @@
 			 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__ */

Added: trunk/girepository/giroffsets.c
==============================================================================
--- (empty file)
+++ trunk/girepository/giroffsets.c	Tue Nov 11 05:10:36 2008
@@ -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;
+    }
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]