fixed race condition where references to partially initialized classes
[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        <config.h>
20 #include        "gtype.h"
21
22 /*
23  * MT safe
24  */
25
26 #include        "gtypeplugin.h"
27 #include        "gvaluecollector.h"
28 #include        "gbsearcharray.h"
29 #include        <string.h>
30
31 #include        "gobjectalias.h"
32
33 /* NOTE: some functions (some internal variants and exported ones)
34  * invalidate data portions of the TypeNodes. if external functions/callbacks
35  * are called, pointers to memory maintained by TypeNodes have to be looked up
36  * again. this affects most of the struct TypeNode fields, e.g. ->children or
37  * CLASSED_NODE_IFACES_ENTRIES() respectively IFACE_NODE_PREREQUISITES() (but
38  * not ->supers[]), as all those memory portions can get realloc()ed during
39  * callback invocation.
40  *
41  * TODO:
42  * - g_type_from_name() should do an ordered array lookup after fetching the
43  *   the quark, instead of a second hashtable lookup.
44  *
45  * LOCKING:
46  * lock handling issues when calling static functions are indicated by
47  * uppercase letter postfixes, all static functions have to have
48  * one of the below postfixes:
49  * - _I:        [Indifferent about locking]
50  *   function doesn't care about locks at all
51  * - _U:        [Unlocked invocation]
52  *   no read or write lock has to be held across function invocation
53  *   (locks may be acquired and released during invocation though)
54  * - _L:        [Locked invocation]
55  *   a write lock or more than 0 read locks have to be held across
56  *   function invocation
57  * - _W:        [Write-locked invocation]
58  *   a write lock has to be held across function invocation
59  * - _Wm:       [Write-locked invocation, mutatable]
60  *   like _W, but the write lock might be released and reacquired
61  *   during invocation, watch your pointers
62  * - _WmREC:    [Write-locked invocation, mutatable, recursive]
63  *   like _Wm, but also acquires recursive mutex class_init_rec_mutex
64  */
65
66 #ifdef LOCK_DEBUG
67 #define G_READ_LOCK(rw_lock)    do { g_printerr (G_STRLOC ": readL++\n"); g_static_rw_lock_reader_lock (rw_lock); } while (0)
68 #define G_READ_UNLOCK(rw_lock)  do { g_printerr (G_STRLOC ": readL--\n"); g_static_rw_lock_reader_unlock (rw_lock); } while (0)
69 #define G_WRITE_LOCK(rw_lock)   do { g_printerr (G_STRLOC ": writeL++\n"); g_static_rw_lock_writer_lock (rw_lock); } while (0)
70 #define G_WRITE_UNLOCK(rw_lock) do { g_printerr (G_STRLOC ": writeL--\n"); g_static_rw_lock_writer_unlock (rw_lock); } while (0)
71 #else
72 #define G_READ_LOCK(rw_lock)    g_static_rw_lock_reader_lock (rw_lock)
73 #define G_READ_UNLOCK(rw_lock)  g_static_rw_lock_reader_unlock (rw_lock)
74 #define G_WRITE_LOCK(rw_lock)   g_static_rw_lock_writer_lock (rw_lock)
75 #define G_WRITE_UNLOCK(rw_lock) g_static_rw_lock_writer_unlock (rw_lock)
76 #endif
77 #define INVALID_RECURSION(func, arg, type_name) G_STMT_START{ \
78     static const gchar _action[] = " invalidly modified type ";  \
79     gpointer _arg = (gpointer) (arg); const gchar *_tname = (type_name), *_fname = (func); \
80     if (_arg) \
81       g_error ("%s(%p)%s`%s'", _fname, _arg, _action, _tname); \
82     else \
83       g_error ("%s()%s`%s'", _fname, _action, _tname); \
84 }G_STMT_END
85 #define g_return_val_if_uninitialized(condition, init_function, return_value) G_STMT_START{     \
86   if (!(condition))                                                                             \
87     {                                                                                           \
88       g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,                                                \
89              "%s: initialization assertion failed, use %s() prior to this function",            \
90              G_STRLOC, G_STRINGIFY (init_function));                                            \
91       return (return_value);                                                                    \
92     }                                                                                           \
93 }G_STMT_END
94
95 #ifdef  G_ENABLE_DEBUG
96 #define DEBUG_CODE(debug_type, code_block)  G_STMT_START {    \
97     if (_g_type_debug_flags & G_TYPE_DEBUG_ ## debug_type) \
98       { code_block; }                                     \
99 } G_STMT_END
100 #else /* !G_ENABLE_DEBUG */
101 #define DEBUG_CODE(debug_type, code_block)  /* code_block */
102 #endif  /* G_ENABLE_DEBUG */
103
104 #define TYPE_FUNDAMENTAL_FLAG_MASK (G_TYPE_FLAG_CLASSED | \
105                                     G_TYPE_FLAG_INSTANTIATABLE | \
106                                     G_TYPE_FLAG_DERIVABLE | \
107                                     G_TYPE_FLAG_DEEP_DERIVABLE)
108 #define TYPE_FLAG_MASK             (G_TYPE_FLAG_ABSTRACT | G_TYPE_FLAG_VALUE_ABSTRACT)
109 #define SIZEOF_FUNDAMENTAL_INFO    ((gssize) MAX (MAX (sizeof (GTypeFundamentalInfo), \
110                                                        sizeof (gpointer)), \
111                                                   sizeof (glong)))
112
113 /* The 2*sizeof(size_t) alignment here is borrowed from
114  * GNU libc, so it should be good most everywhere.
115  * It is more conservative than is needed on some 64-bit
116  * platforms, but ia64 does require a 16-byte alignment.
117  * The SIMD extensions for x86 and ppc32 would want a
118  * larger alignment than this, but we don't need to
119  * do better than malloc.
120  */
121 #define STRUCT_ALIGNMENT (2 * sizeof (gsize))
122 #define ALIGN_STRUCT(offset) \
123       ((offset + (STRUCT_ALIGNMENT - 1)) & -STRUCT_ALIGNMENT)
124
125
126 /* --- typedefs --- */
127 typedef struct _TypeNode        TypeNode;
128 typedef struct _CommonData      CommonData;
129 typedef struct _IFaceData       IFaceData;
130 typedef struct _ClassData       ClassData;
131 typedef struct _InstanceData    InstanceData;
132 typedef union  _TypeData        TypeData;
133 typedef struct _IFaceEntry      IFaceEntry;
134 typedef struct _IFaceHolder     IFaceHolder;
135
136
137 /* --- prototypes --- */
138 static inline GTypeFundamentalInfo*     type_node_fundamental_info_I    (TypeNode               *node);
139 static        void                      type_add_flags_W                (TypeNode               *node,
140                                                                          GTypeFlags              flags);
141 static        void                      type_data_make_W                (TypeNode               *node,
142                                                                          const GTypeInfo        *info,
143                                                                          const GTypeValueTable  *value_table);
144 static inline void                      type_data_ref_Wm                (TypeNode               *node);
145 static inline void                      type_data_unref_WmREC           (TypeNode               *node,
146                                                                          gboolean                uncached);
147 static void                             type_data_last_unref_Wm         (GType                   type,
148                                                                          gboolean                uncached);
149 static inline gpointer                  type_get_qdata_L                (TypeNode               *node,
150                                                                          GQuark                  quark);
151 static inline void                      type_set_qdata_W                (TypeNode               *node,
152                                                                          GQuark                  quark,
153                                                                          gpointer                data);
154 static IFaceHolder*                     type_iface_peek_holder_L        (TypeNode               *iface,
155                                                                          GType                   instance_type);
156 static gboolean                         type_iface_vtable_base_init_Wm  (TypeNode               *iface,
157                                                                          TypeNode               *node);
158 static void                             type_iface_vtable_iface_init_Wm (TypeNode               *iface,
159                                                                          TypeNode               *node);
160 static gboolean                         type_node_is_a_L                (TypeNode               *node,
161                                                                          TypeNode               *iface_node);
162
163
164 /* --- enumeration --- */
165
166 /* The InitState enumeration is used to track the progress of initializing
167  * both classes and interface vtables. Keeping the state of initialization
168  * is necessary to handle new interfaces being added while we are initializing
169  * the class or other interfaces.
170  */
171 typedef enum
172 {
173   UNINITIALIZED,
174   BASE_CLASS_INIT,
175   BASE_IFACE_INIT,
176   CLASS_INIT,
177   IFACE_INIT,
178   INITIALIZED
179 } InitState;
180
181 /* --- structures --- */
182 struct _TypeNode
183 {
184   GTypePlugin *plugin;
185   guint        n_children : 12;
186   guint        n_supers : 8;
187   guint        _prot_n_ifaces_prerequisites : 9;
188   guint        is_classed : 1;
189   guint        is_instantiatable : 1;
190   guint        mutatable_check_cache : 1;       /* combines some common path checks */
191   GType       *children;
192   TypeData * volatile data;
193   GQuark       qname;
194   GData       *global_gdata;
195   union {
196     IFaceEntry  *iface_entries;         /* for !iface types */
197     GType       *prerequisistes;
198   } _prot;
199   GType        supers[1]; /* flexible array */
200 };
201 #define SIZEOF_BASE_TYPE_NODE()                 (G_STRUCT_OFFSET (TypeNode, supers))
202 #define MAX_N_SUPERS                            (255)
203 #define MAX_N_CHILDREN                          (4095)
204 #define MAX_N_IFACES                            (511)
205 #define MAX_N_PREREQUISITES                     (MAX_N_IFACES)
206 #define NODE_TYPE(node)                         (node->supers[0])
207 #define NODE_PARENT_TYPE(node)                  (node->supers[1])
208 #define NODE_FUNDAMENTAL_TYPE(node)             (node->supers[node->n_supers])
209 #define NODE_NAME(node)                         (g_quark_to_string (node->qname))
210 #define NODE_IS_IFACE(node)                     (NODE_FUNDAMENTAL_TYPE (node) == G_TYPE_INTERFACE)
211 #define CLASSED_NODE_N_IFACES(node)             ((node)->_prot_n_ifaces_prerequisites)
212 #define CLASSED_NODE_IFACES_ENTRIES(node)       ((node)->_prot.iface_entries)
213 #define IFACE_NODE_N_PREREQUISITES(node)        ((node)->_prot_n_ifaces_prerequisites)
214 #define IFACE_NODE_PREREQUISITES(node)          ((node)->_prot.prerequisistes)
215 #define iface_node_get_holders_L(node)          ((IFaceHolder*) type_get_qdata_L ((node), static_quark_iface_holder))
216 #define iface_node_set_holders_W(node, holders) (type_set_qdata_W ((node), static_quark_iface_holder, (holders)))
217 #define iface_node_get_dependants_array_L(n)    ((GType*) type_get_qdata_L ((n), static_quark_dependants_array))
218 #define iface_node_set_dependants_array_W(n,d)  (type_set_qdata_W ((n), static_quark_dependants_array, (d)))
219 #define TYPE_ID_MASK                            ((GType) ((1 << G_TYPE_FUNDAMENTAL_SHIFT) - 1))
220
221 #define NODE_IS_ANCESTOR(ancestor, node)                                                    \
222         ((ancestor)->n_supers <= (node)->n_supers &&                                        \
223          (node)->supers[(node)->n_supers - (ancestor)->n_supers] == NODE_TYPE (ancestor))
224
225
226 struct _IFaceHolder
227 {
228   GType           instance_type;
229   GInterfaceInfo *info;
230   GTypePlugin    *plugin;
231   IFaceHolder    *next;
232 };
233 struct _IFaceEntry
234 {
235   GType           iface_type;
236   GTypeInterface *vtable;
237   InitState       init_state;
238 };
239 struct _CommonData
240 {
241   guint             ref_count;
242   GTypeValueTable  *value_table;
243 };
244 struct _IFaceData
245 {
246   CommonData         common;
247   guint16            vtable_size;
248   GBaseInitFunc      vtable_init_base;
249   GBaseFinalizeFunc  vtable_finalize_base;
250   GClassInitFunc     dflt_init;
251   GClassFinalizeFunc dflt_finalize;
252   gconstpointer      dflt_data;
253   gpointer           dflt_vtable;
254 };
255 struct _ClassData
256 {
257   CommonData         common;
258   guint16            class_size;
259   guint              init_state : 4;
260   GBaseInitFunc      class_init_base;
261   GBaseFinalizeFunc  class_finalize_base;
262   GClassInitFunc     class_init;
263   GClassFinalizeFunc class_finalize;
264   gconstpointer      class_data;
265   gpointer           class;
266 };
267 struct _InstanceData
268 {
269   CommonData         common;
270   guint16            class_size;
271   guint              init_state : 4;
272   GBaseInitFunc      class_init_base;
273   GBaseFinalizeFunc  class_finalize_base;
274   GClassInitFunc     class_init;
275   GClassFinalizeFunc class_finalize;
276   gconstpointer      class_data;
277   gpointer           class;
278   guint16            instance_size;
279   guint16            private_size;
280   guint16            n_preallocs;
281   GInstanceInitFunc  instance_init;
282 };
283 union _TypeData
284 {
285   CommonData         common;
286   IFaceData          iface;
287   ClassData          class;
288   InstanceData       instance;
289 };
290 typedef struct {
291   gpointer            cache_data;
292   GTypeClassCacheFunc cache_func;
293 } ClassCacheFunc;
294 typedef struct {
295   gpointer                check_data;
296   GTypeInterfaceCheckFunc check_func;
297 } IFaceCheckFunc;
298
299
300 /* --- variables --- */
301 static GStaticRWLock   type_rw_lock = G_STATIC_RW_LOCK_INIT;
302 static GStaticRecMutex class_init_rec_mutex = G_STATIC_REC_MUTEX_INIT;
303 static guint           static_n_class_cache_funcs = 0;
304 static ClassCacheFunc *static_class_cache_funcs = NULL;
305 static guint           static_n_iface_check_funcs = 0;
306 static IFaceCheckFunc *static_iface_check_funcs = NULL;
307 static GQuark          static_quark_type_flags = 0;
308 static GQuark          static_quark_iface_holder = 0;
309 static GQuark          static_quark_dependants_array = 0;
310 GTypeDebugFlags        _g_type_debug_flags = 0;
311
312
313 /* --- type nodes --- */
314 static GHashTable       *static_type_nodes_ht = NULL;
315 static TypeNode         *static_fundamental_type_nodes[(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1] = { NULL, };
316 static GType             static_fundamental_next = G_TYPE_RESERVED_USER_FIRST;
317
318 static inline TypeNode*
319 lookup_type_node_I (register GType utype)
320 {
321   if (utype > G_TYPE_FUNDAMENTAL_MAX)
322     return (TypeNode*) (utype & ~TYPE_ID_MASK);
323   else
324     return static_fundamental_type_nodes[utype >> G_TYPE_FUNDAMENTAL_SHIFT];
325 }
326
327 static TypeNode*
328 type_node_any_new_W (TypeNode             *pnode,
329                      GType                 ftype,
330                      const gchar          *name,
331                      GTypePlugin          *plugin,
332                      GTypeFundamentalFlags type_flags)
333 {
334   guint n_supers;
335   GType type;
336   TypeNode *node;
337   guint i, node_size = 0;
338   
339   n_supers = pnode ? pnode->n_supers + 1 : 0;
340   
341   if (!pnode)
342     node_size += SIZEOF_FUNDAMENTAL_INFO;             /* fundamental type info */
343   node_size += SIZEOF_BASE_TYPE_NODE ();              /* TypeNode structure */
344   node_size += (sizeof (GType) * (1 + n_supers + 1)); /* self + ancestors + (0) for ->supers[] */
345   node = g_malloc0 (node_size);
346   if (!pnode)                                         /* offset fundamental types */
347     {
348       node = G_STRUCT_MEMBER_P (node, SIZEOF_FUNDAMENTAL_INFO);
349       static_fundamental_type_nodes[ftype >> G_TYPE_FUNDAMENTAL_SHIFT] = node;
350       type = ftype;
351     }
352   else
353     type = (GType) node;
354   
355   g_assert ((type & TYPE_ID_MASK) == 0);
356   
357   node->n_supers = n_supers;
358   if (!pnode)
359     {
360       node->supers[0] = type;
361       node->supers[1] = 0;
362       
363       node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0;
364       node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0;
365       
366       if (NODE_IS_IFACE (node))
367         {
368           IFACE_NODE_N_PREREQUISITES (node) = 0;
369           IFACE_NODE_PREREQUISITES (node) = NULL;
370         }
371       else
372         {
373           CLASSED_NODE_N_IFACES (node) = 0;
374           CLASSED_NODE_IFACES_ENTRIES (node) = NULL;
375         }
376     }
377   else
378     {
379       node->supers[0] = type;
380       memcpy (node->supers + 1, pnode->supers, sizeof (GType) * (1 + pnode->n_supers + 1));
381       
382       node->is_classed = pnode->is_classed;
383       node->is_instantiatable = pnode->is_instantiatable;
384       
385       if (NODE_IS_IFACE (node))
386         {
387           IFACE_NODE_N_PREREQUISITES (node) = 0;
388           IFACE_NODE_PREREQUISITES (node) = NULL;
389         }
390       else
391         {
392           guint j;
393           
394           CLASSED_NODE_N_IFACES (node) = CLASSED_NODE_N_IFACES (pnode);
395           CLASSED_NODE_IFACES_ENTRIES (node) = g_memdup (CLASSED_NODE_IFACES_ENTRIES (pnode),
396                                                          sizeof (CLASSED_NODE_IFACES_ENTRIES (pnode)[0]) *
397                                                          CLASSED_NODE_N_IFACES (node));
398           for (j = 0; j < CLASSED_NODE_N_IFACES (node); j++)
399             {
400               CLASSED_NODE_IFACES_ENTRIES (node)[j].vtable = NULL;
401               CLASSED_NODE_IFACES_ENTRIES (node)[j].init_state = UNINITIALIZED;
402             }
403         }
404       
405       i = pnode->n_children++;
406       pnode->children = g_renew (GType, pnode->children, pnode->n_children);
407       pnode->children[i] = type;
408     }
409   
410   node->plugin = plugin;
411   node->n_children = 0;
412   node->children = NULL;
413   node->data = NULL;
414   node->qname = g_quark_from_string (name);
415   node->global_gdata = NULL;
416   
417   g_hash_table_insert (static_type_nodes_ht,
418                        GUINT_TO_POINTER (node->qname),
419                        (gpointer) type);
420   return node;
421 }
422
423 static inline GTypeFundamentalInfo*
424 type_node_fundamental_info_I (TypeNode *node)
425 {
426   GType ftype = NODE_FUNDAMENTAL_TYPE (node);
427   
428   if (ftype != NODE_TYPE (node))
429     node = lookup_type_node_I (ftype);
430   
431   return node ? G_STRUCT_MEMBER_P (node, -SIZEOF_FUNDAMENTAL_INFO) : NULL;
432 }
433
434 static TypeNode*
435 type_node_fundamental_new_W (GType                 ftype,
436                              const gchar          *name,
437                              GTypeFundamentalFlags type_flags)
438 {
439   GTypeFundamentalInfo *finfo;
440   TypeNode *node;
441   
442   g_assert ((ftype & TYPE_ID_MASK) == 0);
443   g_assert (ftype <= G_TYPE_FUNDAMENTAL_MAX);
444   
445   if (ftype >> G_TYPE_FUNDAMENTAL_SHIFT == static_fundamental_next)
446     static_fundamental_next++;
447   
448   type_flags &= TYPE_FUNDAMENTAL_FLAG_MASK;
449   
450   node = type_node_any_new_W (NULL, ftype, name, NULL, type_flags);
451   
452   finfo = type_node_fundamental_info_I (node);
453   finfo->type_flags = type_flags;
454   
455   return node;
456 }
457
458 static TypeNode*
459 type_node_new_W (TypeNode    *pnode,
460                  const gchar *name,
461                  GTypePlugin *plugin)
462      
463 {
464   g_assert (pnode);
465   g_assert (pnode->n_supers < MAX_N_SUPERS);
466   g_assert (pnode->n_children < MAX_N_CHILDREN);
467   
468   return type_node_any_new_W (pnode, NODE_FUNDAMENTAL_TYPE (pnode), name, plugin, 0);
469 }
470
471 static inline IFaceEntry*
472 type_lookup_iface_entry_L (TypeNode *node,
473                            TypeNode *iface_node)
474 {
475   if (NODE_IS_IFACE (iface_node) && CLASSED_NODE_N_IFACES (node))
476     {
477       IFaceEntry *ifaces = CLASSED_NODE_IFACES_ENTRIES (node) - 1;
478       guint n_ifaces = CLASSED_NODE_N_IFACES (node);
479       GType iface_type = NODE_TYPE (iface_node);
480       
481       do
482         {
483           guint i;
484           IFaceEntry *check;
485           
486           i = (n_ifaces + 1) >> 1;
487           check = ifaces + i;
488           if (iface_type == check->iface_type)
489             return check;
490           else if (iface_type > check->iface_type)
491             {
492               n_ifaces -= i;
493               ifaces = check;
494             }
495           else /* if (iface_type < check->iface_type) */
496             n_ifaces = i - 1;
497         }
498       while (n_ifaces);
499     }
500   
501   return NULL;
502 }
503
504 static inline gboolean
505 type_lookup_prerequisite_L (TypeNode *iface,
506                             GType     prerequisite_type)
507 {
508   if (NODE_IS_IFACE (iface) && IFACE_NODE_N_PREREQUISITES (iface))
509     {
510       GType *prerequisites = IFACE_NODE_PREREQUISITES (iface) - 1;
511       guint n_prerequisites = IFACE_NODE_N_PREREQUISITES (iface);
512       
513       do
514         {
515           guint i;
516           GType *check;
517           
518           i = (n_prerequisites + 1) >> 1;
519           check = prerequisites + i;
520           if (prerequisite_type == *check)
521             return TRUE;
522           else if (prerequisite_type > *check)
523             {
524               n_prerequisites -= i;
525               prerequisites = check;
526             }
527           else /* if (prerequisite_type < *check) */
528             n_prerequisites = i - 1;
529         }
530       while (n_prerequisites);
531     }
532   return FALSE;
533 }
534
535 static gchar*
536 type_descriptive_name_I (GType type)
537 {
538   if (type)
539     {
540       TypeNode *node = lookup_type_node_I (type);
541       
542       return node ? NODE_NAME (node) : "<unknown>";
543     }
544   else
545     return "<invalid>";
546 }
547
548
549 /* --- type consistency checks --- */
550 static gboolean
551 check_plugin_U (GTypePlugin *plugin,
552                 gboolean     need_complete_type_info,
553                 gboolean     need_complete_interface_info,
554                 const gchar *type_name)
555 {
556   /* G_IS_TYPE_PLUGIN() and G_TYPE_PLUGIN_GET_CLASS() are external calls: _U 
557    */
558   if (!plugin)
559     {
560       g_warning ("plugin handle for type `%s' is NULL",
561                  type_name);
562       return FALSE;
563     }
564   if (!G_IS_TYPE_PLUGIN (plugin))
565     {
566       g_warning ("plugin pointer (%p) for type `%s' is invalid",
567                  plugin, type_name);
568       return FALSE;
569     }
570   if (need_complete_type_info && !G_TYPE_PLUGIN_GET_CLASS (plugin)->complete_type_info)
571     {
572       g_warning ("plugin for type `%s' has no complete_type_info() implementation",
573                  type_name);
574       return FALSE;
575     }
576   if (need_complete_interface_info && !G_TYPE_PLUGIN_GET_CLASS (plugin)->complete_interface_info)
577     {
578       g_warning ("plugin for type `%s' has no complete_interface_info() implementation",
579                  type_name);
580       return FALSE;
581     }
582   return TRUE;
583 }
584
585 static gboolean
586 check_type_name_I (const gchar *type_name)
587 {
588   static const gchar extra_chars[] = "-_+";
589   const gchar *p = type_name;
590   gboolean name_valid;
591   
592   if (!type_name[0] || !type_name[1] || !type_name[2])
593     {
594       g_warning ("type name `%s' is too short", type_name);
595       return FALSE;
596     }
597   /* check the first letter */
598   name_valid = (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || p[0] == '_';
599   for (p = type_name + 1; *p; p++)
600     name_valid &= ((p[0] >= 'A' && p[0] <= 'Z') ||
601                    (p[0] >= 'a' && p[0] <= 'z') ||
602                    (p[0] >= '0' && p[0] <= '9') ||
603                    strchr (extra_chars, p[0]));
604   if (!name_valid)
605     {
606       g_warning ("type name `%s' contains invalid characters", type_name);
607       return FALSE;
608     }
609   if (g_type_from_name (type_name))
610     {
611       g_warning ("cannot register existing type `%s'", type_name);
612       return FALSE;
613     }
614   
615   return TRUE;
616 }
617
618 static gboolean
619 check_derivation_I (GType        parent_type,
620                     const gchar *type_name)
621 {
622   TypeNode *pnode;
623   GTypeFundamentalInfo* finfo;
624   
625   pnode = lookup_type_node_I (parent_type);
626   if (!pnode)
627     {
628       g_warning ("cannot derive type `%s' from invalid parent type `%s'",
629                  type_name,
630                  type_descriptive_name_I (parent_type));
631       return FALSE;
632     }
633   finfo = type_node_fundamental_info_I (pnode);
634   /* ensure flat derivability */
635   if (!(finfo->type_flags & G_TYPE_FLAG_DERIVABLE))
636     {
637       g_warning ("cannot derive `%s' from non-derivable parent type `%s'",
638                  type_name,
639                  NODE_NAME (pnode));
640       return FALSE;
641     }
642   /* ensure deep derivability */
643   if (parent_type != NODE_FUNDAMENTAL_TYPE (pnode) &&
644       !(finfo->type_flags & G_TYPE_FLAG_DEEP_DERIVABLE))
645     {
646       g_warning ("cannot derive `%s' from non-fundamental parent type `%s'",
647                  type_name,
648                  NODE_NAME (pnode));
649       return FALSE;
650     }
651   
652   return TRUE;
653 }
654
655 static gboolean
656 check_collect_format_I (const gchar *collect_format)
657 {
658   const gchar *p = collect_format;
659   gchar valid_format[] = { G_VALUE_COLLECT_INT, G_VALUE_COLLECT_LONG,
660                            G_VALUE_COLLECT_INT64, G_VALUE_COLLECT_DOUBLE,
661                            G_VALUE_COLLECT_POINTER, 0 };
662   
663   while (*p)
664     if (!strchr (valid_format, *p++))
665       return FALSE;
666   return p - collect_format <= G_VALUE_COLLECT_FORMAT_MAX_LENGTH;
667 }
668
669 static gboolean
670 check_value_table_I (const gchar           *type_name,
671                      const GTypeValueTable *value_table)
672 {
673   if (!value_table)
674     return FALSE;
675   else if (value_table->value_init == NULL)
676     {
677       if (value_table->value_free || value_table->value_copy ||
678           value_table->value_peek_pointer ||
679           value_table->collect_format || value_table->collect_value ||
680           value_table->lcopy_format || value_table->lcopy_value)
681         g_warning ("cannot handle uninitializable values of type `%s'",
682                    type_name);
683       return FALSE;
684     }
685   else /* value_table->value_init != NULL */
686     {
687       if (!value_table->value_free)
688         {
689           /* +++ optional +++
690            * g_warning ("missing `value_free()' for type `%s'", type_name);
691            * return FALSE;
692            */
693         }
694       if (!value_table->value_copy)
695         {
696           g_warning ("missing `value_copy()' for type `%s'", type_name);
697           return FALSE;
698         }
699       if ((value_table->collect_format || value_table->collect_value) &&
700           (!value_table->collect_format || !value_table->collect_value))
701         {
702           g_warning ("one of `collect_format' and `collect_value()' is unspecified for type `%s'",
703                      type_name);
704           return FALSE;
705         }
706       if (value_table->collect_format && !check_collect_format_I (value_table->collect_format))
707         {
708           g_warning ("the `%s' specification for type `%s' is too long or invalid",
709                      "collect_format",
710                      type_name);
711           return FALSE;
712         }
713       if ((value_table->lcopy_format || value_table->lcopy_value) &&
714           (!value_table->lcopy_format || !value_table->lcopy_value))
715         {
716           g_warning ("one of `lcopy_format' and `lcopy_value()' is unspecified for type `%s'",
717                      type_name);
718           return FALSE;
719         }
720       if (value_table->lcopy_format && !check_collect_format_I (value_table->lcopy_format))
721         {
722           g_warning ("the `%s' specification for type `%s' is too long or invalid",
723                      "lcopy_format",
724                      type_name);
725           return FALSE;
726         }
727     }
728   return TRUE;
729 }
730
731 static gboolean
732 check_type_info_I (TypeNode        *pnode,
733                    GType            ftype,
734                    const gchar     *type_name,
735                    const GTypeInfo *info)
736 {
737   GTypeFundamentalInfo *finfo = type_node_fundamental_info_I (lookup_type_node_I (ftype));
738   gboolean is_interface = ftype == G_TYPE_INTERFACE;
739   
740   g_assert (ftype <= G_TYPE_FUNDAMENTAL_MAX && !(ftype & TYPE_ID_MASK));
741   
742   /* check instance members */
743   if (!(finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) &&
744       (info->instance_size || info->n_preallocs || info->instance_init))
745     {
746       if (pnode)
747         g_warning ("cannot instantiate `%s', derived from non-instantiatable parent type `%s'",
748                    type_name,
749                    NODE_NAME (pnode));
750       else
751         g_warning ("cannot instantiate `%s' as non-instantiatable fundamental",
752                    type_name);
753       return FALSE;
754     }
755   /* check class & interface members */
756   if (!((finfo->type_flags & G_TYPE_FLAG_CLASSED) || is_interface) &&
757       (info->class_init || info->class_finalize || info->class_data ||
758        info->class_size || info->base_init || info->base_finalize))
759     {
760       if (pnode)
761         g_warning ("cannot create class for `%s', derived from non-classed parent type `%s'",
762                    type_name,
763                    NODE_NAME (pnode));
764       else
765         g_warning ("cannot create class for `%s' as non-classed fundamental",
766                    type_name);
767       return FALSE;
768     }
769   /* check interface size */
770   if (is_interface && info->class_size < sizeof (GTypeInterface))
771     {
772       g_warning ("specified interface size for type `%s' is smaller than `GTypeInterface' size",
773                  type_name);
774       return FALSE;
775     }
776   /* check class size */
777   if (finfo->type_flags & G_TYPE_FLAG_CLASSED)
778     {
779       if (info->class_size < sizeof (GTypeClass))
780         {
781           g_warning ("specified class size for type `%s' is smaller than `GTypeClass' size",
782                      type_name);
783           return FALSE;
784         }
785       if (pnode && info->class_size < pnode->data->class.class_size)
786         {
787           g_warning ("specified class size for type `%s' is smaller "
788                      "than the parent type's `%s' class size",
789                      type_name,
790                      NODE_NAME (pnode));
791           return FALSE;
792         }
793     }
794   /* check instance size */
795   if (finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE)
796     {
797       if (info->instance_size < sizeof (GTypeInstance))
798         {
799           g_warning ("specified instance size for type `%s' is smaller than `GTypeInstance' size",
800                      type_name);
801           return FALSE;
802         }
803       if (pnode && info->instance_size < pnode->data->instance.instance_size)
804         {
805           g_warning ("specified instance size for type `%s' is smaller "
806                      "than the parent type's `%s' instance size",
807                      type_name,
808                      NODE_NAME (pnode));
809           return FALSE;
810         }
811     }
812   
813   return TRUE;
814 }
815
816 static TypeNode*
817 find_conforming_child_type_L (TypeNode *pnode,
818                               TypeNode *iface)
819 {
820   TypeNode *node = NULL;
821   guint i;
822   
823   if (type_lookup_iface_entry_L (pnode, iface))
824     return pnode;
825   
826   for (i = 0; i < pnode->n_children && !node; i++)
827     node = find_conforming_child_type_L (lookup_type_node_I (pnode->children[i]), iface);
828   
829   return node;
830 }
831
832 static gboolean
833 check_add_interface_L (GType instance_type,
834                        GType iface_type)
835 {
836   TypeNode *node = lookup_type_node_I (instance_type);
837   TypeNode *iface = lookup_type_node_I (iface_type);
838   IFaceEntry *entry;
839   TypeNode *tnode;
840   GType *prerequisites;
841   guint i;
842
843   
844   if (!node || !node->is_instantiatable)
845     {
846       g_warning ("cannot add interfaces to invalid (non-instantiatable) type `%s'",
847                  type_descriptive_name_I (instance_type));
848       return FALSE;
849     }
850   if (!iface || !NODE_IS_IFACE (iface))
851     {
852       g_warning ("cannot add invalid (non-interface) type `%s' to type `%s'",
853                  type_descriptive_name_I (iface_type),
854                  NODE_NAME (node));
855       return FALSE;
856     }
857   tnode = lookup_type_node_I (NODE_PARENT_TYPE (iface));
858   if (NODE_PARENT_TYPE (tnode) && !type_lookup_iface_entry_L (node, tnode))
859     {
860       /* 2001/7/31:timj: erk, i guess this warning is junk as interface derivation is flat */
861       g_warning ("cannot add sub-interface `%s' to type `%s' which does not conform to super-interface `%s'",
862                  NODE_NAME (iface),
863                  NODE_NAME (node),
864                  NODE_NAME (tnode));
865       return FALSE;
866     }
867   /* allow overriding of interface type introduced for parent type */
868   entry = type_lookup_iface_entry_L (node, iface);
869   if (entry && entry->vtable == NULL && !type_iface_peek_holder_L (iface, NODE_TYPE (node)))
870     {
871       /* ok, we do conform to this interface already, but the interface vtable was not
872        * yet intialized, and we just conform to the interface because it got added to
873        * one of our parents. so we allow overriding of holder info here.
874        */
875       return TRUE;
876     }
877   /* check whether one of our children already conforms (or whether the interface
878    * got added to this node already)
879    */
880   tnode = find_conforming_child_type_L (node, iface);  /* tnode is_a node */
881   if (tnode)
882     {
883       g_warning ("cannot add interface type `%s' to type `%s', since type `%s' already conforms to interface",
884                  NODE_NAME (iface),
885                  NODE_NAME (node),
886                  NODE_NAME (tnode));
887       return FALSE;
888     }
889   prerequisites = IFACE_NODE_PREREQUISITES (iface);
890   for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
891     {
892       tnode = lookup_type_node_I (prerequisites[i]);
893       if (!type_node_is_a_L (node, tnode))
894         {
895           g_warning ("cannot add interface type `%s' to type `%s' which does not conform to prerequisite `%s'",
896                      NODE_NAME (iface),
897                      NODE_NAME (node),
898                      NODE_NAME (tnode));
899           return FALSE;
900         }
901     }
902   return TRUE;
903 }
904
905 static gboolean
906 check_interface_info_I (TypeNode             *iface,
907                         GType                 instance_type,
908                         const GInterfaceInfo *info)
909 {
910   if ((info->interface_finalize || info->interface_data) && !info->interface_init)
911     {
912       g_warning ("interface type `%s' for type `%s' comes without initializer",
913                  NODE_NAME (iface),
914                  type_descriptive_name_I (instance_type));
915       return FALSE;
916     }
917   
918   return TRUE;
919 }
920
921 /* --- type info (type node data) --- */
922 static void
923 type_data_make_W (TypeNode              *node,
924                   const GTypeInfo       *info,
925                   const GTypeValueTable *value_table)
926 {
927   TypeData *data;
928   GTypeValueTable *vtable = NULL;
929   guint vtable_size = 0;
930   
931   g_assert (node->data == NULL && info != NULL);
932   
933   if (!value_table)
934     {
935       TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
936       
937       if (pnode)
938         vtable = pnode->data->common.value_table;
939       else
940         {
941           static const GTypeValueTable zero_vtable = { NULL, };
942           
943           value_table = &zero_vtable;
944         }
945     }
946   if (value_table)
947     {
948       /* need to setup vtable_size since we have to allocate it with data in one chunk */
949       vtable_size = sizeof (GTypeValueTable);
950       if (value_table->collect_format)
951         vtable_size += strlen (value_table->collect_format);
952       if (value_table->lcopy_format)
953         vtable_size += strlen (value_table->lcopy_format);
954       vtable_size += 2;
955     }
956    
957   if (node->is_instantiatable) /* carefull, is_instantiatable is also is_classed */
958     {
959       data = g_malloc0 (sizeof (InstanceData) + vtable_size);
960       if (vtable_size)
961         vtable = G_STRUCT_MEMBER_P (data, sizeof (InstanceData));
962       data->instance.class_size = info->class_size;
963       data->instance.class_init_base = info->base_init;
964       data->instance.class_finalize_base = info->base_finalize;
965       data->instance.class_init = info->class_init;
966       data->instance.class_finalize = info->class_finalize;
967       data->instance.class_data = info->class_data;
968       data->instance.class = NULL;
969       data->instance.init_state = UNINITIALIZED;
970       data->instance.instance_size = info->instance_size;
971       /* We'll set the final value for data->instance.private size
972        * after the parent class has been initialized
973        */
974       data->instance.private_size = 0;
975 #ifdef  DISABLE_MEM_POOLS
976       data->instance.n_preallocs = 0;
977 #else   /* !DISABLE_MEM_POOLS */
978       data->instance.n_preallocs = MIN (info->n_preallocs, 1024);
979 #endif  /* !DISABLE_MEM_POOLS */
980       data->instance.instance_init = info->instance_init;
981     }
982   else if (node->is_classed) /* only classed */
983     {
984       data = g_malloc0 (sizeof (ClassData) + vtable_size);
985       if (vtable_size)
986         vtable = G_STRUCT_MEMBER_P (data, sizeof (ClassData));
987       data->class.class_size = info->class_size;
988       data->class.class_init_base = info->base_init;
989       data->class.class_finalize_base = info->base_finalize;
990       data->class.class_init = info->class_init;
991       data->class.class_finalize = info->class_finalize;
992       data->class.class_data = info->class_data;
993       data->class.class = NULL;
994       data->class.init_state = UNINITIALIZED;
995     }
996   else if (NODE_IS_IFACE (node))
997     {
998       data = g_malloc0 (sizeof (IFaceData) + vtable_size);
999       if (vtable_size)
1000         vtable = G_STRUCT_MEMBER_P (data, sizeof (IFaceData));
1001       data->iface.vtable_size = info->class_size;
1002       data->iface.vtable_init_base = info->base_init;
1003       data->iface.vtable_finalize_base = info->base_finalize;
1004       data->iface.dflt_init = info->class_init;
1005       data->iface.dflt_finalize = info->class_finalize;
1006       data->iface.dflt_data = info->class_data;
1007       data->iface.dflt_vtable = NULL;
1008     }
1009   else
1010     {
1011       data = g_malloc0 (sizeof (CommonData) + vtable_size);
1012       if (vtable_size)
1013         vtable = G_STRUCT_MEMBER_P (data, sizeof (CommonData));
1014     }
1015   
1016   node->data = data;
1017   node->data->common.ref_count = 1;
1018   
1019   if (vtable_size)
1020     {
1021       gchar *p;
1022       
1023       /* we allocate the vtable and its strings together with the type data, so
1024        * children can take over their parent's vtable pointer, and we don't
1025        * need to worry freeing it or not when the child data is destroyed
1026        */
1027       *vtable = *value_table;
1028       p = G_STRUCT_MEMBER_P (vtable, sizeof (*vtable));
1029       p[0] = 0;
1030       vtable->collect_format = p;
1031       if (value_table->collect_format)
1032         {
1033           strcat (p, value_table->collect_format);
1034           p += strlen (value_table->collect_format);
1035         }
1036       p++;
1037       p[0] = 0;
1038       vtable->lcopy_format = p;
1039       if (value_table->lcopy_format)
1040         strcat  (p, value_table->lcopy_format);
1041     }
1042   node->data->common.value_table = vtable;
1043   node->mutatable_check_cache = (node->data->common.value_table->value_init != NULL &&
1044                                  !((G_TYPE_FLAG_VALUE_ABSTRACT | G_TYPE_FLAG_ABSTRACT) &
1045                                    GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags))));
1046   
1047   g_assert (node->data->common.value_table != NULL); /* paranoid */
1048 }
1049
1050 static inline void
1051 type_data_ref_Wm (TypeNode *node)
1052 {
1053   if (!node->data)
1054     {
1055       TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
1056       GTypeInfo tmp_info;
1057       GTypeValueTable tmp_value_table;
1058       
1059       g_assert (node->plugin != NULL);
1060       
1061       if (pnode)
1062         {
1063           type_data_ref_Wm (pnode);
1064           if (node->data)
1065             INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
1066         }
1067       
1068       memset (&tmp_info, 0, sizeof (tmp_info));
1069       memset (&tmp_value_table, 0, sizeof (tmp_value_table));
1070       
1071       G_WRITE_UNLOCK (&type_rw_lock);
1072       g_type_plugin_use (node->plugin);
1073       g_type_plugin_complete_type_info (node->plugin, NODE_TYPE (node), &tmp_info, &tmp_value_table);
1074       G_WRITE_LOCK (&type_rw_lock);
1075       if (node->data)
1076         INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
1077       
1078       check_type_info_I (pnode, NODE_FUNDAMENTAL_TYPE (node), NODE_NAME (node), &tmp_info);
1079       type_data_make_W (node, &tmp_info,
1080                         check_value_table_I (NODE_NAME (node),
1081                                              &tmp_value_table) ? &tmp_value_table : NULL);
1082     }
1083   else
1084     {
1085       g_assert (node->data->common.ref_count > 0);
1086       
1087       node->data->common.ref_count += 1;
1088     }
1089 }
1090
1091 static inline void
1092 type_data_unref_WmREC (TypeNode *node,
1093                        gboolean  uncached)
1094 {
1095   g_assert (node->data && node->data->common.ref_count);
1096   if (node->data->common.ref_count > 1)
1097     node->data->common.ref_count -= 1;
1098   else
1099     {
1100       GType node_type = NODE_TYPE (node);
1101       if (!node->plugin)
1102         {
1103           g_warning ("static type `%s' unreferenced too often",
1104                      NODE_NAME (node));
1105           return;
1106         }
1107       G_WRITE_UNLOCK (&type_rw_lock);
1108       g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
1109       G_WRITE_LOCK (&type_rw_lock);
1110       type_data_last_unref_Wm (node_type, uncached);
1111       g_static_rec_mutex_unlock (&class_init_rec_mutex);
1112     }
1113 }
1114
1115 static void
1116 type_node_add_iface_entry_W (TypeNode   *node,
1117                              GType       iface_type,
1118                              IFaceEntry *parent_entry)
1119 {
1120   IFaceEntry *entries;
1121   guint i;
1122   
1123   g_assert (node->is_instantiatable && CLASSED_NODE_N_IFACES (node) < MAX_N_IFACES);
1124   
1125   entries = CLASSED_NODE_IFACES_ENTRIES (node);
1126   for (i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
1127     if (entries[i].iface_type == iface_type)
1128       {
1129         /* this can happen in two cases:
1130          * - our parent type already conformed to iface_type and node
1131          *   got it's own holder info. here, our children already have
1132          *   entries and NULL vtables, since this will only work for
1133          *   uninitialized classes.
1134          * - an interface type is added to an ancestor after it was
1135          *   added to a child type.
1136          */
1137         if (!parent_entry)
1138           g_assert (entries[i].vtable == NULL && entries[i].init_state == UNINITIALIZED);
1139         else
1140           {
1141             /* sick, interface is added to ancestor *after* child type;
1142              * nothing todo, the entry and our children were already setup correctly
1143              */
1144           }
1145         return;
1146       }
1147     else if (entries[i].iface_type > iface_type)
1148       break;
1149   CLASSED_NODE_N_IFACES (node) += 1;
1150   CLASSED_NODE_IFACES_ENTRIES (node) = g_renew (IFaceEntry,
1151                                                 CLASSED_NODE_IFACES_ENTRIES (node),
1152                                                 CLASSED_NODE_N_IFACES (node));
1153   entries = CLASSED_NODE_IFACES_ENTRIES (node);
1154   g_memmove (entries + i + 1, entries + i, sizeof (entries[0]) * (CLASSED_NODE_N_IFACES (node) - i - 1));
1155   entries[i].iface_type = iface_type;
1156   entries[i].vtable = NULL;
1157   entries[i].init_state = UNINITIALIZED;
1158
1159   if (parent_entry)
1160     {
1161       if (node->data && node->data->class.init_state >= BASE_IFACE_INIT)
1162         {
1163           entries[i].init_state = INITIALIZED;
1164           entries[i].vtable = parent_entry->vtable;
1165         }
1166       for (i = 0; i < node->n_children; i++)
1167         type_node_add_iface_entry_W (lookup_type_node_I (node->children[i]), iface_type, &entries[i]);
1168     }
1169 }
1170
1171 static void
1172 type_add_interface_Wm (TypeNode             *node,
1173                        TypeNode             *iface,
1174                        const GInterfaceInfo *info,
1175                        GTypePlugin          *plugin)
1176 {
1177   IFaceHolder *iholder = g_new0 (IFaceHolder, 1);
1178   IFaceEntry *entry;
1179   guint i;
1180   
1181   g_assert (node->is_instantiatable && NODE_IS_IFACE (iface) && ((info && !plugin) || (!info && plugin)));
1182   
1183   iholder->next = iface_node_get_holders_L (iface);
1184   iface_node_set_holders_W (iface, iholder);
1185   iholder->instance_type = NODE_TYPE (node);
1186   iholder->info = info ? g_memdup (info, sizeof (*info)) : NULL;
1187   iholder->plugin = plugin;
1188
1189   /* create an iface entry for this type */
1190   type_node_add_iface_entry_W (node, NODE_TYPE (iface), NULL);
1191   
1192   /* if the class is already (partly) initialized, we may need to base
1193    * initalize and/or initialize the new interface.
1194    */
1195   if (node->data)
1196     {
1197       InitState class_state = node->data->class.init_state;
1198       
1199       if (class_state >= BASE_IFACE_INIT)
1200         type_iface_vtable_base_init_Wm (iface, node);
1201       
1202       if (class_state >= IFACE_INIT)
1203         type_iface_vtable_iface_init_Wm (iface, node);
1204     }
1205   
1206   /* create iface entries for children of this type */
1207   entry = type_lookup_iface_entry_L (node, iface);
1208   for (i = 0; i < node->n_children; i++)
1209     type_node_add_iface_entry_W (lookup_type_node_I (node->children[i]), NODE_TYPE (iface), entry);
1210 }
1211
1212 static void
1213 type_iface_add_prerequisite_W (TypeNode *iface,
1214                                TypeNode *prerequisite_node)
1215 {
1216   GType prerequisite_type = NODE_TYPE (prerequisite_node);
1217   GType *prerequisites, *dependants;
1218   guint n_dependants, i;
1219   
1220   g_assert (NODE_IS_IFACE (iface) &&
1221             IFACE_NODE_N_PREREQUISITES (iface) < MAX_N_PREREQUISITES &&
1222             (prerequisite_node->is_instantiatable || NODE_IS_IFACE (prerequisite_node)));
1223   
1224   prerequisites = IFACE_NODE_PREREQUISITES (iface);
1225   for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
1226     if (prerequisites[i] == prerequisite_type)
1227       return;                   /* we already have that prerequisiste */
1228     else if (prerequisites[i] > prerequisite_type)
1229       break;
1230   IFACE_NODE_N_PREREQUISITES (iface) += 1;
1231   IFACE_NODE_PREREQUISITES (iface) = g_renew (GType,
1232                                               IFACE_NODE_PREREQUISITES (iface),
1233                                               IFACE_NODE_N_PREREQUISITES (iface));
1234   prerequisites = IFACE_NODE_PREREQUISITES (iface);
1235   g_memmove (prerequisites + i + 1, prerequisites + i,
1236              sizeof (prerequisites[0]) * (IFACE_NODE_N_PREREQUISITES (iface) - i - 1));
1237   prerequisites[i] = prerequisite_type;
1238   
1239   /* we want to get notified when prerequisites get added to prerequisite_node */
1240   if (NODE_IS_IFACE (prerequisite_node))
1241     {
1242       dependants = iface_node_get_dependants_array_L (prerequisite_node);
1243       n_dependants = dependants ? dependants[0] : 0;
1244       n_dependants += 1;
1245       dependants = g_renew (GType, dependants, n_dependants + 1);
1246       dependants[n_dependants] = NODE_TYPE (iface);
1247       dependants[0] = n_dependants;
1248       iface_node_set_dependants_array_W (prerequisite_node, dependants);
1249     }
1250   
1251   /* we need to notify all dependants */
1252   dependants = iface_node_get_dependants_array_L (iface);
1253   n_dependants = dependants ? dependants[0] : 0;
1254   for (i = 1; i <= n_dependants; i++)
1255     type_iface_add_prerequisite_W (lookup_type_node_I (dependants[i]), prerequisite_node);
1256 }
1257
1258 void
1259 g_type_interface_add_prerequisite (GType interface_type,
1260                                    GType prerequisite_type)
1261 {
1262   TypeNode *iface, *prerequisite_node;
1263   IFaceHolder *holders;
1264   
1265   g_return_if_fail (G_TYPE_IS_INTERFACE (interface_type));      /* G_TYPE_IS_INTERFACE() is an external call: _U */
1266   g_return_if_fail (!g_type_is_a (interface_type, prerequisite_type));
1267   g_return_if_fail (!g_type_is_a (prerequisite_type, interface_type));
1268   
1269   iface = lookup_type_node_I (interface_type);
1270   prerequisite_node = lookup_type_node_I (prerequisite_type);
1271   if (!iface || !prerequisite_node || !NODE_IS_IFACE (iface))
1272     {
1273       g_warning ("interface type `%s' or prerequisite type `%s' invalid",
1274                  type_descriptive_name_I (interface_type),
1275                  type_descriptive_name_I (prerequisite_type));
1276       return;
1277     }
1278   G_WRITE_LOCK (&type_rw_lock);
1279   holders = iface_node_get_holders_L (iface);
1280   if (holders)
1281     {
1282       G_WRITE_UNLOCK (&type_rw_lock);
1283       g_warning ("unable to add prerequisite `%s' to interface `%s' which is already in use for `%s'",
1284                  type_descriptive_name_I (prerequisite_type),
1285                  type_descriptive_name_I (interface_type),
1286                  type_descriptive_name_I (holders->instance_type));
1287       return;
1288     }
1289   if (prerequisite_node->is_instantiatable)
1290     {
1291       guint i;
1292       
1293       /* can have at most one publically installable instantiatable prerequisite */
1294       for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
1295         {
1296           TypeNode *prnode = lookup_type_node_I (IFACE_NODE_PREREQUISITES (iface)[i]);
1297           
1298           if (prnode->is_instantiatable)
1299             {
1300               G_WRITE_UNLOCK (&type_rw_lock);
1301               g_warning ("adding prerequisite `%s' to interface `%s' conflicts with existing prerequisite `%s'",
1302                          type_descriptive_name_I (prerequisite_type),
1303                          type_descriptive_name_I (interface_type),
1304                          type_descriptive_name_I (NODE_TYPE (prnode)));
1305               return;
1306             }
1307         }
1308       
1309       for (i = 0; i < prerequisite_node->n_supers + 1; i++)
1310         type_iface_add_prerequisite_W (iface, lookup_type_node_I (prerequisite_node->supers[i]));
1311       G_WRITE_UNLOCK (&type_rw_lock);
1312     }
1313   else if (NODE_IS_IFACE (prerequisite_node))
1314     {
1315       GType *prerequisites;
1316       guint i;
1317       
1318       prerequisites = IFACE_NODE_PREREQUISITES (prerequisite_node);
1319       for (i = 0; i < IFACE_NODE_N_PREREQUISITES (prerequisite_node); i++)
1320         type_iface_add_prerequisite_W (iface, lookup_type_node_I (prerequisites[i]));
1321       type_iface_add_prerequisite_W (iface, prerequisite_node);
1322       G_WRITE_UNLOCK (&type_rw_lock);
1323     }
1324   else
1325     {
1326       G_WRITE_UNLOCK (&type_rw_lock);
1327       g_warning ("prerequisite `%s' for interface `%s' is neither instantiatable nor interface",
1328                  type_descriptive_name_I (prerequisite_type),
1329                  type_descriptive_name_I (interface_type));
1330     }
1331 }
1332
1333 GType* /* free result */
1334 g_type_interface_prerequisites (GType  interface_type,
1335                                 guint *n_prerequisites)
1336 {
1337   TypeNode *iface;
1338   
1339   g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL);
1340
1341   iface = lookup_type_node_I (interface_type);
1342   if (iface)
1343     {
1344       GType *types;
1345       TypeNode *inode = NULL;
1346       guint i, n = 0;
1347       
1348       G_READ_LOCK (&type_rw_lock);
1349       types = g_new0 (GType, IFACE_NODE_N_PREREQUISITES (iface) + 1);
1350       for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
1351         {
1352           GType prerequisite = IFACE_NODE_PREREQUISITES (iface)[i];
1353           TypeNode *node = lookup_type_node_I (prerequisite);
1354           if (node->is_instantiatable &&
1355               (!inode || type_node_is_a_L (node, inode)))
1356             inode = node;
1357           else
1358             types[n++] = NODE_TYPE (node);
1359         }
1360       if (inode)
1361         types[n++] = NODE_TYPE (inode);
1362       
1363       if (n_prerequisites)
1364         *n_prerequisites = n;
1365       G_READ_UNLOCK (&type_rw_lock);
1366       
1367       return types;
1368     }
1369   else
1370     {
1371       if (n_prerequisites)
1372         *n_prerequisites = 0;
1373       
1374       return NULL;
1375     }
1376 }
1377
1378
1379 static IFaceHolder*
1380 type_iface_peek_holder_L (TypeNode *iface,
1381                           GType     instance_type)
1382 {
1383   IFaceHolder *iholder;
1384   
1385   g_assert (NODE_IS_IFACE (iface));
1386   
1387   iholder = iface_node_get_holders_L (iface);
1388   while (iholder && iholder->instance_type != instance_type)
1389     iholder = iholder->next;
1390   return iholder;
1391 }
1392
1393 static IFaceHolder*
1394 type_iface_retrieve_holder_info_Wm (TypeNode *iface,
1395                                     GType     instance_type,
1396                                     gboolean  need_info)
1397 {
1398   IFaceHolder *iholder = type_iface_peek_holder_L (iface, instance_type);
1399   
1400   if (iholder && !iholder->info && need_info)
1401     {
1402       GInterfaceInfo tmp_info;
1403       
1404       g_assert (iholder->plugin != NULL);
1405       
1406       type_data_ref_Wm (iface);
1407       if (iholder->info)
1408         INVALID_RECURSION ("g_type_plugin_*", iface->plugin, NODE_NAME (iface));
1409       
1410       memset (&tmp_info, 0, sizeof (tmp_info));
1411       
1412       G_WRITE_UNLOCK (&type_rw_lock);
1413       g_type_plugin_use (iholder->plugin);
1414       g_type_plugin_complete_interface_info (iholder->plugin, instance_type, NODE_TYPE (iface), &tmp_info);
1415       G_WRITE_LOCK (&type_rw_lock);
1416       if (iholder->info)
1417         INVALID_RECURSION ("g_type_plugin_*", iholder->plugin, NODE_NAME (iface));
1418       
1419       check_interface_info_I (iface, instance_type, &tmp_info);
1420       iholder->info = g_memdup (&tmp_info, sizeof (tmp_info));
1421     }
1422   
1423   return iholder;       /* we don't modify write lock upon returning NULL */
1424 }
1425
1426 static void
1427 type_iface_blow_holder_info_Wm (TypeNode *iface,
1428                                 GType     instance_type)
1429 {
1430   IFaceHolder *iholder = iface_node_get_holders_L (iface);
1431   
1432   g_assert (NODE_IS_IFACE (iface));
1433   
1434   while (iholder->instance_type != instance_type)
1435     iholder = iholder->next;
1436   
1437   if (iholder->info && iholder->plugin)
1438     {
1439       g_free (iholder->info);
1440       iholder->info = NULL;
1441       
1442       G_WRITE_UNLOCK (&type_rw_lock);
1443       g_type_plugin_unuse (iholder->plugin);
1444       G_WRITE_LOCK (&type_rw_lock);
1445       
1446       type_data_unref_WmREC (iface, FALSE);
1447     }
1448 }
1449
1450 /* Assumes type's class already exists
1451  */
1452 static inline size_t
1453 type_total_instance_size_I (TypeNode *node)
1454 {
1455   gsize total_instance_size;
1456
1457   total_instance_size = node->data->instance.instance_size;
1458   if (node->data->instance.private_size != 0)
1459     total_instance_size = ALIGN_STRUCT (total_instance_size) + node->data->instance.private_size;
1460
1461   return total_instance_size;
1462 }
1463
1464 /* --- type structure creation/destruction --- */
1465 typedef struct {
1466   gpointer instance;
1467   gpointer class;
1468 } InstanceRealClass;
1469 static gint
1470 instance_real_class_cmp (gconstpointer p1,
1471                          gconstpointer p2)
1472 {
1473   const InstanceRealClass *irc1 = p1;
1474   const InstanceRealClass *irc2 = p2;
1475   guint8 *i1 = irc1->instance;
1476   guint8 *i2 = irc2->instance;
1477   return G_BSEARCH_ARRAY_CMP (i1, i2);
1478 }
1479 G_LOCK_DEFINE_STATIC (instance_real_class);
1480 static GBSearchArray *instance_real_class_bsa = NULL;
1481 static GBSearchConfig instance_real_class_bconfig = {
1482   sizeof (InstanceRealClass),
1483   instance_real_class_cmp,
1484   0,
1485 };
1486 static inline void
1487 instance_real_class_set (gpointer    instance,
1488                          GTypeClass *class)
1489 {
1490   InstanceRealClass key;
1491   key.instance = instance;
1492   key.class = class;
1493   G_LOCK (instance_real_class);
1494   if (!instance_real_class_bsa)
1495     instance_real_class_bsa = g_bsearch_array_create (&instance_real_class_bconfig);
1496   instance_real_class_bsa = g_bsearch_array_replace (instance_real_class_bsa, &instance_real_class_bconfig, &key);
1497   G_UNLOCK (instance_real_class);
1498 }
1499 static inline void
1500 instance_real_class_remove (gpointer instance)
1501 {
1502   InstanceRealClass key, *node;
1503   guint index;
1504   key.instance = instance;
1505   G_LOCK (instance_real_class);
1506   node = g_bsearch_array_lookup (instance_real_class_bsa, &instance_real_class_bconfig, &key);
1507   index = g_bsearch_array_get_index (instance_real_class_bsa, &instance_real_class_bconfig, node);
1508   instance_real_class_bsa = g_bsearch_array_remove (instance_real_class_bsa, &instance_real_class_bconfig, index);
1509   if (!g_bsearch_array_get_n_nodes (instance_real_class_bsa))
1510     {
1511       g_bsearch_array_free (instance_real_class_bsa, &instance_real_class_bconfig);
1512       instance_real_class_bsa = NULL;
1513     }
1514   G_UNLOCK (instance_real_class);
1515 }
1516 static inline GTypeClass*
1517 instance_real_class_get (gpointer instance)
1518 {
1519   InstanceRealClass key, *node;
1520   GTypeClass *class;
1521   key.instance = instance;
1522   G_LOCK (instance_real_class);
1523   node = instance_real_class_bsa ? g_bsearch_array_lookup (instance_real_class_bsa, &instance_real_class_bconfig, &key) : NULL;
1524   class = node ? node->class : NULL;
1525   G_UNLOCK (instance_real_class);
1526   return class;
1527 }
1528
1529 GTypeInstance*
1530 g_type_create_instance (GType type)
1531 {
1532   TypeNode *node;
1533   GTypeInstance *instance;
1534   GTypeClass *class;
1535   guint i, total_size;
1536   
1537   node = lookup_type_node_I (type);
1538   if (!node || !node->is_instantiatable)
1539     {
1540       g_warning ("cannot create new instance of invalid (non-instantiatable) type `%s'",
1541                  type_descriptive_name_I (type));
1542       return NULL;
1543     }
1544   /* G_TYPE_IS_ABSTRACT() is an external call: _U */
1545   if (!node->mutatable_check_cache && G_TYPE_IS_ABSTRACT (type))
1546     {
1547       g_warning ("cannot create instance of abstract (non-instantiatable) type `%s'",
1548                  type_descriptive_name_I (type));
1549       return NULL;
1550     }
1551   
1552   class = g_type_class_ref (type);
1553   total_size = type_total_instance_size_I (node);
1554
1555   instance = g_slice_alloc0 (total_size);
1556
1557   if (node->data->instance.private_size)
1558     instance_real_class_set (instance, class);
1559   for (i = node->n_supers; i > 0; i--)
1560     {
1561       TypeNode *pnode;
1562       
1563       pnode = lookup_type_node_I (node->supers[i]);
1564       if (pnode->data->instance.instance_init)
1565         {
1566           instance->g_class = pnode->data->instance.class;
1567           pnode->data->instance.instance_init (instance, class);
1568         }
1569     }
1570   if (node->data->instance.private_size)
1571     instance_real_class_remove (instance);
1572
1573   instance->g_class = class;
1574   if (node->data->instance.instance_init)
1575     node->data->instance.instance_init (instance, class);
1576   
1577   return instance;
1578 }
1579
1580 void
1581 g_type_free_instance (GTypeInstance *instance)
1582 {
1583   TypeNode *node;
1584   GTypeClass *class;
1585   
1586   g_return_if_fail (instance != NULL && instance->g_class != NULL);
1587   
1588   class = instance->g_class;
1589   node = lookup_type_node_I (class->g_type);
1590   if (!node || !node->is_instantiatable || !node->data || node->data->class.class != (gpointer) class)
1591     {
1592       g_warning ("cannot free instance of invalid (non-instantiatable) type `%s'",
1593                  type_descriptive_name_I (class->g_type));
1594       return;
1595     }
1596   /* G_TYPE_IS_ABSTRACT() is an external call: _U */
1597   if (!node->mutatable_check_cache && G_TYPE_IS_ABSTRACT (NODE_TYPE (node)))
1598     {
1599       g_warning ("cannot free instance of abstract (non-instantiatable) type `%s'",
1600                  NODE_NAME (node));
1601       return;
1602     }
1603   
1604   instance->g_class = NULL;
1605 #ifdef G_ENABLE_DEBUG  
1606   memset (instance, 0xaa, type_total_instance_size_I (node));
1607 #endif
1608   g_slice_free1 (type_total_instance_size_I (node), instance);
1609
1610   g_type_class_unref (class);
1611 }
1612
1613 static void
1614 type_iface_ensure_dflt_vtable_Wm (TypeNode *iface)
1615 {
1616   g_assert (iface->data);
1617
1618   if (!iface->data->iface.dflt_vtable)
1619     {
1620       GTypeInterface *vtable = g_malloc0 (iface->data->iface.vtable_size);
1621       iface->data->iface.dflt_vtable = vtable;
1622       vtable->g_type = NODE_TYPE (iface);
1623       vtable->g_instance_type = 0;
1624       if (iface->data->iface.vtable_init_base ||
1625           iface->data->iface.dflt_init)
1626         {
1627           G_WRITE_UNLOCK (&type_rw_lock);
1628           if (iface->data->iface.vtable_init_base)
1629             iface->data->iface.vtable_init_base (vtable);
1630           if (iface->data->iface.dflt_init)
1631             iface->data->iface.dflt_init (vtable, (gpointer) iface->data->iface.dflt_data);
1632           G_WRITE_LOCK (&type_rw_lock);
1633         }
1634     }
1635 }
1636
1637
1638 /* This is called to allocate and do the first part of initializing
1639  * the interface vtable; type_iface_vtable_iface_init_Wm() does the remainder.
1640  *
1641  * A FALSE return indicates that we didn't find an init function for
1642  * this type/iface pair, so the vtable from the parent type should
1643  * be used. Note that the write lock is not modified upon a FALSE
1644  * return.
1645  */
1646 static gboolean
1647 type_iface_vtable_base_init_Wm (TypeNode *iface,
1648                                 TypeNode *node)
1649 {
1650   IFaceEntry *entry;
1651   IFaceHolder *iholder;
1652   GTypeInterface *vtable = NULL;
1653   TypeNode *pnode;
1654   
1655   /* type_iface_retrieve_holder_info_Wm() doesn't modify write lock for returning NULL */
1656   iholder = type_iface_retrieve_holder_info_Wm (iface, NODE_TYPE (node), TRUE);
1657   if (!iholder)
1658     return FALSE;       /* we don't modify write lock upon FALSE */
1659
1660   type_iface_ensure_dflt_vtable_Wm (iface);
1661
1662   entry = type_lookup_iface_entry_L (node, iface);
1663
1664   g_assert (iface->data && entry && entry->vtable == NULL && iholder && iholder->info);
1665   
1666   entry->init_state = IFACE_INIT;
1667
1668   pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
1669   if (pnode)    /* want to copy over parent iface contents */
1670     {
1671       IFaceEntry *pentry = type_lookup_iface_entry_L (pnode, iface);
1672       
1673       if (pentry)
1674         vtable = g_memdup (pentry->vtable, iface->data->iface.vtable_size);
1675     }
1676   if (!vtable)
1677     vtable = g_memdup (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size);
1678   entry->vtable = vtable;
1679   vtable->g_type = NODE_TYPE (iface);
1680   vtable->g_instance_type = NODE_TYPE (node);
1681   
1682   if (iface->data->iface.vtable_init_base)
1683     {
1684       G_WRITE_UNLOCK (&type_rw_lock);
1685       iface->data->iface.vtable_init_base (vtable);
1686       G_WRITE_LOCK (&type_rw_lock);
1687     }
1688   return TRUE;  /* initialized the vtable */
1689 }
1690
1691 /* Finishes what type_iface_vtable_base_init_Wm started by
1692  * calling the interface init function.
1693  * this function may only be called for types with their
1694  * own interface holder info, i.e. types for which
1695  * g_type_add_interface*() was called and not children thereof.
1696  */
1697 static void
1698 type_iface_vtable_iface_init_Wm (TypeNode *iface,
1699                                  TypeNode *node)
1700 {
1701   IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
1702   IFaceHolder *iholder = type_iface_peek_holder_L (iface, NODE_TYPE (node));
1703   GTypeInterface *vtable = NULL;
1704   guint i;
1705   
1706   /* iholder->info should have been filled in by type_iface_vtable_base_init_Wm() */
1707   g_assert (iface->data && entry && iholder && iholder->info);
1708   g_assert (entry->init_state == IFACE_INIT); /* assert prior base_init() */
1709   
1710   entry->init_state = INITIALIZED;
1711       
1712   vtable = entry->vtable;
1713
1714   if (iholder->info->interface_init)
1715     {
1716       G_WRITE_UNLOCK (&type_rw_lock);
1717       if (iholder->info->interface_init)
1718         iholder->info->interface_init (vtable, iholder->info->interface_data);
1719       G_WRITE_LOCK (&type_rw_lock);
1720     }
1721   
1722   for (i = 0; i < static_n_iface_check_funcs; i++)
1723     {
1724       GTypeInterfaceCheckFunc check_func = static_iface_check_funcs[i].check_func;
1725       gpointer check_data = static_iface_check_funcs[i].check_data;
1726
1727       G_WRITE_UNLOCK (&type_rw_lock);
1728       check_func (check_data, (gpointer)vtable);
1729       G_WRITE_LOCK (&type_rw_lock);      
1730     }
1731 }
1732
1733 static gboolean
1734 type_iface_vtable_finalize_Wm (TypeNode       *iface,
1735                                TypeNode       *node,
1736                                GTypeInterface *vtable)
1737 {
1738   IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
1739   IFaceHolder *iholder;
1740   
1741   /* type_iface_retrieve_holder_info_Wm() doesn't modify write lock for returning NULL */
1742   iholder = type_iface_retrieve_holder_info_Wm (iface, NODE_TYPE (node), FALSE);
1743   if (!iholder)
1744     return FALSE;       /* we don't modify write lock upon FALSE */
1745   
1746   g_assert (entry && entry->vtable == vtable && iholder->info);
1747   
1748   entry->vtable = NULL;
1749   entry->init_state = UNINITIALIZED;
1750   if (iholder->info->interface_finalize || iface->data->iface.vtable_finalize_base)
1751     {
1752       G_WRITE_UNLOCK (&type_rw_lock);
1753       if (iholder->info->interface_finalize)
1754         iholder->info->interface_finalize (vtable, iholder->info->interface_data);
1755       if (iface->data->iface.vtable_finalize_base)
1756         iface->data->iface.vtable_finalize_base (vtable);
1757       G_WRITE_LOCK (&type_rw_lock);
1758     }
1759   vtable->g_type = 0;
1760   vtable->g_instance_type = 0;
1761   g_free (vtable);
1762   
1763   type_iface_blow_holder_info_Wm (iface, NODE_TYPE (node));
1764   
1765   return TRUE;  /* write lock modified */
1766 }
1767
1768 static void
1769 type_class_init_Wm (TypeNode   *node,
1770                     GTypeClass *pclass)
1771 {
1772   GSList *slist, *init_slist = NULL;
1773   GTypeClass *class;
1774   IFaceEntry *entry;
1775   TypeNode *bnode, *pnode;
1776   guint i;
1777   
1778   g_assert (node->is_classed && node->data &&
1779             node->data->class.class_size &&
1780             !node->data->class.class &&
1781             node->data->class.init_state == UNINITIALIZED);
1782
1783   class = g_malloc0 (node->data->class.class_size);
1784   node->data->class.class = class;
1785   node->data->class.init_state = BASE_CLASS_INIT;
1786   
1787   if (pclass)
1788     {
1789       TypeNode *pnode = lookup_type_node_I (pclass->g_type);
1790       
1791       memcpy (class, pclass, pnode->data->class.class_size);
1792
1793       if (node->is_instantiatable)
1794         {
1795           /* We need to initialize the private_size here rather than in
1796            * type_data_make_W() since the class init for the parent
1797            * class may have changed pnode->data->instance.private_size.
1798            */
1799           node->data->instance.private_size = pnode->data->instance.private_size;
1800         }
1801     }
1802   class->g_type = NODE_TYPE (node);
1803   
1804   G_WRITE_UNLOCK (&type_rw_lock);
1805   
1806   /* stack all base class initialization functions, so we
1807    * call them in ascending order.
1808    */
1809   for (bnode = node; bnode; bnode = lookup_type_node_I (NODE_PARENT_TYPE (bnode)))
1810     if (bnode->data->class.class_init_base)
1811       init_slist = g_slist_prepend (init_slist, (gpointer) bnode->data->class.class_init_base);
1812   for (slist = init_slist; slist; slist = slist->next)
1813     {
1814       GBaseInitFunc class_init_base = (GBaseInitFunc) slist->data;
1815       
1816       class_init_base (class);
1817     }
1818   g_slist_free (init_slist);
1819   
1820   G_WRITE_LOCK (&type_rw_lock);
1821
1822   node->data->class.init_state = BASE_IFACE_INIT;
1823   
1824   /* Before we initialize the class, base initialize all interfaces, either
1825    * from parent, or through our holder info
1826    */
1827   pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
1828
1829   i = 0;
1830   while (i < CLASSED_NODE_N_IFACES (node))
1831     {
1832       entry = &CLASSED_NODE_IFACES_ENTRIES (node)[i];
1833       while (i < CLASSED_NODE_N_IFACES (node) &&
1834              entry->init_state == IFACE_INIT)
1835         {
1836           entry++;
1837           i++;
1838         }
1839
1840       if (i == CLASSED_NODE_N_IFACES (node))
1841         break;
1842
1843       if (!type_iface_vtable_base_init_Wm (lookup_type_node_I (entry->iface_type), node))
1844         {
1845           guint j;
1846           
1847           /* need to get this interface from parent, type_iface_vtable_base_init_Wm()
1848            * doesn't modify write lock upon FALSE, so entry is still valid; 
1849            */
1850           g_assert (pnode != NULL);
1851           
1852           for (j = 0; j < CLASSED_NODE_N_IFACES (pnode); j++)
1853             {
1854               IFaceEntry *pentry = CLASSED_NODE_IFACES_ENTRIES (pnode) + j;
1855               
1856               if (pentry->iface_type == entry->iface_type)
1857                 {
1858                   entry->vtable = pentry->vtable;
1859                   entry->init_state = INITIALIZED;
1860                   break;
1861                 }
1862             }
1863           g_assert (entry->vtable != NULL);
1864         }
1865
1866       /* If the write lock was released, additional interface entries might
1867        * have been inserted into CLASSED_NODE_IFACES_ENTRIES (node); they'll
1868        * be base-initialized when inserted, so we don't have to worry that
1869        * we might miss them. Uninitialized entries can only be moved higher
1870        * when new ones are inserted.
1871        */
1872       i++;
1873     }
1874   
1875   node->data->class.init_state = CLASS_INIT;
1876   
1877   G_WRITE_UNLOCK (&type_rw_lock);
1878
1879   if (node->data->class.class_init)
1880     node->data->class.class_init (class, (gpointer) node->data->class.class_data);
1881   
1882   G_WRITE_LOCK (&type_rw_lock);
1883   
1884   node->data->class.init_state = IFACE_INIT;
1885   
1886   /* finish initializing the interfaces through our holder info.
1887    * inherited interfaces are already init_state == INITIALIZED, because
1888    * they either got setup in the above base_init loop, or during
1889    * class_init from within type_add_interface_Wm() for this or
1890    * an anchestor type.
1891    */
1892   i = 0;
1893   while (TRUE)
1894     {
1895       entry = &CLASSED_NODE_IFACES_ENTRIES (node)[i];
1896       while (i < CLASSED_NODE_N_IFACES (node) &&
1897              entry->init_state == INITIALIZED)
1898         {
1899           entry++;
1900           i++;
1901         }
1902
1903       if (i == CLASSED_NODE_N_IFACES (node))
1904         break;
1905
1906       type_iface_vtable_iface_init_Wm (lookup_type_node_I (entry->iface_type), node);
1907       
1908       /* As in the loop above, additional initialized entries might be inserted
1909        * if the write lock is released, but that's harmless because the entries
1910        * we need to initialize only move higher in the list.
1911        */
1912       i++;
1913     }
1914   
1915   node->data->class.init_state = INITIALIZED;
1916 }
1917
1918 static void
1919 type_data_finalize_class_ifaces_Wm (TypeNode *node)
1920 {
1921   guint i;
1922
1923   g_assert (node->is_instantiatable && node->data && node->data->class.class && node->data->common.ref_count == 0);
1924
1925  reiterate:
1926   for (i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
1927     {
1928       IFaceEntry *entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
1929       if (entry->vtable)
1930         {
1931           if (type_iface_vtable_finalize_Wm (lookup_type_node_I (entry->iface_type), node, entry->vtable))
1932             {
1933               /* refetch entries, IFACES_ENTRIES might be modified */
1934               goto reiterate;
1935             }
1936           else
1937             {
1938               /* type_iface_vtable_finalize_Wm() doesn't modify write lock upon FALSE,
1939                * iface vtable came from parent
1940                */
1941               entry->vtable = NULL;
1942               entry->init_state = UNINITIALIZED;
1943             }
1944         }
1945     }
1946 }
1947
1948 static void
1949 type_data_finalize_class_U (TypeNode  *node,
1950                             ClassData *cdata)
1951 {
1952   GTypeClass *class = cdata->class;
1953   TypeNode *bnode;
1954   
1955   g_assert (cdata->class && cdata->common.ref_count == 0);
1956   
1957   if (cdata->class_finalize)
1958     cdata->class_finalize (class, (gpointer) cdata->class_data);
1959   
1960   /* call all base class destruction functions in descending order
1961    */
1962   if (cdata->class_finalize_base)
1963     cdata->class_finalize_base (class);
1964   for (bnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); bnode; bnode = lookup_type_node_I (NODE_PARENT_TYPE (bnode)))
1965     if (bnode->data->class.class_finalize_base)
1966       bnode->data->class.class_finalize_base (class);
1967   
1968   g_free (cdata->class);
1969 }
1970
1971 static void
1972 type_data_last_unref_Wm (GType    type,
1973                          gboolean uncached)
1974 {
1975   TypeNode *node = lookup_type_node_I (type);
1976   
1977   g_return_if_fail (node != NULL && node->plugin != NULL);
1978   
1979   if (!node->data || node->data->common.ref_count == 0)
1980     {
1981       g_warning ("cannot drop last reference to unreferenced type `%s'",
1982                  type_descriptive_name_I (type));
1983       return;
1984     }
1985
1986   /* call class cache hooks */
1987   if (node->is_classed && node->data && node->data->class.class && static_n_class_cache_funcs && !uncached)
1988     {
1989       guint i;
1990       
1991       G_WRITE_UNLOCK (&type_rw_lock);
1992       G_READ_LOCK (&type_rw_lock);
1993       for (i = 0; i < static_n_class_cache_funcs; i++)
1994         {
1995           GTypeClassCacheFunc cache_func = static_class_cache_funcs[i].cache_func;
1996           gpointer cache_data = static_class_cache_funcs[i].cache_data;
1997           gboolean need_break;
1998           
1999           G_READ_UNLOCK (&type_rw_lock);
2000           need_break = cache_func (cache_data, node->data->class.class);
2001           G_READ_LOCK (&type_rw_lock);
2002           if (!node->data || node->data->common.ref_count == 0)
2003             INVALID_RECURSION ("GType class cache function ", cache_func, NODE_NAME (node));
2004           if (need_break)
2005             break;
2006         }
2007       G_READ_UNLOCK (&type_rw_lock);
2008       G_WRITE_LOCK (&type_rw_lock);
2009     }
2010   
2011   if (node->data->common.ref_count > 1) /* may have been re-referenced meanwhile */
2012     node->data->common.ref_count -= 1;
2013   else
2014     {
2015       GType ptype = NODE_PARENT_TYPE (node);
2016       TypeData *tdata;
2017       
2018       node->data->common.ref_count = 0;
2019       
2020       if (node->is_instantiatable)
2021         {
2022           /* destroy node->data->instance.mem_chunk */
2023         }
2024       
2025       tdata = node->data;
2026       if (node->is_classed && tdata->class.class)
2027         {
2028           if (CLASSED_NODE_N_IFACES (node))
2029             type_data_finalize_class_ifaces_Wm (node);
2030           node->mutatable_check_cache = FALSE;
2031           node->data = NULL;
2032           G_WRITE_UNLOCK (&type_rw_lock);
2033           type_data_finalize_class_U (node, &tdata->class);
2034           G_WRITE_LOCK (&type_rw_lock);
2035         }
2036       else if (NODE_IS_IFACE (node) && tdata->iface.dflt_vtable)
2037         {
2038           node->mutatable_check_cache = FALSE;
2039           node->data = NULL;
2040           if (tdata->iface.dflt_finalize || tdata->iface.vtable_finalize_base)
2041             {
2042               G_WRITE_UNLOCK (&type_rw_lock);
2043               if (tdata->iface.dflt_finalize)
2044                 tdata->iface.dflt_finalize (tdata->iface.dflt_vtable, (gpointer) tdata->iface.dflt_data);
2045               if (tdata->iface.vtable_finalize_base)
2046                 tdata->iface.vtable_finalize_base (tdata->iface.dflt_vtable);
2047               G_WRITE_LOCK (&type_rw_lock);
2048             }
2049           g_free (tdata->iface.dflt_vtable);
2050         }
2051       else
2052         {
2053           node->mutatable_check_cache = FALSE;
2054           node->data = NULL;
2055         }
2056
2057       /* freeing tdata->common.value_table and its contents is taken care of
2058        * by allocating it in one chunk with tdata
2059        */
2060       g_free (tdata);
2061       
2062       G_WRITE_UNLOCK (&type_rw_lock);
2063       g_type_plugin_unuse (node->plugin);
2064       G_WRITE_LOCK (&type_rw_lock);
2065       if (ptype)
2066         type_data_unref_WmREC (lookup_type_node_I (ptype), FALSE);
2067     }
2068 }
2069
2070 void
2071 g_type_add_class_cache_func (gpointer            cache_data,
2072                              GTypeClassCacheFunc cache_func)
2073 {
2074   guint i;
2075   
2076   g_return_if_fail (cache_func != NULL);
2077   
2078   G_WRITE_LOCK (&type_rw_lock);
2079   i = static_n_class_cache_funcs++;
2080   static_class_cache_funcs = g_renew (ClassCacheFunc, static_class_cache_funcs, static_n_class_cache_funcs);
2081   static_class_cache_funcs[i].cache_data = cache_data;
2082   static_class_cache_funcs[i].cache_func = cache_func;
2083   G_WRITE_UNLOCK (&type_rw_lock);
2084 }
2085
2086 void
2087 g_type_remove_class_cache_func (gpointer            cache_data,
2088                                 GTypeClassCacheFunc cache_func)
2089 {
2090   gboolean found_it = FALSE;
2091   guint i;
2092   
2093   g_return_if_fail (cache_func != NULL);
2094   
2095   G_WRITE_LOCK (&type_rw_lock);
2096   for (i = 0; i < static_n_class_cache_funcs; i++)
2097     if (static_class_cache_funcs[i].cache_data == cache_data &&
2098         static_class_cache_funcs[i].cache_func == cache_func)
2099       {
2100         static_n_class_cache_funcs--;
2101         g_memmove (static_class_cache_funcs + i,
2102                    static_class_cache_funcs + i + 1,
2103                    sizeof (static_class_cache_funcs[0]) * (static_n_class_cache_funcs - i));
2104         static_class_cache_funcs = g_renew (ClassCacheFunc, static_class_cache_funcs, static_n_class_cache_funcs);
2105         found_it = TRUE;
2106         break;
2107       }
2108   G_WRITE_UNLOCK (&type_rw_lock);
2109   
2110   if (!found_it)
2111     g_warning (G_STRLOC ": cannot remove unregistered class cache func %p with data %p",
2112                cache_func, cache_data);
2113 }
2114
2115
2116 void
2117 g_type_add_interface_check (gpointer                check_data,
2118                             GTypeInterfaceCheckFunc check_func)
2119 {
2120   guint i;
2121   
2122   g_return_if_fail (check_func != NULL);
2123   
2124   G_WRITE_LOCK (&type_rw_lock);
2125   i = static_n_iface_check_funcs++;
2126   static_iface_check_funcs = g_renew (IFaceCheckFunc, static_iface_check_funcs, static_n_iface_check_funcs);
2127   static_iface_check_funcs[i].check_data = check_data;
2128   static_iface_check_funcs[i].check_func = check_func;
2129   G_WRITE_UNLOCK (&type_rw_lock);
2130 }
2131
2132 void
2133 g_type_remove_interface_check (gpointer                check_data,
2134                                GTypeInterfaceCheckFunc check_func)
2135 {
2136   gboolean found_it = FALSE;
2137   guint i;
2138   
2139   g_return_if_fail (check_func != NULL);
2140   
2141   G_WRITE_LOCK (&type_rw_lock);
2142   for (i = 0; i < static_n_iface_check_funcs; i++)
2143     if (static_iface_check_funcs[i].check_data == check_data &&
2144         static_iface_check_funcs[i].check_func == check_func)
2145       {
2146         static_n_iface_check_funcs--;
2147         g_memmove (static_iface_check_funcs + i,
2148                    static_iface_check_funcs + i + 1,
2149                    sizeof (static_iface_check_funcs[0]) * (static_n_iface_check_funcs - i));
2150         static_iface_check_funcs = g_renew (IFaceCheckFunc, static_iface_check_funcs, static_n_iface_check_funcs);
2151         found_it = TRUE;
2152         break;
2153       }
2154   G_WRITE_UNLOCK (&type_rw_lock);
2155   
2156   if (!found_it)
2157     g_warning (G_STRLOC ": cannot remove unregistered class check func %p with data %p",
2158                check_func, check_data);
2159 }
2160
2161 /* --- type registration --- */
2162 GType
2163 g_type_register_fundamental (GType                       type_id,
2164                              const gchar                *type_name,
2165                              const GTypeInfo            *info,
2166                              const GTypeFundamentalInfo *finfo,
2167                              GTypeFlags                  flags)
2168 {
2169   TypeNode *node;
2170   
2171   g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, 0);
2172   g_return_val_if_fail (type_id > 0, 0);
2173   g_return_val_if_fail (type_name != NULL, 0);
2174   g_return_val_if_fail (info != NULL, 0);
2175   g_return_val_if_fail (finfo != NULL, 0);
2176   
2177   if (!check_type_name_I (type_name))
2178     return 0;
2179   if ((type_id & TYPE_ID_MASK) ||
2180       type_id > G_TYPE_FUNDAMENTAL_MAX)
2181     {
2182       g_warning ("attempt to register fundamental type `%s' with invalid type id (%zu)",
2183                  type_name,
2184                  type_id);
2185       return 0;
2186     }
2187   if ((finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) &&
2188       !(finfo->type_flags & G_TYPE_FLAG_CLASSED))
2189     {
2190       g_warning ("cannot register instantiatable fundamental type `%s' as non-classed",
2191                  type_name);
2192       return 0;
2193     }
2194   if (lookup_type_node_I (type_id))
2195     {
2196       g_warning ("cannot register existing fundamental type `%s' (as `%s')",
2197                  type_descriptive_name_I (type_id),
2198                  type_name);
2199       return 0;
2200     }
2201   
2202   G_WRITE_LOCK (&type_rw_lock);
2203   node = type_node_fundamental_new_W (type_id, type_name, finfo->type_flags);
2204   type_add_flags_W (node, flags);
2205   
2206   if (check_type_info_I (NULL, NODE_FUNDAMENTAL_TYPE (node), type_name, info))
2207     type_data_make_W (node, info,
2208                       check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);
2209   G_WRITE_UNLOCK (&type_rw_lock);
2210   
2211   return NODE_TYPE (node);
2212 }
2213
2214 GType
2215 g_type_register_static_simple (GType             parent_type,
2216                                const gchar      *type_name,
2217                                guint             class_size,
2218                                GClassInitFunc    class_init,
2219                                guint             instance_size,
2220                                GInstanceInitFunc instance_init,
2221                                GTypeFlags        flags)
2222 {
2223   GTypeInfo info;
2224
2225   info.class_size = class_size;
2226   info.base_init = NULL;
2227   info.base_finalize = NULL;
2228   info.class_init = class_init;
2229   info.class_finalize = NULL;
2230   info.class_data = NULL;
2231   info.instance_size = instance_size;
2232   info.n_preallocs = 0;
2233   info.instance_init = instance_init;
2234   info.value_table = NULL;
2235
2236   return g_type_register_static (parent_type, type_name, &info, flags);
2237 }
2238
2239 GType
2240 g_type_register_static (GType            parent_type,
2241                         const gchar     *type_name,
2242                         const GTypeInfo *info,
2243                         GTypeFlags       flags)
2244 {
2245   TypeNode *pnode, *node;
2246   GType type = 0;
2247   
2248   g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, 0);
2249   g_return_val_if_fail (parent_type > 0, 0);
2250   g_return_val_if_fail (type_name != NULL, 0);
2251   g_return_val_if_fail (info != NULL, 0);
2252   
2253   if (!check_type_name_I (type_name) ||
2254       !check_derivation_I (parent_type, type_name))
2255     return 0;
2256   if (info->class_finalize)
2257     {
2258       g_warning ("class finalizer specified for static type `%s'",
2259                  type_name);
2260       return 0;
2261     }
2262   
2263   pnode = lookup_type_node_I (parent_type);
2264   G_WRITE_LOCK (&type_rw_lock);
2265   type_data_ref_Wm (pnode);
2266   if (check_type_info_I (pnode, NODE_FUNDAMENTAL_TYPE (pnode), type_name, info))
2267     {
2268       node = type_node_new_W (pnode, type_name, NULL);
2269       type_add_flags_W (node, flags);
2270       type = NODE_TYPE (node);
2271       type_data_make_W (node, info,
2272                         check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);
2273     }
2274   G_WRITE_UNLOCK (&type_rw_lock);
2275   
2276   return type;
2277 }
2278
2279 GType
2280 g_type_register_dynamic (GType        parent_type,
2281                          const gchar *type_name,
2282                          GTypePlugin *plugin,
2283                          GTypeFlags   flags)
2284 {
2285   TypeNode *pnode, *node;
2286   GType type;
2287   
2288   g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, 0);
2289   g_return_val_if_fail (parent_type > 0, 0);
2290   g_return_val_if_fail (type_name != NULL, 0);
2291   g_return_val_if_fail (plugin != NULL, 0);
2292   
2293   if (!check_type_name_I (type_name) ||
2294       !check_derivation_I (parent_type, type_name) ||
2295       !check_plugin_U (plugin, TRUE, FALSE, type_name))
2296     return 0;
2297   
2298   G_WRITE_LOCK (&type_rw_lock);
2299   pnode = lookup_type_node_I (parent_type);
2300   node = type_node_new_W (pnode, type_name, plugin);
2301   type_add_flags_W (node, flags);
2302   type = NODE_TYPE (node);
2303   G_WRITE_UNLOCK (&type_rw_lock);
2304   
2305   return type;
2306 }
2307
2308 void
2309 g_type_add_interface_static (GType                 instance_type,
2310                              GType                 interface_type,
2311                              const GInterfaceInfo *info)
2312 {
2313   /* G_TYPE_IS_INSTANTIATABLE() is an external call: _U */
2314   g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type));
2315   g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE);
2316
2317   /* we only need to lock class_init_rec_mutex if instance_type already has its
2318    * class initialized, however this function is rarely enough called to take
2319    * the simple route and always acquire class_init_rec_mutex.
2320    */
2321   g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
2322   G_WRITE_LOCK (&type_rw_lock);
2323   if (check_add_interface_L (instance_type, interface_type))
2324     {
2325       TypeNode *node = lookup_type_node_I (instance_type);
2326       TypeNode *iface = lookup_type_node_I (interface_type);
2327       if (check_interface_info_I (iface, NODE_TYPE (node), info))
2328         type_add_interface_Wm (node, iface, info, NULL);
2329     }
2330   G_WRITE_UNLOCK (&type_rw_lock);
2331   g_static_rec_mutex_unlock (&class_init_rec_mutex);
2332 }
2333
2334 void
2335 g_type_add_interface_dynamic (GType        instance_type,
2336                               GType        interface_type,
2337                               GTypePlugin *plugin)
2338 {
2339   TypeNode *node;
2340   /* G_TYPE_IS_INSTANTIATABLE() is an external call: _U */
2341   g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type));
2342   g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE);
2343
2344   node = lookup_type_node_I (instance_type);
2345   if (!check_plugin_U (plugin, FALSE, TRUE, NODE_NAME (node)))
2346     return;
2347
2348   /* see comment in g_type_add_interface_static() about class_init_rec_mutex */
2349   g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
2350   G_WRITE_LOCK (&type_rw_lock);
2351   if (check_add_interface_L (instance_type, interface_type))
2352     {
2353       TypeNode *iface = lookup_type_node_I (interface_type);
2354       type_add_interface_Wm (node, iface, NULL, plugin);
2355     }
2356   G_WRITE_UNLOCK (&type_rw_lock);
2357   g_static_rec_mutex_unlock (&class_init_rec_mutex);
2358 }
2359
2360
2361 /* --- public API functions --- */
2362 gpointer
2363 g_type_class_ref (GType type)
2364 {
2365   TypeNode *node;
2366   GType ptype;
2367
2368   /* optimize for common code path */
2369   G_WRITE_LOCK (&type_rw_lock);
2370   node = lookup_type_node_I (type);
2371   if (node && node->is_classed && node->data &&
2372       node->data->class.class &&
2373       node->data->class.init_state == INITIALIZED)
2374     {
2375       type_data_ref_Wm (node);
2376       G_WRITE_UNLOCK (&type_rw_lock);
2377       return node->data->class.class;
2378     }
2379   if (!node || !node->is_classed ||
2380       (node->data && node->data->common.ref_count < 1))
2381     {
2382       G_WRITE_UNLOCK (&type_rw_lock);
2383       g_warning ("cannot retrieve class for invalid (unclassed) type `%s'",
2384                  type_descriptive_name_I (type));
2385       return NULL;
2386     }
2387   type_data_ref_Wm (node);
2388   ptype = NODE_PARENT_TYPE (node);
2389   G_WRITE_UNLOCK (&type_rw_lock);
2390
2391   g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
2392   /* here, we either have node->data->class.class == NULL, or
2393    * node->data->class.init_state == INITIALIZED, because any
2394    * concurrently running initialization was guarded by class_init_rec_mutex.
2395    */
2396   if (!node->data->class.class) /* class uninitialized */
2397     {
2398       /* acquire reference on parent class */
2399       GTypeClass *pclass = ptype ? g_type_class_ref (ptype) : NULL;
2400       G_WRITE_LOCK (&type_rw_lock);
2401       if (node->data->class.class) /* class was initialized during parent class initialization? */
2402         INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
2403       type_class_init_Wm (node, pclass);
2404       G_WRITE_UNLOCK (&type_rw_lock);
2405     }
2406   g_static_rec_mutex_unlock (&class_init_rec_mutex);
2407
2408   return node->data->class.class;
2409 }
2410
2411 void
2412 g_type_class_unref (gpointer g_class)
2413 {
2414   TypeNode *node;
2415   GTypeClass *class = g_class;
2416   
2417   g_return_if_fail (g_class != NULL);
2418   
2419   node = lookup_type_node_I (class->g_type);
2420   G_WRITE_LOCK (&type_rw_lock);
2421   if (node && node->is_classed && node->data &&
2422       node->data->class.class == class && node->data->common.ref_count > 0)
2423     type_data_unref_WmREC (node, FALSE);
2424   else
2425     g_warning ("cannot unreference class of invalid (unclassed) type `%s'",
2426                type_descriptive_name_I (class->g_type));
2427   G_WRITE_UNLOCK (&type_rw_lock);
2428 }
2429
2430 void
2431 g_type_class_unref_uncached (gpointer g_class)
2432 {
2433   TypeNode *node;
2434   GTypeClass *class = g_class;
2435   
2436   g_return_if_fail (g_class != NULL);
2437   
2438   G_WRITE_LOCK (&type_rw_lock);
2439   node = lookup_type_node_I (class->g_type);
2440   if (node && node->is_classed && node->data &&
2441       node->data->class.class == class && node->data->common.ref_count > 0)
2442     type_data_unref_WmREC (node, TRUE);
2443   else
2444     g_warning ("cannot unreference class of invalid (unclassed) type `%s'",
2445                type_descriptive_name_I (class->g_type));
2446   G_WRITE_UNLOCK (&type_rw_lock);
2447 }
2448
2449 gpointer
2450 g_type_class_peek (GType type)
2451 {
2452   TypeNode *node;
2453   gpointer class;
2454   
2455   node = lookup_type_node_I (type);
2456   G_READ_LOCK (&type_rw_lock);
2457   if (node && node->is_classed && node->data && node->data->class.class) /* common.ref_count _may_ be 0 */
2458     class = node->data->class.class;
2459   else
2460     class = NULL;
2461   G_READ_UNLOCK (&type_rw_lock);
2462   
2463   return class;
2464 }
2465
2466 gpointer
2467 g_type_class_peek_static (GType type)
2468 {
2469   TypeNode *node;
2470   gpointer class;
2471   
2472   node = lookup_type_node_I (type);
2473   G_READ_LOCK (&type_rw_lock);
2474   if (node && node->is_classed && node->data &&
2475       /* peek only static types: */ node->plugin == NULL &&
2476       node->data->class.class) /* common.ref_count _may_ be 0 */
2477     class = node->data->class.class;
2478   else
2479     class = NULL;
2480   G_READ_UNLOCK (&type_rw_lock);
2481   
2482   return class;
2483 }
2484
2485 gpointer
2486 g_type_class_peek_parent (gpointer g_class)
2487 {
2488   TypeNode *node;
2489   gpointer class = NULL;
2490   
2491   g_return_val_if_fail (g_class != NULL, NULL);
2492   
2493   node = lookup_type_node_I (G_TYPE_FROM_CLASS (g_class));
2494   /* We used to acquire a read lock here. That is not necessary, since 
2495    * parent->data->class.class is constant as long as the derived class
2496    * exists. 
2497    */
2498   if (node && node->is_classed && node->data && NODE_PARENT_TYPE (node))
2499     {
2500       node = lookup_type_node_I (NODE_PARENT_TYPE (node));
2501       class = node->data->class.class;
2502     }
2503   else if (NODE_PARENT_TYPE (node))
2504     g_warning (G_STRLOC ": invalid class pointer `%p'", g_class);
2505   
2506   return class;
2507 }
2508
2509 gpointer
2510 g_type_interface_peek (gpointer instance_class,
2511                        GType    iface_type)
2512 {
2513   TypeNode *node;
2514   TypeNode *iface;
2515   gpointer vtable = NULL;
2516   GTypeClass *class = instance_class;
2517   
2518   g_return_val_if_fail (instance_class != NULL, NULL);
2519   
2520   node = lookup_type_node_I (class->g_type);
2521   iface = lookup_type_node_I (iface_type);
2522   if (node && node->is_instantiatable && iface)
2523     {
2524       IFaceEntry *entry;
2525       
2526       G_READ_LOCK (&type_rw_lock);
2527       
2528       entry = type_lookup_iface_entry_L (node, iface);
2529       if (entry && entry->vtable)       /* entry is relocatable */
2530         vtable = entry->vtable;
2531       
2532       G_READ_UNLOCK (&type_rw_lock);
2533     }
2534   else
2535     g_warning (G_STRLOC ": invalid class pointer `%p'", class);
2536   
2537   return vtable;
2538 }
2539
2540 gpointer
2541 g_type_interface_peek_parent (gpointer g_iface)
2542 {
2543   TypeNode *node;
2544   TypeNode *iface;
2545   gpointer vtable = NULL;
2546   GTypeInterface *iface_class = g_iface;
2547   
2548   g_return_val_if_fail (g_iface != NULL, NULL);
2549   
2550   iface = lookup_type_node_I (iface_class->g_type);
2551   node = lookup_type_node_I (iface_class->g_instance_type);
2552   if (node)
2553     node = lookup_type_node_I (NODE_PARENT_TYPE (node));
2554   if (node && node->is_instantiatable && iface)
2555     {
2556       IFaceEntry *entry;
2557       
2558       G_READ_LOCK (&type_rw_lock);
2559       
2560       entry = type_lookup_iface_entry_L (node, iface);
2561       if (entry && entry->vtable)       /* entry is relocatable */
2562         vtable = entry->vtable;
2563       
2564       G_READ_UNLOCK (&type_rw_lock);
2565     }
2566   else if (node)
2567     g_warning (G_STRLOC ": invalid interface pointer `%p'", g_iface);
2568   
2569   return vtable;
2570 }
2571
2572 gpointer
2573 g_type_default_interface_ref (GType g_type)
2574 {
2575   TypeNode *node;
2576   gpointer dflt_vtable;
2577
2578   G_WRITE_LOCK (&type_rw_lock);
2579
2580   node = lookup_type_node_I (g_type);
2581   if (!node || !NODE_IS_IFACE (node) ||
2582       (node->data && node->data->common.ref_count < 1))
2583     {
2584       G_WRITE_UNLOCK (&type_rw_lock);
2585       g_warning ("cannot retrieve default vtable for invalid or non-interface type '%s'",
2586                  type_descriptive_name_I (g_type));
2587       return NULL;
2588     }
2589
2590   if (!node->data || !node->data->iface.dflt_vtable)
2591     {
2592       G_WRITE_UNLOCK (&type_rw_lock);
2593       g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
2594       G_WRITE_LOCK (&type_rw_lock);
2595       node = lookup_type_node_I (g_type);
2596       type_data_ref_Wm (node);
2597       type_iface_ensure_dflt_vtable_Wm (node);
2598       g_static_rec_mutex_unlock (&class_init_rec_mutex);
2599     }
2600   else
2601     type_data_ref_Wm (node); /* ref_count >= 1 already */
2602
2603   dflt_vtable = node->data->iface.dflt_vtable;
2604   G_WRITE_UNLOCK (&type_rw_lock);
2605
2606   return dflt_vtable;
2607 }
2608
2609 gpointer
2610 g_type_default_interface_peek (GType g_type)
2611 {
2612   TypeNode *node;
2613   gpointer vtable;
2614   
2615   node = lookup_type_node_I (g_type);
2616   G_READ_LOCK (&type_rw_lock);
2617   if (node && NODE_IS_IFACE (node) && node->data && node->data->iface.dflt_vtable)
2618     vtable = node->data->iface.dflt_vtable;
2619   else
2620     vtable = NULL;
2621   G_READ_UNLOCK (&type_rw_lock);
2622   
2623   return vtable;
2624 }
2625
2626 void
2627 g_type_default_interface_unref (gpointer g_iface)
2628 {
2629   TypeNode *node;
2630   GTypeInterface *vtable = g_iface;
2631   
2632   g_return_if_fail (g_iface != NULL);
2633   
2634   node = lookup_type_node_I (vtable->g_type);
2635   G_WRITE_LOCK (&type_rw_lock);
2636   if (node && NODE_IS_IFACE (node) &&
2637       node->data->iface.dflt_vtable == g_iface &&
2638       node->data->common.ref_count > 0)
2639     type_data_unref_WmREC (node, FALSE);
2640   else
2641     g_warning ("cannot unreference invalid interface default vtable for '%s'",
2642                type_descriptive_name_I (vtable->g_type));
2643   G_WRITE_UNLOCK (&type_rw_lock);
2644 }
2645
2646 G_CONST_RETURN gchar*
2647 g_type_name (GType type)
2648 {
2649   TypeNode *node;
2650   
2651   g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, NULL);
2652   
2653   node = lookup_type_node_I (type);
2654   
2655   return node ? NODE_NAME (node) : NULL;
2656 }
2657
2658 GQuark
2659 g_type_qname (GType type)
2660 {
2661   TypeNode *node;
2662   
2663   node = lookup_type_node_I (type);
2664   
2665   return node ? node->qname : 0;
2666 }
2667
2668 GType
2669 g_type_from_name (const gchar *name)
2670 {
2671   GType type = 0;
2672   GQuark quark;
2673   
2674   g_return_val_if_fail (name != NULL, 0);
2675   
2676   quark = g_quark_try_string (name);
2677   if (quark)
2678     {
2679       G_READ_LOCK (&type_rw_lock);
2680       type = (GType) g_hash_table_lookup (static_type_nodes_ht, GUINT_TO_POINTER (quark));
2681       G_READ_UNLOCK (&type_rw_lock);
2682     }
2683   
2684   return type;
2685 }
2686
2687 GType
2688 g_type_parent (GType type)
2689 {
2690   TypeNode *node;
2691   
2692   node = lookup_type_node_I (type);
2693   
2694   return node ? NODE_PARENT_TYPE (node) : 0;
2695 }
2696
2697 guint
2698 g_type_depth (GType type)
2699 {
2700   TypeNode *node;
2701   
2702   node = lookup_type_node_I (type);
2703   
2704   return node ? node->n_supers + 1 : 0;
2705 }
2706
2707 GType
2708 g_type_next_base (GType type,
2709                   GType base_type)
2710 {
2711   GType atype = 0;
2712   TypeNode *node;
2713   
2714   node = lookup_type_node_I (type);
2715   if (node)
2716     {
2717       TypeNode *base_node = lookup_type_node_I (base_type);
2718       
2719       if (base_node && base_node->n_supers < node->n_supers)
2720         {
2721           guint n = node->n_supers - base_node->n_supers;
2722           
2723           if (node->supers[n] == base_type)
2724             atype = node->supers[n - 1];
2725         }
2726     }
2727   
2728   return atype;
2729 }
2730
2731 static inline gboolean
2732 type_node_check_conformities_UorL (TypeNode *node,
2733                                    TypeNode *iface_node,
2734                                    /*        support_inheritance */
2735                                    gboolean  support_interfaces,
2736                                    gboolean  support_prerequisites,
2737                                    gboolean  have_lock)
2738 {
2739   gboolean match;
2740   
2741   if (/* support_inheritance && */
2742       NODE_IS_ANCESTOR (iface_node, node))
2743     return TRUE;
2744   
2745   support_interfaces = support_interfaces && node->is_instantiatable && NODE_IS_IFACE (iface_node);
2746   support_prerequisites = support_prerequisites && NODE_IS_IFACE (node);
2747   match = FALSE;
2748   if (support_interfaces || support_prerequisites)
2749     {
2750       if (!have_lock)
2751         G_READ_LOCK (&type_rw_lock);
2752       if (support_interfaces && type_lookup_iface_entry_L (node, iface_node))
2753         match = TRUE;
2754       else if (support_prerequisites && type_lookup_prerequisite_L (node, NODE_TYPE (iface_node)))
2755         match = TRUE;
2756       if (!have_lock)
2757         G_READ_UNLOCK (&type_rw_lock);
2758     }
2759   return match;
2760 }
2761
2762 static gboolean
2763 type_node_is_a_L (TypeNode *node,
2764                   TypeNode *iface_node)
2765 {
2766   return type_node_check_conformities_UorL (node, iface_node, TRUE, TRUE, TRUE);
2767 }
2768
2769 static inline gboolean
2770 type_node_conforms_to_U (TypeNode *node,
2771                          TypeNode *iface_node,
2772                          gboolean  support_interfaces,
2773                          gboolean  support_prerequisites)
2774 {
2775   return type_node_check_conformities_UorL (node, iface_node, support_interfaces, support_prerequisites, FALSE);
2776 }
2777
2778 gboolean
2779 g_type_is_a (GType type,
2780              GType iface_type)
2781 {
2782   TypeNode *node, *iface_node;
2783   gboolean is_a;
2784   
2785   node = lookup_type_node_I (type);
2786   iface_node = lookup_type_node_I (iface_type);
2787   is_a = node && iface_node && type_node_conforms_to_U (node, iface_node, TRUE, TRUE);
2788   
2789   return is_a;
2790 }
2791
2792 GType* /* free result */
2793 g_type_children (GType  type,
2794                  guint *n_children)
2795 {
2796   TypeNode *node;
2797   
2798   node = lookup_type_node_I (type);
2799   if (node)
2800     {
2801       GType *children;
2802       
2803       G_READ_LOCK (&type_rw_lock);      /* ->children is relocatable */
2804       children = g_new (GType, node->n_children + 1);
2805       memcpy (children, node->children, sizeof (GType) * node->n_children);
2806       children[node->n_children] = 0;
2807       
2808       if (n_children)
2809         *n_children = node->n_children;
2810       G_READ_UNLOCK (&type_rw_lock);
2811       
2812       return children;
2813     }
2814   else
2815     {
2816       if (n_children)
2817         *n_children = 0;
2818       
2819       return NULL;
2820     }
2821 }
2822
2823 GType* /* free result */
2824 g_type_interfaces (GType  type,
2825                    guint *n_interfaces)
2826 {
2827   TypeNode *node;
2828   
2829   node = lookup_type_node_I (type);
2830   if (node && node->is_instantiatable)
2831     {
2832       GType *ifaces;
2833       guint i;
2834       
2835       G_READ_LOCK (&type_rw_lock);
2836       ifaces = g_new (GType, CLASSED_NODE_N_IFACES (node) + 1);
2837       for (i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
2838         ifaces[i] = CLASSED_NODE_IFACES_ENTRIES (node)[i].iface_type;
2839       ifaces[i] = 0;
2840       
2841       if (n_interfaces)
2842         *n_interfaces = CLASSED_NODE_N_IFACES (node);
2843       G_READ_UNLOCK (&type_rw_lock);
2844       
2845       return ifaces;
2846     }
2847   else
2848     {
2849       if (n_interfaces)
2850         *n_interfaces = 0;
2851       
2852       return NULL;
2853     }
2854 }
2855
2856 typedef struct _QData QData;
2857 struct _GData
2858 {
2859   guint  n_qdatas;
2860   QData *qdatas;
2861 };
2862 struct _QData
2863 {
2864   GQuark   quark;
2865   gpointer data;
2866 };
2867
2868 static inline gpointer
2869 type_get_qdata_L (TypeNode *node,
2870                   GQuark    quark)
2871 {
2872   GData *gdata = node->global_gdata;
2873   
2874   if (quark && gdata && gdata->n_qdatas)
2875     {
2876       QData *qdatas = gdata->qdatas - 1;
2877       guint n_qdatas = gdata->n_qdatas;
2878       
2879       do
2880         {
2881           guint i;
2882           QData *check;
2883           
2884           i = (n_qdatas + 1) / 2;
2885           check = qdatas + i;
2886           if (quark == check->quark)
2887             return check->data;
2888           else if (quark > check->quark)
2889             {
2890               n_qdatas -= i;
2891               qdatas = check;
2892             }
2893           else /* if (quark < check->quark) */
2894             n_qdatas = i - 1;
2895         }
2896       while (n_qdatas);
2897     }
2898   return NULL;
2899 }
2900
2901 gpointer
2902 g_type_get_qdata (GType  type,
2903                   GQuark quark)
2904 {
2905   TypeNode *node;
2906   gpointer data;
2907   
2908   node = lookup_type_node_I (type);
2909   if (node)
2910     {
2911       G_READ_LOCK (&type_rw_lock);
2912       data = type_get_qdata_L (node, quark);
2913       G_READ_UNLOCK (&type_rw_lock);
2914     }
2915   else
2916     {
2917       g_return_val_if_fail (node != NULL, NULL);
2918       data = NULL;
2919     }
2920   return data;
2921 }
2922
2923 static inline void
2924 type_set_qdata_W (TypeNode *node,
2925                   GQuark    quark,
2926                   gpointer  data)
2927 {
2928   GData *gdata;
2929   QData *qdata;
2930   guint i;
2931   
2932   /* setup qdata list if necessary */
2933   if (!node->global_gdata)
2934     node->global_gdata = g_new0 (GData, 1);
2935   gdata = node->global_gdata;
2936   
2937   /* try resetting old data */
2938   qdata = gdata->qdatas;
2939   for (i = 0; i < gdata->n_qdatas; i++)
2940     if (qdata[i].quark == quark)
2941       {
2942         qdata[i].data = data;
2943         return;
2944       }
2945   
2946   /* add new entry */
2947   gdata->n_qdatas++;
2948   gdata->qdatas = g_renew (QData, gdata->qdatas, gdata->n_qdatas);
2949   qdata = gdata->qdatas;
2950   for (i = 0; i < gdata->n_qdatas - 1; i++)
2951     if (qdata[i].quark > quark)
2952       break;
2953   g_memmove (qdata + i + 1, qdata + i, sizeof (qdata[0]) * (gdata->n_qdatas - i - 1));
2954   qdata[i].quark = quark;
2955   qdata[i].data = data;
2956 }
2957
2958 void
2959 g_type_set_qdata (GType    type,
2960                   GQuark   quark,
2961                   gpointer data)
2962 {
2963   TypeNode *node;
2964   
2965   g_return_if_fail (quark != 0);
2966   
2967   node = lookup_type_node_I (type);
2968   if (node)
2969     {
2970       G_WRITE_LOCK (&type_rw_lock);
2971       type_set_qdata_W (node, quark, data);
2972       G_WRITE_UNLOCK (&type_rw_lock);
2973     }
2974   else
2975     g_return_if_fail (node != NULL);
2976 }
2977
2978 static void
2979 type_add_flags_W (TypeNode  *node,
2980                   GTypeFlags flags)
2981 {
2982   guint dflags;
2983   
2984   g_return_if_fail ((flags & ~TYPE_FLAG_MASK) == 0);
2985   g_return_if_fail (node != NULL);
2986   
2987   if ((flags & TYPE_FLAG_MASK) && node->is_classed && node->data && node->data->class.class)
2988     g_warning ("tagging type `%s' as abstract after class initialization", NODE_NAME (node));
2989   dflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags));
2990   dflags |= flags;
2991   type_set_qdata_W (node, static_quark_type_flags, GUINT_TO_POINTER (dflags));
2992 }
2993
2994 void
2995 g_type_query (GType       type,
2996               GTypeQuery *query)
2997 {
2998   TypeNode *node;
2999   
3000   g_return_if_fail (query != NULL);
3001   
3002   /* if node is not static and classed, we won't allow query */
3003   query->type = 0;
3004   node = lookup_type_node_I (type);
3005   if (node && node->is_classed && !node->plugin)
3006     {
3007       /* type is classed and probably even instantiatable */
3008       G_READ_LOCK (&type_rw_lock);
3009       if (node->data)   /* type is static or referenced */
3010         {
3011           query->type = NODE_TYPE (node);
3012           query->type_name = NODE_NAME (node);
3013           query->class_size = node->data->class.class_size;
3014           query->instance_size = node->is_instantiatable ? node->data->instance.instance_size : 0;
3015         }
3016       G_READ_UNLOCK (&type_rw_lock);
3017     }
3018 }
3019
3020
3021 /* --- implementation details --- */
3022 gboolean
3023 g_type_test_flags (GType type,
3024                    guint flags)
3025 {
3026   TypeNode *node;
3027   gboolean result = FALSE;
3028   
3029   node = lookup_type_node_I (type);
3030   if (node)
3031     {
3032       guint fflags = flags & TYPE_FUNDAMENTAL_FLAG_MASK;
3033       guint tflags = flags & TYPE_FLAG_MASK;
3034       
3035       if (fflags)
3036         {
3037           GTypeFundamentalInfo *finfo = type_node_fundamental_info_I (node);
3038           
3039           fflags = (finfo->type_flags & fflags) == fflags;
3040         }
3041       else
3042         fflags = TRUE;
3043       
3044       if (tflags)
3045         {
3046           G_READ_LOCK (&type_rw_lock);
3047           tflags = (tflags & GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags))) == tflags;
3048           G_READ_UNLOCK (&type_rw_lock);
3049         }
3050       else
3051         tflags = TRUE;
3052       
3053       result = tflags && fflags;
3054     }
3055   
3056   return result;
3057 }
3058
3059 GTypePlugin*
3060 g_type_get_plugin (GType type)
3061 {
3062   TypeNode *node;
3063   
3064   node = lookup_type_node_I (type);
3065   
3066   return node ? node->plugin : NULL;
3067 }
3068
3069 GTypePlugin*
3070 g_type_interface_get_plugin (GType instance_type,
3071                              GType interface_type)
3072 {
3073   TypeNode *node;
3074   TypeNode *iface;
3075   
3076   g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL);    /* G_TYPE_IS_INTERFACE() is an external call: _U */
3077   
3078   node = lookup_type_node_I (instance_type);  
3079   iface = lookup_type_node_I (interface_type);
3080   if (node && iface)
3081     {
3082       IFaceHolder *iholder;
3083       GTypePlugin *plugin;
3084       
3085       G_READ_LOCK (&type_rw_lock);
3086       
3087       iholder = iface_node_get_holders_L (iface);
3088       while (iholder && iholder->instance_type != instance_type)
3089         iholder = iholder->next;
3090       plugin = iholder ? iholder->plugin : NULL;
3091       
3092       G_READ_UNLOCK (&type_rw_lock);
3093       
3094       return plugin;
3095     }
3096   
3097   g_return_val_if_fail (node == NULL, NULL);
3098   g_return_val_if_fail (iface == NULL, NULL);
3099   
3100   g_warning (G_STRLOC ": attempt to look up plugin for invalid instance/interface type pair.");
3101   
3102   return NULL;
3103 }
3104
3105 GType
3106 g_type_fundamental_next (void)
3107 {
3108   GType type;
3109   
3110   G_READ_LOCK (&type_rw_lock);
3111   type = static_fundamental_next;
3112   G_READ_UNLOCK (&type_rw_lock);
3113   type = G_TYPE_MAKE_FUNDAMENTAL (type);
3114   return type <= G_TYPE_FUNDAMENTAL_MAX ? type : 0;
3115 }
3116
3117 GType
3118 g_type_fundamental (GType type_id)
3119 {
3120   TypeNode *node = lookup_type_node_I (type_id);
3121   
3122   return node ? NODE_FUNDAMENTAL_TYPE (node) : 0;
3123 }
3124
3125 gboolean
3126 g_type_check_instance_is_a (GTypeInstance *type_instance,
3127                             GType          iface_type)
3128 {
3129   TypeNode *node, *iface;
3130   gboolean check;
3131   
3132   if (!type_instance || !type_instance->g_class)
3133     return FALSE;
3134   
3135   node = lookup_type_node_I (type_instance->g_class->g_type);
3136   iface = lookup_type_node_I (iface_type);
3137   check = node && node->is_instantiatable && iface && type_node_conforms_to_U (node, iface, TRUE, FALSE);
3138   
3139   return check;
3140 }
3141
3142 gboolean
3143 g_type_check_class_is_a (GTypeClass *type_class,
3144                          GType       is_a_type)
3145 {
3146   TypeNode *node, *iface;
3147   gboolean check;
3148   
3149   if (!type_class)
3150     return FALSE;
3151   
3152   node = lookup_type_node_I (type_class->g_type);
3153   iface = lookup_type_node_I (is_a_type);
3154   check = node && node->is_classed && iface && type_node_conforms_to_U (node, iface, FALSE, FALSE);
3155   
3156   return check;
3157 }
3158
3159 GTypeInstance*
3160 g_type_check_instance_cast (GTypeInstance *type_instance,
3161                             GType          iface_type)
3162 {
3163   if (type_instance)
3164     {
3165       if (type_instance->g_class)
3166         {
3167           TypeNode *node, *iface;
3168           gboolean is_instantiatable, check;
3169           
3170           node = lookup_type_node_I (type_instance->g_class->g_type);
3171           is_instantiatable = node && node->is_instantiatable;
3172           iface = lookup_type_node_I (iface_type);
3173           check = is_instantiatable && iface && type_node_conforms_to_U (node, iface, TRUE, FALSE);
3174           if (check)
3175             return type_instance;
3176           
3177           if (is_instantiatable)
3178             g_warning ("invalid cast from `%s' to `%s'",
3179                        type_descriptive_name_I (type_instance->g_class->g_type),
3180                        type_descriptive_name_I (iface_type));
3181           else
3182             g_warning ("invalid uninstantiatable type `%s' in cast to `%s'",
3183                        type_descriptive_name_I (type_instance->g_class->g_type),
3184                        type_descriptive_name_I (iface_type));
3185         }
3186       else
3187         g_warning ("invalid unclassed pointer in cast to `%s'",
3188                    type_descriptive_name_I (iface_type));
3189     }
3190   
3191   return type_instance;
3192 }
3193
3194 GTypeClass*
3195 g_type_check_class_cast (GTypeClass *type_class,
3196                          GType       is_a_type)
3197 {
3198   if (type_class)
3199     {
3200       TypeNode *node, *iface;
3201       gboolean is_classed, check;
3202       
3203       node = lookup_type_node_I (type_class->g_type);
3204       is_classed = node && node->is_classed;
3205       iface = lookup_type_node_I (is_a_type);
3206       check = is_classed && iface && type_node_conforms_to_U (node, iface, FALSE, FALSE);
3207       if (check)
3208         return type_class;
3209       
3210       if (is_classed)
3211         g_warning ("invalid class cast from `%s' to `%s'",
3212                    type_descriptive_name_I (type_class->g_type),
3213                    type_descriptive_name_I (is_a_type));
3214       else
3215         g_warning ("invalid unclassed type `%s' in class cast to `%s'",
3216                    type_descriptive_name_I (type_class->g_type),
3217                    type_descriptive_name_I (is_a_type));
3218     }
3219   else
3220     g_warning ("invalid class cast from (NULL) pointer to `%s'",
3221                type_descriptive_name_I (is_a_type));
3222   return type_class;
3223 }
3224
3225 gboolean
3226 g_type_check_instance (GTypeInstance *type_instance)
3227 {
3228   /* this function is just here to make the signal system
3229    * conveniently elaborated on instance checks
3230    */
3231   if (type_instance)
3232     {
3233       if (type_instance->g_class)
3234         {
3235           TypeNode *node = lookup_type_node_I (type_instance->g_class->g_type);
3236           
3237           if (node && node->is_instantiatable)
3238             return TRUE;
3239           
3240           g_warning ("instance of invalid non-instantiatable type `%s'",
3241                      type_descriptive_name_I (type_instance->g_class->g_type));
3242         }
3243       else
3244         g_warning ("instance with invalid (NULL) class pointer");
3245     }
3246   else
3247     g_warning ("invalid (NULL) pointer instance");
3248   
3249   return FALSE;
3250 }
3251
3252 static inline gboolean
3253 type_check_is_value_type_U (GType type)
3254 {
3255   GTypeFlags tflags = G_TYPE_FLAG_VALUE_ABSTRACT;
3256   TypeNode *node;
3257   
3258   /* common path speed up */
3259   node = lookup_type_node_I (type);
3260   if (node && node->mutatable_check_cache)
3261     return TRUE;
3262   
3263   G_READ_LOCK (&type_rw_lock);
3264  restart_check:
3265   if (node)
3266     {
3267       if (node->data && node->data->common.ref_count > 0 &&
3268           node->data->common.value_table->value_init)
3269         tflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags));
3270       else if (NODE_IS_IFACE (node))
3271         {
3272           guint i;
3273           
3274           for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++)
3275             {
3276               GType prtype = IFACE_NODE_PREREQUISITES (node)[i];
3277               TypeNode *prnode = lookup_type_node_I (prtype);
3278               
3279               if (prnode->is_instantiatable)
3280                 {
3281                   type = prtype;
3282                   node = lookup_type_node_I (type);
3283                   goto restart_check;
3284                 }
3285             }
3286         }
3287     }
3288   G_READ_UNLOCK (&type_rw_lock);
3289   
3290   return !(tflags & G_TYPE_FLAG_VALUE_ABSTRACT);
3291 }
3292
3293 gboolean
3294 g_type_check_is_value_type (GType type)
3295 {
3296   return type_check_is_value_type_U (type);
3297 }
3298
3299 gboolean
3300 g_type_check_value (GValue *value)
3301 {
3302   return value && type_check_is_value_type_U (value->g_type);
3303 }
3304
3305 gboolean
3306 g_type_check_value_holds (GValue *value,
3307                           GType   type)
3308 {
3309   return value && type_check_is_value_type_U (value->g_type) && g_type_is_a (value->g_type, type);
3310 }
3311
3312 GTypeValueTable*
3313 g_type_value_table_peek (GType type)
3314 {
3315   GTypeValueTable *vtable = NULL;
3316   TypeNode *node = lookup_type_node_I (type);
3317   gboolean has_refed_data, has_table;
3318   TypeData *data;
3319
3320   /* speed up common code path, we're not 100% safe here,
3321    * but we should only get called with referenced types anyway
3322    */
3323   data = node ? node->data : NULL;
3324   if (node && node->mutatable_check_cache)
3325     return data->common.value_table;
3326
3327   G_READ_LOCK (&type_rw_lock);
3328   
3329  restart_table_peek:
3330   has_refed_data = node && node->data && node->data->common.ref_count;
3331   has_table = has_refed_data && node->data->common.value_table->value_init;
3332   if (has_refed_data)
3333     {
3334       if (has_table)
3335         vtable = node->data->common.value_table;
3336       else if (NODE_IS_IFACE (node))
3337         {
3338           guint i;
3339           
3340           for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++)
3341             {
3342               GType prtype = IFACE_NODE_PREREQUISITES (node)[i];
3343               TypeNode *prnode = lookup_type_node_I (prtype);
3344               
3345               if (prnode->is_instantiatable)
3346                 {
3347                   type = prtype;
3348                   node = lookup_type_node_I (type);
3349                   goto restart_table_peek;
3350                 }
3351             }
3352         }
3353     }
3354   
3355   G_READ_UNLOCK (&type_rw_lock);
3356   
3357   if (vtable)
3358     return vtable;
3359   
3360   if (!node)
3361     g_warning (G_STRLOC ": type id `%zu' is invalid", type);
3362   if (!has_refed_data)
3363     g_warning ("can't peek value table for type `%s' which is not currently referenced",
3364                type_descriptive_name_I (type));
3365   
3366   return NULL;
3367 }
3368
3369 G_CONST_RETURN gchar*
3370 g_type_name_from_instance (GTypeInstance *instance)
3371 {
3372   if (!instance)
3373     return "<NULL-instance>";
3374   else
3375     return g_type_name_from_class (instance->g_class);
3376 }
3377
3378 G_CONST_RETURN gchar*
3379 g_type_name_from_class (GTypeClass *g_class)
3380 {
3381   if (!g_class)
3382     return "<NULL-class>";
3383   else
3384     return g_type_name (g_class->g_type);
3385 }
3386
3387
3388 /* --- initialization --- */
3389 void
3390 g_type_init_with_debug_flags (GTypeDebugFlags debug_flags)
3391 {
3392   G_LOCK_DEFINE_STATIC (type_init_lock);
3393   const gchar *env_string;
3394   GTypeInfo info;
3395   TypeNode *node;
3396   volatile GType votype;
3397   
3398   G_LOCK (type_init_lock);
3399   
3400   G_WRITE_LOCK (&type_rw_lock);
3401   
3402   if (static_quark_type_flags)
3403     {
3404       G_WRITE_UNLOCK (&type_rw_lock);
3405       G_UNLOCK (type_init_lock);
3406       return;
3407     }
3408   
3409   /* setup GObject library wide debugging flags */
3410   _g_type_debug_flags = debug_flags & G_TYPE_DEBUG_MASK;
3411   env_string = g_getenv ("GOBJECT_DEBUG");
3412   if (env_string != NULL)
3413     {
3414       static GDebugKey debug_keys[] = {
3415         { "objects", G_TYPE_DEBUG_OBJECTS },
3416         { "signals", G_TYPE_DEBUG_SIGNALS },
3417       };
3418       
3419       _g_type_debug_flags |= g_parse_debug_string (env_string,
3420                                                    debug_keys,
3421                                                    sizeof (debug_keys) / sizeof (debug_keys[0]));
3422       env_string = NULL;
3423     }
3424   
3425   /* quarks */
3426   static_quark_type_flags = g_quark_from_static_string ("-g-type-private--GTypeFlags");
3427   static_quark_iface_holder = g_quark_from_static_string ("-g-type-private--IFaceHolder");
3428   static_quark_dependants_array = g_quark_from_static_string ("-g-type-private--dependants-array");
3429   
3430   /* type qname hash table */
3431   static_type_nodes_ht = g_hash_table_new (g_direct_hash, g_direct_equal);
3432   
3433   /* invalid type G_TYPE_INVALID (0)
3434    */
3435   static_fundamental_type_nodes[0] = NULL;
3436   
3437   /* void type G_TYPE_NONE
3438    */
3439   node = type_node_fundamental_new_W (G_TYPE_NONE, g_intern_static_string ("void"), 0);
3440   votype = NODE_TYPE (node);
3441   g_assert (votype == G_TYPE_NONE);
3442   
3443   /* interface fundamental type G_TYPE_INTERFACE (!classed)
3444    */
3445   memset (&info, 0, sizeof (info));
3446   node = type_node_fundamental_new_W (G_TYPE_INTERFACE, g_intern_static_string ("GInterface"), G_TYPE_FLAG_DERIVABLE);
3447   votype = NODE_TYPE (node);
3448   type_data_make_W (node, &info, NULL);
3449   g_assert (votype == G_TYPE_INTERFACE);
3450   
3451   G_WRITE_UNLOCK (&type_rw_lock);
3452   
3453   g_value_c_init ();
3454
3455   /* G_TYPE_TYPE_PLUGIN
3456    */
3457   votype = g_type_plugin_get_type ();
3458   
3459   /* G_TYPE_* value types
3460    */
3461   g_value_types_init ();
3462   
3463   /* G_TYPE_ENUM & G_TYPE_FLAGS
3464    */
3465   g_enum_types_init ();
3466   
3467   /* G_TYPE_BOXED
3468    */
3469   g_boxed_type_init ();
3470   
3471   /* G_TYPE_PARAM
3472    */
3473   g_param_type_init ();
3474   
3475   /* G_TYPE_OBJECT
3476    */
3477   g_object_type_init ();
3478   
3479   /* G_TYPE_PARAM_* pspec types
3480    */
3481   g_param_spec_types_init ();
3482   
3483   /* Value Transformations
3484    */
3485   g_value_transforms_init ();
3486   
3487   /* Signal system
3488    */
3489   g_signal_init ();
3490   
3491   G_UNLOCK (type_init_lock);
3492 }
3493
3494 void 
3495 g_type_init (void)
3496 {
3497   g_type_init_with_debug_flags (0);
3498 }
3499
3500 void
3501 g_type_class_add_private (gpointer g_class,
3502                           gsize    private_size)
3503 {
3504   GType instance_type = ((GTypeClass *)g_class)->g_type;
3505   TypeNode *node = lookup_type_node_I (instance_type);
3506   gsize offset;
3507
3508   g_return_if_fail (private_size > 0);
3509
3510   if (!node || !node->is_instantiatable || !node->data || node->data->class.class != g_class)
3511     {
3512       g_warning ("cannot add private field to invalid (non-instantiatable) type '%s'",
3513                  type_descriptive_name_I (instance_type));
3514       return;
3515     }
3516
3517   if (NODE_PARENT_TYPE (node))
3518     {
3519       TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
3520       if (node->data->instance.private_size != pnode->data->instance.private_size)
3521         {
3522           g_warning ("g_type_add_private() called multiple times for the same type");
3523           return;
3524         }
3525     }
3526   
3527   G_WRITE_LOCK (&type_rw_lock);
3528
3529   offset = ALIGN_STRUCT (node->data->instance.private_size);
3530   node->data->instance.private_size = offset + private_size;
3531   
3532   G_WRITE_UNLOCK (&type_rw_lock);
3533 }
3534
3535 gpointer
3536 g_type_instance_get_private (GTypeInstance *instance,
3537                              GType          private_type)
3538 {
3539   TypeNode *instance_node;
3540   TypeNode *private_node;
3541   TypeNode *parent_node;
3542   GTypeClass *class;
3543   gsize offset;
3544
3545   g_return_val_if_fail (instance != NULL && instance->g_class != NULL, NULL);
3546
3547   /* while instances are initialized, their class pointers change,
3548    * so figure the instances real class first
3549    */
3550   class = instance_real_class_get (instance);
3551   if (!class)
3552     class = instance->g_class;
3553
3554   instance_node = lookup_type_node_I (class->g_type);
3555   if (G_UNLIKELY (!instance_node || !instance_node->is_instantiatable))
3556     {
3557       g_warning ("instance of invalid non-instantiatable type `%s'",
3558                  type_descriptive_name_I (instance->g_class->g_type));
3559       return NULL;
3560     }
3561
3562   private_node = lookup_type_node_I (private_type);
3563   if (G_UNLIKELY (!private_node || !NODE_IS_ANCESTOR (private_node, instance_node)))
3564     {
3565       g_warning ("attempt to retrieve private data for invalid type '%s'",
3566                  type_descriptive_name_I (private_type));
3567       return NULL;
3568     }
3569
3570   /* Note that we don't need a read lock, since instance existing
3571    * means that the instance class and all parent classes
3572    * exist, so the node->data, node->data->instance.instance_size,
3573    * and node->data->instance.private_size are not going to be changed.
3574    * for any of the relevant types.
3575    */
3576
3577   offset = ALIGN_STRUCT (instance_node->data->instance.instance_size);
3578
3579   if (NODE_PARENT_TYPE (private_node))
3580     {
3581       parent_node = lookup_type_node_I (NODE_PARENT_TYPE (private_node));
3582       g_assert (parent_node->data && parent_node->data->common.ref_count);
3583
3584       if (G_UNLIKELY (private_node->data->instance.private_size == parent_node->data->instance.private_size))
3585         {
3586           g_warning ("g_type_instance_get_private() requires a prior call to g_type_class_add_private()");
3587           return NULL;
3588         }
3589
3590       offset += ALIGN_STRUCT (parent_node->data->instance.private_size);
3591     }
3592
3593   return G_STRUCT_MEMBER_P (instance, offset);
3594 }
3595
3596 #define __G_TYPE_C__
3597 #include "gobjectaliasdef.c"