]> gcc.gnu.org Git - gcc.git/commitdiff
(class_pose_as): lazy copy dtables.
authorKresten Krab Thorup <krab@gcc.gnu.org>
Tue, 24 Aug 1993 09:59:41 +0000 (09:59 +0000)
committerKresten Krab Thorup <krab@gcc.gnu.org>
Tue, 24 Aug 1993 09:59:41 +0000 (09:59 +0000)
#include sarray.h
(class_pose_as): Rewritten

From-SVN: r5202

gcc/objc/class.c

index c9af0eb1bbf24436b1894974c2d475b0f07b73c2..7521ad66d200740bf48b8a9d79154bc4c8d96c15 100644 (file)
@@ -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;
+}
+  
This page took 0.0656600000000001 seconds and 5 git commands to generate.