got rid of g_set_error_handler(), g_set_warning_handler(),
[platform/upstream/glib.git] / gobject / gtype.c
1 /* GObject - GLib Type, Object, Parameter and Signal Library
2  * Copyright (C) 1998-1999, 2000-2001 Tim Janik and Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General
15  * Public License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include        "gtype.h"
20
21 /*
22  * MT safe
23  */
24
25 #include        "gtypeplugin.h"
26 #include        "gvaluecollector.h"
27 #include        <string.h>
28
29
30 /* NOTE: some functions (some internal variants and exported ones)
31  * invalidate data portions of the TypeNodes. if external functions/callbacks
32  * are called, pointers to memory maintained by TypeNodes have to be looked up
33  * again. this affects most of the struct TypeNode fields, e.g. ->children or
34  * CLASSED_NODE_IFACES_ENTRIES() respectively IFACE_NODE_PREREQUISITES() (but
35  * not ->supers[]), as all those memory portions can get realloc()ed during
36  * callback invocation.
37  *
38  * TODO:
39  * - g_type_from_name() should do an ordered array lookup after fetching the
40  *   the quark, instead of a second hashtable lookup.
41  * - speedup checks for virtual types, steal a bit somewhere
42  *
43  * FIXME:
44  * - force interface initialization for already existing classes
45  *
46  * LOCKING:
47  * lock handling issues when calling static functions are indicated by
48  * uppercase letter postfixes, all static functions have to have
49  * one of the below postfixes:
50  * - _I:        [Indifferent about locking]
51  *   function doesn't care about locks at all
52  * - _U:        [Unlocked invocation]
53  *   no read or write lock has to be held across function invocation
54  *   (locks may be acquired and released during invocation though)
55  * - _L:        [Locked invocation]
56  *   a write lock or more than 0 read locks have to be held across
57  *   function invocation
58  * - _W:        [Write-locked invocation]
59  *   a write lock has to be held across function invokation
60  * - _Wm:       [Write-locked invocation, mutatable]
61  *   like _W, but the write lock might be released and reacquired
62  *   during invocation, watch your pointers
63  */
64
65 static GStaticRWLock            type_rw_lock = G_STATIC_RW_LOCK_INIT;
66 #define G_READ_LOCK(rw_lock)    g_static_rw_lock_reader_lock (rw_lock)
67 #define G_READ_UNLOCK(rw_lock)  g_static_rw_lock_reader_unlock (rw_lock)
68 #define G_WRITE_LOCK(rw_lock)   g_static_rw_lock_writer_lock (rw_lock)
69 #define G_WRITE_UNLOCK(rw_lock) g_static_rw_lock_writer_unlock (rw_lock)
70 #define INVALID_RECURSION(func, arg, type_name) G_STMT_START{ \
71     static const gchar *_action = " invalidly modified type "; \
72     gpointer _arg = (gpointer) (arg); const gchar *_tname = (type_name), *_fname = (func); \
73     if (_arg) \
74       g_error ("%s(%p)%s`%s'", _fname, _arg, _action, _tname); \
75     else \
76       g_error ("%s()%s`%s'", _fname, _action, _tname); \
77 }G_STMT_END
78 #define g_return_val_if_uninitialized(condition, init_function, return_value) G_STMT_START{     \
79   if (!(condition))                                                                             \
80     {                                                                                           \
81       g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,                                                \
82              "%s: initialization assertion failed, use %s() prior to this function",            \
83              G_STRLOC, G_STRINGIFY (init_function));                                            \
84       return (return_value);                                                                    \
85     }                                                                                           \
86 }G_STMT_END
87
88 #ifdef  G_ENABLE_DEBUG
89 #define DEBUG_CODE(debug_type, code_block)  G_STMT_START {    \
90     if (_g_type_debug_flags & G_TYPE_DEBUG_ ## debug_type) \
91       { code_block; }                                     \
92 } G_STMT_END
93 #else /* !G_ENABLE_DEBUG */
94 #define DEBUG_CODE(debug_type, code_block)  /* code_block */
95 #endif  /* G_ENABLE_DEBUG */
96
97 #define TYPE_FUNDAMENTAL_FLAG_MASK (G_TYPE_FLAG_CLASSED | \
98                                     G_TYPE_FLAG_INSTANTIATABLE | \
99                                     G_TYPE_FLAG_DERIVABLE | \
100                                     G_TYPE_FLAG_DEEP_DERIVABLE)
101 #define TYPE_FLAG_MASK             (G_TYPE_FLAG_ABSTRACT | G_TYPE_FLAG_VALUE_ABSTRACT)
102 #define SIZEOF_FUNDAMENTAL_INFO    ((gssize) MAX (MAX (sizeof (GTypeFundamentalInfo), \
103                                                        sizeof (gpointer)), \
104                                                   sizeof (glong)))
105
106
107 /* --- typedefs --- */
108 typedef struct _TypeNode        TypeNode;
109 typedef struct _CommonData      CommonData;
110 typedef struct _IFaceData       IFaceData;
111 typedef struct _ClassData       ClassData;
112 typedef struct _InstanceData    InstanceData;
113 typedef union  _TypeData        TypeData;
114 typedef struct _IFaceEntry      IFaceEntry;
115 typedef struct _IFaceHolder     IFaceHolder;
116
117
118 /* --- prototypes --- */
119 static inline GTypeFundamentalInfo*     type_node_fundamental_info_L    (TypeNode               *node);
120 static        void                      type_add_flags_W                (TypeNode               *node,
121                                                                          GTypeFlags              flags);
122 static        void                      type_data_make_W                (TypeNode               *node,
123                                                                          const GTypeInfo        *info,
124                                                                          const GTypeValueTable  *value_table);
125 static inline void                      type_data_ref_Wm                (TypeNode               *node);
126 static inline void                      type_data_unref_Wm              (TypeNode               *node,
127                                                                          gboolean                uncached);
128 static        void                      type_data_last_unref_Wm         (GType                   type,
129                                                                          gboolean                uncached);
130 static inline gpointer                  type_get_qdata_L                (TypeNode               *node,
131                                                                          GQuark                  quark);
132 static inline void                      type_set_qdata_W                (TypeNode               *node,
133                                                                          GQuark                  quark,
134                                                                          gpointer                data);
135 static IFaceHolder*                     type_iface_peek_holder_L        (TypeNode               *iface,
136                                                                          GType                   instance_type);
137
138
139 /* --- structures --- */
140 struct _GValue  /* kludge, keep in sync with gvalue.h */
141 {
142   GType g_type;
143 };
144 struct _TypeNode
145 {
146   GTypePlugin *plugin;
147   guint        n_children : 12;
148   guint        n_supers : 8;
149   guint        _prot_n_ifaces_prerequisites : 9;
150   guint        is_classed : 1;
151   guint        is_instantiatable : 1;
152   guint        free_flag : 1;
153   GType       *children;
154   TypeData    *data;
155   GQuark       qname;
156   GData       *global_gdata;
157   union {
158     IFaceEntry  *iface_entries;         /* for !iface types */
159     GType       *prerequisistes;
160   } _prot;
161   GType        supers[1]; /* flexible array */
162 };
163 #define SIZEOF_BASE_TYPE_NODE()                 (G_STRUCT_OFFSET (TypeNode, supers))
164 #define MAX_N_SUPERS                            (255)
165 #define MAX_N_CHILDREN                          (4095)
166 #define MAX_N_IFACES                            (511)
167 #define MAX_N_PREREQUISITES                     (MAX_N_IFACES)
168 #define NODE_TYPE(node)                         (node->supers[0])
169 #define NODE_PARENT_TYPE(node)                  (node->supers[1])
170 #define NODE_NAME(node)                         (g_quark_to_string (node->qname))
171 #define NODE_IS_IFACE(node)                     (G_TYPE_IS_INTERFACE (NODE_TYPE (node)))
172 #define CLASSED_NODE_N_IFACES(node)             ((node)->_prot_n_ifaces_prerequisites)
173 #define CLASSED_NODE_IFACES_ENTRIES(node)       ((node)->_prot.iface_entries)
174 #define IFACE_NODE_N_PREREQUISITES(node)        ((node)->_prot_n_ifaces_prerequisites)
175 #define IFACE_NODE_PREREQUISITES(node)          ((node)->_prot.prerequisistes)
176 #define iface_node_get_holders_L(node)          ((IFaceHolder*) type_get_qdata_L ((node), static_quark_iface_holder))
177 #define iface_node_set_holders_W(node, holders) (type_set_qdata_W ((node), static_quark_iface_holder, (holders)))
178 #define iface_node_get_dependants_array_L(n)    ((GType*) type_get_qdata_L ((n), static_quark_dependants_array))
179 #define iface_node_set_dependants_array_W(n,d)  (type_set_qdata_W ((n), static_quark_dependants_array, (d)))
180
181 struct _IFaceHolder
182 {
183   GType           instance_type;
184   GInterfaceInfo *info;
185   GTypePlugin    *plugin;
186   IFaceHolder    *next;
187 };
188 struct _IFaceEntry
189 {
190   GType           iface_type;
191   GTypeInterface *vtable;
192 };
193 struct _CommonData
194 {
195   guint             ref_count;
196   GTypeValueTable  *value_table;
197 };
198 struct _IFaceData
199 {
200   CommonData         common;
201   guint16            vtable_size;
202   GBaseInitFunc      vtable_init_base;
203   GBaseFinalizeFunc  vtable_finalize_base;
204 };
205 struct _ClassData
206 {
207   CommonData         common;
208   guint16            class_size;
209   GBaseInitFunc      class_init_base;
210   GBaseFinalizeFunc  class_finalize_base;
211   GClassInitFunc     class_init;
212   GClassFinalizeFunc class_finalize;
213   gconstpointer      class_data;
214   gpointer           class;
215 };
216 struct _InstanceData
217 {
218   CommonData         common;
219   guint16            class_size;
220   GBaseInitFunc      class_init_base;
221   GBaseFinalizeFunc  class_finalize_base;
222   GClassInitFunc     class_init;
223   GClassFinalizeFunc class_finalize;
224   gconstpointer      class_data;
225   gpointer           class;
226   guint16            instance_size;
227   guint16            n_preallocs;
228   GInstanceInitFunc  instance_init;
229   GMemChunk        *mem_chunk;
230 };
231 union _TypeData
232 {
233   CommonData         common;
234   IFaceData          iface;
235   ClassData          class;
236   InstanceData       instance;
237 };
238 typedef struct {
239   gpointer            cache_data;
240   GTypeClassCacheFunc cache_func;
241 } ClassCacheFunc;
242
243
244 /* --- variables --- */
245 static guint           static_n_class_cache_funcs = 0;
246 static ClassCacheFunc *static_class_cache_funcs = NULL;
247 static GType           static_last_fundamental_id = 0;
248 static GQuark          static_quark_type_flags = 0;
249 static GQuark          static_quark_iface_holder = 0;
250 static GQuark          static_quark_dependants_array = 0;
251 GTypeDebugFlags        _g_type_debug_flags = 0;
252
253
254 /* --- externs --- */
255 const char  *g_log_domain_gruntime = "GRuntime";
256
257
258 /* --- type nodes --- */
259 static GHashTable       *static_type_nodes_ht = NULL;
260 static GType            *static_branch_seqnos = NULL;
261 static TypeNode       ***static_type_nodes = NULL;
262
263 static inline TypeNode*
264 lookup_type_node_L (register GType utype)
265 {
266   register GType ftype = G_TYPE_FUNDAMENTAL (utype);
267   register GType b_seqno = G_TYPE_BRANCH_SEQNO (utype);
268   
269   if (ftype < static_last_fundamental_id && b_seqno < static_branch_seqnos[ftype])
270     return static_type_nodes[ftype][b_seqno];
271   else
272     return NULL;
273 }
274
275 static TypeNode*
276 type_node_any_new_W (TypeNode             *pnode,
277                      GType                 ftype,
278                      const gchar          *name,
279                      GTypePlugin          *plugin,
280                      GTypeFundamentalFlags type_flags)
281 {
282   guint branch_last, n_supers;
283   GType type;
284   TypeNode *node;
285   guint i, node_size = 0;
286   
287   n_supers = pnode ? pnode->n_supers + 1 : 0;
288   branch_last = static_branch_seqnos[ftype]++;
289   type = G_TYPE_DERIVE_ID (ftype, branch_last);
290   g_assert ((type & G_TYPE_FLAG_RESERVED_ID_BIT) == 0);
291   if (!branch_last || g_bit_storage (branch_last - 1) < g_bit_storage (static_branch_seqnos[ftype] - 1))
292     static_type_nodes[ftype] = g_renew (TypeNode*, static_type_nodes[ftype], 1 << g_bit_storage (static_branch_seqnos[ftype] - 1));
293   
294   if (!pnode)
295     node_size += SIZEOF_FUNDAMENTAL_INFO;             /* fundamental type info */
296   node_size += SIZEOF_BASE_TYPE_NODE ();              /* TypeNode structure */
297   node_size += (sizeof (GType) * (1 + n_supers + 1)); /* self + ancestors + 0 for ->supers[] */
298   node = g_malloc0 (node_size);
299   if (!pnode)                                         /* offset fundamental types */
300     node = G_STRUCT_MEMBER_P (node, SIZEOF_FUNDAMENTAL_INFO);
301   static_type_nodes[ftype][branch_last] = node;
302   
303   node->n_supers = n_supers;
304   if (!pnode)
305     {
306       node->supers[0] = type;
307       node->supers[1] = 0;
308       
309       node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0;
310       node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0;
311       
312       if (NODE_IS_IFACE (node))
313         {
314           IFACE_NODE_N_PREREQUISITES (node) = 0;
315           IFACE_NODE_PREREQUISITES (node) = NULL;
316         }
317       else
318         {
319           CLASSED_NODE_N_IFACES (node) = 0;
320           CLASSED_NODE_IFACES_ENTRIES (node) = NULL;
321         }
322     }
323   else
324     {
325       node->supers[0] = type;
326       memcpy (node->supers + 1, pnode->supers, sizeof (GType) * (1 + pnode->n_supers + 1));
327       
328       node->is_classed = pnode->is_classed;
329       node->is_instantiatable = pnode->is_instantiatable;
330       
331       if (NODE_IS_IFACE (node))
332         {
333           IFACE_NODE_N_PREREQUISITES (node) = 0;
334           IFACE_NODE_PREREQUISITES (node) = NULL;
335         }
336       else
337         {
338           guint j;
339
340           CLASSED_NODE_N_IFACES (node) = CLASSED_NODE_N_IFACES (pnode);
341           CLASSED_NODE_IFACES_ENTRIES (node) = g_memdup (CLASSED_NODE_IFACES_ENTRIES (pnode),
342                                                          sizeof (CLASSED_NODE_IFACES_ENTRIES (pnode)[0]) *
343                                                          CLASSED_NODE_N_IFACES (node));
344           for (j = 0; j < CLASSED_NODE_N_IFACES (node); j++)
345             CLASSED_NODE_IFACES_ENTRIES (node)[j].vtable = NULL;
346         }
347       
348       i = pnode->n_children++;
349       pnode->children = g_renew (GType, pnode->children, pnode->n_children);
350       pnode->children[i] = type;
351     }
352   
353   node->plugin = plugin;
354   node->n_children = 0;
355   node->children = NULL;
356   node->data = NULL;
357   node->qname = g_quark_from_string (name);
358   node->global_gdata = NULL;
359   
360   g_hash_table_insert (static_type_nodes_ht,
361                        GUINT_TO_POINTER (node->qname),
362                        GUINT_TO_POINTER (type));
363   return node;
364 }
365
366 static inline GTypeFundamentalInfo*
367 type_node_fundamental_info_L (TypeNode *node)
368 {
369   GType ftype = G_TYPE_FUNDAMENTAL (NODE_TYPE (node));
370   
371   if (ftype != NODE_TYPE (node))
372     node = lookup_type_node_L (ftype);
373   
374   return node ? G_STRUCT_MEMBER_P (node, - SIZEOF_FUNDAMENTAL_INFO) : NULL;
375 }
376
377 static TypeNode*
378 type_node_fundamental_new_W (GType                 ftype,
379                              const gchar          *name,
380                              GTypeFundamentalFlags type_flags)
381 {
382   GTypeFundamentalInfo *finfo;
383   TypeNode *node;
384   guint i, flast;
385   
386   flast = static_last_fundamental_id;
387   
388   g_assert (ftype == G_TYPE_FUNDAMENTAL (ftype));
389   
390   type_flags &= TYPE_FUNDAMENTAL_FLAG_MASK;
391   
392   static_last_fundamental_id = MAX (static_last_fundamental_id, ftype + 1);
393   if (static_last_fundamental_id > flast)
394     {
395       static_type_nodes = g_renew (TypeNode**, static_type_nodes, static_last_fundamental_id);
396       static_branch_seqnos = g_renew (GType, static_branch_seqnos, static_last_fundamental_id);
397       for (i = flast; i < static_last_fundamental_id; i++)
398         {
399           static_type_nodes[i] = NULL;
400           static_branch_seqnos[i] = 0;
401         }
402     }
403   g_assert (static_branch_seqnos[ftype] == 0);
404   
405   node = type_node_any_new_W (NULL, ftype, name, NULL, type_flags);
406   
407   finfo = type_node_fundamental_info_L (node);
408   finfo->type_flags = type_flags;
409   
410   return node;
411 }
412
413 static TypeNode*
414 type_node_new_W (TypeNode    *pnode,
415                  const gchar *name,
416                  GTypePlugin *plugin)
417      
418 {
419   g_assert (pnode);
420   g_assert (pnode->n_supers < MAX_N_SUPERS);
421   g_assert (pnode->n_children < MAX_N_CHILDREN);
422   
423   return type_node_any_new_W (pnode, G_TYPE_FUNDAMENTAL (NODE_TYPE (pnode)), name, plugin, 0);
424 }
425
426 static inline IFaceEntry*
427 type_lookup_iface_entry_L (TypeNode *node,
428                            TypeNode *iface_node)
429 {
430   if (NODE_IS_IFACE (iface_node) && CLASSED_NODE_N_IFACES (node))
431     {
432       IFaceEntry *ifaces = CLASSED_NODE_IFACES_ENTRIES (node) - 1;
433       guint n_ifaces = CLASSED_NODE_N_IFACES (node);
434       GType iface_type = NODE_TYPE (iface_node);
435       
436       do
437         {
438           guint i;
439           IFaceEntry *check;
440           
441           i = (n_ifaces + 1) >> 1;
442           check = ifaces + i;
443           if (iface_type == check->iface_type)
444             return check;
445           else if (iface_type > check->iface_type)
446             {
447               n_ifaces -= i;
448               ifaces = check;
449             }
450           else /* if (iface_type < check->iface_type) */
451             n_ifaces = i - 1;
452         }
453       while (n_ifaces);
454     }
455   
456   return NULL;
457 }
458
459 static inline gboolean
460 type_lookup_prerequisite_L (TypeNode *iface,
461                             GType     prerequisite_type)
462 {
463   if (NODE_IS_IFACE (iface) && IFACE_NODE_N_PREREQUISITES (iface))
464     {
465       GType *prerequisites = IFACE_NODE_PREREQUISITES (iface) - 1;
466       guint n_prerequisites = IFACE_NODE_N_PREREQUISITES (iface);
467
468       do
469         {
470           guint i;
471           GType *check;
472           
473           i = (n_prerequisites + 1) >> 1;
474           check = prerequisites + i;
475           if (prerequisite_type == *check)
476             return TRUE;
477           else if (prerequisite_type > *check)
478             {
479               n_prerequisites -= i;
480               prerequisites = check;
481             }
482           else /* if (prerequisite_type < *check) */
483             n_prerequisites = i - 1;
484         }
485       while (n_prerequisites);
486     }
487   return FALSE;
488 }
489
490 static inline gchar*
491 type_descriptive_name_L (GType type)
492 {
493   if (type)
494     {
495       TypeNode *node = lookup_type_node_L (type);
496       
497       return node ? NODE_NAME (node) : "<unknown>";
498     }
499   else
500     return "<invalid>";
501 }
502
503 static inline gchar*
504 type_descriptive_name_U (GType type)
505 {
506   const gchar *name;
507   
508   G_READ_LOCK (&type_rw_lock);
509   name = type_descriptive_name_L (type);
510   G_READ_UNLOCK (&type_rw_lock);
511   
512   return (gchar *)name;
513 }
514
515
516 /* --- type consistency checks --- */
517 static gboolean
518 check_plugin_U (GTypePlugin *plugin,
519                 gboolean     need_complete_type_info,
520                 gboolean     need_complete_interface_info,
521                 const gchar *type_name)
522 {
523   /* G_IS_TYPE_PLUGIN() and G_TYPE_PLUGIN_GET_CLASS() are external calls: _U 
524    */
525   if (!plugin)
526     {
527       g_warning ("plugin handle for type `%s' is NULL",
528                  type_name);
529       return FALSE;
530     }
531   if (!G_IS_TYPE_PLUGIN (plugin))
532     {
533       g_warning ("plugin pointer (%p) for type `%s' is invalid",
534                  plugin, type_name);
535       return FALSE;
536     }
537   if (need_complete_type_info && !G_TYPE_PLUGIN_GET_CLASS (plugin)->complete_type_info)
538     {
539       g_warning ("plugin for type `%s' has no complete_type_info() implementation",
540                  type_name);
541       return FALSE;
542     }
543   if (need_complete_interface_info && !G_TYPE_PLUGIN_GET_CLASS (plugin)->complete_interface_info)
544     {
545       g_warning ("plugin for type `%s' has no complete_interface_info() implementation",
546                  type_name);
547       return FALSE;
548     }
549   return TRUE;
550 }
551
552 static gboolean
553 check_type_name_U (const gchar *type_name)
554 {
555   static const gchar *extra_chars = "-_+";
556   const gchar *p = type_name;
557   gboolean name_valid;
558   
559   if (!type_name[0] || !type_name[1] || !type_name[2])
560     {
561       g_warning ("type name `%s' is too short", type_name);
562       return FALSE;
563     }
564   /* check the first letter */
565   name_valid = (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || p[0] == '_';
566   for (p = type_name + 1; *p; p++)
567     name_valid &= ((p[0] >= 'A' && p[0] <= 'Z') ||
568                    (p[0] >= 'a' && p[0] <= 'z') ||
569                    (p[0] >= '0' && p[0] <= '9') ||
570                    strchr (extra_chars, p[0]));
571   if (!name_valid)
572     {
573       g_warning ("type name `%s' contains invalid characters", type_name);
574       return FALSE;
575     }
576   if (g_type_from_name (type_name))
577     {
578       g_warning ("cannot register existing type `%s'", type_name);
579       return FALSE;
580     }
581   
582   return TRUE;
583 }
584
585 static gboolean
586 check_derivation_U (GType        parent_type,
587                     const gchar *type_name)
588 {
589   TypeNode *pnode;
590   GTypeFundamentalInfo* finfo;
591   
592   G_READ_LOCK (&type_rw_lock);
593   pnode = lookup_type_node_L (parent_type);
594   if (!pnode)
595     {
596       G_READ_UNLOCK (&type_rw_lock);
597       g_warning ("cannot derive type `%s' from invalid parent type `%s'",
598                  type_name,
599                  type_descriptive_name_U (parent_type));
600       return FALSE;
601     }
602   finfo = type_node_fundamental_info_L (pnode);
603   /* ensure flat derivability */
604   if (!(finfo->type_flags & G_TYPE_FLAG_DERIVABLE))
605     {
606       G_READ_UNLOCK (&type_rw_lock);
607       g_warning ("cannot derive `%s' from non-derivable parent type `%s'",
608                  type_name,
609                  NODE_NAME (pnode));
610       return FALSE;
611     }
612   /* ensure deep derivability */
613   if (parent_type != G_TYPE_FUNDAMENTAL (parent_type) &&
614       !(finfo->type_flags & G_TYPE_FLAG_DEEP_DERIVABLE))
615     {
616       G_READ_UNLOCK (&type_rw_lock);
617       g_warning ("cannot derive `%s' from non-fundamental parent type `%s'",
618                  type_name,
619                  NODE_NAME (pnode));
620       return FALSE;
621     }
622   G_READ_UNLOCK (&type_rw_lock);
623   
624   return TRUE;
625 }
626
627 static gboolean
628 check_collect_format_I (const gchar *collect_format)
629 {
630   const gchar *p = collect_format;
631   gchar valid_format[] = { G_VALUE_COLLECT_INT, G_VALUE_COLLECT_LONG,
632                            G_VALUE_COLLECT_DOUBLE, G_VALUE_COLLECT_POINTER,
633                            0 };
634
635   while (*p)
636     if (!strchr (valid_format, *p++))
637       return FALSE;
638   return p - collect_format <= G_VALUE_COLLECT_FORMAT_MAX_LENGTH;
639 }
640
641 static gboolean
642 check_value_table_I (const gchar           *type_name,
643                      const GTypeValueTable *value_table)
644 {
645   if (!value_table)
646     return FALSE;
647   else if (value_table->value_init == NULL)
648     {
649       if (value_table->value_free || value_table->value_copy ||
650           value_table->value_peek_pointer ||
651           value_table->collect_format || value_table->collect_value ||
652           value_table->lcopy_format || value_table->lcopy_value)
653         g_warning ("cannot handle uninitializable values of type `%s'",
654                    type_name);
655       return FALSE;
656     }
657   else /* value_table->value_init != NULL */
658     {
659       if (!value_table->value_free)
660         {
661           /* +++ optional +++
662            * g_warning ("missing `value_free()' for type `%s'", type_name);
663            * return FALSE;
664            */
665         }
666       if (!value_table->value_copy)
667         {
668           g_warning ("missing `value_copy()' for type `%s'", type_name);
669           return FALSE;
670         }
671       if ((value_table->collect_format || value_table->collect_value) &&
672           (!value_table->collect_format || !value_table->collect_value))
673         {
674           g_warning ("one of `collect_format' and `collect_value()' is unspecified for type `%s'",
675                      type_name);
676           return FALSE;
677         }
678       if (value_table->collect_format && !check_collect_format_I (value_table->collect_format))
679         {
680           g_warning ("the `%s' specification for type `%s' is too long or invalid",
681                      "collect_format",
682                      type_name);
683           return FALSE;
684         }
685       if ((value_table->lcopy_format || value_table->lcopy_value) &&
686           (!value_table->lcopy_format || !value_table->lcopy_value))
687         {
688           g_warning ("one of `lcopy_format' and `lcopy_value()' is unspecified for type `%s'",
689                      type_name);
690           return FALSE;
691         }
692       if (value_table->lcopy_format && !check_collect_format_I (value_table->lcopy_format))
693         {
694           g_warning ("the `%s' specification for type `%s' is too long or invalid",
695                      "lcopy_format",
696                      type_name);
697           return FALSE;
698         }
699     }
700   return TRUE;
701 }
702
703 static gboolean
704 check_type_info_L (TypeNode        *pnode,
705                    GType            ftype,
706                    const gchar     *type_name,
707                    const GTypeInfo *info)
708 {
709   GTypeFundamentalInfo *finfo = type_node_fundamental_info_L (lookup_type_node_L (ftype));
710   gboolean is_interface = G_TYPE_IS_INTERFACE (ftype);
711   
712   /* check instance members */
713   if (!(finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) &&
714       (info->instance_size || info->n_preallocs || info->instance_init))
715     {
716       if (pnode)
717         g_warning ("cannot instantiate `%s', derived from non-instantiatable parent type `%s'",
718                    type_name,
719                    NODE_NAME (pnode));
720       else
721         g_warning ("cannot instantiate `%s' as non-instantiatable fundamental",
722                    type_name);
723       return FALSE;
724     }
725   /* check class & interface members */
726   if (!(finfo->type_flags & G_TYPE_FLAG_CLASSED) &&
727       (info->class_init || info->class_finalize || info->class_data ||
728        (!is_interface && (info->class_size || info->base_init || info->base_finalize))))
729     {
730       if (pnode)
731         g_warning ("cannot create class for `%s', derived from non-classed parent type `%s'",
732                    type_name,
733                    NODE_NAME (pnode));
734       else
735         g_warning ("cannot create class for `%s' as non-classed fundamental",
736                    type_name);
737       return FALSE;
738     }
739   /* check interface size */
740   if (is_interface && info->class_size < sizeof (GTypeInterface))
741     {
742       g_warning ("specified interface size for type `%s' is smaller than `GTypeInterface' size",
743                  type_name);
744       return FALSE;
745     }
746   /* check class size */
747   if (finfo->type_flags & G_TYPE_FLAG_CLASSED)
748     {
749       if (info->class_size < sizeof (GTypeClass))
750         {
751           g_warning ("specified class size for type `%s' is smaller than `GTypeClass' size",
752                      type_name);
753           return FALSE;
754         }
755       if (pnode && info->class_size < pnode->data->class.class_size)
756         {
757           g_warning ("specified class size for type `%s' is smaller "
758                      "than the parent type's `%s' class size",
759                      type_name,
760                      NODE_NAME (pnode));
761           return FALSE;
762         }
763     }
764   /* check instance size */
765   if (finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE)
766     {
767       if (info->instance_size < sizeof (GTypeInstance))
768         {
769           g_warning ("specified instance size for type `%s' is smaller than `GTypeInstance' size",
770                      type_name);
771           return FALSE;
772         }
773       if (pnode && info->instance_size < pnode->data->instance.instance_size)
774         {
775           g_warning ("specified instance size for type `%s' is smaller "
776                      "than the parent type's `%s' instance size",
777                      type_name,
778                      NODE_NAME (pnode));
779           return FALSE;
780         }
781     }
782   
783   return TRUE;
784 }
785
786 static TypeNode*
787 find_conforming_child_type_L (TypeNode *pnode,
788                               TypeNode *iface)
789 {
790   TypeNode *node = NULL;
791   guint i;
792   
793   if (type_lookup_iface_entry_L (pnode, iface))
794     return pnode;
795   
796   for (i = 0; i < pnode->n_children && !node; i++)
797     node = find_conforming_child_type_L (lookup_type_node_L (pnode->children[i]), iface);
798   
799   return node;
800 }
801
802 static gboolean
803 check_add_interface_L (GType instance_type,
804                        GType iface_type)
805 {
806   TypeNode *node = lookup_type_node_L (instance_type);
807   TypeNode *iface = lookup_type_node_L (iface_type);
808   IFaceEntry *entry;
809   TypeNode *tnode;
810   
811   if (!node || !node->is_instantiatable)
812     {
813       g_warning ("cannot add interfaces to invalid (non-instantiatable) type `%s'",
814                  type_descriptive_name_L (instance_type));
815       return FALSE;
816     }
817   if (!iface || !NODE_IS_IFACE (iface))
818     {
819       g_warning ("cannot add invalid (non-interface) type `%s' to type `%s'",
820                  type_descriptive_name_L (iface_type),
821                  NODE_NAME (node));
822       return FALSE;
823     }
824   tnode = lookup_type_node_L (NODE_PARENT_TYPE (iface));
825   if (NODE_PARENT_TYPE (tnode) && !type_lookup_iface_entry_L (node, tnode))
826     {
827       /* 2001/7/31:timj: erk, i guess this warning is junk as interface derivation is flat */
828       g_warning ("cannot add sub-interface `%s' to type `%s' which does not conform to super-interface `%s'",
829                  NODE_NAME (iface),
830                  NODE_NAME (node),
831                  NODE_NAME (tnode));
832       return FALSE;
833     }
834   /* allow overriding of interface type introduced for parent type */
835   entry = type_lookup_iface_entry_L (node, iface);
836   if (entry && entry->vtable == NULL && !type_iface_peek_holder_L (iface, NODE_TYPE (node)))
837     {
838       /* ok, we do conform to this interface already, but the interface vtable was not
839        * yet intialized, and we just conform to the interface because it got added to
840        * one of our parents. so we allow overriding of holder info here.
841        */
842       return TRUE;
843     }
844   /* check whether one of our children already conforms (or whether the interface
845    * got added to this node already)
846    */
847   tnode = find_conforming_child_type_L (node, iface);  /* tnode is_a node */
848   if (tnode)
849     {
850       g_warning ("cannot add interface type `%s' to type `%s', since type `%s' already conforms to interface",
851                  NODE_NAME (iface),
852                  NODE_NAME (node),
853                  NODE_NAME (tnode));
854       return FALSE;
855     }
856   return TRUE;
857 }
858
859 static gboolean
860 check_interface_info_L (TypeNode             *iface,
861                         GType                 instance_type,
862                         const GInterfaceInfo *info)
863 {
864   if ((info->interface_finalize || info->interface_data) && !info->interface_init)
865     {
866       g_warning ("interface type `%s' for type `%s' comes without initializer",
867                  NODE_NAME (iface),
868                  type_descriptive_name_L (instance_type));
869       return FALSE;
870     }
871   
872   return TRUE;
873 }
874
875 /* --- type info (type node data) --- */
876 static void
877 type_data_make_W (TypeNode              *node,
878                   const GTypeInfo       *info,
879                   const GTypeValueTable *value_table)
880 {
881   TypeData *data;
882   GTypeValueTable *vtable = NULL;
883   guint vtable_size = 0;
884   
885   g_assert (node->data == NULL && info != NULL);
886   
887   if (!value_table)
888     {
889       TypeNode *pnode = lookup_type_node_L (NODE_PARENT_TYPE (node));
890       
891       if (pnode)
892         vtable = pnode->data->common.value_table;
893       else
894         {
895           static const GTypeValueTable zero_vtable = { NULL, };
896           
897           value_table = &zero_vtable;
898         }
899     }
900   if (value_table)
901     {
902       /* need to setup vtable_size since we have to allocate it with data in one chunk */
903       vtable_size = sizeof (GTypeValueTable);
904       if (value_table->collect_format)
905         vtable_size += strlen (value_table->collect_format);
906       if (value_table->lcopy_format)
907         vtable_size += strlen (value_table->lcopy_format);
908       vtable_size += 2;
909     }
910   
911   if (node->is_instantiatable) /* carefull, is_instantiatable is also is_classed */
912     {
913       data = g_malloc0 (sizeof (InstanceData) + vtable_size);
914       if (vtable_size)
915         vtable = G_STRUCT_MEMBER_P (data, sizeof (InstanceData));
916       data->instance.class_size = info->class_size;
917       data->instance.class_init_base = info->base_init;
918       data->instance.class_finalize_base = info->base_finalize;
919       data->instance.class_init = info->class_init;
920       data->instance.class_finalize = info->class_finalize;
921       data->instance.class_data = info->class_data;
922       data->instance.class = NULL;
923       data->instance.instance_size = info->instance_size;
924 #ifdef  DISABLE_MEM_POOLS
925       data->instance.n_preallocs = 0;
926 #else   /* !DISABLE_MEM_POOLS */
927       data->instance.n_preallocs = MIN (info->n_preallocs, 1024);
928 #endif  /* !DISABLE_MEM_POOLS */
929       data->instance.instance_init = info->instance_init;
930       data->instance.mem_chunk = NULL;
931     }
932   else if (node->is_classed) /* only classed */
933     {
934       data = g_malloc0 (sizeof (ClassData) + vtable_size);
935       if (vtable_size)
936         vtable = G_STRUCT_MEMBER_P (data, sizeof (ClassData));
937       data->class.class_size = info->class_size;
938       data->class.class_init_base = info->base_init;
939       data->class.class_finalize_base = info->base_finalize;
940       data->class.class_init = info->class_init;
941       data->class.class_finalize = info->class_finalize;
942       data->class.class_data = info->class_data;
943       data->class.class = NULL;
944     }
945   else if (NODE_IS_IFACE (node))
946     {
947       data = g_malloc0 (sizeof (IFaceData) + vtable_size);
948       if (vtable_size)
949         vtable = G_STRUCT_MEMBER_P (data, sizeof (IFaceData));
950       data->iface.vtable_size = info->class_size;
951       data->iface.vtable_init_base = info->base_init;
952       data->iface.vtable_finalize_base = info->base_finalize;
953     }
954   else
955     {
956       data = g_malloc0 (sizeof (CommonData) + vtable_size);
957       if (vtable_size)
958         vtable = G_STRUCT_MEMBER_P (data, sizeof (CommonData));
959     }
960   
961   node->data = data;
962   node->data->common.ref_count = 1;
963   
964   if (vtable_size)
965     {
966       gchar *p;
967
968       /* we allocate the vtable and its strings together with the type data, so
969        * children can take over their parent's vtable pointer, and we don't
970        * need to worry freeing it or not when the child data is destroyed
971        */
972       *vtable = *value_table;
973       p = G_STRUCT_MEMBER_P (vtable, sizeof (*vtable));
974       p[0] = 0;
975       vtable->collect_format = p;
976       if (value_table->collect_format)
977         {
978           strcat (p, value_table->collect_format);
979           p += strlen (value_table->collect_format);
980         }
981       p++;
982       p[0] = 0;
983       vtable->lcopy_format = p;
984       if (value_table->lcopy_format)
985         strcat  (p, value_table->lcopy_format);
986     }
987   node->data->common.value_table = vtable;
988   
989   g_assert (node->data->common.value_table != NULL); /* paranoid */
990 }
991
992 static inline void
993 type_data_ref_Wm (TypeNode *node)
994 {
995   if (!node->data)
996     {
997       TypeNode *pnode = lookup_type_node_L (NODE_PARENT_TYPE (node));
998       GTypeInfo tmp_info;
999       GTypeValueTable tmp_value_table;
1000       
1001       g_assert (node->plugin != NULL);
1002       
1003       if (pnode)
1004         {
1005           type_data_ref_Wm (pnode);
1006           if (node->data)
1007             INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
1008         }
1009       
1010       memset (&tmp_info, 0, sizeof (tmp_info));
1011       memset (&tmp_value_table, 0, sizeof (tmp_value_table));
1012       
1013       G_WRITE_UNLOCK (&type_rw_lock);
1014       g_type_plugin_use (node->plugin);
1015       g_type_plugin_complete_type_info (node->plugin, NODE_TYPE (node), &tmp_info, &tmp_value_table);
1016       G_WRITE_LOCK (&type_rw_lock);
1017       if (node->data)
1018         INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
1019       
1020       check_type_info_L (pnode, G_TYPE_FUNDAMENTAL (NODE_TYPE (node)), NODE_NAME (node), &tmp_info);
1021       type_data_make_W (node, &tmp_info,
1022                         check_value_table_I (NODE_NAME (node),
1023                                              &tmp_value_table) ? &tmp_value_table : NULL);
1024     }
1025   else
1026     {
1027       g_assert (node->data->common.ref_count > 0);
1028       
1029       node->data->common.ref_count += 1;
1030     }
1031 }
1032
1033 static inline void
1034 type_data_unref_Wm (TypeNode *node,
1035                     gboolean  uncached)
1036 {
1037   g_assert (node->data && node->data->common.ref_count);
1038   
1039   if (node->data->common.ref_count > 1)
1040     node->data->common.ref_count -= 1;
1041   else
1042     {
1043       if (!node->plugin)
1044         {
1045           g_warning ("static type `%s' unreferenced too often",
1046                      NODE_NAME (node));
1047           return;
1048         }
1049       
1050       type_data_last_unref_Wm (NODE_TYPE (node), uncached);
1051     }
1052 }
1053
1054 static void
1055 type_node_add_iface_entry_W (TypeNode *node,
1056                              GType     iface_type)
1057 {
1058   IFaceEntry *entries;
1059   guint i;
1060   
1061   g_assert (node->is_instantiatable && CLASSED_NODE_N_IFACES (node) < MAX_N_IFACES);
1062   
1063   entries = CLASSED_NODE_IFACES_ENTRIES (node);
1064   for (i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
1065     if (entries[i].iface_type == iface_type)
1066       {
1067         /* this can (should) only happen if our parent type already conformed
1068          * to iface_type and node got it's own holder info. here, our
1069          * children should already have entries with NULL vtables, so
1070          * we're actually done.
1071          */
1072         g_assert (entries[i].vtable == NULL);
1073         return;
1074       }
1075     else if (entries[i].iface_type > iface_type)
1076       break;
1077   CLASSED_NODE_N_IFACES (node) += 1;
1078   CLASSED_NODE_IFACES_ENTRIES (node) = g_renew (IFaceEntry,
1079                                                 CLASSED_NODE_IFACES_ENTRIES (node),
1080                                                 CLASSED_NODE_N_IFACES (node));
1081   entries = CLASSED_NODE_IFACES_ENTRIES (node);
1082   g_memmove (entries + i + 1, entries + i, sizeof (entries[0]) * (CLASSED_NODE_N_IFACES (node) - i - 1));
1083   entries[i].iface_type = iface_type;
1084   entries[i].vtable = NULL;
1085   
1086   for (i = 0; i < node->n_children; i++)
1087     type_node_add_iface_entry_W (lookup_type_node_L (node->children[i]), iface_type);
1088 }
1089
1090 static void
1091 type_add_interface_W (TypeNode             *node,
1092                       TypeNode             *iface,
1093                       const GInterfaceInfo *info,
1094                       GTypePlugin          *plugin)
1095 {
1096   IFaceHolder *iholder = g_new0 (IFaceHolder, 1);
1097   
1098   /* we must not call any functions of GInterfaceInfo from within here, since
1099    * we got most probably called from _within_ a type registration function
1100    */
1101   g_assert (node->is_instantiatable && NODE_IS_IFACE (iface) && ((info && !plugin) || (!info && plugin)));
1102   
1103   iholder->next = iface_node_get_holders_L (iface);
1104   iface_node_set_holders_W (iface, iholder);
1105   iholder->instance_type = NODE_TYPE (node);
1106   iholder->info = info ? g_memdup (info, sizeof (*info)) : NULL;
1107   iholder->plugin = plugin;
1108   
1109   type_node_add_iface_entry_W (node, NODE_TYPE (iface));
1110 }
1111
1112 static void
1113 type_iface_add_prerequisite_W (TypeNode *iface,
1114                                TypeNode *prerequisite_node)
1115 {
1116   GType prerequisite_type = NODE_TYPE (prerequisite_node);
1117   GType *prerequisites, *dependants;
1118   guint n_dependants, i;
1119
1120   g_assert (NODE_IS_IFACE (iface) &&
1121             IFACE_NODE_N_PREREQUISITES (iface) < MAX_N_PREREQUISITES &&
1122             (prerequisite_node->is_instantiatable || NODE_IS_IFACE (prerequisite_node)));
1123
1124   prerequisites = IFACE_NODE_PREREQUISITES (iface);
1125   for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
1126     if (prerequisites[i] == prerequisite_type)
1127       return;                   /* we already have that prerequisiste */
1128     else if (prerequisites[i] > prerequisite_type)
1129       break;
1130   IFACE_NODE_N_PREREQUISITES (iface) += 1;
1131   IFACE_NODE_PREREQUISITES (iface) = g_renew (GType,
1132                                               IFACE_NODE_PREREQUISITES (iface),
1133                                               IFACE_NODE_N_PREREQUISITES (iface));
1134   prerequisites = IFACE_NODE_PREREQUISITES (iface);
1135   g_memmove (prerequisites + i + 1, prerequisites + i,
1136              sizeof (prerequisites[0]) * (IFACE_NODE_N_PREREQUISITES (iface) - i - 1));
1137   prerequisites[i] = prerequisite_type;
1138
1139   /* we want to get notified when prerequisites get added to prerequisite_node */
1140   if (NODE_IS_IFACE (prerequisite_node))
1141     {
1142       dependants = iface_node_get_dependants_array_L (prerequisite_node);
1143       n_dependants = dependants ? dependants[0] : 0;
1144       n_dependants += 1;
1145       dependants = g_renew (GType, dependants, n_dependants + 1);
1146       dependants[n_dependants] = NODE_TYPE (iface);
1147       dependants[0] = n_dependants;
1148       iface_node_set_dependants_array_W (prerequisite_node, dependants);
1149     }
1150
1151   /* we need to notify all dependants */
1152   dependants = iface_node_get_dependants_array_L (iface);
1153   n_dependants = dependants ? dependants[0] : 0;
1154   for (i = 1; i <= n_dependants; i++)
1155     type_iface_add_prerequisite_W (lookup_type_node_L (dependants[i]), prerequisite_node);
1156 }
1157
1158 void
1159 g_type_interface_add_prerequisite (GType interface_type,
1160                                    GType prerequisite_type)
1161 {
1162   TypeNode *iface, *prerequisite_node;
1163   IFaceHolder *holders;
1164
1165   g_return_if_fail (G_TYPE_IS_INTERFACE (interface_type));
1166   g_return_if_fail (!g_type_is_a (interface_type, prerequisite_type));
1167   g_return_if_fail (!g_type_is_a (prerequisite_type, interface_type));
1168
1169   G_WRITE_LOCK (&type_rw_lock);
1170   iface = lookup_type_node_L (interface_type);
1171   prerequisite_node = lookup_type_node_L (prerequisite_type);
1172   if (!iface || !prerequisite_node || !NODE_IS_IFACE (iface))
1173     {
1174       g_warning ("interface type `%s' or prerequisite type `%s' invalid",
1175                  type_descriptive_name_L (interface_type),
1176                  type_descriptive_name_L (prerequisite_type));
1177       G_WRITE_UNLOCK (&type_rw_lock);
1178       return;
1179     }
1180   holders = iface_node_get_holders_L (iface);
1181   if (holders)
1182     {
1183       g_warning ("unable to add prerequisite `%s' to interface `%s' which is already in use for `%s'",
1184                  type_descriptive_name_L (prerequisite_type),
1185                  type_descriptive_name_L (interface_type),
1186                  type_descriptive_name_L (holders->instance_type));
1187       G_WRITE_UNLOCK (&type_rw_lock);
1188       return;
1189     }
1190   if (prerequisite_node->is_instantiatable)
1191     {
1192       guint i;
1193
1194       /* can have at most one publically installable instantiatable prerequisite */
1195       for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
1196         {
1197           TypeNode *prnode = lookup_type_node_L (IFACE_NODE_PREREQUISITES (iface)[i]);
1198
1199           if (prnode->is_instantiatable)
1200             {
1201               g_warning ("adding prerequisite `%s' to interface `%s' conflicts with existing prerequisite `%s'",
1202                          type_descriptive_name_L (prerequisite_type),
1203                          type_descriptive_name_L (interface_type),
1204                          type_descriptive_name_L (NODE_TYPE (prnode)));
1205               G_WRITE_UNLOCK (&type_rw_lock);
1206               return;
1207             }
1208         }
1209
1210       for (i = 0; i < prerequisite_node->n_supers + 1; i++)
1211         type_iface_add_prerequisite_W (iface, lookup_type_node_L (prerequisite_node->supers[i]));
1212     }
1213   else if (NODE_IS_IFACE (prerequisite_node))
1214     {
1215       GType *dependants;
1216       guint n_dependants, i;
1217
1218       dependants = iface_node_get_dependants_array_L (prerequisite_node);
1219       n_dependants = dependants ? dependants[0] : 0;
1220       for (i = 1; i <= n_dependants; i++)
1221         type_iface_add_prerequisite_W (iface, lookup_type_node_L (dependants[i]));
1222       type_iface_add_prerequisite_W (iface, prerequisite_node);
1223     }
1224   else
1225     g_warning ("prerequisite `%s' for interface `%s' is neither instantiatable nor interface",
1226                type_descriptive_name_L (prerequisite_type),
1227                type_descriptive_name_L (interface_type));
1228   G_WRITE_UNLOCK (&type_rw_lock);
1229 }
1230
1231 static IFaceHolder*
1232 type_iface_peek_holder_L (TypeNode *iface,
1233                           GType     instance_type)
1234 {
1235   IFaceHolder *iholder;
1236
1237   g_assert (NODE_IS_IFACE (iface));
1238
1239   iholder = iface_node_get_holders_L (iface);
1240   while (iholder && iholder->instance_type != instance_type)
1241     iholder = iholder->next;
1242   return iholder;
1243 }
1244
1245 static IFaceHolder*
1246 type_iface_retrive_holder_info_Wm (TypeNode *iface,
1247                                    GType     instance_type,
1248                                    gboolean  need_info)
1249 {
1250   IFaceHolder *iholder = type_iface_peek_holder_L (iface, instance_type);
1251
1252   if (iholder && !iholder->info && need_info)
1253     {
1254       GInterfaceInfo tmp_info;
1255       
1256       g_assert (iholder->plugin != NULL);
1257       
1258       type_data_ref_Wm (iface);
1259       if (iholder->info)
1260         INVALID_RECURSION ("g_type_plugin_*", iface->plugin, NODE_NAME (iface));
1261       
1262       memset (&tmp_info, 0, sizeof (tmp_info));
1263       
1264       G_WRITE_UNLOCK (&type_rw_lock);
1265       g_type_plugin_use (iholder->plugin);
1266       g_type_plugin_complete_interface_info (iholder->plugin, instance_type, NODE_TYPE (iface), &tmp_info);
1267       G_WRITE_LOCK (&type_rw_lock);
1268       if (iholder->info)
1269         INVALID_RECURSION ("g_type_plugin_*", iholder->plugin, NODE_NAME (iface));
1270       
1271       check_interface_info_L (iface, instance_type, &tmp_info);
1272       iholder->info = g_memdup (&tmp_info, sizeof (tmp_info));
1273     }
1274   
1275   return iholder;       /* we don't modify write lock upon returning NULL */
1276 }
1277
1278 static void
1279 type_iface_blow_holder_info_Wm (TypeNode *iface,
1280                                 GType     instance_type)
1281 {
1282   IFaceHolder *iholder = iface_node_get_holders_L (iface);
1283   
1284   g_assert (NODE_IS_IFACE (iface));
1285   
1286   while (iholder->instance_type != instance_type)
1287     iholder = iholder->next;
1288   
1289   if (iholder->info && iholder->plugin)
1290     {
1291       g_free (iholder->info);
1292       iholder->info = NULL;
1293       
1294       G_WRITE_UNLOCK (&type_rw_lock);
1295       g_type_plugin_unuse (iholder->plugin);
1296       G_WRITE_LOCK (&type_rw_lock);
1297       
1298       type_data_unref_Wm (iface, FALSE);
1299     }
1300 }
1301
1302
1303 /* --- type structure creation/destruction --- */
1304 GTypeInstance*
1305 g_type_create_instance (GType type)
1306 {
1307   TypeNode *node;
1308   GTypeInstance *instance;
1309   GTypeClass *class;
1310   guint i;
1311   
1312   G_READ_LOCK (&type_rw_lock);
1313   node = lookup_type_node_L (type);
1314   G_READ_UNLOCK (&type_rw_lock);
1315   if (!node || !node->is_instantiatable)
1316     {
1317       g_warning ("cannot create new instance of invalid (non-instantiatable) type `%s'",
1318                  type_descriptive_name_U (type));
1319       return NULL;
1320     }
1321   /* G_TYPE_IS_ABSTRACT() is an external call: _U */
1322   if (G_TYPE_IS_ABSTRACT (type))
1323     {
1324       g_warning ("cannot create instance of abstract (non-instantiatable) type `%s'",
1325                  type_descriptive_name_U (type));
1326       return NULL;
1327     }
1328   
1329   class = g_type_class_ref (type);
1330   
1331   if (node->data->instance.n_preallocs)
1332     {
1333       G_WRITE_LOCK (&type_rw_lock);
1334       if (!node->data->instance.mem_chunk)
1335         node->data->instance.mem_chunk = g_mem_chunk_new (NODE_NAME (node),
1336                                                           node->data->instance.instance_size,
1337                                                           (node->data->instance.instance_size *
1338                                                            node->data->instance.n_preallocs),
1339                                                           G_ALLOC_AND_FREE);
1340       instance = g_chunk_new0 (GTypeInstance, node->data->instance.mem_chunk);
1341       G_WRITE_UNLOCK (&type_rw_lock);
1342     }
1343   else
1344     instance = g_malloc0 (node->data->instance.instance_size);  /* fine without read lock */
1345   for (i = node->n_supers; i > 0; i--)
1346     {
1347       TypeNode *pnode;
1348       
1349       G_READ_LOCK (&type_rw_lock);
1350       pnode = lookup_type_node_L (node->supers[i]);
1351       G_READ_UNLOCK (&type_rw_lock);
1352       
1353       if (pnode->data->instance.instance_init)
1354         {
1355           instance->g_class = pnode->data->instance.class;
1356           pnode->data->instance.instance_init (instance, class);
1357         }
1358     }
1359   instance->g_class = class;
1360   
1361   if (node->data->instance.instance_init)
1362     node->data->instance.instance_init (instance, class);
1363   
1364   return instance;
1365 }
1366
1367 void
1368 g_type_free_instance (GTypeInstance *instance)
1369 {
1370   TypeNode *node;
1371   GTypeClass *class;
1372   
1373   g_return_if_fail (instance != NULL && instance->g_class != NULL);
1374   
1375   G_READ_LOCK (&type_rw_lock);
1376   class = instance->g_class;
1377   node = lookup_type_node_L (class->g_type);
1378   if (!node || !node->is_instantiatable || !node->data || node->data->class.class != (gpointer) class)
1379     {
1380       g_warning ("cannot free instance of invalid (non-instantiatable) type `%s'",
1381                  type_descriptive_name_L (class->g_type));
1382       G_READ_UNLOCK (&type_rw_lock);
1383       return;
1384     }
1385   G_READ_UNLOCK (&type_rw_lock);
1386   /* G_TYPE_IS_ABSTRACT() is an external call: _U */
1387   if (G_TYPE_IS_ABSTRACT (NODE_TYPE (node)))
1388     {
1389       g_warning ("cannot free instance of abstract (non-instantiatable) type `%s'",
1390                  NODE_NAME (node));
1391       return;
1392     }
1393   
1394   instance->g_class = NULL;
1395   memset (instance, 0xaa, node->data->instance.instance_size);  /* FIXME: debugging hack */
1396   if (node->data->instance.n_preallocs)
1397     {
1398       G_WRITE_LOCK (&type_rw_lock);
1399       g_chunk_free (instance, node->data->instance.mem_chunk);
1400       G_WRITE_UNLOCK (&type_rw_lock);
1401     }
1402   else
1403     g_free (instance);
1404   
1405   g_type_class_unref (class);
1406 }
1407
1408 static gboolean
1409 type_iface_vtable_init_Wm (TypeNode *iface,
1410                            TypeNode *node)
1411 {
1412   IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
1413   IFaceHolder *iholder;
1414   GTypeInterface *vtable = NULL;
1415   TypeNode *pnode;
1416
1417   /* type_iface_retrive_holder_info_Wm() doesn't modify write lock for returning NULL */
1418   iholder = type_iface_retrive_holder_info_Wm (iface, NODE_TYPE (node), TRUE);
1419   if (!iholder)
1420     return FALSE;       /* we don't modify write lock upon FALSE */
1421   
1422   g_assert (iface->data && entry && entry->vtable == NULL && iholder && iholder->info);
1423   
1424   pnode = lookup_type_node_L (NODE_PARENT_TYPE (node));
1425   if (pnode)    /* want to copy over parent iface contents */
1426     {
1427       IFaceEntry *pentry = type_lookup_iface_entry_L (pnode, iface);
1428
1429       if (pentry)
1430         vtable = g_memdup (pentry->vtable, iface->data->iface.vtable_size);
1431     }
1432   if (!vtable)
1433     vtable = g_malloc0 (iface->data->iface.vtable_size);
1434   entry->vtable = vtable;
1435   vtable->g_type = NODE_TYPE (iface);
1436   vtable->g_instance_type = NODE_TYPE (node);
1437   
1438   if (iface->data->iface.vtable_init_base || iholder->info->interface_init)
1439     {
1440       G_WRITE_UNLOCK (&type_rw_lock);
1441       if (iface->data->iface.vtable_init_base)
1442         iface->data->iface.vtable_init_base (vtable);
1443       if (iholder->info->interface_init)
1444         iholder->info->interface_init (vtable, iholder->info->interface_data);
1445       G_WRITE_LOCK (&type_rw_lock);
1446     }
1447   return TRUE;  /* write lock modified */
1448 }
1449
1450 static gboolean
1451 type_iface_vtable_finalize_Wm (TypeNode       *iface,
1452                                TypeNode       *node,
1453                                GTypeInterface *vtable)
1454 {
1455   IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
1456   IFaceHolder *iholder;
1457
1458   /* type_iface_retrive_holder_info_Wm() doesn't modify write lock for returning NULL */
1459   iholder = type_iface_retrive_holder_info_Wm (iface, NODE_TYPE (node), FALSE);
1460   if (!iholder)
1461     return FALSE;       /* we don't modify write lock upon FALSE */
1462   
1463   g_assert (entry && entry->vtable == vtable && iholder->info);
1464   
1465   entry->vtable = NULL;
1466   if (iholder->info->interface_finalize || iface->data->iface.vtable_finalize_base)
1467     {
1468       G_WRITE_UNLOCK (&type_rw_lock);
1469       if (iholder->info->interface_finalize)
1470         iholder->info->interface_finalize (vtable, iholder->info->interface_data);
1471       if (iface->data->iface.vtable_finalize_base)
1472         iface->data->iface.vtable_finalize_base (vtable);
1473       G_WRITE_LOCK (&type_rw_lock);
1474     }
1475   vtable->g_type = 0;
1476   vtable->g_instance_type = 0;
1477   g_free (vtable);
1478   
1479   type_iface_blow_holder_info_Wm (iface, NODE_TYPE (node));
1480
1481   return TRUE;  /* write lock modified */
1482 }
1483
1484 static void
1485 type_class_init_Wm (TypeNode   *node,
1486                     GTypeClass *pclass)
1487 {
1488   GSList *slist, *init_slist = NULL;
1489   GTypeClass *class;
1490   IFaceEntry *entry;
1491   TypeNode *bnode, *pnode;
1492   guint i;
1493   
1494   g_assert (node->is_classed && node->data &&
1495             node->data->class.class_size &&
1496             !node->data->class.class);
1497   
1498   class = g_malloc0 (node->data->class.class_size);
1499   node->data->class.class = class;
1500   
1501   if (pclass)
1502     {
1503       TypeNode *pnode = lookup_type_node_L (pclass->g_type);
1504       
1505       memcpy (class, pclass, pnode->data->class.class_size);
1506     }
1507   class->g_type = NODE_TYPE (node);
1508   
1509   G_WRITE_UNLOCK (&type_rw_lock);
1510   
1511   /* stack all base class initialization functions, so we
1512    * call them in ascending order.
1513    */
1514   G_READ_LOCK (&type_rw_lock);
1515   for (bnode = node; bnode; bnode = lookup_type_node_L (NODE_PARENT_TYPE (bnode)))
1516     if (bnode->data->class.class_init_base)
1517       init_slist = g_slist_prepend (init_slist, (gpointer) bnode->data->class.class_init_base);
1518   G_READ_UNLOCK (&type_rw_lock);
1519   for (slist = init_slist; slist; slist = slist->next)
1520     {
1521       GBaseInitFunc class_init_base = (GBaseInitFunc) slist->data;
1522       
1523       class_init_base (class);
1524     }
1525   g_slist_free (init_slist);
1526   
1527   if (node->data->class.class_init)
1528     node->data->class.class_init (class, (gpointer) node->data->class.class_data);
1529   
1530   G_WRITE_LOCK (&type_rw_lock);
1531   
1532   /* ok, we got the class done, now initialize all interfaces, either
1533    * from parent, or through our holder info
1534    */
1535   pnode = lookup_type_node_L (NODE_PARENT_TYPE (node));
1536   entry = CLASSED_NODE_IFACES_ENTRIES (node) + 0;
1537   while (entry)
1538     {
1539       g_assert (entry->vtable == NULL);
1540       
1541       if (!type_iface_vtable_init_Wm (lookup_type_node_L (entry->iface_type), node))
1542         {
1543           guint j;
1544
1545           /* type_iface_vtable_init_Wm() doesn't modify write lock upon FALSE,
1546            * need to get this interface from parent
1547            */
1548           g_assert (pnode != NULL);
1549
1550           for (j = 0; j < CLASSED_NODE_N_IFACES (pnode); j++)
1551             {
1552               IFaceEntry *pentry = CLASSED_NODE_IFACES_ENTRIES (pnode) + j;
1553
1554               if (pentry->iface_type == entry->iface_type)
1555                 {
1556                   entry->vtable = pentry->vtable;
1557                   break;
1558                 }
1559             }
1560           g_assert (entry->vtable != NULL);
1561         }
1562
1563       /* refetch entry, IFACES_ENTRIES might be modified */
1564       for (entry = NULL, i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
1565         if (!CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable)
1566           entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
1567     }
1568 }
1569
1570 static void
1571 type_data_finalize_class_ifaces_Wm (TypeNode *node)
1572 {
1573   IFaceEntry *entry;
1574   guint i;
1575   
1576   g_assert (node->is_instantiatable && node->data && node->data->class.class && node->data->common.ref_count == 0);
1577   
1578   g_message ("finalizing interfaces for %sClass `%s'",
1579              type_descriptive_name_L (G_TYPE_FUNDAMENTAL (NODE_TYPE (node))),
1580              type_descriptive_name_L (NODE_TYPE (node)));
1581   
1582   for (entry = NULL, i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
1583     if (CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable &&
1584         CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable->g_instance_type == NODE_TYPE (node))
1585       entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
1586   while (entry)
1587     {
1588       if (!type_iface_vtable_finalize_Wm (lookup_type_node_L (entry->iface_type), node, entry->vtable))
1589         {
1590           /* type_iface_vtable_finalize_Wm() doesn't modify write lock upon FALSE,
1591            * iface vtable came from parent
1592            */
1593           entry->vtable = NULL;
1594         }
1595       
1596       /* refetch entry, IFACES_ENTRIES might be modified */
1597       for (entry = NULL, i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
1598         if (CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable &&
1599             CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable->g_instance_type == NODE_TYPE (node))
1600           entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
1601     }
1602 }
1603
1604 static void
1605 type_data_finalize_class_U (TypeNode  *node,
1606                             ClassData *cdata)
1607 {
1608   GTypeClass *class = cdata->class;
1609   TypeNode *bnode;
1610   
1611   g_assert (cdata->class && cdata->common.ref_count == 0);
1612   
1613   if (cdata->class_finalize)
1614     cdata->class_finalize (class, (gpointer) cdata->class_data);
1615   
1616   /* call all base class destruction functions in descending order
1617    */
1618   if (cdata->class_finalize_base)
1619     cdata->class_finalize_base (class);
1620   G_READ_LOCK (&type_rw_lock);
1621   for (bnode = lookup_type_node_L (NODE_PARENT_TYPE (node)); bnode; bnode = lookup_type_node_L (NODE_PARENT_TYPE (bnode)))
1622     if (bnode->data->class.class_finalize_base)
1623       {
1624         G_READ_UNLOCK (&type_rw_lock);
1625         bnode->data->class.class_finalize_base (class);
1626         G_READ_LOCK (&type_rw_lock);
1627       }
1628   G_READ_UNLOCK (&type_rw_lock);
1629   
1630   class->g_type = 0;
1631   g_free (cdata->class);
1632 }
1633
1634 static void
1635 type_data_last_unref_Wm (GType    type,
1636                          gboolean uncached)
1637 {
1638   TypeNode *node = lookup_type_node_L (type);
1639   
1640   g_return_if_fail (node != NULL && node->plugin != NULL);
1641   
1642   if (!node->data || node->data->common.ref_count == 0)
1643     {
1644       g_warning ("cannot drop last reference to unreferenced type `%s'",
1645                  type_descriptive_name_U (type));
1646       return;
1647     }
1648   
1649   if (node->is_classed && node->data && node->data->class.class && static_n_class_cache_funcs)
1650     {
1651       guint i;
1652       
1653       G_WRITE_UNLOCK (&type_rw_lock);
1654       G_READ_LOCK (&type_rw_lock);
1655       for (i = 0; i < static_n_class_cache_funcs; i++)
1656         {
1657           GTypeClassCacheFunc cache_func = static_class_cache_funcs[i].cache_func;
1658           gpointer cache_data = static_class_cache_funcs[i].cache_data;
1659           gboolean need_break;
1660           
1661           G_READ_UNLOCK (&type_rw_lock);
1662           need_break = cache_func (cache_data, node->data->class.class);
1663           G_READ_LOCK (&type_rw_lock);
1664           if (!node->data || node->data->common.ref_count == 0)
1665             INVALID_RECURSION ("GType class cache function ", cache_func, NODE_NAME (node));
1666           if (need_break)
1667             break;
1668         }
1669       G_READ_UNLOCK (&type_rw_lock);
1670       G_WRITE_LOCK (&type_rw_lock);
1671     }
1672   
1673   if (node->data->common.ref_count > 1) /* may have been re-referenced meanwhile */
1674     node->data->common.ref_count -= 1;
1675   else
1676     {
1677       GType ptype = NODE_PARENT_TYPE (node);
1678       TypeData *tdata;
1679       
1680       node->data->common.ref_count = 0;
1681       
1682       if (node->is_instantiatable && node->data->instance.mem_chunk)
1683         {
1684           g_mem_chunk_destroy (node->data->instance.mem_chunk);
1685           node->data->instance.mem_chunk = NULL;
1686         }
1687       
1688       tdata = node->data;
1689       if (node->is_classed && tdata->class.class)
1690         {
1691           if (CLASSED_NODE_N_IFACES (node))
1692             type_data_finalize_class_ifaces_Wm (node);
1693           node->data = NULL;
1694           G_WRITE_UNLOCK (&type_rw_lock);
1695           type_data_finalize_class_U (node, &tdata->class);
1696           G_WRITE_LOCK (&type_rw_lock);
1697         }
1698       else
1699         node->data = NULL;
1700
1701       /* freeing tdata->common.value_table and its contents is taking care of
1702        * by allocating it in one chunk with tdata
1703        */
1704       g_free (tdata);
1705       
1706       if (ptype)
1707         type_data_unref_Wm (lookup_type_node_L (ptype), FALSE);
1708       G_WRITE_UNLOCK (&type_rw_lock);
1709       g_type_plugin_unuse (node->plugin);
1710       G_WRITE_LOCK (&type_rw_lock);
1711     }
1712 }
1713
1714 void
1715 g_type_add_class_cache_func (gpointer            cache_data,
1716                              GTypeClassCacheFunc cache_func)
1717 {
1718   guint i;
1719   
1720   g_return_if_fail (cache_func != NULL);
1721   
1722   G_WRITE_LOCK (&type_rw_lock);
1723   i = static_n_class_cache_funcs++;
1724   static_class_cache_funcs = g_renew (ClassCacheFunc, static_class_cache_funcs, static_n_class_cache_funcs);
1725   static_class_cache_funcs[i].cache_data = cache_data;
1726   static_class_cache_funcs[i].cache_func = cache_func;
1727   G_WRITE_UNLOCK (&type_rw_lock);
1728 }
1729
1730 void
1731 g_type_remove_class_cache_func (gpointer            cache_data,
1732                                 GTypeClassCacheFunc cache_func)
1733 {
1734   gboolean found_it = FALSE;
1735   guint i;
1736   
1737   g_return_if_fail (cache_func != NULL);
1738   
1739   G_WRITE_LOCK (&type_rw_lock);
1740   for (i = 0; i < static_n_class_cache_funcs; i++)
1741     if (static_class_cache_funcs[i].cache_data == cache_data &&
1742         static_class_cache_funcs[i].cache_func == cache_func)
1743       {
1744         static_n_class_cache_funcs--;
1745         g_memmove (static_class_cache_funcs + i,
1746                    static_class_cache_funcs + i + 1,
1747                    sizeof (static_class_cache_funcs[0]) * (static_n_class_cache_funcs - i));
1748         static_class_cache_funcs = g_renew (ClassCacheFunc, static_class_cache_funcs, static_n_class_cache_funcs);
1749         found_it = TRUE;
1750         break;
1751       }
1752   G_WRITE_UNLOCK (&type_rw_lock);
1753   
1754   if (!found_it)
1755     g_warning (G_STRLOC ": cannot remove unregistered class cache func %p with data %p",
1756                cache_func, cache_data);
1757 }
1758
1759
1760 /* --- type registration --- */
1761 GType
1762 g_type_register_fundamental (GType                       type_id,
1763                              const gchar                *type_name,
1764                              const GTypeInfo            *info,
1765                              const GTypeFundamentalInfo *finfo,
1766                              GTypeFlags                  flags)
1767 {
1768   GTypeFundamentalInfo *node_finfo;
1769   TypeNode *node;
1770   
1771   g_return_val_if_uninitialized (static_last_fundamental_id, g_type_init, 0);
1772   g_return_val_if_fail (type_id > 0, 0);
1773   g_return_val_if_fail (type_name != NULL, 0);
1774   g_return_val_if_fail (info != NULL, 0);
1775   g_return_val_if_fail (finfo != NULL, 0);
1776   
1777   if (!check_type_name_U (type_name))
1778     return 0;
1779   if (G_TYPE_FUNDAMENTAL (type_id) != type_id)
1780     {
1781       g_warning ("cannot register fundamental type `%s' with non-fundamental id (%u)",
1782                  type_name,
1783                  type_id);
1784       return 0;
1785     }
1786   if ((finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) &&
1787       !(finfo->type_flags & G_TYPE_FLAG_CLASSED))
1788     {
1789       g_warning ("cannot register instantiatable fundamental type `%s' as non-classed",
1790                  type_name);
1791       return 0;
1792     }
1793   G_WRITE_LOCK (&type_rw_lock);
1794   if (lookup_type_node_L (type_id))
1795     {
1796       G_WRITE_UNLOCK (&type_rw_lock);
1797       g_warning ("cannot register existing fundamental type `%s' (as `%s')",
1798                  type_descriptive_name_U (type_id),
1799                  type_name);
1800       return 0;
1801     }
1802   
1803   node = type_node_fundamental_new_W (type_id, type_name, finfo->type_flags);
1804   node_finfo = type_node_fundamental_info_L (node);
1805   type_add_flags_W (node, flags);
1806   
1807   if (check_type_info_L (NULL, G_TYPE_FUNDAMENTAL (NODE_TYPE (node)), type_name, info))
1808     type_data_make_W (node, info,
1809                       check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);
1810   G_WRITE_UNLOCK (&type_rw_lock);
1811   
1812   return NODE_TYPE (node);
1813 }
1814
1815 GType
1816 g_type_register_static (GType            parent_type,
1817                         const gchar     *type_name,
1818                         const GTypeInfo *info,
1819                         GTypeFlags       flags)
1820 {
1821   TypeNode *pnode, *node;
1822   GType type = 0;
1823   
1824   g_return_val_if_uninitialized (static_last_fundamental_id, g_type_init, 0);
1825   g_return_val_if_fail (parent_type > 0, 0);
1826   g_return_val_if_fail (type_name != NULL, 0);
1827   g_return_val_if_fail (info != NULL, 0);
1828   
1829   if (!check_type_name_U (type_name) ||
1830       !check_derivation_U (parent_type, type_name))
1831     return 0;
1832   if (info->class_finalize)
1833     {
1834       g_warning ("class finalizer specified for static type `%s'",
1835                  type_name);
1836       return 0;
1837     }
1838   
1839   G_WRITE_LOCK (&type_rw_lock);
1840   pnode = lookup_type_node_L (parent_type);
1841   type_data_ref_Wm (pnode);
1842   if (check_type_info_L (pnode, G_TYPE_FUNDAMENTAL (parent_type), type_name, info))
1843     {
1844       node = type_node_new_W (pnode, type_name, NULL);
1845       type_add_flags_W (node, flags);
1846       type = NODE_TYPE (node);
1847       type_data_make_W (node, info,
1848                         check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);
1849     }
1850   G_WRITE_UNLOCK (&type_rw_lock);
1851   
1852   return type;
1853 }
1854
1855 GType
1856 g_type_register_dynamic (GType        parent_type,
1857                          const gchar *type_name,
1858                          GTypePlugin *plugin,
1859                          GTypeFlags   flags)
1860 {
1861   TypeNode *pnode, *node;
1862   GType type;
1863   
1864   g_return_val_if_uninitialized (static_last_fundamental_id, g_type_init, 0);
1865   g_return_val_if_fail (parent_type > 0, 0);
1866   g_return_val_if_fail (type_name != NULL, 0);
1867   g_return_val_if_fail (plugin != NULL, 0);
1868   
1869   if (!check_type_name_U (type_name) ||
1870       !check_derivation_U (parent_type, type_name) ||
1871       !check_plugin_U (plugin, TRUE, FALSE, type_name))
1872     return 0;
1873   
1874   G_WRITE_LOCK (&type_rw_lock);
1875   pnode = lookup_type_node_L (parent_type);
1876   node = type_node_new_W (pnode, type_name, plugin);
1877   type_add_flags_W (node, flags);
1878   type = NODE_TYPE (node);
1879   G_WRITE_UNLOCK (&type_rw_lock);
1880   
1881   return type;
1882 }
1883
1884 void
1885 g_type_add_interface_static (GType                 instance_type,
1886                              GType                 interface_type,
1887                              const GInterfaceInfo *info)
1888 {
1889   /* G_TYPE_IS_INSTANTIATABLE() is an external call: _U */
1890   g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type));
1891   g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE);
1892   
1893   G_WRITE_LOCK (&type_rw_lock);
1894   if (check_add_interface_L (instance_type, interface_type))
1895     {
1896       TypeNode *node = lookup_type_node_L (instance_type);
1897       TypeNode *iface = lookup_type_node_L (interface_type);
1898       
1899       if (check_interface_info_L (iface, NODE_TYPE (node), info))
1900         {
1901           type_add_interface_W (node, iface, info, NULL);
1902           /* if we have a class already, the interface vtable needs to
1903            * be initialized as well
1904            */
1905           if (node->data && node->data->class.class)
1906             type_iface_vtable_init_Wm (iface, node);
1907         }
1908     }
1909   G_WRITE_UNLOCK (&type_rw_lock);
1910 }
1911
1912 void
1913 g_type_add_interface_dynamic (GType        instance_type,
1914                               GType        interface_type,
1915                               GTypePlugin *plugin)
1916 {
1917   TypeNode *node;
1918   
1919   /* G_TYPE_IS_INSTANTIATABLE() is an external call: _U */
1920   g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type));
1921   g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE);
1922   
1923   G_READ_LOCK (&type_rw_lock);
1924   node = lookup_type_node_L (instance_type);
1925   G_READ_UNLOCK (&type_rw_lock);
1926   if (!check_plugin_U (plugin, FALSE, TRUE, NODE_NAME (node)))
1927     return;
1928   
1929   G_WRITE_LOCK (&type_rw_lock);
1930   if (check_add_interface_L (instance_type, interface_type))
1931     {
1932       TypeNode *iface = lookup_type_node_L (interface_type);
1933       
1934       type_add_interface_W (node, iface, NULL, plugin);
1935       /* if we have a class already, the interface vtable needs to
1936        * be initialized as well
1937        */
1938       if (node->data && node->data->class.class)
1939         type_iface_vtable_init_Wm (iface, node);
1940     }
1941   G_WRITE_UNLOCK (&type_rw_lock);
1942 }
1943
1944
1945 /* --- public API functions --- */
1946 gpointer
1947 g_type_class_ref (GType type)
1948 {
1949   TypeNode *node;
1950   
1951   /* optimize for common code path
1952    */
1953   G_WRITE_LOCK (&type_rw_lock);
1954   node = lookup_type_node_L (type);
1955   if (node && node->is_classed && node->data &&
1956       node->data->class.class && node->data->common.ref_count > 0)
1957     {
1958       type_data_ref_Wm (node);
1959       G_WRITE_UNLOCK (&type_rw_lock);
1960       
1961       return node->data->class.class;
1962     }
1963   
1964   if (!node || !node->is_classed ||
1965       (node->data && node->data->common.ref_count < 1))
1966     {
1967       G_WRITE_UNLOCK (&type_rw_lock);
1968       g_warning ("cannot retrive class for invalid (unclassed) type `%s'",
1969                  type_descriptive_name_U (type));
1970       return NULL;
1971     }
1972   
1973   type_data_ref_Wm (node);
1974   
1975   if (!node->data->class.class)
1976     {
1977       GType ptype = NODE_PARENT_TYPE (node);
1978       GTypeClass *pclass = NULL;
1979       
1980       if (ptype)
1981         {
1982           G_WRITE_UNLOCK (&type_rw_lock);
1983           pclass = g_type_class_ref (ptype);
1984           if (node->data->class.class)
1985             INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
1986           G_WRITE_LOCK (&type_rw_lock);
1987         }
1988       
1989       type_class_init_Wm (node, pclass);
1990     }
1991   G_WRITE_UNLOCK (&type_rw_lock);
1992   
1993   return node->data->class.class;
1994 }
1995
1996 void
1997 g_type_class_unref (gpointer g_class)
1998 {
1999   TypeNode *node;
2000   GTypeClass *class = g_class;
2001   
2002   g_return_if_fail (g_class != NULL);
2003   
2004   G_WRITE_LOCK (&type_rw_lock);
2005   node = lookup_type_node_L (class->g_type);
2006   if (node && node->is_classed && node->data &&
2007       node->data->class.class == class && node->data->common.ref_count > 0)
2008     type_data_unref_Wm (node, FALSE);
2009   else
2010     g_warning ("cannot unreference class of invalid (unclassed) type `%s'",
2011                type_descriptive_name_L (class->g_type));
2012   G_WRITE_UNLOCK (&type_rw_lock);
2013 }
2014
2015 void
2016 g_type_class_unref_uncached (gpointer g_class)
2017 {
2018   TypeNode *node;
2019   GTypeClass *class = g_class;
2020   
2021   g_return_if_fail (g_class != NULL);
2022   
2023   G_WRITE_LOCK (&type_rw_lock);
2024   node = lookup_type_node_L (class->g_type);
2025   if (node && node->is_classed && node->data &&
2026       node->data->class.class == class && node->data->common.ref_count > 0)
2027     type_data_unref_Wm (node, TRUE);
2028   else
2029     g_warning ("cannot unreference class of invalid (unclassed) type `%s'",
2030                type_descriptive_name_L (class->g_type));
2031   G_WRITE_UNLOCK (&type_rw_lock);
2032 }
2033
2034 gpointer
2035 g_type_class_peek (GType type)
2036 {
2037   TypeNode *node;
2038   gpointer class;
2039   
2040   G_READ_LOCK (&type_rw_lock);
2041   node = lookup_type_node_L (type);
2042   if (node && node->is_classed && node->data && node->data->class.class) /* common.ref_count _may_ be 0 */
2043     class = node->data->class.class;
2044   else
2045     class = NULL;
2046   G_READ_UNLOCK (&type_rw_lock);
2047   
2048   return class;
2049 }
2050
2051 gpointer
2052 g_type_class_peek_parent (gpointer g_class)
2053 {
2054   TypeNode *node;
2055   gpointer class = NULL;
2056   
2057   g_return_val_if_fail (g_class != NULL, NULL);
2058   
2059   G_READ_LOCK (&type_rw_lock);
2060   node = lookup_type_node_L (G_TYPE_FROM_CLASS (g_class));
2061   if (node && node->is_classed && node->data && NODE_PARENT_TYPE (node))
2062     {
2063       node = lookup_type_node_L (NODE_PARENT_TYPE (node));
2064       class = node->data->class.class;
2065     }
2066   else if (NODE_PARENT_TYPE (node))
2067     g_warning (G_STRLOC ": invalid class pointer `%p'", g_class);
2068   G_READ_UNLOCK (&type_rw_lock);
2069   
2070   return class;
2071 }
2072
2073 gpointer
2074 g_type_interface_peek (gpointer instance_class,
2075                        GType    iface_type)
2076 {
2077   TypeNode *node;
2078   TypeNode *iface;
2079   gpointer vtable = NULL;
2080   GTypeClass *class = instance_class;
2081   
2082   g_return_val_if_fail (instance_class != NULL, NULL);
2083   
2084   G_READ_LOCK (&type_rw_lock);
2085   node = lookup_type_node_L (class->g_type);
2086   iface = lookup_type_node_L (iface_type);
2087   if (node && node->is_instantiatable && iface)
2088     {
2089       IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
2090       
2091       if (entry && entry->vtable)
2092         vtable = entry->vtable;
2093     }
2094   else
2095     g_warning (G_STRLOC ": invalid class pointer `%p'", class);
2096   G_READ_UNLOCK (&type_rw_lock);
2097   
2098   return vtable;
2099 }
2100
2101 gpointer
2102 g_type_interface_peek_parent (gpointer g_iface)
2103 {
2104   TypeNode *node;
2105   TypeNode *iface;
2106   gpointer vtable = NULL;
2107   GTypeInterface *iface_class = g_iface;
2108
2109   g_return_val_if_fail (g_iface != NULL, NULL);
2110
2111   G_READ_LOCK (&type_rw_lock);
2112   iface = lookup_type_node_L (iface_class->g_type);
2113   node = lookup_type_node_L (iface_class->g_instance_type);
2114   if (node)
2115     node = lookup_type_node_L (NODE_PARENT_TYPE (node));
2116   if (node && node->is_instantiatable && iface)
2117     {
2118       IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
2119
2120       if (entry && entry->vtable)
2121         vtable = entry->vtable;
2122     }
2123   else if (node)
2124     g_warning (G_STRLOC ": invalid interface pointer `%p'", g_iface);
2125   G_READ_UNLOCK (&type_rw_lock);
2126
2127   return vtable;
2128 }
2129
2130 G_CONST_RETURN gchar*
2131 g_type_name (GType type)
2132 {
2133   TypeNode *node;
2134   
2135   g_return_val_if_uninitialized (static_last_fundamental_id, g_type_init, NULL);
2136
2137   G_READ_LOCK (&type_rw_lock);
2138   node = lookup_type_node_L (type);
2139   G_READ_UNLOCK (&type_rw_lock);
2140   
2141   return node ? NODE_NAME (node) : NULL;
2142 }
2143
2144 GQuark
2145 g_type_qname (GType type)
2146 {
2147   TypeNode *node;
2148   
2149   G_READ_LOCK (&type_rw_lock);
2150   node = lookup_type_node_L (type);
2151   G_READ_UNLOCK (&type_rw_lock);
2152   
2153   return node ? node->qname : 0;
2154 }
2155
2156 GType
2157 g_type_from_name (const gchar *name)
2158 {
2159   GType type = 0;
2160   GQuark quark;
2161   
2162   g_return_val_if_fail (name != NULL, 0);
2163   
2164   quark = g_quark_try_string (name);
2165   if (quark)
2166     {
2167       G_READ_LOCK (&type_rw_lock);
2168       type = GPOINTER_TO_UINT (g_hash_table_lookup (static_type_nodes_ht, GUINT_TO_POINTER (quark)));
2169       G_READ_UNLOCK (&type_rw_lock);
2170     }
2171   
2172   return type;
2173 }
2174
2175 GType
2176 g_type_parent (GType type)
2177 {
2178   TypeNode *node;
2179   
2180   G_READ_LOCK (&type_rw_lock);
2181   node = lookup_type_node_L (type);
2182   G_READ_UNLOCK (&type_rw_lock);
2183   
2184   return node ? NODE_PARENT_TYPE (node) : 0;
2185 }
2186
2187 guint
2188 g_type_depth (GType type)
2189 {
2190   TypeNode *node;
2191   
2192   G_READ_LOCK (&type_rw_lock);
2193   node = lookup_type_node_L (type);
2194   G_READ_UNLOCK (&type_rw_lock);
2195   
2196   return node ? node->n_supers + 1 : 0;
2197 }
2198
2199 GType
2200 g_type_next_base (GType type,
2201                   GType base_type)
2202 {
2203   GType atype = 0;
2204   TypeNode *node;
2205   
2206   G_READ_LOCK (&type_rw_lock);
2207   node = lookup_type_node_L (type);
2208   if (node)
2209     {
2210       TypeNode *base_node = lookup_type_node_L (base_type);
2211       
2212       if (base_node && base_node->n_supers < node->n_supers)
2213         {
2214           guint n = node->n_supers - base_node->n_supers;
2215           
2216           if (node->supers[n] == base_type)
2217             atype = node->supers[n - 1];
2218         }
2219     }
2220   G_READ_UNLOCK (&type_rw_lock);
2221   
2222   return atype;
2223 }
2224
2225 static inline gboolean
2226 type_node_is_a_L (TypeNode *node,
2227                   TypeNode *iface_node,
2228                   /*        support_inheritance */
2229                   gboolean  support_interfaces,
2230                   gboolean  support_prerequisites)
2231 {
2232   if (support_interfaces &&
2233       node->is_instantiatable && NODE_IS_IFACE (iface_node) &&
2234       type_lookup_iface_entry_L (node, iface_node) != NULL)
2235     return TRUE;
2236   else if (/* support_inheritance && */
2237            iface_node->n_supers <= node->n_supers &&
2238            node->supers[node->n_supers - iface_node->n_supers] == NODE_TYPE (iface_node))
2239     return TRUE;
2240   else if (support_prerequisites &&
2241            NODE_IS_IFACE (node) &&
2242            type_lookup_prerequisite_L (node, NODE_TYPE (iface_node)))
2243     return TRUE;
2244   else
2245     return FALSE;
2246 }
2247
2248 gboolean
2249 g_type_is_a (GType type,
2250              GType iface_type)
2251 {
2252   TypeNode *node, *iface_node;
2253   gboolean is_a;
2254
2255   G_READ_LOCK (&type_rw_lock);
2256   node = lookup_type_node_L (type);
2257   iface_node = lookup_type_node_L (iface_type);
2258   is_a = node && iface_node && type_node_is_a_L (node, iface_node, TRUE, TRUE);
2259   G_READ_UNLOCK (&type_rw_lock);
2260
2261   return is_a;
2262 }
2263
2264 guint
2265 g_type_fundamental_branch_last (GType type)
2266 {
2267   GType ftype = G_TYPE_FUNDAMENTAL (type);
2268   guint last_type;
2269   
2270   G_READ_LOCK (&type_rw_lock);
2271   last_type = ftype < static_last_fundamental_id ? static_branch_seqnos[ftype] : 0;
2272   G_READ_UNLOCK (&type_rw_lock);
2273   
2274   return last_type;
2275 }
2276
2277 GType* /* free result */
2278 g_type_children (GType  type,
2279                  guint *n_children)
2280 {
2281   TypeNode *node;
2282   
2283   G_READ_LOCK (&type_rw_lock);
2284   node = lookup_type_node_L (type);
2285   if (node)
2286     {
2287       GType *children = g_new (GType, node->n_children + 1);
2288       
2289       memcpy (children, node->children, sizeof (GType) * node->n_children);
2290       children[node->n_children] = 0;
2291       
2292       if (n_children)
2293         *n_children = node->n_children;
2294       G_READ_UNLOCK (&type_rw_lock);
2295       
2296       return children;
2297     }
2298   else
2299     {
2300       G_READ_UNLOCK (&type_rw_lock);
2301       if (n_children)
2302         *n_children = 0;
2303       
2304       return NULL;
2305     }
2306 }
2307
2308 GType* /* free result */
2309 g_type_interfaces (GType  type,
2310                    guint *n_interfaces)
2311 {
2312   TypeNode *node;
2313   
2314   G_READ_LOCK (&type_rw_lock);
2315   node = lookup_type_node_L (type);
2316   if (node && node->is_instantiatable)
2317     {
2318       GType *ifaces = g_new (GType, CLASSED_NODE_N_IFACES (node) + 1);
2319       guint i;
2320       
2321       for (i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
2322         ifaces[i] = CLASSED_NODE_IFACES_ENTRIES (node)[i].iface_type;
2323       ifaces[i] = 0;
2324       
2325       if (n_interfaces)
2326         *n_interfaces = CLASSED_NODE_N_IFACES (node);
2327       G_READ_UNLOCK (&type_rw_lock);
2328       
2329       return ifaces;
2330     }
2331   else
2332     {
2333       G_READ_UNLOCK (&type_rw_lock);
2334       if (n_interfaces)
2335         *n_interfaces = 0;
2336       
2337       return NULL;
2338     }
2339 }
2340
2341 typedef struct _QData QData;
2342 struct _GData
2343 {
2344   guint  n_qdatas;
2345   QData *qdatas;
2346 };
2347 struct _QData
2348 {
2349   GQuark   quark;
2350   gpointer data;
2351 };
2352
2353 static inline gpointer
2354 type_get_qdata_L (TypeNode *node,
2355                   GQuark    quark)
2356 {
2357   GData *gdata = node->global_gdata;
2358   
2359   if (quark && gdata && gdata->n_qdatas)
2360     {
2361       QData *qdatas = gdata->qdatas - 1;
2362       guint n_qdatas = gdata->n_qdatas;
2363       
2364       do
2365         {
2366           guint i;
2367           QData *check;
2368           
2369           i = (n_qdatas + 1) / 2;
2370           check = qdatas + i;
2371           if (quark == check->quark)
2372             return check->data;
2373           else if (quark > check->quark)
2374             {
2375               n_qdatas -= i;
2376               qdatas = check;
2377             }
2378           else /* if (quark < check->quark) */
2379             n_qdatas = i - 1;
2380         }
2381       while (n_qdatas);
2382     }
2383   return NULL;
2384 }
2385
2386 gpointer
2387 g_type_get_qdata (GType  type,
2388                   GQuark quark)
2389 {
2390   TypeNode *node;
2391   gpointer data;
2392   
2393   G_READ_LOCK (&type_rw_lock);
2394   node = lookup_type_node_L (type);
2395   if (node)
2396     {
2397       data = type_get_qdata_L (node, quark);
2398       G_READ_UNLOCK (&type_rw_lock);
2399     }
2400   else
2401     {
2402       G_READ_UNLOCK (&type_rw_lock);
2403       g_return_val_if_fail (node != NULL, NULL);
2404       data = NULL;
2405     }
2406   return data;
2407 }
2408
2409 static inline void
2410 type_set_qdata_W (TypeNode *node,
2411                   GQuark    quark,
2412                   gpointer  data)
2413 {
2414   GData *gdata;
2415   QData *qdata;
2416   guint i;
2417   
2418   /* setup qdata list if necessary */
2419   if (!node->global_gdata)
2420     node->global_gdata = g_new0 (GData, 1);
2421   gdata = node->global_gdata;
2422   
2423   /* try resetting old data */
2424   qdata = gdata->qdatas;
2425   for (i = 0; i < gdata->n_qdatas; i++)
2426     if (qdata[i].quark == quark)
2427       {
2428         qdata[i].data = data;
2429         return;
2430       }
2431   
2432   /* add new entry */
2433   gdata->n_qdatas++;
2434   gdata->qdatas = g_renew (QData, gdata->qdatas, gdata->n_qdatas);
2435   qdata = gdata->qdatas;
2436   for (i = 0; i < gdata->n_qdatas - 1; i++)
2437     if (qdata[i].quark > quark)
2438       break;
2439   g_memmove (qdata + i + 1, qdata + i, sizeof (qdata[0]) * (gdata->n_qdatas - i - 1));
2440   qdata[i].quark = quark;
2441   qdata[i].data = data;
2442 }
2443
2444 void
2445 g_type_set_qdata (GType    type,
2446                   GQuark   quark,
2447                   gpointer data)
2448 {
2449   TypeNode *node;
2450   
2451   g_return_if_fail (quark != 0);
2452   
2453   G_WRITE_LOCK (&type_rw_lock);
2454   node = lookup_type_node_L (type);
2455   if (node)
2456     {
2457       type_set_qdata_W (node, quark, data);
2458       G_WRITE_UNLOCK (&type_rw_lock);
2459     }
2460   else
2461     {
2462       G_WRITE_UNLOCK (&type_rw_lock);
2463       g_return_if_fail (node != NULL);
2464     }
2465 }
2466
2467 static void
2468 type_add_flags_W (TypeNode  *node,
2469                   GTypeFlags flags)
2470 {
2471   guint dflags;
2472   
2473   g_return_if_fail ((flags & ~TYPE_FLAG_MASK) == 0);
2474   g_return_if_fail (node != NULL);
2475   
2476   if ((flags & TYPE_FLAG_MASK) && node->is_classed && node->data && node->data->class.class)
2477     g_warning ("tagging type `%s' as abstract after class initialization", NODE_NAME (node));
2478   dflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags));
2479   dflags |= flags;
2480   type_set_qdata_W (node, static_quark_type_flags, GUINT_TO_POINTER (dflags));
2481 }
2482
2483 void
2484 g_type_query (GType       type,
2485               GTypeQuery *query)
2486 {
2487   TypeNode *node;
2488
2489   g_return_if_fail (query != NULL);
2490   
2491   G_READ_LOCK (&type_rw_lock);
2492   node = lookup_type_node_L (type);
2493   if (node && node->is_classed && !node->plugin && node->data)
2494     {
2495       /* type is classed and static, probably even instantiatable */
2496
2497       query->type = NODE_TYPE (node);
2498       query->type_name = NODE_NAME (node);
2499       query->class_size = node->data->class.class_size;
2500       query->instance_size = node->is_instantiatable ? node->data->instance.instance_size : 0;
2501     }
2502   else
2503     {
2504       /* node is not static and classed, won't allow query */
2505       query->type = 0;
2506     }
2507   G_READ_UNLOCK (&type_rw_lock);
2508 }
2509
2510
2511 /* --- implementation details --- */
2512 gboolean
2513 g_type_check_flags (GType type,
2514                     guint flags)
2515 {
2516   TypeNode *node;
2517   gboolean result = FALSE;
2518   
2519   G_READ_LOCK (&type_rw_lock);
2520   node = lookup_type_node_L (type);
2521   if (node)
2522     {
2523       guint fflags = flags & TYPE_FUNDAMENTAL_FLAG_MASK;
2524       guint tflags = flags & TYPE_FLAG_MASK;
2525       
2526       if (fflags)
2527         {
2528           GTypeFundamentalInfo *finfo = type_node_fundamental_info_L (node);
2529           
2530           fflags = (finfo->type_flags & fflags) == fflags;
2531         }
2532       else
2533         fflags = TRUE;
2534       
2535       if (tflags)
2536         tflags = (tflags & GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags))) == tflags;
2537       else
2538         tflags = TRUE;
2539       
2540       result = tflags && fflags;
2541     }
2542   G_READ_UNLOCK (&type_rw_lock);
2543   
2544   return result;
2545 }
2546
2547 GTypePlugin*
2548 g_type_get_plugin (GType type)
2549 {
2550   TypeNode *node;
2551   
2552   G_READ_LOCK (&type_rw_lock);
2553   node = lookup_type_node_L (type);
2554   G_READ_UNLOCK (&type_rw_lock);
2555   
2556   return node ? node->plugin : NULL;
2557 }
2558
2559 GTypePlugin*
2560 g_type_interface_get_plugin (GType instance_type,
2561                              GType interface_type)
2562 {
2563   TypeNode *node;
2564   TypeNode *iface;
2565   
2566   g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL);
2567   
2568   G_READ_LOCK (&type_rw_lock);
2569   node = lookup_type_node_L (instance_type);  
2570   iface = lookup_type_node_L (interface_type);
2571   if (node && iface)
2572     {
2573       IFaceHolder *iholder = iface_node_get_holders_L (iface);
2574       
2575       while (iholder && iholder->instance_type != instance_type)
2576         iholder = iholder->next;
2577       G_READ_UNLOCK (&type_rw_lock);
2578       
2579       if (iholder)
2580         return iholder->plugin;
2581     }
2582   else
2583     G_READ_UNLOCK (&type_rw_lock);
2584   
2585   g_return_val_if_fail (node == NULL, NULL);
2586   g_return_val_if_fail (iface == NULL, NULL);
2587   
2588   g_warning (G_STRLOC ": attempt to look up plugin for invalid instance/interface type pair.");
2589   
2590   return NULL;
2591 }
2592
2593 GType
2594 g_type_fundamental_last (void)
2595 {
2596   GType type;
2597   
2598   G_READ_LOCK (&type_rw_lock);
2599   type = static_last_fundamental_id;
2600   G_READ_UNLOCK (&type_rw_lock);
2601   
2602   return type;
2603 }
2604
2605 gboolean
2606 g_type_instance_is_a (GTypeInstance *type_instance,
2607                       GType          iface_type)
2608 {
2609   TypeNode *node, *iface;
2610   gboolean check;
2611
2612   if (!type_instance || !type_instance->g_class)
2613     return FALSE;
2614
2615   G_READ_LOCK (&type_rw_lock);
2616   node = lookup_type_node_L (type_instance->g_class->g_type);
2617   iface = lookup_type_node_L (iface_type);
2618   check = node && node->is_instantiatable && iface && type_node_is_a_L (node, iface, TRUE, FALSE);
2619   G_READ_UNLOCK (&type_rw_lock);
2620
2621   return check;
2622 }
2623
2624 gboolean
2625 g_type_class_is_a (GTypeClass *type_class,
2626                    GType       is_a_type)
2627 {
2628   TypeNode *node, *iface;
2629   gboolean check;
2630
2631   if (!type_class)
2632     return FALSE;
2633
2634   G_READ_LOCK (&type_rw_lock);
2635   node = lookup_type_node_L (type_class->g_type);
2636   iface = lookup_type_node_L (is_a_type);
2637   check = node && node->is_classed && iface && type_node_is_a_L (node, iface, FALSE, FALSE);
2638   G_READ_UNLOCK (&type_rw_lock);
2639
2640   return check;
2641 }
2642
2643 GTypeInstance*
2644 g_type_check_instance_cast (GTypeInstance *type_instance,
2645                             GType          iface_type)
2646 {
2647   if (type_instance)
2648     {
2649       if (type_instance->g_class)
2650         {
2651           TypeNode *node, *iface;
2652           gboolean is_instantiatable, check;
2653
2654           G_READ_LOCK (&type_rw_lock);
2655           node = lookup_type_node_L (type_instance->g_class->g_type);
2656           is_instantiatable = node && node->is_instantiatable;
2657           iface = lookup_type_node_L (iface_type);
2658           check = is_instantiatable && iface && type_node_is_a_L (node, iface, TRUE, FALSE);
2659           G_READ_UNLOCK (&type_rw_lock);
2660           if (check)
2661             return type_instance;
2662
2663           if (is_instantiatable)
2664             g_warning ("invalid cast from `%s' to `%s'",
2665                        type_descriptive_name_U (type_instance->g_class->g_type),
2666                        type_descriptive_name_U (iface_type));
2667           else
2668             g_warning ("invalid uninstantiatable type `%s' in cast to `%s'",
2669                        type_descriptive_name_U (type_instance->g_class->g_type),
2670                        type_descriptive_name_U (iface_type));
2671         }
2672       else
2673         g_warning ("invalid unclassed pointer in cast to `%s'",
2674                    type_descriptive_name_U (iface_type));
2675     }
2676   else
2677     g_warning ("invalid cast from (NULL) pointer to `%s'",
2678                type_descriptive_name_U (iface_type));
2679   
2680   return type_instance;
2681 }
2682
2683 GTypeClass*
2684 g_type_check_class_cast (GTypeClass *type_class,
2685                          GType       is_a_type)
2686 {
2687   if (type_class)
2688     {
2689       TypeNode *node, *iface;
2690       gboolean is_classed, check;
2691       
2692       G_READ_LOCK (&type_rw_lock);
2693       node = lookup_type_node_L (type_class->g_type);
2694       is_classed = node && node->is_classed;
2695       iface = lookup_type_node_L (is_a_type);
2696       check = is_classed && iface && type_node_is_a_L (node, iface, FALSE, FALSE);
2697       G_READ_UNLOCK (&type_rw_lock);
2698       if (check)
2699         return type_class;
2700
2701       if (is_classed)
2702         g_warning ("invalid class cast from `%s' to `%s'",
2703                    type_descriptive_name_U (type_class->g_type),
2704                    type_descriptive_name_U (is_a_type));
2705       else
2706         g_warning ("invalid unclassed type `%s' in class cast to `%s'",
2707                    type_descriptive_name_U (type_class->g_type),
2708                    type_descriptive_name_U (is_a_type));
2709     }
2710   else
2711     g_warning ("invalid class cast from (NULL) pointer to `%s'",
2712                type_descriptive_name_U (is_a_type));
2713   return type_class;
2714 }
2715
2716 gboolean
2717 g_type_check_instance (GTypeInstance *type_instance)
2718 {
2719   /* this function is just here to make the signal system
2720    * conveniently elaborated on instance checks
2721    */
2722   if (type_instance)
2723     {
2724       if (type_instance->g_class)
2725         {
2726           TypeNode *node;
2727           gboolean is_instantiatable;
2728           
2729           G_READ_LOCK (&type_rw_lock);
2730           node = lookup_type_node_L (type_instance->g_class->g_type);
2731           is_instantiatable = node && node->is_instantiatable;
2732           G_READ_UNLOCK (&type_rw_lock);
2733           if (is_instantiatable)
2734             return TRUE;
2735
2736           g_warning ("instance of invalid non-instantiatable type `%s'",
2737                      type_descriptive_name_U (type_instance->g_class->g_type));
2738         }
2739       else
2740         g_warning ("instance with invalid (NULL) class pointer");
2741     }
2742   else
2743     g_warning ("invalid (NULL) pointer instance");
2744
2745   return FALSE;
2746 }
2747
2748 static inline gboolean
2749 type_check_is_value_type_U (GType type)
2750 {
2751   GTypeFlags tflags = G_TYPE_FLAG_VALUE_ABSTRACT;
2752   TypeNode *node;
2753
2754   G_READ_LOCK (&type_rw_lock);
2755  restart_check:
2756   node = lookup_type_node_L (type);
2757   if (node)
2758     {
2759       if (node->data && node->data->common.ref_count > 0 &&
2760           node->data->common.value_table->value_init)
2761         tflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags));
2762       else if (NODE_IS_IFACE (node))
2763         {
2764           guint i;
2765
2766           for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++)
2767             {
2768               GType prtype = IFACE_NODE_PREREQUISITES (node)[i];
2769               TypeNode *prnode = lookup_type_node_L (prtype);
2770
2771               if (prnode->is_instantiatable)
2772                 {
2773                   type = prtype;
2774                   goto restart_check;
2775                 }
2776             }
2777         }
2778     }
2779   G_READ_UNLOCK (&type_rw_lock);
2780
2781   return !(tflags & G_TYPE_FLAG_VALUE_ABSTRACT);
2782 }
2783
2784 gboolean
2785 g_type_check_is_value_type (GType type)
2786 {
2787   return type_check_is_value_type_U (type);
2788 }
2789
2790 gboolean
2791 g_type_check_value (GValue *value)
2792 {
2793   return value && type_check_is_value_type_U (value->g_type);
2794 }
2795
2796 gboolean
2797 g_type_check_value_holds (GValue *value,
2798                           GType   type)
2799 {
2800   return value && type_check_is_value_type_U (value->g_type) && g_type_is_a (value->g_type, type);
2801 }
2802
2803 GTypeValueTable*
2804 g_type_value_table_peek (GType type)
2805 {
2806   TypeNode *node;
2807   GTypeValueTable *vtable;
2808   
2809   G_READ_LOCK (&type_rw_lock);
2810  restart_table_peek:
2811   node = lookup_type_node_L (type);
2812   if (!node)
2813     {
2814       g_warning (G_STRLOC ": type id `%u' is invalid", type);
2815       G_READ_UNLOCK (&type_rw_lock);
2816       return NULL;
2817     }
2818   if (!node->data || node->data->common.ref_count < 1)
2819     {
2820       g_warning ("can't peek value table for type `%s' which is not currently referenced",
2821                  type_descriptive_name_L (type));
2822       G_READ_UNLOCK (&type_rw_lock);
2823       return NULL;
2824     }
2825   if (node->data->common.value_table->value_init)
2826     vtable = node->data->common.value_table;
2827   else if (NODE_IS_IFACE (node))
2828     {
2829       guint i;
2830
2831       for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++)
2832         {
2833           GType prtype = IFACE_NODE_PREREQUISITES (node)[i];
2834           TypeNode *prnode = lookup_type_node_L (prtype);
2835
2836           if (prnode->is_instantiatable)
2837             {
2838               type = prtype;
2839               goto restart_table_peek;
2840             }
2841         }
2842       vtable = NULL;
2843     }
2844   else
2845     vtable = NULL;
2846   G_READ_UNLOCK (&type_rw_lock);
2847   
2848   return vtable;
2849 }
2850
2851 G_CONST_RETURN gchar*
2852 g_type_name_from_instance (GTypeInstance *instance)
2853 {
2854   if (!instance)
2855     return "<NULL-instance>";
2856   else
2857     return g_type_name_from_class (instance->g_class);
2858 }
2859
2860 G_CONST_RETURN gchar*
2861 g_type_name_from_class (GTypeClass *g_class)
2862 {
2863   if (!g_class)
2864     return "<NULL-class>";
2865   else
2866     return g_type_name (g_class->g_type);
2867 }
2868
2869
2870 /* --- foreign prototypes --- */
2871 extern void     g_value_types_init      (void); /* sync with gvaluetypes.c */
2872 extern void     g_enum_types_init       (void); /* sync with genums.c */
2873 extern void     g_param_type_init       (void); /* sync with gparam.c */
2874 extern void     g_boxed_type_init       (void); /* sync with gboxed.c */
2875 extern void     g_object_type_init      (void); /* sync with gobject.c */
2876 extern void     g_param_spec_types_init (void); /* sync with gparamspecs.c */
2877 extern void     g_value_transforms_init (void); /* sync with gvaluetransform.c */
2878 extern void     g_signal_init           (void); /* sync with gsignal.c */
2879
2880
2881 /* --- initialization --- */
2882 void
2883 g_type_init_with_debug_flags (GTypeDebugFlags debug_flags)
2884 {
2885   G_LOCK_DEFINE_STATIC (type_init_lock);
2886   static TypeNode *type0_node = NULL;
2887   const gchar *env_string;
2888   GTypeInfo info;
2889   TypeNode *node;
2890   GType type;
2891   
2892   G_LOCK (type_init_lock);
2893   
2894   G_WRITE_LOCK (&type_rw_lock);
2895   
2896   if (static_last_fundamental_id)
2897     {
2898       G_WRITE_UNLOCK (&type_rw_lock);
2899       G_UNLOCK (type_init_lock);
2900       return;
2901     }
2902
2903   /* setup GRuntime wide debugging flags */
2904   _g_type_debug_flags = debug_flags & G_TYPE_DEBUG_MASK;
2905   env_string = g_getenv ("GRUNTIME_DEBUG");
2906   if (env_string != NULL)
2907     {
2908       static GDebugKey debug_keys[] = {
2909         { "objects", G_TYPE_DEBUG_OBJECTS },
2910         { "signals", G_TYPE_DEBUG_SIGNALS },
2911       };
2912
2913       _g_type_debug_flags |= g_parse_debug_string (env_string,
2914                                                    debug_keys,
2915                                                    sizeof (debug_keys) / sizeof (debug_keys[0]));
2916       env_string = NULL;
2917     }
2918   
2919   /* quarks */
2920   static_quark_type_flags = g_quark_from_static_string ("-g-type-private--GTypeFlags");
2921   static_quark_iface_holder = g_quark_from_static_string ("-g-type-private--IFaceHolder");
2922   static_quark_dependants_array = g_quark_from_static_string ("-g-type-private--dependants-array");
2923   
2924   /* type qname hash table */
2925   static_type_nodes_ht = g_hash_table_new (g_direct_hash, g_direct_equal);
2926   
2927   /* invalid type G_TYPE_INVALID (0)
2928    */
2929   static_last_fundamental_id = 1;
2930   static_type_nodes = g_renew (TypeNode**, static_type_nodes, static_last_fundamental_id);
2931   static_type_nodes[0] = &type0_node;
2932   static_branch_seqnos = g_renew (GType, static_branch_seqnos, static_last_fundamental_id);
2933   static_branch_seqnos[0] = 1;
2934   
2935   /* void type G_TYPE_NONE
2936    */
2937   node = type_node_fundamental_new_W (G_TYPE_NONE, "void", 0);
2938   type = NODE_TYPE (node);
2939   g_assert (type == G_TYPE_NONE);
2940   
2941   /* interface fundamental type G_TYPE_INTERFACE (!classed)
2942    */
2943   memset (&info, 0, sizeof (info));
2944   node = type_node_fundamental_new_W (G_TYPE_INTERFACE, "GInterface", G_TYPE_FLAG_DERIVABLE);
2945   type = NODE_TYPE (node);
2946   type_data_make_W (node, &info, NULL);
2947   g_assert (type == G_TYPE_INTERFACE);
2948   
2949   G_WRITE_UNLOCK (&type_rw_lock);
2950   
2951   /* G_TYPE_TYPE_PLUGIN
2952    */
2953   g_type_plugin_get_type ();
2954   
2955   /* G_TYPE_* value types
2956    */
2957   g_value_types_init ();
2958   
2959   /* G_TYPE_ENUM & G_TYPE_FLAGS
2960    */
2961   g_enum_types_init ();
2962   
2963   /* G_TYPE_BOXED
2964    */
2965   g_boxed_type_init ();
2966   
2967   /* G_TYPE_PARAM
2968    */
2969   g_param_type_init ();
2970   
2971   /* G_TYPE_OBJECT
2972    */
2973   g_object_type_init ();
2974   
2975   /* G_TYPE_PARAM_* pspec types
2976    */
2977   g_param_spec_types_init ();
2978   
2979   /* Value Transformations
2980    */
2981   g_value_transforms_init ();
2982
2983   /* Signal system
2984    */
2985   g_signal_init ();
2986   
2987   G_UNLOCK (type_init_lock);
2988 }
2989
2990 void 
2991 g_type_init (void)
2992 {
2993   g_type_init_with_debug_flags (0);
2994 }