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.
5 This file is part of GNU CC.
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.
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
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. */
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. */
26 #include "runtime.h" /* the kitchen sink */
28 /* Initial number of buckets size of class hash table. */
29 #define CLASS_HASH_SIZE 32
31 void __objc_init_class_tables()
33 /* Allocate the class hash table */
39 __objc_class_hash = strhash_new(CLASS_HASH_SIZE);
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) {
50 /* make sure the table is there */
51 assert(__objc_class_hash);
53 /* make sure it's not a meta class */
54 assert(CLS_ISCLASS(class));
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);
60 /* The class isn't in the hash table. Add the class and assign a class
62 static unsigned int class_number = 1;
64 CLS_SETNUMBER(class, class_number);
65 CLS_SETNUMBER(class->class_pointer, class_number);
68 hash_add (&__objc_class_hash, class->name, class);
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)
83 fprintf(stderr, "WARNING: %s was called with NULL class name !\n",
91 /* Make sure the class hash table exists. */
92 assert (__objc_class_hash);
94 class = hash_value_for_key (__objc_class_hash, name);
101 if (_objc_lookup_class)
102 return (*_objc_lookup_class)(name);
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 */
111 objc_get_class (const char *name)
117 /* Make sure the class hash table exists. */
118 assert (__objc_class_hash);
120 class = hash_value_for_key (__objc_class_hash, name);
127 if (_objc_lookup_class)
128 class = (*_objc_lookup_class)(name);
133 objc_error(nil, OBJC_ERR_BAD_CLASS,
134 "objc runtime: cannot find class %s\n", name);
139 objc_get_meta_class(const char *name)
141 return objc_get_class(name)->class_pointer;
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.
150 while ((class = objc_next_class(&es)))
151 ... do something with class;
154 objc_next_class(void **enum_state)
158 /* make sure the table is there */
159 assert(__objc_class_hash);
161 *(node_ptr*)enum_state =
162 hash_next(__objc_class_hash, *(node_ptr*)enum_state);
166 if (*(node_ptr*)enum_state)
167 return (*(node_ptr*)enum_state)->value;
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()
177 Class object_class = objc_get_class ("Object");
179 assert(object_class);
183 /* Assign subclass links */
184 for (node = hash_next (__objc_class_hash, NULL); node;
185 node = hash_next (__objc_class_hash, node))
187 Class class1 = node->value;
189 /* Make sure we have what we think we have. */
190 assert (CLS_ISCLASS(class1));
191 assert (CLS_ISMETA(class1->class_pointer));
193 /* The class_pointer of all meta classes point to Object's meta class. */
194 class1->class_pointer->class_pointer = object_class->class_pointer;
196 if (!(CLS_ISRESOLV(class1)))
198 CLS_SETRESOLV(class1);
199 CLS_SETRESOLV(class1->class_pointer);
201 if(class1->super_class)
204 = objc_get_class ((char *) class1->super_class);
206 assert (a_super_class);
208 DEBUG_PRINTF ("making class connections for: %s\n",
209 class1->name ? class1->name : "<NoName>");
211 /* assign subclass links for superclass */
212 class1->sibling_class = a_super_class->subclass_list;
213 a_super_class->subclass_list = class1;
215 /* Assign subclass links for meta class of superclass */
216 if (a_super_class->class_pointer)
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;
224 else /* a root class, make its meta object */
225 /* be a subclass of Object */
227 class1->class_pointer->sibling_class
228 = object_class->subclass_list;
229 object_class->subclass_list = class1->class_pointer;
234 /* Assign superclass links */
235 for (node = hash_next (__objc_class_hash, NULL); node;
236 node = hash_next (__objc_class_hash, node))
238 Class class1 = node->value;
240 for (sub_class = class1->subclass_list; sub_class;
241 sub_class = sub_class->sibling_class)
243 sub_class->super_class = class1;
244 if(CLS_ISCLASS(sub_class))
245 sub_class->class_pointer->super_class = class1->class_pointer;
254 #define CLASSOF(c) ((c)->class_pointer)
256 Class class_pose_as (Class impostor, Class super_class)
261 if (!CLS_ISRESOLV (impostor))
262 __objc_resolve_class_links ();
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);
273 Class *subclass = &(super_class->subclass_list);
275 /* move subclasses of super_class to impostor */
278 Class nextSub = (*subclass)->sibling_class;
280 if (*subclass != impostor)
282 Class sub = *subclass;
285 sub->sibling_class = impostor->subclass_list;
286 sub->super_class = impostor;
287 impostor->subclass_list = sub;
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))
296 CLASSOF (sub)->sibling_class =
297 CLASSOF (impostor)->subclass_list;
298 CLASSOF (sub)->super_class = CLASSOF (impostor);
299 CLASSOF (impostor)->subclass_list = CLASSOF (sub);
306 /* set subclasses of superclass to be impostor only */
307 super_class->subclass_list = impostor;
308 CLASSOF (super_class)->subclass_list = CLASSOF (impostor);
310 /* set impostor to have no sibling classes */
311 impostor->sibling_class = 0;
312 CLASSOF (impostor)->sibling_class = 0;
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));
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. */
325 for (node = hash_next (__objc_class_hash, NULL); node;
326 node = hash_next (__objc_class_hash, node))
328 class1 = (Class)node->value;
329 if (class1 == super_class)
331 node->value = impostor; /* change hash table value */
337 /* next, we update the dispatch tables... */
338 __objc_update_dispatch_table_for_class (CLASSOF (impostor));
339 __objc_update_dispatch_table_for_class (impostor);