From 499056939e05450db87c2caadd659345617d026e Mon Sep 17 00:00:00 2001 From: Kresten Krab Thorup Date: Tue, 24 Aug 1993 09:59:41 +0000 Subject: [PATCH] (class_pose_as): lazy copy dtables. #include sarray.h (class_pose_as): Rewritten From-SVN: r5202 --- gcc/objc/class.c | 210 ++++++++++++++++++++++------------------------- 1 file changed, 96 insertions(+), 114 deletions(-) diff --git a/gcc/objc/class.c b/gcc/objc/class.c index c9af0eb1bbf..7521ad66d20 100644 --- a/gcc/objc/class.c +++ b/gcc/objc/class.c @@ -25,7 +25,7 @@ You should have received a copy of the GNU General Public License along with 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; @@ -211,140 +211,122 @@ void __objc_resolve_class_links() } -/* 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. */ +#define CLASSOF(c) ((c)->class_pointer) + Class* class_pose_as (Class* impostor, Class* super_class) { - Class* new_class = (Class*) __objc_xcalloc (1, sizeof (Class)); - MetaClass* new_meta_class = - (MetaClass*) __objc_xmalloc(sizeof (MetaClass)); - char *new_name = (char *)__objc_xmalloc ((size_t)strlen ((char*)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)); - + 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); - /* 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; - new_class->dtable = impostor->dtable; - - /* 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; - new_meta_class->dtable = impostor->class_pointer->dtable; - - /* 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* *classpp; - MetaClass* *metaclasspp; + Class **subclass = &(super_class->subclass_list); + BOOL super_is_base_class = NO; - /* Remove impostor from subclass list of super_class */ - for (classpp = &(super_class->subclass_list); - *classpp; - classpp = &((*classpp)->sibling_class)) + /* move subclasses of super_class to impostor */ + while (*subclass) { - if (*classpp == impostor) - *classpp = (*classpp)->sibling_class; - if (*classpp == 0) - break; + Class *nextSub = (*subclass)->sibling_class; + + /* this happens when super_class is a base class */ + if (*subclass == CLASSOF (super_class)) + { + super_is_base_class = YES; + } + else if (*subclass != impostor) + { + Class *sub = *subclass; + + /* classes */ + sub->sibling_class = impostor->subclass_list; + sub->super_class = impostor; + impostor->subclass_list = 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; } - /* Do the same for the meta classes */ + /* 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; - for (metaclasspp = &(super_class->class_pointer->subclass_list); - *metaclasspp; - metaclasspp = &((*metaclasspp)->sibling_class)) + /* impostor has a sibling... */ + if (super_is_base_class) { - if (*metaclasspp == impostor->class_pointer) - *metaclasspp = (*metaclasspp)->sibling_class; - if (*metaclasspp == 0) - break; + CLASSOF (super_class)->sibling_class = 0; + impostor->sibling_class = CLASSOF (super_class); } + } + + /* check relationship of impostor and super_class */ + assert (impostor->super_class == super_class); + assert (CLASSOF (impostor)->super_class == CLASSOF (super_class)); - /* From the loop above, classpp now points to the sibling_class entry */ - /* of the last element in the list of subclasses for super_class */ + /* by now, the re-organization of the class hierachy + is done. We only need to update various tables. */ - /* 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 */ + /* First, we change the names in the hash table. + This will change the behavior of objc_get_class () */ + { + char* buffer = (char*) __objc_xmalloc(strlen (super_class->name) + 2); - *classpp = impostor->subclass_list; - new_class->subclass_list = super_class->subclass_list; - super_class->subclass_list = new_class; - new_class->sibling_class = 0; + strcpy (buffer+1, super_class->name); + buffer[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; + /* keep on prepending '*' until the name is unique */ + while (hash_value_for_key (__objc_class_hash, buffer)) + { + char *bbuffer = (char*) __objc_xmalloc (strlen (buffer)+2); - /* 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; + strcpy (bbuffer+1, buffer); + bbuffer[0] = '*'; + free (buffer); + buffer = bbuffer; + } - for (metaclasspp = &(new_meta_class->subclass_list); *metaclasspp; - metaclasspp = &((*metaclasspp)->sibling_class)) - (*metaclasspp)->super_class = new_meta_class; + hash_remove (__objc_class_hash, super_class->name); + hash_add (&__objc_class_hash, buffer, super_class); + hash_add (&__objc_class_hash, super_class->name, impostor); + /* Note that -name and +name will still respond with + the same strings as before. This way any + -isKindOfGivenName: will always work. */ } - /* 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*) new_meta_class); - __objc_update_dispatch_table_for_class (new_class); - - return new_class; -} + /* next, we update the dispatch tables... */ + { + Class *subclass; + + for (subclass = impostor->subclass_list; + subclass; subclass = subclass->sibling_class) + { + /* we use the opportunity to check what we did */ + assert (subclass->super_class == impostor); + assert (CLASSOF (subclass)->super_class == CLASSOF (impostor)); + __objc_update_dispatch_table_for_class (CLASSOF (subclass)); + __objc_update_dispatch_table_for_class (subclass); + } + } + + return impostor; +} + -- 2.30.2