/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- * GObject introspection: Typelib creation * * Copyright (C) 2005 Matthias Clasen * Copyright (C) 2008,2009 Red Hat, Inc. * * SPDX-License-Identifier: LGPL-2.1-or-later * * 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 "config.h" #include "girnode-private.h" #include "gitypelib-internal.h" #include #include #include #ifdef _MSC_VER #define strtoll _strtoi64 #define strtoull _strtoui64 #endif static gulong string_count = 0; static gulong unique_string_count = 0; static gulong string_size = 0; static gulong unique_string_size = 0; static gulong types_count = 0; static gulong unique_types_count = 0; void gi_ir_node_init_stats (void) { string_count = 0; unique_string_count = 0; string_size = 0; unique_string_size = 0; types_count = 0; unique_types_count = 0; } void gi_ir_node_dump_stats (void) { g_message ("%lu strings (%lu before sharing), %lu bytes (%lu before sharing)", unique_string_count, string_count, unique_string_size, string_size); 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))) const char * gi_ir_node_type_to_string (GIIrNodeTypeId type) { switch (type) { case GI_IR_NODE_FUNCTION: return "function"; case GI_IR_NODE_CALLBACK: return "callback"; case GI_IR_NODE_PARAM: return "param"; case GI_IR_NODE_TYPE: return "type"; case GI_IR_NODE_OBJECT: return "object"; case GI_IR_NODE_INTERFACE: return "interface"; case GI_IR_NODE_SIGNAL: return "signal"; case GI_IR_NODE_PROPERTY: return "property"; case GI_IR_NODE_VFUNC: return "vfunc"; case GI_IR_NODE_FIELD: return "field"; case GI_IR_NODE_ENUM: return "enum"; case GI_IR_NODE_FLAGS: return "flags"; case GI_IR_NODE_BOXED: return "boxed"; case GI_IR_NODE_STRUCT: return "struct"; case GI_IR_NODE_VALUE: return "value"; case GI_IR_NODE_CONSTANT: return "constant"; case GI_IR_NODE_XREF: return "xref"; case GI_IR_NODE_UNION: return "union"; default: return "unknown"; } } GIIrNode * gi_ir_node_new (GIIrNodeTypeId type, GIIrModule *module) { GIIrNode *node = NULL; switch (type) { case GI_IR_NODE_FUNCTION: case GI_IR_NODE_CALLBACK: node = g_malloc0 (sizeof (GIIrNodeFunction)); break; case GI_IR_NODE_PARAM: node = g_malloc0 (sizeof (GIIrNodeParam)); break; case GI_IR_NODE_TYPE: node = g_malloc0 (sizeof (GIIrNodeType)); break; case GI_IR_NODE_OBJECT: case GI_IR_NODE_INTERFACE: node = g_malloc0 (sizeof (GIIrNodeInterface)); break; case GI_IR_NODE_SIGNAL: node = g_malloc0 (sizeof (GIIrNodeSignal)); break; case GI_IR_NODE_PROPERTY: node = g_malloc0 (sizeof (GIIrNodeProperty)); break; case GI_IR_NODE_VFUNC: node = g_malloc0 (sizeof (GIIrNodeFunction)); break; case GI_IR_NODE_FIELD: node = g_malloc0 (sizeof (GIIrNodeField)); break; case GI_IR_NODE_ENUM: case GI_IR_NODE_FLAGS: node = g_malloc0 (sizeof (GIIrNodeEnum)); break; case GI_IR_NODE_BOXED: node = g_malloc0 (sizeof (GIIrNodeBoxed)); break; case GI_IR_NODE_STRUCT: node = g_malloc0 (sizeof (GIIrNodeStruct)); break; case GI_IR_NODE_VALUE: node = g_malloc0 (sizeof (GIIrNodeValue)); break; case GI_IR_NODE_CONSTANT: node = g_malloc0 (sizeof (GIIrNodeConstant)); break; case GI_IR_NODE_XREF: node = g_malloc0 (sizeof (GIIrNodeXRef)); break; case GI_IR_NODE_UNION: node = g_malloc0 (sizeof (GIIrNodeUnion)); break; default: g_error ("Unhandled node type %d", type); break; } node->type = type; node->module = module; node->offset = 0; node->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); return node; } void gi_ir_node_free (GIIrNode *node) { GList *l; if (node == NULL) return; switch (node->type) { case GI_IR_NODE_FUNCTION: case GI_IR_NODE_CALLBACK: { GIIrNodeFunction *function = (GIIrNodeFunction *)node; g_free (node->name); g_free (function->symbol); g_free (function->property); gi_ir_node_free ((GIIrNode *)function->result); for (l = function->parameters; l; l = l->next) gi_ir_node_free ((GIIrNode *)l->data); g_list_free (function->parameters); } break; case GI_IR_NODE_TYPE: { GIIrNodeType *type = (GIIrNodeType *)node; g_free (node->name); gi_ir_node_free ((GIIrNode *)type->parameter_type1); gi_ir_node_free ((GIIrNode *)type->parameter_type2); g_free (type->giinterface); g_strfreev (type->errors); } break; case GI_IR_NODE_PARAM: { GIIrNodeParam *param = (GIIrNodeParam *)node; g_free (node->name); gi_ir_node_free ((GIIrNode *)param->type); } break; case GI_IR_NODE_PROPERTY: { GIIrNodeProperty *property = (GIIrNodeProperty *)node; g_free (node->name); g_free (property->setter); g_free (property->getter); gi_ir_node_free ((GIIrNode *)property->type); } break; case GI_IR_NODE_SIGNAL: { GIIrNodeSignal *signal = (GIIrNodeSignal *)node; g_free (node->name); for (l = signal->parameters; l; l = l->next) gi_ir_node_free ((GIIrNode *)l->data); g_list_free (signal->parameters); gi_ir_node_free ((GIIrNode *)signal->result); } break; case GI_IR_NODE_VFUNC: { GIIrNodeVFunc *vfunc = (GIIrNodeVFunc *)node; g_free (node->name); g_free (vfunc->invoker); for (l = vfunc->parameters; l; l = l->next) gi_ir_node_free ((GIIrNode *)l->data); g_list_free (vfunc->parameters); gi_ir_node_free ((GIIrNode *)vfunc->result); } break; case GI_IR_NODE_FIELD: { GIIrNodeField *field = (GIIrNodeField *)node; g_free (node->name); gi_ir_node_free ((GIIrNode *)field->type); gi_ir_node_free ((GIIrNode *)field->callback); } break; case GI_IR_NODE_OBJECT: case GI_IR_NODE_INTERFACE: { GIIrNodeInterface *iface = (GIIrNodeInterface *)node; g_free (node->name); g_free (iface->gtype_name); g_free (iface->gtype_init); g_free (iface->ref_func); g_free (iface->unref_func); g_free (iface->set_value_func); g_free (iface->get_value_func); g_free (iface->glib_type_struct); g_free (iface->parent); for (l = iface->interfaces; l; l = l->next) g_free ((GIIrNode *)l->data); g_list_free (iface->interfaces); for (l = iface->members; l; l = l->next) gi_ir_node_free ((GIIrNode *)l->data); g_list_free (iface->members); } break; case GI_IR_NODE_VALUE: { g_free (node->name); } break; case GI_IR_NODE_ENUM: case GI_IR_NODE_FLAGS: { GIIrNodeEnum *enum_ = (GIIrNodeEnum *)node; g_free (node->name); g_free (enum_->gtype_name); g_free (enum_->gtype_init); g_free (enum_->error_domain); for (l = enum_->values; l; l = l->next) gi_ir_node_free ((GIIrNode *)l->data); g_list_free (enum_->values); for (l = enum_->methods; l; l = l->next) gi_ir_node_free ((GIIrNode *)l->data); g_list_free (enum_->methods); } break; case GI_IR_NODE_BOXED: { GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; g_free (node->name); g_free (boxed->gtype_name); g_free (boxed->gtype_init); for (l = boxed->members; l; l = l->next) gi_ir_node_free ((GIIrNode *)l->data); g_list_free (boxed->members); } break; case GI_IR_NODE_STRUCT: { GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; g_free (node->name); g_free (struct_->gtype_name); g_free (struct_->gtype_init); g_free (struct_->copy_func); g_free (struct_->free_func); for (l = struct_->members; l; l = l->next) gi_ir_node_free ((GIIrNode *)l->data); g_list_free (struct_->members); } break; case GI_IR_NODE_CONSTANT: { GIIrNodeConstant *constant = (GIIrNodeConstant *)node; g_free (node->name); g_free (constant->value); gi_ir_node_free ((GIIrNode *)constant->type); } break; case GI_IR_NODE_XREF: { GIIrNodeXRef *xref = (GIIrNodeXRef *)node; g_free (node->name); g_free (xref->namespace); } break; case GI_IR_NODE_UNION: { GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; g_free (node->name); g_free (union_->gtype_name); g_free (union_->gtype_init); g_free (union_->copy_func); g_free (union_->free_func); gi_ir_node_free ((GIIrNode *)union_->discriminator_type); for (l = union_->members; l; l = l->next) gi_ir_node_free ((GIIrNode *)l->data); for (l = union_->discriminators; l; l = l->next) gi_ir_node_free ((GIIrNode *)l->data); } break; default: g_error ("Unhandled node type %d", node->type); break; } g_hash_table_destroy (node->attributes); g_free (node); } /* returns the fixed size of the blob */ uint32_t gi_ir_node_get_size (GIIrNode *node) { GList *l; int size, n; switch (node->type) { case GI_IR_NODE_CALLBACK: size = sizeof (CallbackBlob); break; case GI_IR_NODE_FUNCTION: size = sizeof (FunctionBlob); break; case GI_IR_NODE_PARAM: /* See the comment in the GI_IR_NODE_PARAM/ArgBlob writing below */ size = sizeof (ArgBlob) - sizeof (SimpleTypeBlob); break; case GI_IR_NODE_TYPE: size = sizeof (SimpleTypeBlob); break; case GI_IR_NODE_OBJECT: { GIIrNodeInterface *iface = (GIIrNodeInterface *)node; n = g_list_length (iface->interfaces); size = sizeof (ObjectBlob) + 2 * (n + (n % 2)); for (l = iface->members; l; l = l->next) size += gi_ir_node_get_size ((GIIrNode *)l->data); } break; case GI_IR_NODE_INTERFACE: { GIIrNodeInterface *iface = (GIIrNodeInterface *)node; n = g_list_length (iface->prerequisites); size = sizeof (InterfaceBlob) + 2 * (n + (n % 2)); for (l = iface->members; l; l = l->next) size += gi_ir_node_get_size ((GIIrNode *)l->data); } break; case GI_IR_NODE_ENUM: case GI_IR_NODE_FLAGS: { GIIrNodeEnum *enum_ = (GIIrNodeEnum *)node; size = sizeof (EnumBlob); for (l = enum_->values; l; l = l->next) size += gi_ir_node_get_size ((GIIrNode *)l->data); for (l = enum_->methods; l; l = l->next) size += gi_ir_node_get_size ((GIIrNode *)l->data); } break; case GI_IR_NODE_VALUE: size = sizeof (ValueBlob); break; case GI_IR_NODE_STRUCT: { GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; size = sizeof (StructBlob); for (l = struct_->members; l; l = l->next) size += gi_ir_node_get_size ((GIIrNode *)l->data); } break; case GI_IR_NODE_BOXED: { GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; size = sizeof (StructBlob); for (l = boxed->members; l; l = l->next) size += gi_ir_node_get_size ((GIIrNode *)l->data); } break; case GI_IR_NODE_PROPERTY: size = sizeof (PropertyBlob); break; case GI_IR_NODE_SIGNAL: size = sizeof (SignalBlob); break; case GI_IR_NODE_VFUNC: size = sizeof (VFuncBlob); break; case GI_IR_NODE_FIELD: { GIIrNodeField *field = (GIIrNodeField *)node; size = sizeof (FieldBlob); if (field->callback) size += gi_ir_node_get_size ((GIIrNode *)field->callback); } break; case GI_IR_NODE_CONSTANT: size = sizeof (ConstantBlob); break; case GI_IR_NODE_XREF: size = 0; break; case GI_IR_NODE_UNION: { GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; size = sizeof (UnionBlob); for (l = union_->members; l; l = l->next) size += gi_ir_node_get_size ((GIIrNode *)l->data); for (l = union_->discriminators; l; l = l->next) size += gi_ir_node_get_size ((GIIrNode *)l->data); } break; default: g_error ("Unhandled node type '%s'", gi_ir_node_type_to_string (node->type)); size = 0; } g_debug ("node %p type '%s' size %d", node, gi_ir_node_type_to_string (node->type), size); return size; } static void add_attribute_size (gpointer key, gpointer value, gpointer data) { const char *key_str = key; const char *value_str = value; int *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 (including attributes) */ static uint32_t gi_ir_node_get_full_size_internal (GIIrNode *parent, GIIrNode *node) { GList *l; int size, n; if (node == NULL && parent != NULL) g_error ("Caught NULL node, parent=%s", parent->name); g_debug ("node %p type '%s'", node, gi_ir_node_type_to_string (node->type)); switch (node->type) { case GI_IR_NODE_CALLBACK: { GIIrNodeFunction *function = (GIIrNodeFunction *)node; size = sizeof (CallbackBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); for (l = function->parameters; l; l = l->next) { size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); } size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)function->result); } break; case GI_IR_NODE_FUNCTION: { GIIrNodeFunction *function = (GIIrNodeFunction *)node; size = sizeof (FunctionBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); size += ALIGN_VALUE (strlen (function->symbol) + 1, 4); for (l = function->parameters; l; l = l->next) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)function->result); } break; case GI_IR_NODE_PARAM: { GIIrNodeParam *param = (GIIrNodeParam *)node; /* See the comment in the GI_IR_NODE_PARAM/ArgBlob writing below */ size = sizeof (ArgBlob) - sizeof (SimpleTypeBlob); if (node->name) size += ALIGN_VALUE (strlen (node->name) + 1, 4); size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)param->type); } break; case GI_IR_NODE_TYPE: { GIIrNodeType *type = (GIIrNodeType *)node; size = sizeof (SimpleTypeBlob); if (!GI_TYPE_TAG_IS_BASIC (type->tag)) { g_debug ("node %p type tag '%s'", node, gi_type_tag_to_string (type->tag)); switch (type->tag) { case GI_TYPE_TAG_ARRAY: size = sizeof (ArrayTypeBlob); if (type->parameter_type1) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)type->parameter_type1); break; case GI_TYPE_TAG_INTERFACE: size += sizeof (InterfaceTypeBlob); break; case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: size += sizeof (ParamTypeBlob); if (type->parameter_type1) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)type->parameter_type1); break; case GI_TYPE_TAG_GHASH: size += sizeof (ParamTypeBlob) * 2; if (type->parameter_type1) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)type->parameter_type1); if (type->parameter_type2) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)type->parameter_type2); break; case GI_TYPE_TAG_ERROR: size += sizeof (ErrorTypeBlob); break; default: g_error ("Unknown type tag %d", type->tag); break; } } } break; case GI_IR_NODE_OBJECT: { GIIrNodeInterface *iface = (GIIrNodeInterface *)node; n = g_list_length (iface->interfaces); size = sizeof(ObjectBlob); if (iface->parent) size += ALIGN_VALUE (strlen (iface->parent) + 1, 4); if (iface->glib_type_struct) size += ALIGN_VALUE (strlen (iface->glib_type_struct) + 1, 4); size += ALIGN_VALUE (strlen (node->name) + 1, 4); size += ALIGN_VALUE (strlen (iface->gtype_name) + 1, 4); if (iface->gtype_init) size += ALIGN_VALUE (strlen (iface->gtype_init) + 1, 4); if (iface->ref_func) size += ALIGN_VALUE (strlen (iface->ref_func) + 1, 4); if (iface->unref_func) size += ALIGN_VALUE (strlen (iface->unref_func) + 1, 4); if (iface->set_value_func) size += ALIGN_VALUE (strlen (iface->set_value_func) + 1, 4); if (iface->get_value_func) size += ALIGN_VALUE (strlen (iface->get_value_func) + 1, 4); size += 2 * (n + (n % 2)); for (l = iface->members; l; l = l->next) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); } break; case GI_IR_NODE_INTERFACE: { GIIrNodeInterface *iface = (GIIrNodeInterface *)node; n = g_list_length (iface->prerequisites); size = sizeof (InterfaceBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); size += ALIGN_VALUE (strlen (iface->gtype_name) + 1, 4); size += ALIGN_VALUE (strlen (iface->gtype_init) + 1, 4); size += 2 * (n + (n % 2)); for (l = iface->members; l; l = l->next) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); } break; case GI_IR_NODE_ENUM: case GI_IR_NODE_FLAGS: { GIIrNodeEnum *enum_ = (GIIrNodeEnum *)node; size = sizeof (EnumBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); if (enum_->gtype_name) { size += ALIGN_VALUE (strlen (enum_->gtype_name) + 1, 4); size += ALIGN_VALUE (strlen (enum_->gtype_init) + 1, 4); } if (enum_->error_domain) size += ALIGN_VALUE (strlen (enum_->error_domain) + 1, 4); for (l = enum_->values; l; l = l->next) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); for (l = enum_->methods; l; l = l->next) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); } break; case GI_IR_NODE_VALUE: { size = sizeof (ValueBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); } break; case GI_IR_NODE_STRUCT: { GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; size = sizeof (StructBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); if (struct_->gtype_name) size += ALIGN_VALUE (strlen (struct_->gtype_name) + 1, 4); if (struct_->gtype_init) size += ALIGN_VALUE (strlen (struct_->gtype_init) + 1, 4); if (struct_->copy_func) size += ALIGN_VALUE (strlen (struct_->copy_func) + 1, 4); if (struct_->free_func) size += ALIGN_VALUE (strlen (struct_->free_func) + 1, 4); for (l = struct_->members; l; l = l->next) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); } break; case GI_IR_NODE_BOXED: { GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; size = sizeof (StructBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); if (boxed->gtype_name) { size += ALIGN_VALUE (strlen (boxed->gtype_name) + 1, 4); size += ALIGN_VALUE (strlen (boxed->gtype_init) + 1, 4); } for (l = boxed->members; l; l = l->next) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); } break; case GI_IR_NODE_PROPERTY: { GIIrNodeProperty *prop = (GIIrNodeProperty *)node; size = sizeof (PropertyBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)prop->type); } break; case GI_IR_NODE_SIGNAL: { GIIrNodeSignal *signal = (GIIrNodeSignal *)node; size = sizeof (SignalBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); for (l = signal->parameters; l; l = l->next) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)signal->result); } break; case GI_IR_NODE_VFUNC: { GIIrNodeVFunc *vfunc = (GIIrNodeVFunc *)node; size = sizeof (VFuncBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); for (l = vfunc->parameters; l; l = l->next) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)vfunc->result); } break; case GI_IR_NODE_FIELD: { GIIrNodeField *field = (GIIrNodeField *)node; size = sizeof (FieldBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); if (field->callback) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)field->callback); else size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)field->type); } break; case GI_IR_NODE_CONSTANT: { GIIrNodeConstant *constant = (GIIrNodeConstant *)node; size = sizeof (ConstantBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); /* FIXME non-string values */ size += ALIGN_VALUE (strlen (constant->value) + 1, 4); size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)constant->type); } break; case GI_IR_NODE_XREF: { GIIrNodeXRef *xref = (GIIrNodeXRef *)node; size = 0; size += ALIGN_VALUE (strlen (node->name) + 1, 4); size += ALIGN_VALUE (strlen (xref->namespace) + 1, 4); } break; case GI_IR_NODE_UNION: { GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; size = sizeof (UnionBlob); size += ALIGN_VALUE (strlen (node->name) + 1, 4); if (union_->gtype_name) size += ALIGN_VALUE (strlen (union_->gtype_name) + 1, 4); if (union_->gtype_init) size += ALIGN_VALUE (strlen (union_->gtype_init) + 1, 4); if (union_->copy_func) size += ALIGN_VALUE (strlen (union_->copy_func) + 1, 4); if (union_->free_func) size += ALIGN_VALUE (strlen (union_->free_func) + 1, 4); for (l = union_->members; l; l = l->next) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); for (l = union_->discriminators; l; l = l->next) size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); } break; default: g_error ("Unknown type tag %d", node->type); size = 0; } g_debug ("node %s%s%s%p type '%s' full size %d", node->name ? "'" : "", node->name ? node->name : "", node->name ? "' " : "", node, gi_ir_node_type_to_string (node->type), size); g_hash_table_foreach (node->attributes, add_attribute_size, &size); return size; } uint32_t gi_ir_node_get_full_size (GIIrNode *node) { return gi_ir_node_get_full_size_internal (NULL, node); } int gi_ir_node_cmp (GIIrNode *node, GIIrNode *other) { if (node->type < other->type) return -1; else if (node->type > other->type) return 1; else return strcmp (node->name, other->name); } gboolean gi_ir_node_can_have_member (GIIrNode *node) { switch (node->type) { case GI_IR_NODE_OBJECT: case GI_IR_NODE_INTERFACE: case GI_IR_NODE_BOXED: case GI_IR_NODE_STRUCT: case GI_IR_NODE_UNION: return TRUE; /* list others individually rather than with default: so that compiler * warns if new node types are added without adding them to the switch */ case GI_IR_NODE_INVALID: case GI_IR_NODE_FUNCTION: case GI_IR_NODE_CALLBACK: case GI_IR_NODE_ENUM: case GI_IR_NODE_FLAGS: case GI_IR_NODE_CONSTANT: case GI_IR_NODE_INVALID_0: case GI_IR_NODE_PARAM: case GI_IR_NODE_TYPE: case GI_IR_NODE_PROPERTY: case GI_IR_NODE_SIGNAL: case GI_IR_NODE_VALUE: case GI_IR_NODE_VFUNC: case GI_IR_NODE_FIELD: case GI_IR_NODE_XREF: return FALSE; default: g_assert_not_reached (); }; return FALSE; } void gi_ir_node_add_member (GIIrNode *node, GIIrNodeFunction *member) { g_return_if_fail (node != NULL); g_return_if_fail (member != NULL); switch (node->type) { case GI_IR_NODE_OBJECT: case GI_IR_NODE_INTERFACE: { GIIrNodeInterface *iface = (GIIrNodeInterface *)node; iface->members = g_list_insert_sorted (iface->members, member, (GCompareFunc) gi_ir_node_cmp); break; } case GI_IR_NODE_BOXED: { GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; boxed->members = g_list_insert_sorted (boxed->members, member, (GCompareFunc) gi_ir_node_cmp); break; } case GI_IR_NODE_STRUCT: { GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; struct_->members = g_list_insert_sorted (struct_->members, member, (GCompareFunc) gi_ir_node_cmp); break; } case GI_IR_NODE_UNION: { GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; union_->members = g_list_insert_sorted (union_->members, member, (GCompareFunc) gi_ir_node_cmp); break; } default: g_error ("Cannot add a member to unknown type tag type %d", node->type); break; } } const char * gi_ir_node_param_direction_string (GIIrNodeParam * node) { if (node->out) { if (node->in) return "in-out"; else return "out"; } return "in"; } static int64_t parse_int_value (const char *str) { return g_ascii_strtoll (str, NULL, 0); } static uint64_t parse_uint_value (const char *str) { return g_ascii_strtoull (str, NULL, 0); } static double parse_float_value (const char *str) { return g_ascii_strtod (str, NULL); } static gboolean parse_boolean_value (const char *str) { if (g_ascii_strcasecmp (str, "TRUE") == 0) return TRUE; if (g_ascii_strcasecmp (str, "FALSE") == 0) return FALSE; return parse_int_value (str) ? TRUE : FALSE; } static GIIrNode * find_entry_node (GIIrTypelibBuild *build, const char *name, uint16_t *idx) { GIIrModule *module = build->module; GList *l; unsigned int i; unsigned int n_names; char **names; GIIrNode *result = NULL; g_assert (name != NULL); g_assert (strlen (name) > 0); names = g_strsplit (name, ".", 0); n_names = g_strv_length (names); if (n_names > 2) g_error ("Too many name parts"); for (l = module->entries, i = 1; l; l = l->next, i++) { GIIrNode *node = (GIIrNode *)l->data; if (n_names > 1) { if (node->type != GI_IR_NODE_XREF) continue; if (((GIIrNodeXRef *)node)->namespace == NULL || strcmp (((GIIrNodeXRef *)node)->namespace, names[0]) != 0) continue; } if (strcmp (node->name, names[n_names - 1]) == 0) { if (idx) *idx = i; result = node; goto out; } } if (n_names > 1) { GIIrNode *node = gi_ir_node_new (GI_IR_NODE_XREF, module); ((GIIrNodeXRef *)node)->namespace = g_strdup (names[0]); node->name = g_strdup (names[1]); module->entries = g_list_append (module->entries, node); if (idx) *idx = g_list_length (module->entries); result = node; g_debug ("Creating XREF: %s %s", names[0], names[1]); goto out; } gi_ir_module_fatal (build, -1, "type reference '%s' not found", name); out: g_strfreev (names); return result; } static uint16_t find_entry (GIIrTypelibBuild *build, const char *name) { uint16_t idx = 0; find_entry_node (build, name, &idx); return idx; } static GIIrModule * find_namespace (GIIrModule *module, const char *name) { GIIrModule *target; GList *l; if (strcmp (module->name, name) == 0) return module; for (l = module->include_modules; l; l = l->next) { GIIrModule *submodule = l->data; if (strcmp (submodule->name, name) == 0) return submodule; target = find_namespace (submodule, name); if (target) return target; } return NULL; } GIIrNode * gi_ir_find_node (GIIrTypelibBuild *build, GIIrModule *src_module, const char *name) { GList *l; GIIrNode *return_node = NULL; char **names = g_strsplit (name, ".", 0); unsigned n_names = g_strv_length (names); const char *target_name; GIIrModule *target_module; if (n_names == 1) { target_module = src_module; target_name = name; } else { target_module = find_namespace (build->module, names[0]); target_name = names[1]; } /* find_namespace() may return NULL. */ if (target_module == NULL) goto done; for (l = target_module->entries; l; l = l->next) { GIIrNode *node = (GIIrNode *)l->data; if (strcmp (node->name, target_name) == 0) { return_node = node; break; } } done: g_strfreev (names); return return_node; } static int get_index_of_member_type (GIIrNodeInterface *node, GIIrNodeTypeId type, const char *name) { int index = -1; GList *l; for (l = node->members; l; l = l->next) { GIIrNode *member_node = l->data; if (member_node->type != type) continue; index++; if (strcmp (member_node->name, name) == 0) break; } return index; } static void serialize_type (GIIrTypelibBuild *build, GIIrNodeType *node, GString *str) { int i; if (GI_TYPE_TAG_IS_BASIC (node->tag)) { g_string_append_printf (str, "%s%s", gi_type_tag_to_string (node->tag), node->is_pointer ? "*" : ""); } else if (node->tag == GI_TYPE_TAG_ARRAY) { if (node->array_type == GI_ARRAY_TYPE_C) { serialize_type (build, node->parameter_type1, str); g_string_append (str, "["); if (node->has_length) g_string_append_printf (str, "length=%d", node->length); else if (node->has_size) g_string_append_printf (str, "fixed-size=%d", node->size); if (node->zero_terminated) g_string_append_printf (str, "%szero-terminated=1", node->has_length ? "," : ""); g_string_append (str, "]"); if (node->is_pointer) g_string_append (str, "*"); } else if (node->array_type == GI_ARRAY_TYPE_BYTE_ARRAY) { /* We on purpose skip serializing parameter_type1, which should always be void* */ g_string_append (str, "GByteArray"); } else { if (node->array_type == GI_ARRAY_TYPE_ARRAY) g_string_append (str, "GArray"); else g_string_append (str, "GPtrArray"); if (node->parameter_type1) { g_string_append (str, "<"); serialize_type (build, node->parameter_type1, str); g_string_append (str, ">"); } } } else if (node->tag == GI_TYPE_TAG_INTERFACE) { GIIrNode *iface; char *name; iface = find_entry_node (build, node->giinterface, NULL); if (iface) { if (iface->type == GI_IR_NODE_XREF) g_string_append_printf (str, "%s.", ((GIIrNodeXRef *)iface)->namespace); name = iface->name; } else { g_warning ("Interface for type reference %s not found", node->giinterface); name = node->giinterface; } g_string_append_printf (str, "%s%s", name, node->is_pointer ? "*" : ""); } else if (node->tag == GI_TYPE_TAG_GLIST) { g_string_append (str, "GList"); if (node->parameter_type1) { g_string_append (str, "<"); serialize_type (build, node->parameter_type1, str); g_string_append (str, ">"); } } else if (node->tag == GI_TYPE_TAG_GSLIST) { g_string_append (str, "GSList"); if (node->parameter_type1) { g_string_append (str, "<"); serialize_type (build, node->parameter_type1, str); g_string_append (str, ">"); } } else if (node->tag == GI_TYPE_TAG_GHASH) { g_string_append (str, "GHashTable"); if (node->parameter_type1) { g_string_append (str, "<"); serialize_type (build, node->parameter_type1, str); g_string_append (str, ","); serialize_type (build, node->parameter_type2, str); g_string_append (str, ">"); } } else if (node->tag == GI_TYPE_TAG_ERROR) { g_string_append (str, "GError"); if (node->errors) { g_string_append (str, "<"); for (i = 0; node->errors[i]; i++) { if (i > 0) g_string_append (str, ","); g_string_append (str, node->errors[i]); } g_string_append (str, ">"); } } } static void gi_ir_node_build_members (GList **members, GIIrNodeTypeId type, uint16_t *count, GIIrNode *parent, GIIrTypelibBuild *build, uint32_t *offset, uint32_t *offset2, uint16_t *count2) { GList *l = *members; while (l) { GIIrNode *member = (GIIrNode *)l->data; GList *next = l->next; if (member->type == type) { (*count)++; gi_ir_node_build_typelib (member, parent, build, offset, offset2, count2); *members = g_list_delete_link (*members, l); } l = next; } } static void gi_ir_node_check_unhandled_members (GList **members, GIIrNodeTypeId container_type) { #if 0 if (*members) { GList *l; for (l = *members; l; l = l->next) { GIIrNode *member = (GIIrNode *)l->data; g_printerr ("Unhandled '%s' member '%s' type '%s'\n", gi_ir_node_type_to_string (container_type), member->name, gi_ir_node_type_to_string (member->type)); } g_list_free (*members); *members = NULL; g_error ("Unhandled members. Aborting."); } #else g_list_free (*members); *members = NULL; #endif } void gi_ir_node_build_typelib (GIIrNode *node, GIIrNode *parent, GIIrTypelibBuild *build, uint32_t *offset, uint32_t *offset2, uint16_t *count2) { gboolean appended_stack; GHashTable *strings = build->strings; GHashTable *types = build->types; uint8_t *data = build->data; GList *l; uint32_t old_offset = *offset; uint32_t old_offset2 = *offset2; g_assert (node != NULL); g_debug ("build_typelib: %s%s(%s)", node->name ? node->name : "", node->name ? " " : "", gi_ir_node_type_to_string (node->type)); if (build->stack) appended_stack = node != (GIIrNode*)build->stack->data; else appended_stack = TRUE; if (appended_stack) build->stack = g_list_prepend (build->stack, node); gi_ir_node_compute_offsets (build, node); /* 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->nodes_with_attributes = g_list_prepend (build->nodes_with_attributes, node); build->n_attributes += g_hash_table_size (node->attributes); switch (node->type) { case GI_IR_NODE_TYPE: { GIIrNodeType *type = (GIIrNodeType *)node; SimpleTypeBlob *blob = (SimpleTypeBlob *)&data[*offset]; *offset += sizeof (SimpleTypeBlob); if (GI_TYPE_TAG_IS_BASIC (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 { GString *str; char *s; gpointer value; str = g_string_new (0); serialize_type (build, type, str); s = g_string_free (str, FALSE); types_count += 1; value = g_hash_table_lookup (types, s); if (value) { blob->offset = GPOINTER_TO_UINT (value); g_free (s); } else { unique_types_count += 1; g_hash_table_insert (types, s, GUINT_TO_POINTER(*offset2)); blob->offset = *offset2; switch (type->tag) { case GI_TYPE_TAG_ARRAY: { ArrayTypeBlob *array = (ArrayTypeBlob *)&data[*offset2]; uint32_t pos; array->pointer = type->is_pointer; array->reserved = 0; array->tag = type->tag; array->zero_terminated = type->zero_terminated; array->has_length = type->has_length; array->has_size = type->has_size; array->array_type = type->array_type; array->reserved2 = 0; if (array->has_length) array->dimensions.length = type->length; else if (array->has_size) array->dimensions.size = type->size; else array->dimensions.length = -1; pos = *offset2 + G_STRUCT_OFFSET (ArrayTypeBlob, type); *offset2 += sizeof (ArrayTypeBlob); gi_ir_node_build_typelib ((GIIrNode *)type->parameter_type1, node, build, &pos, offset2, NULL); } break; case GI_TYPE_TAG_INTERFACE: { InterfaceTypeBlob *iface = (InterfaceTypeBlob *)&data[*offset2]; *offset2 += sizeof (InterfaceTypeBlob); iface->pointer = type->is_pointer; iface->reserved = 0; iface->tag = type->tag; iface->reserved2 = 0; iface->interface = find_entry (build, type->giinterface); } break; case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: { ParamTypeBlob *param = (ParamTypeBlob *)&data[*offset2]; uint32_t pos; param->pointer = 1; param->reserved = 0; param->tag = type->tag; param->reserved2 = 0; param->n_types = 1; pos = *offset2 + G_STRUCT_OFFSET (ParamTypeBlob, type); *offset2 += sizeof (ParamTypeBlob) + sizeof (SimpleTypeBlob); gi_ir_node_build_typelib ((GIIrNode *)type->parameter_type1, node, build, &pos, offset2, NULL); } break; case GI_TYPE_TAG_GHASH: { ParamTypeBlob *param = (ParamTypeBlob *)&data[*offset2]; uint32_t pos; param->pointer = 1; param->reserved = 0; param->tag = type->tag; param->reserved2 = 0; param->n_types = 2; pos = *offset2 + G_STRUCT_OFFSET (ParamTypeBlob, type); *offset2 += sizeof (ParamTypeBlob) + sizeof (SimpleTypeBlob)*2; gi_ir_node_build_typelib ((GIIrNode *)type->parameter_type1, node, build, &pos, offset2, NULL); gi_ir_node_build_typelib ((GIIrNode *)type->parameter_type2, node, build, &pos, offset2, NULL); } break; case GI_TYPE_TAG_ERROR: { ErrorTypeBlob *error_blob = (ErrorTypeBlob *)&data[*offset2]; error_blob->pointer = 1; error_blob->reserved = 0; error_blob->tag = type->tag; error_blob->reserved2 = 0; error_blob->n_domains = 0; *offset2 += sizeof (ErrorTypeBlob); } break; default: g_error ("Unknown type tag %d", type->tag); break; } } } } break; case GI_IR_NODE_FIELD: { GIIrNodeField *field = (GIIrNodeField *)node; FieldBlob *blob; blob = (FieldBlob *)&data[*offset]; blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->readable = field->readable; blob->writable = field->writable; blob->reserved = 0; blob->bits = 0; if (field->offset >= 0) blob->struct_offset = field->offset; else blob->struct_offset = 0xFFFF; /* mark as unknown */ if (field->callback) { blob->has_embedded_type = TRUE; blob->type.offset = GI_INFO_TYPE_CALLBACK; *offset += sizeof (FieldBlob); gi_ir_node_build_typelib ((GIIrNode *)field->callback, node, build, offset, offset2, NULL); /* Fields with callbacks are bigger than normal, update count2 * as an extra hint which represents the number of fields which are * callbacks. This allows us to gain constant time performance in the * repository for skipping over the fields section. */ if (count2) (*count2)++; } else { blob->has_embedded_type = FALSE; /* We handle the size member specially below, so subtract it */ *offset += sizeof (FieldBlob) - sizeof (SimpleTypeBlob); gi_ir_node_build_typelib ((GIIrNode *)field->type, node, build, offset, offset2, NULL); } } break; case GI_IR_NODE_PROPERTY: { GIIrNodeProperty *prop = (GIIrNodeProperty *)node; PropertyBlob *blob = (PropertyBlob *)&data[*offset]; /* We handle the size member specially below, so subtract it */ *offset += sizeof (PropertyBlob) - sizeof (SimpleTypeBlob); blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->deprecated = prop->deprecated; blob->readable = prop->readable; blob->writable = prop->writable; blob->construct = prop->construct; blob->construct_only = prop->construct_only; blob->transfer_ownership = prop->transfer; blob->transfer_container_ownership = prop->shallow_transfer; blob->reserved = 0; if (prop->setter != NULL) { int index = get_index_of_member_type ((GIIrNodeInterface*)parent, GI_IR_NODE_FUNCTION, prop->setter); if (index == -1) { g_error ("Unknown setter %s for property %s:%s", prop->setter, parent->name, node->name); } blob->setter = (uint16_t) index; } else blob->setter = ACCESSOR_SENTINEL; if (prop->getter != NULL) { int index = get_index_of_member_type ((GIIrNodeInterface*)parent, GI_IR_NODE_FUNCTION, prop->getter); if (index == -1) { g_error ("Unknown getter %s for property %s:%s", prop->getter, parent->name, node->name); } blob->getter = (uint16_t) index; } else blob->getter = ACCESSOR_SENTINEL; gi_ir_node_build_typelib ((GIIrNode *)prop->type, node, build, offset, offset2, NULL); } break; case GI_IR_NODE_FUNCTION: { FunctionBlob *blob = (FunctionBlob *)&data[*offset]; SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2]; GIIrNodeFunction *function = (GIIrNodeFunction *)node; uint32_t signature; unsigned int n; signature = *offset2; n = g_list_length (function->parameters); *offset += sizeof (FunctionBlob); *offset2 += sizeof (SignatureBlob) + n * sizeof (ArgBlob); blob->blob_type = BLOB_TYPE_FUNCTION; blob->deprecated = function->deprecated; blob->is_static = !function->is_method; blob->setter = FALSE; blob->getter = FALSE; blob->constructor = function->is_constructor; blob->wraps_vfunc = function->wraps_vfunc; blob->throws = function->throws; /* Deprecated. Also stored in SignatureBlob. */ blob->index = 0; blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->symbol = gi_ir_write_string (function->symbol, strings, data, offset2); blob->signature = signature; if (function->is_setter || function->is_getter) { int index = get_index_of_member_type ((GIIrNodeInterface*)parent, GI_IR_NODE_PROPERTY, function->property); if (index == -1) { g_error ("Unknown property %s:%s for accessor %s", parent->name, function->property, function->symbol); } blob->setter = function->is_setter; blob->getter = function->is_getter; blob->index = (uint16_t) index; } /* function->result is special since it doesn't appear in the serialized format but * we do want the attributes for it to appear */ build->nodes_with_attributes = g_list_prepend (build->nodes_with_attributes, function->result); build->n_attributes += g_hash_table_size (((GIIrNode *) function->result)->attributes); g_assert (((GIIrNode *) function->result)->offset == 0); ((GIIrNode *) function->result)->offset = signature; g_debug ("building function '%s'", function->symbol); gi_ir_node_build_typelib ((GIIrNode *)function->result->type, node, build, &signature, offset2, NULL); blob2->may_return_null = function->result->nullable; blob2->caller_owns_return_value = function->result->transfer; blob2->caller_owns_return_container = function->result->shallow_transfer; blob2->skip_return = function->result->skip; blob2->instance_transfer_ownership = function->instance_transfer_full; blob2->reserved = 0; blob2->n_arguments = n; blob2->throws = function->throws; signature += 4; for (l = function->parameters; l; l = l->next) { GIIrNode *param = (GIIrNode *)l->data; gi_ir_node_build_typelib (param, node, build, &signature, offset2, NULL); } } break; case GI_IR_NODE_CALLBACK: { CallbackBlob *blob = (CallbackBlob *)&data[*offset]; SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2]; GIIrNodeFunction *function = (GIIrNodeFunction *)node; uint32_t signature; unsigned int n; signature = *offset2; n = g_list_length (function->parameters); *offset += sizeof (CallbackBlob); *offset2 += sizeof (SignatureBlob) + n * sizeof (ArgBlob); blob->blob_type = BLOB_TYPE_CALLBACK; blob->deprecated = function->deprecated; blob->reserved = 0; blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->signature = signature; gi_ir_node_build_typelib ((GIIrNode *)function->result->type, node, build, &signature, offset2, NULL); blob2->may_return_null = function->result->nullable; blob2->caller_owns_return_value = function->result->transfer; blob2->caller_owns_return_container = function->result->shallow_transfer; blob2->reserved = 0; blob2->n_arguments = n; blob2->throws = function->throws; signature += 4; for (l = function->parameters; l; l = l->next) { GIIrNode *param = (GIIrNode *)l->data; gi_ir_node_build_typelib (param, node, build, &signature, offset2, NULL); } } break; case GI_IR_NODE_SIGNAL: { SignalBlob *blob = (SignalBlob *)&data[*offset]; SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2]; GIIrNodeSignal *signal = (GIIrNodeSignal *)node; uint32_t signature; unsigned int n; signature = *offset2; n = g_list_length (signal->parameters); *offset += sizeof (SignalBlob); *offset2 += sizeof (SignatureBlob) + n * sizeof (ArgBlob); blob->deprecated = signal->deprecated; blob->run_first = signal->run_first; blob->run_last = signal->run_last; blob->run_cleanup = signal->run_cleanup; blob->no_recurse = signal->no_recurse; blob->detailed = signal->detailed; blob->action = signal->action; blob->no_hooks = signal->no_hooks; blob->has_class_closure = 0; /* FIXME */ blob->true_stops_emit = 0; /* FIXME */ blob->reserved = 0; blob->class_closure = 0; /* FIXME */ blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->signature = signature; /* signal->result is special since it doesn't appear in the serialized format but * we do want the attributes for it to appear */ build->nodes_with_attributes = g_list_prepend (build->nodes_with_attributes, signal->result); build->n_attributes += g_hash_table_size (((GIIrNode *) signal->result)->attributes); g_assert (((GIIrNode *) signal->result)->offset == 0); ((GIIrNode *) signal->result)->offset = signature; gi_ir_node_build_typelib ((GIIrNode *)signal->result->type, node, build, &signature, offset2, NULL); blob2->may_return_null = signal->result->nullable; blob2->caller_owns_return_value = signal->result->transfer; blob2->caller_owns_return_container = signal->result->shallow_transfer; blob2->instance_transfer_ownership = signal->instance_transfer_full; blob2->reserved = 0; blob2->n_arguments = n; signature += 4; for (l = signal->parameters; l; l = l->next) { GIIrNode *param = (GIIrNode *)l->data; gi_ir_node_build_typelib (param, node, build, &signature, offset2, NULL); } } break; case GI_IR_NODE_VFUNC: { VFuncBlob *blob = (VFuncBlob *)&data[*offset]; SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2]; GIIrNodeVFunc *vfunc = (GIIrNodeVFunc *)node; uint32_t signature; unsigned int n; signature = *offset2; n = g_list_length (vfunc->parameters); *offset += sizeof (VFuncBlob); *offset2 += sizeof (SignatureBlob) + n * sizeof (ArgBlob); blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->must_chain_up = 0; /* FIXME */ blob->must_be_implemented = 0; /* FIXME */ blob->must_not_be_implemented = 0; /* FIXME */ blob->class_closure = 0; /* FIXME */ blob->throws = vfunc->throws; /* Deprecated. Also stored in SignatureBlob. */ blob->reserved = 0; if (vfunc->invoker) { int index = get_index_of_member_type ((GIIrNodeInterface*)parent, GI_IR_NODE_FUNCTION, vfunc->invoker); if (index == -1) { g_error ("Unknown member function %s for vfunc %s", vfunc->invoker, node->name); } blob->invoker = (uint16_t) index; } else blob->invoker = 0x3ff; /* max of 10 bits */ blob->struct_offset = vfunc->offset; blob->reserved2 = 0; blob->signature = signature; gi_ir_node_build_typelib ((GIIrNode *)vfunc->result->type, node, build, &signature, offset2, NULL); blob2->may_return_null = vfunc->result->nullable; blob2->caller_owns_return_value = vfunc->result->transfer; blob2->caller_owns_return_container = vfunc->result->shallow_transfer; blob2->instance_transfer_ownership = vfunc->instance_transfer_full; blob2->reserved = 0; blob2->n_arguments = n; blob2->throws = vfunc->throws; signature += 4; for (l = vfunc->parameters; l; l = l->next) { GIIrNode *param = (GIIrNode *)l->data; gi_ir_node_build_typelib (param, node, build, &signature, offset2, NULL); } } break; case GI_IR_NODE_PARAM: { ArgBlob *blob = (ArgBlob *)&data[*offset]; GIIrNodeParam *param = (GIIrNodeParam *)node; /* The offset for this one is smaller than the struct because * we recursively build the simple type inline here below. */ *offset += sizeof (ArgBlob) - sizeof (SimpleTypeBlob); blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->in = param->in; blob->out = param->out; blob->caller_allocates = param->caller_allocates; blob->nullable = param->nullable; blob->skip = param->skip; blob->optional = param->optional; blob->transfer_ownership = param->transfer; blob->transfer_container_ownership = param->shallow_transfer; blob->return_value = param->retval; blob->scope = param->scope; blob->reserved = 0; blob->closure = param->closure; blob->destroy = param->destroy; gi_ir_node_build_typelib ((GIIrNode *)param->type, node, build, offset, offset2, NULL); } break; case GI_IR_NODE_STRUCT: { StructBlob *blob = (StructBlob *)&data[*offset]; GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; GList *members; blob->blob_type = BLOB_TYPE_STRUCT; blob->foreign = struct_->foreign; blob->deprecated = struct_->deprecated; blob->is_gtype_struct = struct_->is_gtype_struct; blob->reserved = 0; blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->alignment = struct_->alignment; blob->size = struct_->size; if (struct_->gtype_name) { blob->unregistered = FALSE; blob->gtype_name = gi_ir_write_string (struct_->gtype_name, strings, data, offset2); blob->gtype_init = gi_ir_write_string (struct_->gtype_init, strings, data, offset2); } else { blob->unregistered = TRUE; blob->gtype_name = 0; blob->gtype_init = 0; } if (struct_->copy_func) blob->copy_func = gi_ir_write_string (struct_->copy_func, strings, data, offset2); if (struct_->free_func) blob->free_func = gi_ir_write_string (struct_->free_func, strings, data, offset2); blob->n_fields = 0; blob->n_methods = 0; *offset += sizeof (StructBlob); members = g_list_copy (struct_->members); gi_ir_node_build_members (&members, GI_IR_NODE_FIELD, &blob->n_fields, node, build, offset, offset2, NULL); gi_ir_node_build_members (&members, GI_IR_NODE_FUNCTION, &blob->n_methods, node, build, offset, offset2, NULL); gi_ir_node_check_unhandled_members (&members, node->type); g_assert (members == NULL); } break; case GI_IR_NODE_BOXED: { StructBlob *blob = (StructBlob *)&data[*offset]; GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; GList *members; blob->blob_type = BLOB_TYPE_BOXED; blob->deprecated = boxed->deprecated; blob->unregistered = FALSE; blob->reserved = 0; blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->gtype_name = gi_ir_write_string (boxed->gtype_name, strings, data, offset2); blob->gtype_init = gi_ir_write_string (boxed->gtype_init, strings, data, offset2); blob->alignment = boxed->alignment; blob->size = boxed->size; blob->n_fields = 0; blob->n_methods = 0; *offset += sizeof (StructBlob); members = g_list_copy (boxed->members); gi_ir_node_build_members (&members, GI_IR_NODE_FIELD, &blob->n_fields, node, build, offset, offset2, NULL); gi_ir_node_build_members (&members, GI_IR_NODE_FUNCTION, &blob->n_methods, node, build, offset, offset2, NULL); gi_ir_node_check_unhandled_members (&members, node->type); g_assert (members == NULL); } break; case GI_IR_NODE_UNION: { UnionBlob *blob = (UnionBlob *)&data[*offset]; GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; GList *members; blob->blob_type = BLOB_TYPE_UNION; blob->deprecated = union_->deprecated; blob->reserved = 0; blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->alignment = union_->alignment; blob->size = union_->size; if (union_->gtype_name) { blob->unregistered = FALSE; blob->gtype_name = gi_ir_write_string (union_->gtype_name, strings, data, offset2); blob->gtype_init = gi_ir_write_string (union_->gtype_init, strings, data, offset2); } else { blob->unregistered = TRUE; blob->gtype_name = 0; blob->gtype_init = 0; } blob->n_fields = 0; blob->n_functions = 0; blob->discriminator_offset = union_->discriminator_offset; if (union_->copy_func) blob->copy_func = gi_ir_write_string (union_->copy_func, strings, data, offset2); if (union_->free_func) blob->free_func = gi_ir_write_string (union_->free_func, strings, data, offset2); /* We don't support Union discriminators right now. */ /* if (union_->discriminator_type) { *offset += 28; blob->discriminated = TRUE; gi_ir_node_build_typelib ((GIIrNode *)union_->discriminator_type, build, offset, offset2, NULL); } else { */ *offset += sizeof (UnionBlob); blob->discriminated = FALSE; blob->discriminator_type.offset = 0; members = g_list_copy (union_->members); gi_ir_node_build_members (&members, GI_IR_NODE_FIELD, &blob->n_fields, node, build, offset, offset2, NULL); gi_ir_node_build_members (&members, GI_IR_NODE_FUNCTION, &blob->n_functions, node, build, offset, offset2, NULL); gi_ir_node_check_unhandled_members (&members, node->type); g_assert (members == NULL); if (union_->discriminator_type) { for (l = union_->discriminators; l; l = l->next) { GIIrNode *member = (GIIrNode *)l->data; gi_ir_node_build_typelib (member, node, build, offset, offset2, NULL); } } } break; case GI_IR_NODE_ENUM: case GI_IR_NODE_FLAGS: { EnumBlob *blob = (EnumBlob *)&data[*offset]; GIIrNodeEnum *enum_ = (GIIrNodeEnum *)node; *offset += sizeof (EnumBlob); if (node->type == GI_IR_NODE_ENUM) blob->blob_type = BLOB_TYPE_ENUM; else blob->blob_type = BLOB_TYPE_FLAGS; blob->deprecated = enum_->deprecated; blob->reserved = 0; blob->storage_type = enum_->storage_type; blob->name = gi_ir_write_string (node->name, strings, data, offset2); if (enum_->gtype_name) { blob->unregistered = FALSE; blob->gtype_name = gi_ir_write_string (enum_->gtype_name, strings, data, offset2); blob->gtype_init = gi_ir_write_string (enum_->gtype_init, strings, data, offset2); } else { blob->unregistered = TRUE; blob->gtype_name = 0; blob->gtype_init = 0; } if (enum_->error_domain) blob->error_domain = gi_ir_write_string (enum_->error_domain, strings, data, offset2); else blob->error_domain = 0; blob->n_values = 0; blob->n_methods = 0; for (l = enum_->values; l; l = l->next) { GIIrNode *value = (GIIrNode *)l->data; blob->n_values++; gi_ir_node_build_typelib (value, node, build, offset, offset2, NULL); } for (l = enum_->methods; l; l = l->next) { GIIrNode *method = (GIIrNode *)l->data; blob->n_methods++; gi_ir_node_build_typelib (method, node, build, offset, offset2, NULL); } } break; case GI_IR_NODE_OBJECT: { ObjectBlob *blob = (ObjectBlob *)&data[*offset]; GIIrNodeInterface *object = (GIIrNodeInterface *)node; GList *members; blob->blob_type = BLOB_TYPE_OBJECT; blob->abstract = object->abstract; blob->fundamental = object->fundamental; blob->final_ = object->final_; blob->deprecated = object->deprecated; blob->reserved = 0; blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->gtype_name = gi_ir_write_string (object->gtype_name, strings, data, offset2); blob->gtype_init = gi_ir_write_string (object->gtype_init, strings, data, offset2); if (object->ref_func) blob->ref_func = gi_ir_write_string (object->ref_func, strings, data, offset2); if (object->unref_func) blob->unref_func = gi_ir_write_string (object->unref_func, strings, data, offset2); if (object->set_value_func) blob->set_value_func = gi_ir_write_string (object->set_value_func, strings, data, offset2); if (object->get_value_func) blob->get_value_func = gi_ir_write_string (object->get_value_func, strings, data, offset2); if (object->parent) blob->parent = find_entry (build, object->parent); else blob->parent = 0; if (object->glib_type_struct) blob->gtype_struct = find_entry (build, object->glib_type_struct); else blob->gtype_struct = 0; blob->n_interfaces = 0; blob->n_fields = 0; blob->n_properties = 0; blob->n_methods = 0; blob->n_signals = 0; blob->n_vfuncs = 0; blob->n_constants = 0; blob->n_field_callbacks = 0; *offset += sizeof(ObjectBlob); for (l = object->interfaces; l; l = l->next) { blob->n_interfaces++; *(uint16_t *)&data[*offset] = find_entry (build, (char *)l->data); *offset += 2; } members = g_list_copy (object->members); *offset = ALIGN_VALUE (*offset, 4); gi_ir_node_build_members (&members, GI_IR_NODE_FIELD, &blob->n_fields, node, build, offset, offset2, &blob->n_field_callbacks); *offset = ALIGN_VALUE (*offset, 4); gi_ir_node_build_members (&members, GI_IR_NODE_PROPERTY, &blob->n_properties, node, build, offset, offset2, NULL); *offset = ALIGN_VALUE (*offset, 4); gi_ir_node_build_members (&members, GI_IR_NODE_FUNCTION, &blob->n_methods, node, build, offset, offset2, NULL); *offset = ALIGN_VALUE (*offset, 4); gi_ir_node_build_members (&members, GI_IR_NODE_SIGNAL, &blob->n_signals, node, build, offset, offset2, NULL); *offset = ALIGN_VALUE (*offset, 4); gi_ir_node_build_members (&members, GI_IR_NODE_VFUNC, &blob->n_vfuncs, node, build, offset, offset2, NULL); *offset = ALIGN_VALUE (*offset, 4); gi_ir_node_build_members (&members, GI_IR_NODE_CONSTANT, &blob->n_constants, node, build, offset, offset2, NULL); gi_ir_node_check_unhandled_members (&members, node->type); g_assert (members == NULL); } break; case GI_IR_NODE_INTERFACE: { InterfaceBlob *blob = (InterfaceBlob *)&data[*offset]; GIIrNodeInterface *iface = (GIIrNodeInterface *)node; GList *members; blob->blob_type = BLOB_TYPE_INTERFACE; blob->deprecated = iface->deprecated; blob->reserved = 0; blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->gtype_name = gi_ir_write_string (iface->gtype_name, strings, data, offset2); blob->gtype_init = gi_ir_write_string (iface->gtype_init, strings, data, offset2); if (iface->glib_type_struct) blob->gtype_struct = find_entry (build, iface->glib_type_struct); else blob->gtype_struct = 0; blob->n_prerequisites = 0; blob->n_properties = 0; blob->n_methods = 0; blob->n_signals = 0; blob->n_vfuncs = 0; blob->n_constants = 0; *offset += sizeof (InterfaceBlob); for (l = iface->prerequisites; l; l = l->next) { blob->n_prerequisites++; *(uint16_t *)&data[*offset] = find_entry (build, (char *)l->data); *offset += 2; } members = g_list_copy (iface->members); *offset = ALIGN_VALUE (*offset, 4); gi_ir_node_build_members (&members, GI_IR_NODE_PROPERTY, &blob->n_properties, node, build, offset, offset2, NULL); *offset = ALIGN_VALUE (*offset, 4); gi_ir_node_build_members (&members, GI_IR_NODE_FUNCTION, &blob->n_methods, node, build, offset, offset2, NULL); *offset = ALIGN_VALUE (*offset, 4); gi_ir_node_build_members (&members, GI_IR_NODE_SIGNAL, &blob->n_signals, node, build, offset, offset2, NULL); *offset = ALIGN_VALUE (*offset, 4); gi_ir_node_build_members (&members, GI_IR_NODE_VFUNC, &blob->n_vfuncs, node, build, offset, offset2, NULL); *offset = ALIGN_VALUE (*offset, 4); gi_ir_node_build_members (&members, GI_IR_NODE_CONSTANT, &blob->n_constants, node, build, offset, offset2, NULL); gi_ir_node_check_unhandled_members (&members, node->type); g_assert (members == NULL); } break; case GI_IR_NODE_VALUE: { GIIrNodeValue *value = (GIIrNodeValue *)node; ValueBlob *blob = (ValueBlob *)&data[*offset]; *offset += sizeof (ValueBlob); blob->deprecated = value->deprecated; blob->reserved = 0; blob->unsigned_value = value->value >= 0 ? 1 : 0; blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->value = (int32_t) value->value; } break; case GI_IR_NODE_CONSTANT: { GIIrNodeConstant *constant = (GIIrNodeConstant *)node; ConstantBlob *blob = (ConstantBlob *)&data[*offset]; uint32_t pos; pos = *offset + G_STRUCT_OFFSET (ConstantBlob, type); *offset += sizeof (ConstantBlob); blob->blob_type = BLOB_TYPE_CONSTANT; blob->deprecated = constant->deprecated; blob->reserved = 0; blob->name = gi_ir_write_string (node->name, strings, data, offset2); blob->offset = *offset2; switch (constant->type->tag) { case GI_TYPE_TAG_BOOLEAN: blob->size = 4; *(gboolean*)&data[blob->offset] = parse_boolean_value (constant->value); break; case GI_TYPE_TAG_INT8: blob->size = 1; *(int8_t *)&data[blob->offset] = (int8_t) parse_int_value (constant->value); break; case GI_TYPE_TAG_UINT8: blob->size = 1; *(uint8_t *)&data[blob->offset] = (uint8_t) parse_uint_value (constant->value); break; case GI_TYPE_TAG_INT16: blob->size = 2; *(int16_t *)&data[blob->offset] = (int16_t) parse_int_value (constant->value); break; case GI_TYPE_TAG_UINT16: blob->size = 2; *(uint16_t *)&data[blob->offset] = (uint16_t) parse_uint_value (constant->value); break; case GI_TYPE_TAG_INT32: blob->size = 4; *(int32_t *)&data[blob->offset] = (int32_t) parse_int_value (constant->value); break; case GI_TYPE_TAG_UINT32: blob->size = 4; *(uint32_t*)&data[blob->offset] = (uint32_t) parse_uint_value (constant->value); break; case GI_TYPE_TAG_INT64: blob->size = 8; DO_ALIGNED_COPY (&data[blob->offset], parse_int_value (constant->value), int64_t); break; case GI_TYPE_TAG_UINT64: blob->size = 8; DO_ALIGNED_COPY (&data[blob->offset], parse_uint_value (constant->value), uint64_t); break; case GI_TYPE_TAG_FLOAT: blob->size = sizeof (float); DO_ALIGNED_COPY (&data[blob->offset], parse_float_value (constant->value), float); break; case GI_TYPE_TAG_DOUBLE: blob->size = sizeof (double); DO_ALIGNED_COPY (&data[blob->offset], parse_float_value (constant->value), double); break; case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: blob->size = strlen (constant->value) + 1; memcpy (&data[blob->offset], constant->value, blob->size); break; default: break; } *offset2 += ALIGN_VALUE (blob->size, 4); gi_ir_node_build_typelib ((GIIrNode *)constant->type, node, build, &pos, offset2, NULL); } break; default: g_assert_not_reached (); } g_debug ("node %s%s%s%p type '%s', offset %d -> %d, offset2 %d -> %d", node->name ? "'" : "", node->name ? node->name : "", node->name ? "' " : "", node, gi_ir_node_type_to_string (node->type), old_offset, *offset, old_offset2, *offset2); if (*offset2 - old_offset2 + *offset - old_offset > gi_ir_node_get_full_size (node)) g_error ("exceeding space reservation; offset: %d (prev %d) offset2: %d (prev %d) nodesize: %d", *offset, old_offset, *offset2, old_offset2, gi_ir_node_get_full_size (node)); if (appended_stack) build->stack = g_list_delete_link (build->stack, build->stack); } /* if str is already in the pool, return previous location, otherwise write str * to the typelib at offset, put it in the pool and update offset. If the * typelib is not large enough to hold the string, reallocate it. */ uint32_t gi_ir_write_string (const char *str, GHashTable *strings, uint8_t *data, uint32_t *offset) { uint32_t start; void *value; string_count += 1; string_size += strlen (str); value = g_hash_table_lookup (strings, str); if (value) return GPOINTER_TO_UINT (value); unique_string_count += 1; unique_string_size += strlen (str); g_hash_table_insert (strings, (void *)str, GUINT_TO_POINTER (*offset)); start = *offset; *offset = ALIGN_VALUE (start + strlen (str) + 1, 4); strcpy ((char *)&data[start], str); return start; }