* Add this nice filesystem testing tool that I've recently
[dragonfly.git] / contrib / libobjc / class.c
1 /* GNU Objective C Runtime class related functions
2    Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
3    Contributed by Kresten Krab Thorup and Dennis Glatting.
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 2, or (at your option) any later version.
10
11 GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14 details.
15
16 You should have received a copy of the GNU General Public License along with
17 GNU CC; see the file COPYING.  If not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 /* As a special exception, if you link this library with files compiled with
21    GCC to produce an executable, this does not cause the resulting executable
22    to be covered by the GNU General Public License. This exception does not
23    however invalidate any other reasons why the executable file might be
24    covered by the GNU General Public License.  */
25
26 #include "runtime.h"            /* the kitchen sink */
27 #include "sarray.h"
28
29 /* The table of classname->class.  Used for objc_lookup_class and friends */
30 static cache_ptr __objc_class_hash = 0;                 /* !T:MUTEX */
31
32 /* This is a hook which is called by objc_get_class and 
33    objc_lookup_class if the runtime is not able to find the class.
34    This may e.g. try to load in the class using dynamic loading */
35 Class (*_objc_lookup_class)(const char* name) = 0;      /* !T:SAFE */
36
37
38 /* True when class links has been resolved */     
39 BOOL __objc_class_links_resolved = NO;                  /* !T:UNUSED */
40
41
42 /* Initial number of buckets size of class hash table. */
43 #define CLASS_HASH_SIZE 32
44
45 void __objc_init_class_tables()
46 {
47   /* Allocate the class hash table */
48
49   if(__objc_class_hash)
50     return;
51
52   objc_mutex_lock(__objc_runtime_mutex);
53
54   __objc_class_hash
55     =  hash_new (CLASS_HASH_SIZE,
56                  (hash_func_type) hash_string,
57                  (compare_func_type) compare_strings);
58
59   objc_mutex_unlock(__objc_runtime_mutex);
60 }  
61
62 /* This function adds a class to the class hash table, and assigns the 
63    class a number, unless it's already known */
64 void
65 __objc_add_class_to_hash(Class class)
66 {
67   Class h_class;
68
69   objc_mutex_lock(__objc_runtime_mutex);
70
71   /* make sure the table is there */
72   assert(__objc_class_hash);
73
74   /* make sure it's not a meta class */  
75   assert(CLS_ISCLASS(class));
76
77   /* Check to see if the class is already in the hash table.  */
78   h_class = hash_value_for_key (__objc_class_hash, class->name);
79   if (!h_class)
80     {
81       /* The class isn't in the hash table.  Add the class and assign a class
82          number.  */
83       static unsigned int class_number = 1;
84
85       CLS_SETNUMBER(class, class_number);
86       CLS_SETNUMBER(class->class_pointer, class_number);
87
88       ++class_number;
89       hash_add (&__objc_class_hash, class->name, class);
90     }
91
92   objc_mutex_unlock(__objc_runtime_mutex);
93 }
94
95 /* Get the class object for the class named NAME.  If NAME does not
96    identify a known class, the hook _objc_lookup_class is called.  If
97    this fails, nil is returned */
98 Class objc_lookup_class (const char* name)
99 {
100   Class class;
101
102   objc_mutex_lock(__objc_runtime_mutex);
103
104   /* Make sure the class hash table exists.  */
105   assert (__objc_class_hash);
106
107   class = hash_value_for_key (__objc_class_hash, name);
108
109   objc_mutex_unlock(__objc_runtime_mutex);
110
111   if (class)
112     return class;
113
114   if (_objc_lookup_class)
115     return (*_objc_lookup_class)(name);
116   else
117     return 0;
118 }
119
120 /* Get the class object for the class named NAME.  If NAME does not
121    identify a known class, the hook _objc_lookup_class is called.  If
122    this fails,  an error message is issued and the system aborts */
123 Class
124 objc_get_class (const char *name)
125 {
126   Class class;
127
128   objc_mutex_lock(__objc_runtime_mutex);
129
130   /* Make sure the class hash table exists.  */
131   assert (__objc_class_hash);
132
133   class = hash_value_for_key (__objc_class_hash, name);
134
135   objc_mutex_unlock(__objc_runtime_mutex);
136
137   if (class)
138     return class;
139
140   if (_objc_lookup_class)
141     class = (*_objc_lookup_class)(name);
142
143   if(class)
144     return class;
145   
146   objc_error(nil, OBJC_ERR_BAD_CLASS, 
147              "objc runtime: cannot find class %s\n", name);
148   return 0;
149 }
150
151 MetaClass
152 objc_get_meta_class(const char *name)
153 {
154   return objc_get_class(name)->class_pointer;
155 }
156
157 /* This function provides a way to enumerate all the classes in the
158    executable.  Pass *ENUM_STATE == NULL to start the enumeration.  The
159    function will return 0 when there are no more classes.  
160    For example: 
161        id class; 
162        void *es = NULL;
163        while ((class = objc_next_class(&es)))
164          ... do something with class; 
165 */
166 Class
167 objc_next_class(void **enum_state)
168 {
169   objc_mutex_lock(__objc_runtime_mutex);
170
171   /* make sure the table is there */
172   assert(__objc_class_hash);
173
174   *(node_ptr*)enum_state = 
175     hash_next(__objc_class_hash, *(node_ptr*)enum_state);
176
177   objc_mutex_unlock(__objc_runtime_mutex);
178
179   if (*(node_ptr*)enum_state)
180     return (*(node_ptr*)enum_state)->value;
181   return (Class)0;
182 }
183
184 /* Resolve super/subclass links for all classes.  The only thing we 
185    can be sure of is that the class_pointer for class objects point 
186    to the right meta class objects */
187 void __objc_resolve_class_links()
188 {
189   node_ptr node;
190   Class object_class = objc_get_class ("Object");
191
192   assert(object_class);
193
194   objc_mutex_lock(__objc_runtime_mutex);
195
196   /* Assign subclass links */
197   for (node = hash_next (__objc_class_hash, NULL); node;
198        node = hash_next (__objc_class_hash, node))
199     {
200       Class class1 = node->value;
201
202       /* Make sure we have what we think we have.  */
203       assert (CLS_ISCLASS(class1));
204       assert (CLS_ISMETA(class1->class_pointer));
205
206       /* The class_pointer of all meta classes point to Object's meta class. */
207       class1->class_pointer->class_pointer = object_class->class_pointer;
208
209       if (!(CLS_ISRESOLV(class1)))
210         {
211           CLS_SETRESOLV(class1);
212           CLS_SETRESOLV(class1->class_pointer);
213               
214           if(class1->super_class)
215             {   
216               Class a_super_class 
217                 = objc_get_class ((char *) class1->super_class);
218               
219               assert (a_super_class);
220               
221               DEBUG_PRINTF ("making class connections for: %s\n",
222                             class1->name);
223               
224               /* assign subclass links for superclass */
225               class1->sibling_class = a_super_class->subclass_list;
226               a_super_class->subclass_list = class1;
227               
228               /* Assign subclass links for meta class of superclass */
229               if (a_super_class->class_pointer)
230                 {
231                   class1->class_pointer->sibling_class
232                     = a_super_class->class_pointer->subclass_list;
233                   a_super_class->class_pointer->subclass_list 
234                     = class1->class_pointer;
235                 }
236             }
237           else                  /* a root class, make its meta object */
238                                 /* be a subclass of Object */
239             {
240               class1->class_pointer->sibling_class 
241                 = object_class->subclass_list;
242               object_class->subclass_list = class1->class_pointer;
243             }
244         }
245     }
246
247   /* Assign superclass links */
248   for (node = hash_next (__objc_class_hash, NULL); node;
249        node = hash_next (__objc_class_hash, node))
250     {
251       Class class1 = node->value;
252       Class sub_class;
253       for (sub_class = class1->subclass_list; sub_class;
254            sub_class = sub_class->sibling_class)
255         {
256           sub_class->super_class = class1;
257           if(CLS_ISCLASS(sub_class))
258             sub_class->class_pointer->super_class = class1->class_pointer;
259         }
260     }
261
262   objc_mutex_unlock(__objc_runtime_mutex);
263 }
264
265
266
267 #define CLASSOF(c) ((c)->class_pointer)
268
269 Class
270 class_pose_as (Class impostor, Class super_class)
271 {
272   node_ptr node;
273   Class class1;
274
275   if (!CLS_ISRESOLV (impostor))
276     __objc_resolve_class_links ();
277
278   /* preconditions */
279   assert (impostor);
280   assert (super_class);
281   assert (impostor->super_class == super_class);
282   assert (CLS_ISCLASS (impostor));
283   assert (CLS_ISCLASS (super_class));
284   assert (impostor->instance_size == super_class->instance_size);
285
286   {
287     Class *subclass = &(super_class->subclass_list);
288
289     /* move subclasses of super_class to impostor */
290     while (*subclass)
291       {
292         Class nextSub = (*subclass)->sibling_class;
293
294         if (*subclass != impostor)
295           {
296             Class sub = *subclass;
297
298             /* classes */
299             sub->sibling_class = impostor->subclass_list;
300             sub->super_class = impostor;
301             impostor->subclass_list = sub;
302
303             /* It will happen that SUB is not a class object if it is 
304                the top of the meta class hierarchy chain.  (root
305                meta-class objects inherit their class object)  If that is
306                the case... don't mess with the meta-meta class. */ 
307             if (CLS_ISCLASS (sub))
308               {
309                 /* meta classes */
310                 CLASSOF (sub)->sibling_class = 
311                   CLASSOF (impostor)->subclass_list;
312                 CLASSOF (sub)->super_class = CLASSOF (impostor);
313                 CLASSOF (impostor)->subclass_list = CLASSOF (sub);
314               }
315           }
316
317         *subclass = nextSub;
318       }
319
320     /* set subclasses of superclass to be impostor only */
321     super_class->subclass_list = impostor;
322     CLASSOF (super_class)->subclass_list = CLASSOF (impostor);
323     
324     /* set impostor to have no sibling classes */
325     impostor->sibling_class = 0;
326     CLASSOF (impostor)->sibling_class = 0;
327   }
328   
329   /* check relationship of impostor and super_class is kept. */
330   assert (impostor->super_class == super_class);
331   assert (CLASSOF (impostor)->super_class == CLASSOF (super_class));
332
333   /* This is how to update the lookup table. Regardless of
334      what the keys of the hashtable is, change all values that are
335      superclass into impostor. */
336
337   objc_mutex_lock(__objc_runtime_mutex);
338
339   for (node = hash_next (__objc_class_hash, NULL); node;
340        node = hash_next (__objc_class_hash, node))
341     {
342       class1 = (Class)node->value;
343       if (class1 == super_class)
344         {
345           node->value = impostor; /* change hash table value */
346         }
347     }      
348
349   objc_mutex_unlock(__objc_runtime_mutex);
350
351   /* next, we update the dispatch tables... */
352   __objc_update_dispatch_table_for_class (CLASSOF (impostor));
353   __objc_update_dispatch_table_for_class (impostor);
354
355   return impostor;
356 }
357   
358