Commit 49905693 by Kresten Krab Thorup

(class_pose_as): lazy copy dtables.

#include sarray.h
(class_pose_as): Rewritten

From-SVN: r5202
parent 0b3d89ca
...@@ -25,7 +25,7 @@ You should have received a copy of the GNU General Public License along with ...@@ -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. */ covered by the GNU General Public License. */
#include "runtime.h" /* the kitchen sink */ #include "runtime.h" /* the kitchen sink */
#include "sarray.h"
/* The table of classname->class. Used for objc_lookup_class and friends */ /* The table of classname->class. Used for objc_lookup_class and friends */
static cache_ptr __objc_class_hash = 0; static cache_ptr __objc_class_hash = 0;
...@@ -211,140 +211,122 @@ void __objc_resolve_class_links() ...@@ -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 #define CLASSOF(c) ((c)->class_pointer)
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* Class*
class_pose_as (Class* impostor, Class* super_class) class_pose_as (Class* impostor, Class* super_class)
{ {
Class* new_class = (Class*) __objc_xcalloc (1, sizeof (Class)); if (!CLS_ISRESOLV (impostor))
MetaClass* new_meta_class = __objc_resolve_class_links ();
(MetaClass*) __objc_xmalloc(sizeof (MetaClass));
char *new_name = (char *)__objc_xmalloc ((size_t)strlen ((char*)super_class->name) + 12); /* 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);
/* We must know the state of the hierachy. Do initial setup if needed */ {
if(!CLS_ISRESOLV(impostor)) Class **subclass = &(super_class->subclass_list);
__objc_resolve_class_links(); BOOL super_is_base_class = NO;
assert (new_class); /* move subclasses of super_class to impostor */
assert (new_meta_class); while (*subclass)
assert (new_name); {
Class *nextSub = (*subclass)->sibling_class;
assert (CLS_ISCLASS(impostor)); /* this happens when super_class is a base class */
assert (CLS_ISCLASS(super_class)); if (*subclass == CLASSOF (super_class))
{
super_is_base_class = YES;
}
else if (*subclass != impostor)
{
Class *sub = *subclass;
assert (impostor->instance_size == super_class->instance_size); /* classes */
sub->sibling_class = impostor->subclass_list;
sub->super_class = impostor;
impostor->subclass_list = sub;
/* Create the impostor class. */ /* meta classes */
new_class->class_pointer = new_meta_class; CLASSOF (sub)->sibling_class = CLASSOF (impostor)->subclass_list;
new_class->super_class = super_class; CLASSOF (sub)->super_class = CLASSOF (impostor);
new_class->name = super_class->name; CLASSOF (impostor)->subclass_list = CLASSOF (sub);
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;
/* Remove impostor from subclass list of super_class */ *subclass = nextSub;
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 */ /* 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); /* impostor has a sibling... */
*metaclasspp; if (super_is_base_class)
metaclasspp = &((*metaclasspp)->sibling_class))
{ {
if (*metaclasspp == impostor->class_pointer) CLASSOF (super_class)->sibling_class = 0;
*metaclasspp = (*metaclasspp)->sibling_class; impostor->sibling_class = CLASSOF (super_class);
if (*metaclasspp == 0) }
break;
} }
/* From the loop above, classpp now points to the sibling_class entry */ /* check relationship of impostor and super_class */
/* of the last element in the list of subclasses for super_class */ assert (impostor->super_class == super_class);
assert (CLASSOF (impostor)->super_class == CLASSOF (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; /* by now, the re-organization of the class hierachy
new_class->subclass_list = super_class->subclass_list; is done. We only need to update various tables. */
super_class->subclass_list = new_class;
new_class->sibling_class = 0;
/* Do the same thing for the meta classes */ /* First, we change the names in the hash table.
*metaclasspp = impostor->class_pointer->subclass_list; This will change the behavior of objc_get_class () */
new_meta_class->subclass_list = super_class->class_pointer->subclass_list; {
super_class->class_pointer->subclass_list = new_meta_class; char* buffer = (char*) __objc_xmalloc(strlen (super_class->name) + 2);
new_meta_class->sibling_class = 0;
/* Update superclass links for all subclasses of new_class */ strcpy (buffer+1, super_class->name);
for (classpp = &(new_class->subclass_list); *classpp; buffer[0] = '*';
classpp = &((*classpp)->sibling_class))
(*classpp)->super_class = new_class;
for (metaclasspp = &(new_meta_class->subclass_list); *metaclasspp; /* keep on prepending '*' until the name is unique */
metaclasspp = &((*metaclasspp)->sibling_class)) while (hash_value_for_key (__objc_class_hash, buffer))
(*metaclasspp)->super_class = new_meta_class; {
char *bbuffer = (char*) __objc_xmalloc (strlen (buffer)+2);
strcpy (bbuffer+1, buffer);
bbuffer[0] = '*';
free (buffer);
buffer = bbuffer;
} }
/* 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); hash_remove (__objc_class_hash, super_class->name);
sprintf (new_name, "%s*", super_class->name); hash_add (&__objc_class_hash, buffer, super_class);
super_class->name = new_name; hash_add (&__objc_class_hash, super_class->name, impostor);
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 /* Note that -name and +name will still respond with
number. */ the same strings as before. This way any
__objc_add_class_to_hash (new_class); -isKindOfGivenName: will always work. */
}
/* Now update dispatch tables for new_class and it's subclasses */ /* next, we update the dispatch tables... */
__objc_update_dispatch_table_for_class ((Class*) new_meta_class); {
__objc_update_dispatch_table_for_class (new_class); 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 new_class; return impostor;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment