diff options
author | Tom Wood <wood@gnu.org> | 1993-04-10 01:05:19 +0000 |
---|---|---|
committer | Tom Wood <wood@gnu.org> | 1993-04-10 01:05:19 +0000 |
commit | c72fc2d9d984e877d5f912c3e59e8a12d1aad03c (patch) | |
tree | c39971c9d7ab0c5af58d8e1646e5441330042183 /gcc/objc/class.c | |
parent | b2055d6de346dec843ac1ca854180c12c8830930 (diff) | |
download | gcc-c72fc2d9d984e877d5f912c3e59e8a12d1aad03c.zip gcc-c72fc2d9d984e877d5f912c3e59e8a12d1aad03c.tar.gz gcc-c72fc2d9d984e877d5f912c3e59e8a12d1aad03c.tar.bz2 |
Initial revision
From-SVN: r4077
Diffstat (limited to 'gcc/objc/class.c')
-rw-r--r-- | gcc/objc/class.c | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/gcc/objc/class.c b/gcc/objc/class.c new file mode 100644 index 0000000..a5feef5 --- /dev/null +++ b/gcc/objc/class.c @@ -0,0 +1,378 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup, 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, 675 Mass Ave, Cambridge, MA 02139, 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 */ + + +/* The table of classname->class. Used for objc_lookup_class and friends */ +static cache_ptr __objc_class_hash = 0; + +/* 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_t (*_objc_lookup_class)(const char* name) = 0; + + +/* True when class links has been resolved */ +BOOL __objc_class_links_resolved = NO; + + +/* 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_class_hash + = hash_new (CLASS_HASH_SIZE, + (hash_func_type) hash_string, + (compare_func_type) compare_strings); +} + +/* 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_t class) +{ + Class_t h_class; + + /* 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); + } +} + +/* 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_t objc_lookup_class (const char* name) +{ + Class_t class; + + /* Make sure the class hash table exists. */ + assert (__objc_class_hash); + + class = hash_value_for_key (__objc_class_hash, name); + + 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_t +objc_get_class (const char *name) +{ + Class_t class; + + /* Make sure the class hash table exists. */ + assert (__objc_class_hash); + + class = hash_value_for_key (__objc_class_hash, name); + + if (class) + return class; + + if (_objc_lookup_class) + class = (*_objc_lookup_class)(name); + + if(class) + return class; + + fprintf(stderr, "objc runtime: cannot find class %s\n", name); + abort(); +} + + +/* 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_t class1; + Class_t object_class = objc_get_class ("Object"); + + assert(object_class); + + /* Assign subclass links */ + for (node = hash_next (__objc_class_hash, NULL); node; + node = hash_next (__objc_class_hash, node)) + { + Class_t 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_t 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_t class1 = node->value; + Class_t 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; + } + } +} + + +/* This is a incomplete implementation of posing. This function does the + bulk of the work but does not initialize the class method caches. That is + a run-time specific operation. + +I implement posing by hiding SUPER_CLASS, creating new class and meta class + structures, initializing it with IMPOSTOR, and changing it such that it is + identified as SUPER_CLASS. SUPER_CLASS remains in the hierarchy but is + inaccessible by the means. The class hierarchy is then re arranged such + that all of the subclasses of SUPER_CLASS now inherit from the new class + structures -- except the impostor itself. The only dramatic effect on the + application is that subclasses of SUPER_CLASS cannot do a [ .... + super_class ] and expect their real super class. */ +Class_t +class_pose_as (Class_t impostor, Class_t super_class) +{ + Class_t new_class = (Class_t) calloc (1, sizeof (Class)); + MetaClass_t new_meta_class = + (MetaClass_t) __objc_xmalloc(sizeof (MetaClass)); + node_ptr node; + char *new_name = (char *)__objc_xmalloc (strlen (super_class->name) + 12); + + /* We must know the state of the hierachy. Do initial setup if needed */ + if(!CLS_ISRESOLV(impostor)) + __objc_resolve_class_links(); + + assert (new_class); + assert (new_meta_class); + assert (new_name); + + assert (CLS_ISCLASS(impostor)); + assert (CLS_ISCLASS(super_class)); + + assert (impostor->instance_size == super_class->instance_size); + + /* Create the impostor class. */ + new_class->class_pointer = new_meta_class; + new_class->super_class = super_class; + new_class->name = super_class->name; + new_class->version = super_class->version; + new_class->info = super_class->info; + new_class->instance_size = super_class->instance_size; + new_class->ivars = super_class->ivars; + new_class->methods = impostor->methods; +#ifdef OBJC_SPARSE_LOOKUP + new_class->dtable = impostor->dtable; +#else + new_class->cache = impostor->cache; +#endif + + /* Create the impostor meta class. */ + new_meta_class->class_pointer = super_class->class_pointer->class_pointer; + new_meta_class->super_class = super_class->class_pointer->super_class; + new_meta_class->name = super_class->class_pointer->name; + new_meta_class->version = super_class->class_pointer->version; + new_meta_class->info = super_class->class_pointer->info; + new_meta_class->instance_size = super_class->class_pointer->instance_size; + new_meta_class->ivars = super_class->class_pointer->ivars; + new_meta_class->methods = impostor->class_pointer->methods; +#ifdef OBJC_SPARSE_LOOKUP + new_meta_class->dtable = impostor->class_pointer->dtable; +#else + new_meta_class->cache = impostor->class_pointer->cache; +#endif + + /* Now change super/subclass links of all related classes. This is rather + complex, since we have both super_class link, and subclass_list for the + involved classes. */ + { + Class_t *classpp; + MetaClass_t *metaclasspp; + + /* Remove impostor from subclass list of super_class */ + for (classpp = &(super_class->subclass_list); + *classpp; + classpp = &((*classpp)->sibling_class)) + { + if (*classpp == impostor) + *classpp = (*classpp)->sibling_class; + if (*classpp == 0) + break; + } + + /* Do the same for the meta classes */ + + for (metaclasspp = &(super_class->class_pointer->subclass_list); + *metaclasspp; + metaclasspp = &((*metaclasspp)->sibling_class)) + { + if (*metaclasspp == impostor->class_pointer) + *metaclasspp = (*metaclasspp)->sibling_class; + if (*metaclasspp == 0) + break; + } + + /* From the loop above, classpp now points to the sibling_class entry */ + /* of the last element in the list of subclasses for super_class */ + + /* Append the subclass list of impostor to the subclass list of */ + /* superclass, and excange those two and set subclass of */ + /* super_class to be impostor only */ + + *classpp = impostor->subclass_list; + new_class->subclass_list = super_class->subclass_list; + super_class->subclass_list = new_class; + new_class->sibling_class = 0; + + /* Do the same thing for the meta classes */ + *metaclasspp = impostor->class_pointer->subclass_list; + new_meta_class->subclass_list = super_class->class_pointer->subclass_list; + super_class->class_pointer->subclass_list = new_meta_class; + new_meta_class->sibling_class = 0; + + /* Update superclass links for all subclasses of new_class */ + for (classpp = &(new_class->subclass_list); *classpp; + classpp = &((*classpp)->sibling_class)) + (*classpp)->super_class = new_class; + + for (metaclasspp = &(new_meta_class->subclass_list); *metaclasspp; + metaclasspp = &((*metaclasspp)->sibling_class)) + (*metaclasspp)->super_class = new_meta_class; + + } + + /* Delete the class from the hash table, change its name so that it can no + longer be found, then place it back into the hash table using its new + name. + + Don't worry about the class number. It is already assigned. + memory is lost with the hash key.) */ + hash_remove (__objc_class_hash, super_class->name); + sprintf (new_name, "%s*", super_class->name); + super_class->name = new_name; + super_class->class_pointer->name = new_name; + hash_add (&__objc_class_hash, super_class->name, super_class); + + /* Place the impostor class in class hash table and assign it a class + number. */ + __objc_add_class_to_hash (new_class); + + /* Now update dispatch tables for new_class and it's subclasses */ + __objc_update_dispatch_table_for_class ((Class_t) new_meta_class); + __objc_update_dispatch_table_for_class (new_class); + + return new_class; +} + +#ifdef OBJC_HASH_LOOKUP +__objc_class_hash_tables_size () +{ + node_ptr node; + Class_t class1; + int total = 0; + + for (node = hash_next (__objc_class_hash, NULL); node; + node = hash_next (__objc_class_hash, node)) + { + Class_t class1 = node->value; + total += (class1->cache->mask)*sizeof(struct objc_bucket); + total += sizeof(struct objc_cache); + } + + return total; +} +#endif |