diff options
author | Ben Elliston <bje@cygnus.com> | 1998-09-21 01:22:07 +0000 |
---|---|---|
committer | Ben Elliston <bje@gcc.gnu.org> | 1998-09-21 11:22:07 +1000 |
commit | 88e17b57eb71b79759e59d68883ce797d00488fb (patch) | |
tree | 74295f11944f5c930aca90bb544749afb89e227c /libobjc/class.c | |
parent | 2325c774f8fdb0cabad328aba994a8224bb1c021 (diff) | |
download | gcc-88e17b57eb71b79759e59d68883ce797d00488fb.tar.gz |
1998-09-21 Ben Elliston <bje@cygnus.com>
* New directory. Moved files from ../gcc/objc.
From-SVN: r22514
Diffstat (limited to 'libobjc/class.c')
-rw-r--r-- | libobjc/class.c | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/libobjc/class.c b/libobjc/class.c new file mode 100644 index 00000000000..44aa1b9f98e --- /dev/null +++ b/libobjc/class.c @@ -0,0 +1,358 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup and Dennis Glatting. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" /* the kitchen sink */ +#include "sarray.h" + +/* The table of classname->class. Used for objc_lookup_class and friends */ +static cache_ptr __objc_class_hash = 0; /* !T:MUTEX */ + +/* This is a hook which is called by objc_get_class and + objc_lookup_class if the runtime is not able to find the class. + This may e.g. try to load in the class using dynamic loading */ +Class (*_objc_lookup_class)(const char* name) = 0; /* !T:SAFE */ + + +/* True when class links has been resolved */ +BOOL __objc_class_links_resolved = NO; /* !T:UNUSED */ + + +/* Initial number of buckets size of class hash table. */ +#define CLASS_HASH_SIZE 32 + +void __objc_init_class_tables() +{ + /* Allocate the class hash table */ + + if(__objc_class_hash) + return; + + objc_mutex_lock(__objc_runtime_mutex); + + __objc_class_hash + = hash_new (CLASS_HASH_SIZE, + (hash_func_type) hash_string, + (compare_func_type) compare_strings); + + objc_mutex_unlock(__objc_runtime_mutex); +} + +/* This function adds a class to the class hash table, and assigns the + class a number, unless it's already known */ +void +__objc_add_class_to_hash(Class class) +{ + Class h_class; + + objc_mutex_lock(__objc_runtime_mutex); + + /* make sure the table is there */ + assert(__objc_class_hash); + + /* make sure it's not a meta class */ + assert(CLS_ISCLASS(class)); + + /* Check to see if the class is already in the hash table. */ + h_class = hash_value_for_key (__objc_class_hash, class->name); + if (!h_class) + { + /* The class isn't in the hash table. Add the class and assign a class + number. */ + static unsigned int class_number = 1; + + CLS_SETNUMBER(class, class_number); + CLS_SETNUMBER(class->class_pointer, class_number); + + ++class_number; + hash_add (&__objc_class_hash, class->name, class); + } + + objc_mutex_unlock(__objc_runtime_mutex); +} + +/* Get the class object for the class named NAME. If NAME does not + identify a known class, the hook _objc_lookup_class is called. If + this fails, nil is returned */ +Class objc_lookup_class (const char* name) +{ + Class class; + + objc_mutex_lock(__objc_runtime_mutex); + + /* Make sure the class hash table exists. */ + assert (__objc_class_hash); + + class = hash_value_for_key (__objc_class_hash, name); + + objc_mutex_unlock(__objc_runtime_mutex); + + if (class) + return class; + + if (_objc_lookup_class) + return (*_objc_lookup_class)(name); + else + return 0; +} + +/* Get the class object for the class named NAME. If NAME does not + identify a known class, the hook _objc_lookup_class is called. If + this fails, an error message is issued and the system aborts */ +Class +objc_get_class (const char *name) +{ + Class class; + + objc_mutex_lock(__objc_runtime_mutex); + + /* Make sure the class hash table exists. */ + assert (__objc_class_hash); + + class = hash_value_for_key (__objc_class_hash, name); + + objc_mutex_unlock(__objc_runtime_mutex); + + if (class) + return class; + + if (_objc_lookup_class) + class = (*_objc_lookup_class)(name); + + if(class) + return class; + + objc_error(nil, OBJC_ERR_BAD_CLASS, + "objc runtime: cannot find class %s\n", name); + return 0; +} + +MetaClass +objc_get_meta_class(const char *name) +{ + return objc_get_class(name)->class_pointer; +} + +/* This function provides a way to enumerate all the classes in the + executable. Pass *ENUM_STATE == NULL to start the enumeration. The + function will return 0 when there are no more classes. + For example: + id class; + void *es = NULL; + while ((class = objc_next_class(&es))) + ... do something with class; +*/ +Class +objc_next_class(void **enum_state) +{ + objc_mutex_lock(__objc_runtime_mutex); + + /* make sure the table is there */ + assert(__objc_class_hash); + + *(node_ptr*)enum_state = + hash_next(__objc_class_hash, *(node_ptr*)enum_state); + + objc_mutex_unlock(__objc_runtime_mutex); + + if (*(node_ptr*)enum_state) + return (*(node_ptr*)enum_state)->value; + return (Class)0; +} + +/* Resolve super/subclass links for all classes. The only thing we + can be sure of is that the class_pointer for class objects point + to the right meta class objects */ +void __objc_resolve_class_links() +{ + node_ptr node; + Class object_class = objc_get_class ("Object"); + + assert(object_class); + + objc_mutex_lock(__objc_runtime_mutex); + + /* Assign subclass links */ + for (node = hash_next (__objc_class_hash, NULL); node; + node = hash_next (__objc_class_hash, node)) + { + Class class1 = node->value; + + /* Make sure we have what we think we have. */ + assert (CLS_ISCLASS(class1)); + assert (CLS_ISMETA(class1->class_pointer)); + + /* The class_pointer of all meta classes point to Object's meta class. */ + class1->class_pointer->class_pointer = object_class->class_pointer; + + if (!(CLS_ISRESOLV(class1))) + { + CLS_SETRESOLV(class1); + CLS_SETRESOLV(class1->class_pointer); + + if(class1->super_class) + { + Class a_super_class + = objc_get_class ((char *) class1->super_class); + + assert (a_super_class); + + DEBUG_PRINTF ("making class connections for: %s\n", + class1->name); + + /* assign subclass links for superclass */ + class1->sibling_class = a_super_class->subclass_list; + a_super_class->subclass_list = class1; + + /* Assign subclass links for meta class of superclass */ + if (a_super_class->class_pointer) + { + class1->class_pointer->sibling_class + = a_super_class->class_pointer->subclass_list; + a_super_class->class_pointer->subclass_list + = class1->class_pointer; + } + } + else /* a root class, make its meta object */ + /* be a subclass of Object */ + { + class1->class_pointer->sibling_class + = object_class->subclass_list; + object_class->subclass_list = class1->class_pointer; + } + } + } + + /* Assign superclass links */ + for (node = hash_next (__objc_class_hash, NULL); node; + node = hash_next (__objc_class_hash, node)) + { + Class class1 = node->value; + Class sub_class; + for (sub_class = class1->subclass_list; sub_class; + sub_class = sub_class->sibling_class) + { + sub_class->super_class = class1; + if(CLS_ISCLASS(sub_class)) + sub_class->class_pointer->super_class = class1->class_pointer; + } + } + + objc_mutex_unlock(__objc_runtime_mutex); +} + + + +#define CLASSOF(c) ((c)->class_pointer) + +Class +class_pose_as (Class impostor, Class super_class) +{ + node_ptr node; + Class class1; + + if (!CLS_ISRESOLV (impostor)) + __objc_resolve_class_links (); + + /* preconditions */ + assert (impostor); + assert (super_class); + assert (impostor->super_class == super_class); + assert (CLS_ISCLASS (impostor)); + assert (CLS_ISCLASS (super_class)); + assert (impostor->instance_size == super_class->instance_size); + + { + Class *subclass = &(super_class->subclass_list); + + /* move subclasses of super_class to impostor */ + while (*subclass) + { + Class nextSub = (*subclass)->sibling_class; + + if (*subclass != impostor) + { + Class sub = *subclass; + + /* classes */ + sub->sibling_class = impostor->subclass_list; + sub->super_class = impostor; + impostor->subclass_list = sub; + + /* It will happen that SUB is not a class object if it is + the top of the meta class hierarchy chain. (root + meta-class objects inherit their class object) If that is + the case... don't mess with the meta-meta class. */ + if (CLS_ISCLASS (sub)) + { + /* meta classes */ + CLASSOF (sub)->sibling_class = + CLASSOF (impostor)->subclass_list; + CLASSOF (sub)->super_class = CLASSOF (impostor); + CLASSOF (impostor)->subclass_list = CLASSOF (sub); + } + } + + *subclass = nextSub; + } + + /* set subclasses of superclass to be impostor only */ + super_class->subclass_list = impostor; + CLASSOF (super_class)->subclass_list = CLASSOF (impostor); + + /* set impostor to have no sibling classes */ + impostor->sibling_class = 0; + CLASSOF (impostor)->sibling_class = 0; + } + + /* check relationship of impostor and super_class is kept. */ + assert (impostor->super_class == super_class); + assert (CLASSOF (impostor)->super_class == CLASSOF (super_class)); + + /* This is how to update the lookup table. Regardless of + what the keys of the hashtable is, change all values that are + superclass into impostor. */ + + objc_mutex_lock(__objc_runtime_mutex); + + for (node = hash_next (__objc_class_hash, NULL); node; + node = hash_next (__objc_class_hash, node)) + { + class1 = (Class)node->value; + if (class1 == super_class) + { + node->value = impostor; /* change hash table value */ + } + } + + objc_mutex_unlock(__objc_runtime_mutex); + + /* next, we update the dispatch tables... */ + __objc_update_dispatch_table_for_class (CLASSOF (impostor)); + __objc_update_dispatch_table_for_class (impostor); + + return impostor; +} + + |