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 5This file is part of GNU CC. 6 7GNU CC is free software; you can redistribute it and/or modify it under the 8terms of the GNU General Public License as published by the Free Software 9Foundation; either version 2, or (at your option) any later version. 10 11GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY 12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14details. 15 16You should have received a copy of the GNU General Public License along with 17GNU CC; see the file COPYING. If not, write to the Free Software 18Foundation, 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 */ 30static 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 */ 35Class (*_objc_lookup_class)(const char* name) = 0; /* !T:SAFE */ 36 37 38/* True when class links has been resolved */ 39BOOL __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 45void __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 */ 64void 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 */ 98Class 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 */ 123Class 124objc_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 151MetaClass 152objc_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*/ 166Class 167objc_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 */ 187void __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 269Class 270class_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 359