]> err.no Git - sope/blob - gnustep-objc/class.c
added scriptaculous
[sope] / gnustep-objc / 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
28 /* Initial number of buckets size of class hash table. */
29 #define CLASS_HASH_SIZE 32
30
31 void __objc_init_class_tables()
32 {
33   /* Allocate the class hash table */
34
35   if(__objc_class_hash)
36     return;
37
38   RUNTIME_LOCK;
39   __objc_class_hash = strhash_new(CLASS_HASH_SIZE);
40   RUNTIME_UNLOCK;
41 }
42
43 /* This function adds a class to the class hash table, and assigns the 
44    class a number, unless it's already known */
45 void __objc_add_class_to_hash(Class class) {
46   Class h_class;
47
48   RUNTIME_LOCK;
49
50   /* make sure the table is there */
51   assert(__objc_class_hash);
52
53   /* make sure it's not a meta class */  
54   assert(CLS_ISCLASS(class));
55
56   /* Check to see if the class is already in the hash table.  */
57   h_class = hash_value_for_key (__objc_class_hash, class->name);
58   if (!h_class)
59     {
60       /* The class isn't in the hash table.  Add the class and assign a class
61          number.  */
62       static unsigned int class_number = 1;
63
64       CLS_SETNUMBER(class, class_number);
65       CLS_SETNUMBER(class->class_pointer, class_number);
66
67       ++class_number;
68       hash_add (&__objc_class_hash, class->name, class);
69     }
70
71   RUNTIME_UNLOCK;
72 }
73
74 /* Get the class object for the class named NAME.  If NAME does not
75    identify a known class, the hook _objc_lookup_class is called.  If
76    this fails, nil is returned */
77 Class objc_lookup_class (const char* name)
78 {
79   Class class;
80
81   if (name == NULL) {
82     abort();
83     fprintf(stderr, "WARNING: %s was called with NULL class name !\n",
84             __PRETTY_FUNCTION__);
85     fflush(stderr);
86     return Nil;
87   }
88
89   RUNTIME_LOCK;
90
91   /* Make sure the class hash table exists.  */
92   assert (__objc_class_hash);
93
94   class = hash_value_for_key (__objc_class_hash, name);
95
96   RUNTIME_UNLOCK;
97
98   if (class)
99     return class;
100
101   if (_objc_lookup_class)
102     return (*_objc_lookup_class)(name);
103   else
104     return 0;
105 }
106
107 /* Get the class object for the class named NAME.  If NAME does not
108    identify a known class, the hook _objc_lookup_class is called.  If
109    this fails,  an error message is issued and the system aborts */
110 Class
111 objc_get_class (const char *name)
112 {
113   Class class;
114
115   RUNTIME_LOCK;
116
117   /* Make sure the class hash table exists.  */
118   assert (__objc_class_hash);
119
120   class = hash_value_for_key (__objc_class_hash, name);
121
122   RUNTIME_UNLOCK;
123
124   if (class)
125     return class;
126
127   if (_objc_lookup_class)
128     class = (*_objc_lookup_class)(name);
129
130   if(class)
131     return class;
132   
133   objc_error(nil, OBJC_ERR_BAD_CLASS, 
134              "objc runtime: cannot find class %s\n", name);
135   return 0;
136 }
137
138 MetaClass
139 objc_get_meta_class(const char *name)
140 {
141   return objc_get_class(name)->class_pointer;
142 }
143
144 /* This function provides a way to enumerate all the classes in the
145    executable.  Pass *ENUM_STATE == NULL to start the enumeration.  The
146    function will return 0 when there are no more classes.  
147    For example: 
148        id class; 
149        void *es = NULL;
150        while ((class = objc_next_class(&es)))
151          ... do something with class; 
152 */
153 Class
154 objc_next_class(void **enum_state)
155 {
156   RUNTIME_LOCK;
157
158   /* make sure the table is there */
159   assert(__objc_class_hash);
160
161   *(node_ptr*)enum_state = 
162     hash_next(__objc_class_hash, *(node_ptr*)enum_state);
163
164   RUNTIME_UNLOCK;
165
166   if (*(node_ptr*)enum_state)
167     return (*(node_ptr*)enum_state)->value;
168   return (Class)0;
169 }
170
171 /* Resolve super/subclass links for all classes.  The only thing we 
172    can be sure of is that the class_pointer for class objects point 
173    to the right meta class objects */
174 void __objc_resolve_class_links()
175 {
176   node_ptr node;
177   Class object_class = objc_get_class ("Object");
178
179   assert(object_class);
180
181   RUNTIME_LOCK;
182
183   /* Assign subclass links */
184   for (node = hash_next (__objc_class_hash, NULL); node;
185        node = hash_next (__objc_class_hash, node))
186     {
187       Class class1 = node->value;
188
189       /* Make sure we have what we think we have.  */
190       assert (CLS_ISCLASS(class1));
191       assert (CLS_ISMETA(class1->class_pointer));
192
193       /* The class_pointer of all meta classes point to Object's meta class. */
194       class1->class_pointer->class_pointer = object_class->class_pointer;
195
196       if (!(CLS_ISRESOLV(class1)))
197         {
198           CLS_SETRESOLV(class1);
199           CLS_SETRESOLV(class1->class_pointer);
200               
201           if(class1->super_class)
202             {   
203               Class a_super_class 
204                 = objc_get_class ((char *) class1->super_class);
205               
206               assert (a_super_class);
207               
208               DEBUG_PRINTF ("making class connections for: %s\n",
209                             class1->name ? class1->name : "<NoName>");
210               
211               /* assign subclass links for superclass */
212               class1->sibling_class = a_super_class->subclass_list;
213               a_super_class->subclass_list = class1;
214               
215               /* Assign subclass links for meta class of superclass */
216               if (a_super_class->class_pointer)
217                 {
218                   class1->class_pointer->sibling_class
219                     = a_super_class->class_pointer->subclass_list;
220                   a_super_class->class_pointer->subclass_list 
221                     = class1->class_pointer;
222                 }
223             }
224           else                  /* a root class, make its meta object */
225                                 /* be a subclass of Object */
226             {
227               class1->class_pointer->sibling_class 
228                 = object_class->subclass_list;
229               object_class->subclass_list = class1->class_pointer;
230             }
231         }
232     }
233
234   /* Assign superclass links */
235   for (node = hash_next (__objc_class_hash, NULL); node;
236        node = hash_next (__objc_class_hash, node))
237     {
238       Class class1 = node->value;
239       Class sub_class;
240       for (sub_class = class1->subclass_list; sub_class;
241            sub_class = sub_class->sibling_class)
242         {
243           sub_class->super_class = class1;
244           if(CLS_ISCLASS(sub_class))
245             sub_class->class_pointer->super_class = class1->class_pointer;
246         }
247     }
248
249   RUNTIME_UNLOCK;
250 }
251
252
253
254 #define CLASSOF(c) ((c)->class_pointer)
255
256 Class class_pose_as (Class impostor, Class super_class)
257 {
258   node_ptr node;
259   Class class1;
260
261   if (!CLS_ISRESOLV (impostor))
262     __objc_resolve_class_links ();
263
264   /* preconditions */
265   assert (impostor);
266   assert (super_class);
267   assert (impostor->super_class == super_class);
268   assert (CLS_ISCLASS (impostor));
269   assert (CLS_ISCLASS (super_class));
270   assert (impostor->instance_size == super_class->instance_size);
271
272   {
273     Class *subclass = &(super_class->subclass_list);
274
275     /* move subclasses of super_class to impostor */
276     while (*subclass)
277       {
278         Class nextSub = (*subclass)->sibling_class;
279
280         if (*subclass != impostor)
281           {
282             Class sub = *subclass;
283
284             /* classes */
285             sub->sibling_class = impostor->subclass_list;
286             sub->super_class = impostor;
287             impostor->subclass_list = sub;
288
289             /* It will happen that SUB is not a class object if it is 
290                the top of the meta class hierarchy chain.  (root
291                meta-class objects inherit their class object)  If that is
292                the case... don't mess with the meta-meta class. */ 
293             if (CLS_ISCLASS (sub))
294               {
295                 /* meta classes */
296                 CLASSOF (sub)->sibling_class = 
297                   CLASSOF (impostor)->subclass_list;
298                 CLASSOF (sub)->super_class = CLASSOF (impostor);
299                 CLASSOF (impostor)->subclass_list = CLASSOF (sub);
300               }
301           }
302
303         *subclass = nextSub;
304       }
305
306     /* set subclasses of superclass to be impostor only */
307     super_class->subclass_list = impostor;
308     CLASSOF (super_class)->subclass_list = CLASSOF (impostor);
309     
310     /* set impostor to have no sibling classes */
311     impostor->sibling_class = 0;
312     CLASSOF (impostor)->sibling_class = 0;
313   }
314   
315   /* check relationship of impostor and super_class is kept. */
316   assert (impostor->super_class == super_class);
317   assert (CLASSOF (impostor)->super_class == CLASSOF (super_class));
318
319   /* This is how to update the lookup table. Regardless of
320      what the keys of the hashtable is, change all values that are
321      superclass into impostor. */
322
323   RUNTIME_LOCK;
324
325   for (node = hash_next (__objc_class_hash, NULL); node;
326        node = hash_next (__objc_class_hash, node))
327     {
328       class1 = (Class)node->value;
329       if (class1 == super_class)
330         {
331           node->value = impostor; /* change hash table value */
332         }
333     }      
334
335   RUNTIME_UNLOCK;
336
337   /* next, we update the dispatch tables... */
338   __objc_update_dispatch_table_for_class (CLASSOF (impostor));
339   __objc_update_dispatch_table_for_class (impostor);
340
341   return impostor;
342 }