Fix Alignment Errors.
[gnome.gobject-introspection] / girepository / girnode.c
index 7863c25..ede6d3b 100644 (file)
@@ -1,6 +1,7 @@
 /* GObject introspection: Typelib creation
  *
  * Copyright (C) 2005 Matthias Clasen
+ * Copyright (C) 2008,2009 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
@@ -52,6 +53,13 @@ _g_irnode_dump_stats (void)
   g_message ("%lu types (%lu before sharing)", unique_types_count, types_count);
 }
 
+#define DO_ALIGNED_COPY(dest_addr, value, type) \
+do {                                            \
+       type tmp_var;                           \
+       tmp_var = value;                        \
+       memcpy(dest_addr, &tmp_var, sizeof(type));      \
+} while(0)
+
 #define ALIGN_VALUE(this, boundary) \
   (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
 
@@ -184,6 +192,9 @@ g_ir_node_new (GIrNodeTypeId type)
     }
 
   node->type = type;
+  node->offset = 0;
+  node->attributes = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                            g_free, g_free);
 
   return node;
 }
@@ -261,6 +272,7 @@ g_ir_node_free (GIrNode *node)
        GIrNodeVFunc *vfunc = (GIrNodeVFunc *)node;
        
        g_free (node->name);
+       g_free (vfunc->invoker);
        for (l = vfunc->parameters; l; l = l->next)
          g_ir_node_free ((GIrNode *)l->data);
        g_list_free (vfunc->parameters);
@@ -274,6 +286,7 @@ g_ir_node_free (GIrNode *node)
        
        g_free (node->name);
        g_ir_node_free ((GIrNode *)field->type);
+       g_ir_node_free ((GIrNode *)field->callback);
       }
       break;
 
@@ -400,6 +413,8 @@ g_ir_node_free (GIrNode *node)
       break;
     } 
 
+  g_hash_table_destroy (node->attributes);
+
   g_free (node);
 }
 
@@ -501,7 +516,13 @@ g_ir_node_get_size (GIrNode *node)
       break;
 
     case G_IR_NODE_FIELD:
-      size = sizeof (FieldBlob);
+      {
+       GIrNodeField *field = (GIrNodeField *)node;
+
+        size = sizeof (FieldBlob);
+        if (field->callback)
+          size += g_ir_node_get_size ((GIrNode *)field->callback);
+      }
       break;
 
     case G_IR_NODE_CONSTANT:
@@ -540,6 +561,18 @@ g_ir_node_get_size (GIrNode *node)
   return size;
 }
 
+static void
+add_attribute_size (gpointer key, gpointer value, gpointer data)
+{
+  const gchar *key_str = key;
+  const gchar *value_str = value;
+  gint *size_p = data;
+
+  *size_p += sizeof (AttributeBlob);
+  *size_p += ALIGN_VALUE (strlen (key_str) + 1, 4);
+  *size_p += ALIGN_VALUE (strlen (value_str) + 1, 4);
+}
+
 /* returns the full size of the blob including variable-size parts */
 static guint32
 g_ir_node_get_full_size_internal (GIrNode *parent,
@@ -778,7 +811,10 @@ g_ir_node_get_full_size_internal (GIrNode *parent,
 
        size = sizeof (FieldBlob);
        size += ALIGN_VALUE (strlen (node->name) + 1, 4);
-       size += g_ir_node_get_full_size_internal (node, (GIrNode *)field->type);        
+       if (field->callback)
+          size += g_ir_node_get_full_size_internal (node, (GIrNode *)field->callback);
+       else
+          size += g_ir_node_get_full_size_internal (node, (GIrNode *)field->type);
       }
       break;
 
@@ -851,6 +887,14 @@ g_ir_node_get_full_size (GIrNode *node)
   return g_ir_node_get_full_size_internal (NULL, node);
 }
 
+guint32
+g_ir_node_get_attribute_size (GIrNode *node)
+{
+  guint32 size = 0;
+  g_hash_table_foreach (node->attributes, add_attribute_size, &size);
+  return size;
+}
+
 int
 g_ir_node_cmp (GIrNode *node,
                GIrNode *other)
@@ -1053,7 +1097,7 @@ find_entry_node (GIrModule   *module,
       goto out;
     }
 
-  g_warning ("Entry '%s' not found", name);
+  g_ir_module_fatal (module, 0, "Type reference '%s' not found", name);
 
  out:
 
@@ -1160,6 +1204,30 @@ g_ir_find_node (GIrModule  *module,
   return node != NULL;
 }
 
+static int
+get_index_of_member_type (GIrNodeInterface *node,
+                          GIrNodeTypeId type,
+                          const char *name)
+{
+  guint index = -1;
+  GList *l;
+
+  for (l = node->members; l; l = l->next)
+    {
+      GIrNode *node = l->data;
+
+      if (node->type != type)
+        continue;
+
+      index++;
+
+      if (strcmp (node->name, name) == 0)
+        break;
+    }
+
+  return index;
+}
+
 static void
 serialize_type (GIrModule    *module, 
                GList        *modules,
@@ -1178,6 +1246,8 @@ serialize_type (GIrModule    *module,
     "uint32", 
     "int64", 
     "uint64", 
+    "short",
+    "ushort",
     "int",
     "uint",
     "long",
@@ -1186,11 +1256,10 @@ serialize_type (GIrModule    *module,
     "size",
     "float", 
     "double",
+    "time_t",
+    "GType",
     "utf8", 
     "filename",
-    "string",
-    "sequence",
-    "any"
   };
   
   if (node->tag < GI_TYPE_TAG_ARRAY)
@@ -1288,6 +1357,7 @@ static void
 g_ir_node_build_members (GList         **members,
                         GIrNodeTypeId   type,
                         guint16        *count,
+                        GIrNode        *parent,
                          GIrTypelibBuild *build,
                         guint32        *offset,
                         guint32        *offset2)
@@ -1302,7 +1372,7 @@ g_ir_node_build_members (GList         **members,
       if (member->type == type)
        {
          (*count)++;
-         g_ir_node_build_typelib (member, build, offset, offset2);
+         g_ir_node_build_typelib (member, parent, build, offset, offset2);
          *members = g_list_delete_link (*members, l);
        }
       l = next;
@@ -1340,6 +1410,7 @@ g_ir_node_check_unhandled_members (GList         **members,
 
 void
 g_ir_node_build_typelib (GIrNode         *node,
+                         GIrNode         *parent,
                          GIrTypelibBuild *build,
                          guint32         *offset,
                          guint32         *offset2)
@@ -1362,6 +1433,15 @@ g_ir_node_build_typelib (GIrNode         *node,
 
   g_ir_node_compute_offsets (node, module, modules);
 
+  /* We should only be building each node once.  If we do a typelib expansion, we also
+   * reset the offset in girmodule.c.
+   */
+  g_assert (node->offset == 0);
+  node->offset = *offset;
+  build->offset_ordered_nodes = g_list_prepend (build->offset_ordered_nodes, node);
+
+  build->n_attributes += g_hash_table_size (node->attributes);
+
   switch (node->type)
     {
     case G_IR_NODE_TYPE:
@@ -1375,11 +1455,11 @@ g_ir_node_build_typelib (GIrNode         *node,
            type->tag == GI_TYPE_TAG_UTF8 ||
            type->tag == GI_TYPE_TAG_FILENAME)
          { 
-           blob->reserved = 0;
-           blob->reserved2 = 0;
-           blob->pointer = type->is_pointer;
-           blob->reserved3 = 0;
-           blob->tag = type->tag;
+           blob->flags.reserved = 0;
+           blob->flags.reserved2 = 0;
+           blob->flags.pointer = type->is_pointer;
+           blob->flags.reserved3 = 0;
+           blob->flags.tag = type->tag;
          }
        else 
          {
@@ -1419,17 +1499,17 @@ g_ir_node_build_typelib (GIrNode         *node,
                       array->has_size = type->has_size;
                      array->reserved2 = 0;
                       if (array->has_length)
-                        array->length = type->length;
+                        array->dimensions.length = type->length;
                       else if (array->has_size)
-                        array->size  = type->size;
+                        array->dimensions.size  = type->size;
                       else
-                        array->length = -1;
+                        array->dimensions.length = -1;
                      
                      pos = *offset2 + G_STRUCT_OFFSET (ArrayTypeBlob, type);
                      *offset2 += sizeof (ArrayTypeBlob);
                      
-                     g_ir_node_build_typelib ((GIrNode *)type->parameter_type1, 
-                                              build, &pos, offset2);
+                     g_ir_node_build_typelib ((GIrNode *)type->parameter_type1,
+                                              node, build, &pos, offset2);
                    }
                    break;
                    
@@ -1463,7 +1543,7 @@ g_ir_node_build_typelib (GIrNode         *node,
                      *offset2 += sizeof (ParamTypeBlob) + sizeof (SimpleTypeBlob);
                      
                      g_ir_node_build_typelib ((GIrNode *)type->parameter_type1, 
-                                              build, &pos, offset2);
+                                              node, build, &pos, offset2);
                    }
                    break;
                    
@@ -1482,9 +1562,9 @@ g_ir_node_build_typelib (GIrNode         *node,
                      *offset2 += sizeof (ParamTypeBlob) + sizeof (SimpleTypeBlob)*2;
                      
                      g_ir_node_build_typelib ((GIrNode *)type->parameter_type1, 
-                                              build, &pos, offset2);
+                                              node, build, &pos, offset2);
                      g_ir_node_build_typelib ((GIrNode *)type->parameter_type2, 
-                                              build, &pos, offset2);
+                                              node, build, &pos, offset2);
                    }
                    break;
                    
@@ -1524,8 +1604,6 @@ g_ir_node_build_typelib (GIrNode         *node,
        FieldBlob *blob;
 
        blob = (FieldBlob *)&data[*offset];
-       /* We handle the size member specially below, so subtract it */
-       *offset += sizeof (FieldBlob) - sizeof (SimpleTypeBlob);
 
        blob->name = write_string (node->name, strings, data, offset2);
        blob->readable = field->readable;
@@ -1537,8 +1615,22 @@ g_ir_node_build_typelib (GIrNode         *node,
        else
          blob->struct_offset = 0xFFFF; /* mark as unknown */
 
-        g_ir_node_build_typelib ((GIrNode *)field->type, 
-                                build, offset, offset2);
+        if (field->callback)
+          {
+            blob->has_embedded_type = TRUE;
+            blob->type.offset = GI_INFO_TYPE_CALLBACK;
+           *offset += sizeof (FieldBlob);
+            g_ir_node_build_typelib ((GIrNode *)field->callback,
+                                    node, build, offset, offset2);
+          }
+        else
+          {
+            blob->has_embedded_type = FALSE;
+            /* We handle the size member specially below, so subtract it */
+           *offset += sizeof (FieldBlob) - sizeof (SimpleTypeBlob);
+            g_ir_node_build_typelib ((GIrNode *)field->type,
+                                    node, build, offset, offset2);
+          }
       }
       break;
 
@@ -1558,7 +1650,7 @@ g_ir_node_build_typelib (GIrNode         *node,
        blob->reserved = 0;
 
         g_ir_node_build_typelib ((GIrNode *)prop->type, 
-                                build, offset, offset2);
+                                node, build, offset, offset2);
       }
       break;
 
@@ -1592,7 +1684,7 @@ g_ir_node_build_typelib (GIrNode         *node,
        g_debug ("building function '%s'", function->symbol);
 
         g_ir_node_build_typelib ((GIrNode *)function->result->type, 
-                                build, &signature, offset2);
+                                node, build, &signature, offset2);
 
        blob2->may_return_null = function->result->allow_none;
        blob2->caller_owns_return_value = function->result->transfer;
@@ -1606,7 +1698,7 @@ g_ir_node_build_typelib (GIrNode         *node,
          {
            GIrNode *param = (GIrNode *)l->data;
 
-           g_ir_node_build_typelib (param, build, &signature, offset2);
+           g_ir_node_build_typelib (param, node, build, &signature, offset2);
          }
 
       }
@@ -1633,7 +1725,7 @@ g_ir_node_build_typelib (GIrNode         *node,
        blob->signature = signature;
        
         g_ir_node_build_typelib ((GIrNode *)function->result->type, 
-                                build, &signature, offset2);
+                                node, build, &signature, offset2);
 
        blob2->may_return_null = function->result->allow_none;
        blob2->caller_owns_return_value = function->result->transfer;
@@ -1647,7 +1739,7 @@ g_ir_node_build_typelib (GIrNode         *node,
          {
            GIrNode *param = (GIrNode *)l->data;
 
-           g_ir_node_build_typelib (param, build, &signature, offset2);
+           g_ir_node_build_typelib (param, node, build, &signature, offset2);
          }
       }
       break;
@@ -1682,7 +1774,7 @@ g_ir_node_build_typelib (GIrNode         *node,
        blob->signature = signature;
        
         g_ir_node_build_typelib ((GIrNode *)signal->result->type, 
-                                build, &signature, offset2);
+                                node, build, &signature, offset2);
 
        blob2->may_return_null = signal->result->allow_none;
        blob2->caller_owns_return_value = signal->result->transfer;
@@ -1696,7 +1788,7 @@ g_ir_node_build_typelib (GIrNode         *node,
          {
            GIrNode *param = (GIrNode *)l->data;
 
-           g_ir_node_build_typelib (param, build, &signature, offset2);
+           g_ir_node_build_typelib (param, node, build, &signature, offset2);
          }
       }
       break;
@@ -1722,12 +1814,24 @@ g_ir_node_build_typelib (GIrNode         *node,
        blob->class_closure = 0; /* FIXME */
        blob->reserved = 0;
 
+       if (vfunc->invoker)
+         {
+           int index = get_index_of_member_type ((GIrNodeInterface*)parent, G_IR_NODE_FUNCTION, vfunc->invoker);
+           if (index == -1)
+             {
+               g_error ("Unknown member function %s for vfunc %s", vfunc->invoker, node->name);
+             }
+            blob->invoker = (guint) index;
+         }
+       else
+         blob->invoker = 0x3ff; /* max of 10 bits */
+
        blob->struct_offset = vfunc->offset;
        blob->reserved2 = 0;
        blob->signature = signature;
        
         g_ir_node_build_typelib ((GIrNode *)vfunc->result->type, 
-                                build, &signature, offset2);
+                                node, build, &signature, offset2);
 
        blob2->may_return_null = vfunc->result->allow_none;
        blob2->caller_owns_return_value = vfunc->result->transfer;
@@ -1741,7 +1845,7 @@ g_ir_node_build_typelib (GIrNode         *node,
          {
            GIrNode *param = (GIrNode *)l->data;
 
-           g_ir_node_build_typelib (param, build, &signature, offset2);
+           g_ir_node_build_typelib (param, node, build, &signature, offset2);
          }
       }
       break;
@@ -1770,7 +1874,7 @@ g_ir_node_build_typelib (GIrNode         *node,
         blob->closure = param->closure;
         blob->destroy = param->destroy;
         
-        g_ir_node_build_typelib ((GIrNode *)param->type, build, offset, offset2);
+        g_ir_node_build_typelib ((GIrNode *)param->type, node, build, offset, offset2);
       }
       break;
 
@@ -1809,10 +1913,10 @@ g_ir_node_build_typelib (GIrNode         *node,
        members = g_list_copy (struct_->members);
 
        g_ir_node_build_members (&members, G_IR_NODE_FIELD, &blob->n_fields,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        g_ir_node_build_members (&members, G_IR_NODE_FUNCTION, &blob->n_methods,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        g_ir_node_check_unhandled_members (&members, node->type);
 
@@ -1844,10 +1948,10 @@ g_ir_node_build_typelib (GIrNode         *node,
        members = g_list_copy (boxed->members);
 
        g_ir_node_build_members (&members, G_IR_NODE_FIELD, &blob->n_fields,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        g_ir_node_build_members (&members, G_IR_NODE_FUNCTION, &blob->n_methods,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        g_ir_node_check_unhandled_members (&members, node->type);
 
@@ -1904,10 +2008,10 @@ g_ir_node_build_typelib (GIrNode         *node,
        members = g_list_copy (union_->members);
 
        g_ir_node_build_members (&members, G_IR_NODE_FIELD, &blob->n_fields,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        g_ir_node_build_members (&members, G_IR_NODE_FUNCTION, &blob->n_functions,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        g_ir_node_check_unhandled_members (&members, node->type);
 
@@ -1919,7 +2023,7 @@ g_ir_node_build_typelib (GIrNode         *node,
              {
                GIrNode *member = (GIrNode *)l->data;
                
-               g_ir_node_build_typelib (member, build, offset, offset2);
+               g_ir_node_build_typelib (member, node, build, offset, offset2);
              }
          }
       }
@@ -1963,7 +2067,7 @@ g_ir_node_build_typelib (GIrNode         *node,
            GIrNode *value = (GIrNode *)l->data;
 
            blob->n_values++;
-           g_ir_node_build_typelib (value, build, offset, offset2);
+           g_ir_node_build_typelib (value, node, build, offset, offset2);
          }
       }
       break;
@@ -2010,27 +2114,27 @@ g_ir_node_build_typelib (GIrNode         *node,
 
        *offset = ALIGN_VALUE (*offset, 4);
        g_ir_node_build_members (&members, G_IR_NODE_FIELD, &blob->n_fields,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        *offset = ALIGN_VALUE (*offset, 4);
        g_ir_node_build_members (&members, G_IR_NODE_PROPERTY, &blob->n_properties,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        *offset = ALIGN_VALUE (*offset, 4);
        g_ir_node_build_members (&members, G_IR_NODE_FUNCTION, &blob->n_methods,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        *offset = ALIGN_VALUE (*offset, 4);
        g_ir_node_build_members (&members, G_IR_NODE_SIGNAL, &blob->n_signals,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        *offset = ALIGN_VALUE (*offset, 4);
        g_ir_node_build_members (&members, G_IR_NODE_VFUNC, &blob->n_vfuncs,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        *offset = ALIGN_VALUE (*offset, 4);
        g_ir_node_build_members (&members, G_IR_NODE_CONSTANT, &blob->n_constants,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        g_ir_node_check_unhandled_members (&members, node->type);
 
@@ -2073,23 +2177,23 @@ g_ir_node_build_typelib (GIrNode         *node,
 
        *offset = ALIGN_VALUE (*offset, 4);
        g_ir_node_build_members (&members, G_IR_NODE_PROPERTY, &blob->n_properties,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        *offset = ALIGN_VALUE (*offset, 4);
        g_ir_node_build_members (&members, G_IR_NODE_FUNCTION, &blob->n_methods,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        *offset = ALIGN_VALUE (*offset, 4);
        g_ir_node_build_members (&members, G_IR_NODE_SIGNAL, &blob->n_signals,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        *offset = ALIGN_VALUE (*offset, 4);
        g_ir_node_build_members (&members, G_IR_NODE_VFUNC, &blob->n_vfuncs,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        *offset = ALIGN_VALUE (*offset, 4);
        g_ir_node_build_members (&members, G_IR_NODE_CONSTANT, &blob->n_constants,
-                                build, offset, offset2);
+                                node, build, offset, offset2);
 
        g_ir_node_check_unhandled_members (&members, node->type);
 
@@ -2174,11 +2278,19 @@ g_ir_node_build_typelib (GIrNode         *node,
            break;
          case GI_TYPE_TAG_INT64:
            blob->size = 8;
-           *(gint64*)&data[blob->offset] = (gint64) parse_int_value (constant->value);
+           DO_ALIGNED_COPY(&data[blob->offset], parse_int_value (constant->value), gint64);
            break;
          case GI_TYPE_TAG_UINT64:
            blob->size = 8;
-           *(guint64*)&data[blob->offset] = (guint64) parse_uint_value (constant->value);
+           DO_ALIGNED_COPY(&data[blob->offset], parse_uint_value (constant->value), guint64);
+           break;
+         case GI_TYPE_TAG_SHORT:
+           blob->size = sizeof (gshort);
+           *(gshort*)&data[blob->offset] = (gshort) parse_int_value (constant->value);
+           break;
+         case GI_TYPE_TAG_USHORT:
+           blob->size = sizeof (gushort);
+           *(gushort*)&data[blob->offset] = (gushort) parse_uint_value (constant->value);
            break;
          case GI_TYPE_TAG_INT:
            blob->size = sizeof (gint);
@@ -2191,21 +2303,21 @@ g_ir_node_build_typelib (GIrNode         *node,
          case GI_TYPE_TAG_SSIZE: /* FIXME */
          case GI_TYPE_TAG_LONG:
            blob->size = sizeof (glong);
-           *(glong*)&data[blob->offset] = (glong) parse_int_value (constant->value);
+           DO_ALIGNED_COPY(&data[blob->offset], parse_int_value (constant->value), glong);
            break;
          case GI_TYPE_TAG_SIZE: /* FIXME */
          case GI_TYPE_TAG_TIME_T: 
          case GI_TYPE_TAG_ULONG:
            blob->size = sizeof (gulong);
-           *(gulong*)&data[blob->offset] = (gulong) parse_uint_value (constant->value);
+           DO_ALIGNED_COPY(&data[blob->offset], parse_uint_value (constant->value), gulong);
            break;
          case GI_TYPE_TAG_FLOAT:
            blob->size = sizeof (gfloat);
-           *(gfloat*)&data[blob->offset] = (gfloat) parse_float_value (constant->value);
+           DO_ALIGNED_COPY(&data[blob->offset], parse_float_value (constant->value), gfloat);
            break;
          case GI_TYPE_TAG_DOUBLE:
            blob->size = sizeof (gdouble);
-           *(gdouble*)&data[blob->offset] = (gdouble) parse_float_value (constant->value);
+           DO_ALIGNED_COPY(&data[blob->offset], parse_float_value (constant->value), gdouble);
            break;
          case GI_TYPE_TAG_UTF8:
          case GI_TYPE_TAG_FILENAME:
@@ -2215,7 +2327,7 @@ g_ir_node_build_typelib (GIrNode         *node,
          }
        *offset2 += ALIGN_VALUE (blob->size, 4);
        
-       g_ir_node_build_typelib ((GIrNode *)constant->type, build, &pos, offset2);
+       g_ir_node_build_typelib ((GIrNode *)constant->type, node, build, &pos, offset2);
       }
       break;
     default:
@@ -2230,7 +2342,8 @@ g_ir_node_build_typelib (GIrNode         *node,
           old_offset, *offset, old_offset2, *offset2);
 
   if (*offset2 - old_offset2 + *offset - old_offset > g_ir_node_get_full_size (node))
-    g_error ("exceeding space reservation !!");
+    g_error ("exceeding space reservation; offset: %d (prev %d) offset2: %d (prev %d) nodesize: %d",
+             *offset, old_offset, *offset2, old_offset2, g_ir_node_get_full_size (node));
 }
 
 /* if str is already in the pool, return previous location, otherwise write str