Objective-C Issues

krab-runtime

People ( From: lines )
 bradcox@sitevax.gmu.edu (Brad Cox; 703 968 8229)
 Dennis Glatting 
 Kresten Krab Thorup 
Subjects ( 4 mails )
 Gnu objc runtime [comments and bug reports]
 Re: Gnu objc runtime [comments and bug reports]
 Re: [krab@iesd.auc.dk: Gnu objc runtime [comments and bug reports]]
 Help with the runtime
Document
Return-Path: 
Date: Wed, 10 Feb 1993 03:17:38 +0100
From: Kresten Krab Thorup 
To: rms@gnu.ai.mit.edu, gnu-objc-submissions@prep.ai.mit.edu
Subject: Gnu objc runtime [comments and bug reports]
Cc: krab@iesd.auc.dk

Hi  !

I have found a number of bugs in the current runtime -- the following
list describes the patch included below.

   * class Object *   

     # Added methods for alloc/init scheme.  

     # Changed isEqual so that bcmp on instances is done, instead of
     comparing the object pointers only.  I dont know if this is the
     right semathics, but it surely is more natural.  

     # Changed hash function to be more portable, and so that it only
     uses `self' if it cannot avoid it.  It is a desired property,
     that two isEqual instances gives the same hash value.  

     # Added perform with two objects.  

     # Fixed subclassResponsibility, notImplemented and
     doesNotRecognize, which didnt sel_getName the selector before it
     was printet!    

     # Fixed readFrom so that it does better checking, and gives more
     meaningful error messages.  It now also checks the version. 

   * mutex.h * 

     # Added support for my own (soon-to-be-released) co routines.
     These are done in ObjC, so it's quite nice...   
  
   * objc-proto.h *  
   
      # Fixed it so that is include'able from objective C code.  It
      wasnt - HOST_BITS_PER_LONG was missing. 

   * objc.h *

      #  Fixed so that it is include'able from objc code. varargs.h
      was missing. 

   * record.h *

      #  Fixed two BAD assertions, checking record_entries instead of
      record_capacity. 

   * core.c *

      # Changed list of included files, so that it may now be compiled
      with an objc compiler.   

      # Changed msgSend scheme:  objc_msgSend is now a pointer two a
      function. core.c defines two messengers, one equal to the
      present doing extensively initialization checking, and one
      bare-bone with no such checks (more on initialization at next item)
      This also allows the programmer to do his own messengers -- fun!

      # execClass is heavily changed. 

        The first time it is called, it installs the heavy version
	of objc_msgSend, so that initialization is handles correctly.
	This one is called __initializing_objc_msgSend -- there is
	also a msgSendSuper with a name like that...

	Fixed terrible bug in resolving of class relationship.  In
	line 351, it doesnt check if a class has already been
	resolved, so it will try numerous times... Making only more
	garbage each time.   

	Added debugging `printf' displaying cause of failure if
	execClass cannot resolve all classes. 

	When all classes have their class-relationships resolved,
	(i.e. the last time it is called), It calls +initialize for
	all classes.  (still using the heavy messenger)  it is not
	called if it has already been done if a +initialize method has
	invoked it indirectly by doing message passing to other
	objects.

	Finally, the fast messenger is installed -- we know that all
	classes have been initialized.  This one is called
	__builtin_objc_msgSend -- is such names only for compilers? 
 
      # Changed initialize_class to get a Class_t instead of a class
      names, all invocations said someclass->name, so we can save a
      little in lookup here.   Also the class is marked as initialized
      BEFORE the +initialize method is invoked -- this is needed, if
      that method somehow calls a method in the class it comes from.

      # Changed all malloc, calloc etc to either __objc_xmalloc and
      friends, or simply xmalloc and friends.  This gives more control
      of how allocation is done.  Why does malloc come in those two
      flavours anyway?
 
    * hash.c *  

      # Changed calloc, malloc into xcalloc, xmalloc -- we _want_
      fatal errors if such things fail...

      
This actually makes it possible to compile and run objective C
programs using GNU C.  

I am working on a collection library -- it is mostly finished, I'm
writing some documentation currently.   It's designed purely after
Smalltalk, of course with appropriate performance onsiderations.  I
hope to be able to let you test it out for me in the near future.

Any comments on the above are stongly appreciated.

/Kresten

======================================================================
diff -c ../orig/Object.h objc/Object.h
*** ../orig/Object.h	Tue Feb  9 20:20:19 1993
--- objc/Object.h	Mon Feb  8 21:07:19 1993
***************
*** 49,54 ****
--- 49,57 ----
  /* Creating, copying, and freeing instances */
  
  + new;
+ + alloc;
+ - init;
+ 
  + free;
  - free;
  - copy;
***************
*** 62,67 ****
--- 65,71 ----
  - ( Class_t )class;
  - ( Class_t )superClass;
  - ( const char* )name;
+ + ( BOOL )isEqual:aClass;
  
  /* Identifying and comparing instances */
  
***************
*** 85,90 ****
--- 89,95 ----
  
  - perform:( SEL )aSel;
  - perform:( SEL )aSel with:aObject;
+ - perform:( SEL )aSel with:firstObject with:secondObject;
  
  /* Posing */
  
diff -c ../orig/mutex.h objc/mutex.h
*** ../orig/mutex.h	Tue Feb  9 20:20:20 1993
--- objc/mutex.h	Tue Feb  9 00:32:13 1993
***************
*** 36,46 ****
  #define MUTEX_UNLOCK(mutex) mutex_unlock (mutex)
  #define MUTEX_ISLOCK(mutex)     mutex->lock /* Gak */
  
! #elif defined (OSF)
  
! #elif defined (mach)
  
! #elif defined (sun)
  /*
   * Sun lwp uses monitors.
   *
--- 36,46 ----
  #define MUTEX_UNLOCK(mutex) mutex_unlock (mutex)
  #define MUTEX_ISLOCK(mutex)     mutex->lock /* Gak */
  
! #elif defined (OSF) && !defined (COROUTINES)
  
! #elif defined (mach) && !defined (COROUTINES)
  
! #elif defined (sun) && !defined (COROUTINES)
  /*
   * Sun lwp uses monitors.
   *
***************
*** 86,91 ****
--- 86,102 ----
   * A environment where threads are implemented as a
   *  set of coroutines.
   */
+ 
+ #include    /* this is my co-routine impl (KKT) */
+ 
+ #define MUTEX Semaphore*
+ #define MUTEX_ALLOC(mutex)   { *mutex = [Semaphore alloc]; }
+ #define MUTEX_INIT(mutex)    [mutex init]
+ #define MUTEX_FREE(mutex)    [mutex free]
+ #define MUTEX_LOCK(mutex)    [mutex wait]
+ #define MUTEX_ISLOCK(mutex)  [mutex wouldBlock]
+ #define MUTEX_UNLOCK(mutex)  [mutex signal]
+ 
  
  #endif
  #endif
diff -c ../orig/objc-proto.h objc/objc-proto.h
*** ../orig/objc-proto.h	Tue Feb  9 20:20:20 1993
--- objc/objc-proto.h	Mon Feb  8 11:37:34 1993
***************
*** 27,32 ****
--- 27,37 ----
  #ifndef __objc_proto_INCLUDE_GNU
  #define __objc_proto_INCLUDE_GNU
  
+ #ifndef HOST_BITS_PER_LONG         /* missing? */
+ #include 
+ #define HOST_BITS_PER_LONG (sizeof(long)*CHAR_BIT)
+ #endif
+ 
  /* This used to be #ifndef __OBJC__, but it turns out that
     object.m needs these declarations.  I don't understand why one
     might want to avoid them in object.m.  */
diff -c ../orig/objc.h objc/objc.h
*** ../orig/objc.h	Tue Feb  9 20:20:20 1993
--- objc/objc.h	Mon Feb  8 11:37:34 1993
***************
*** 27,32 ****
--- 27,34 ----
  #ifndef __objc_INCLUDE_GNU
  #define __objc_INCLUDE_GNU
  
+ #include 
+ 
  /* If someone is using a c++ compiler then adjust the types in the
     file back to C.  */
  #ifdef __cplusplus
diff -c ../orig/record.h objc/record.h
*** ../orig/record.h	Tue Feb  9 20:20:21 1993
--- objc/record.h	Tue Feb  9 03:23:10 1993
***************
*** 92,98 ****
  record_store_at (unsigned int i, void *value, struct record *record)
  {
    assert (i);
!   assert (i <= record_entries (record));
  
    record->records[i] = value;
  }
--- 92,98 ----
  record_store_at (unsigned int i, void *value, struct record *record)
  {
    assert (i);
!   assert (i <= record_capacity (record));
  
    record->records[i] = value;
  }
***************
*** 121,127 ****
  record_get (unsigned int i, struct record *record)
  {
    assert (i);
!   assert (i <= record_entries (record));
    return record->records[i];
  }
  
--- 121,127 ----
  record_get (unsigned int i, struct record *record)
  {
    assert (i);
!   assert (i <= record_capacity (record));
    return record->records[i];
  }
  
diff -c ../orig/core.c objc/core.c
*** ../orig/core.c	Tue Feb  9 20:20:19 1993
--- objc/core.c	Tue Feb  9 06:27:16 1993
***************
*** 23,34 ****
     This exception does not however invalidate any other reasons why
     the executable file might be covered by the GNU General Public License.  */
  
- #include "tconfig.h"
  #include "assert.h"
  #include 
! #include "gstdarg.h"
  #include 
! #include "gstddef.h"
  
  #include "hash.h"
  #include "objc.h"
--- 23,33 ----
     This exception does not however invalidate any other reasons why
     the executable file might be covered by the GNU General Public License.  */
  
  #include "assert.h"
  #include 
! #include "stdarg.h"
  #include 
! #include "stddef.h"
  
  #include "hash.h"
  #include "objc.h"
***************
*** 56,62 ****
  static SEL    record_selector (const char*);
  static void   record_methods_from_class (Class_t);
  static void   record_methods_from_list (MethodList_t);
! static void   initialize_class (const char*);
  /*
   * This is a hash table of Class_t structures. 
   *
--- 55,75 ----
  static SEL    record_selector (const char*);
  static void   record_methods_from_class (Class_t);
  static void   record_methods_from_list (MethodList_t);
! static void   initialize_class (Class_t);
! 
! /* objc_msgSend comes in 3 variants... */
! IMP objc_msgSend(id receiver, SEL selector);
! IMP __builtin_objc_msgSend(id receiver, SEL selector);
! IMP __initializing_objc_msgSend(id receiver, SEL selector);
! IMP (*__objc_msgSend)(id receiver, SEL selector) = __initializing_objc_msgSend;
! 
! /* as does objc_msgSendSuper */
! IMP objc_msgSendSuper(Super_t receiver, SEL selector);
! IMP __builtin_objc_msgSendSuper(Super_t receiver, SEL selector);
! IMP __initializing_objc_msgSendSuper(Super_t receiver, SEL selector);
! IMP (*__objc_msgSendSuper)(Super_t receiver, SEL selector) =
!        __initializing_objc_msgSendSuper;
! 
  /*
   * This is a hash table of Class_t structures. 
   *
***************
*** 84,89 ****
--- 97,105 ----
  /* This mutex provides a course lock for method dispatch.  */
  MUTEX	runtimeMutex;
  
+ /* This mutex provides lock for malloc and friends */
+ MUTEX   mallocMutex;
+ 
  /*
   * This hash table is used by the initialization routines.  When the
   * constructor function (__objc_execClass) is called it is passed a pointer
***************
*** 185,203 ****
    exit (1);
  }
  
! static void *
  xmalloc (unsigned int size)
  {
!   void *ptr = (void *) malloc (size);
    if (ptr == 0)
      fatal ("virtual memory exceeded");
    return ptr;
  }
  
! static void *
  xcalloc (unsigned int size, unsigned int units)
  {
!   void *ptr = (void *) calloc (size, units);
    if (ptr == 0)
      fatal ("virtual memory exceeded");
    return ptr;
--- 201,230 ----
    exit (1);
  }
  
!  void *
  xmalloc (unsigned int size)
  {
!   void *ptr;
!   ptr = (void *) malloc (size);
!   if (ptr == 0)
!     fatal ("virtual memory exceeded");
!   return ptr;
! }
! 
!  void *
! xrealloc (void* ptr, unsigned int size)
! {
!   ptr = (void *) realloc (ptr, size);
    if (ptr == 0)
      fatal ("virtual memory exceeded");
    return ptr;
  }
  
!  void *
  xcalloc (unsigned int size, unsigned int units)
  {
!   void *ptr;
!   ptr = (void *) calloc (size, units);
    if (ptr == 0)
      fatal ("virtual memory exceeded");
    return ptr;
***************
*** 206,212 ****
  void *
  __objc_xmalloc (unsigned int size)
  {
!   void *ptr = (void *) malloc (size);
    if (ptr == 0)
      fatal ("virtual memory exceeded");
    return ptr;
--- 233,240 ----
  void *
  __objc_xmalloc (unsigned int size)
  {
!   void *ptr;
!   ptr = (void *) malloc (size);
    if (ptr == 0)
      fatal ("virtual memory exceeded");
    return ptr;
***************
*** 215,221 ****
  void *
  __objc_xrealloc (void *optr, unsigned int size)
  {
!   void *ptr = (void *) realloc (optr, size);
    if (ptr == 0)
      fatal ("virtual memory exceeded");
    return ptr;
--- 243,250 ----
  void *
  __objc_xrealloc (void *optr, unsigned int size)
  {
!   void *ptr;
!   ptr = (void *) realloc (optr, size);
    if (ptr == 0)
      fatal ("virtual memory exceeded");
    return ptr;
***************
*** 224,230 ****
  void *
  __objc_xcalloc (unsigned int size, unsigned int units)
  {
!   void *ptr = (void *) calloc (size, units);
    if (ptr == 0)
      fatal ("virtual memory exceeded");
    return ptr;
--- 253,260 ----
  void *
  __objc_xcalloc (unsigned int size, unsigned int units)
  {
!   void *ptr;
!   ptr = (void *) calloc (size, units);
    if (ptr == 0)
      fatal ("virtual memory exceeded");
    return ptr;
***************
*** 247,254 ****
   * The purpose of this function is to gather the module pointers so that they
   * may be processed by the initialization clean up routine. 
   */
! void 
! __objc_execClass (Module_t module)
  {
    /* Has we processed any constructors previously? 
       Flag used to indicate that some global data structures
--- 277,284 ----
   * The purpose of this function is to gather the module pointers so that they
   * may be processed by the initialization clean up routine. 
   */
! void            /* it is declared void* in objc-actions.c */
! __objc_execClass (void* theModule)
  {
    /* Has we processed any constructors previously? 
       Flag used to indicate that some global data structures
***************
*** 255,260 ****
--- 285,291 ----
       need to be built.  */
    static BOOL previous_constructors = 0;
  
+   Module_t    module = (Module_t)theModule;	/* see above */
    Symtab_t    symtab = module->symtab;
    Class_t     object_class;
    node_ptr node;
***************
*** 273,287 ****
       some data structures.  */
    if (!previous_constructors) {
  
      /* Enable malloc debugging. This'll slow'er down! */
  #if defined (DEBUG) && defined (NeXT)
      malloc_debug (62);
  #endif
  
-     /* Allocate and initialize the mutex.  */
-     MUTEX_ALLOC (&runtimeMutex);
-     MUTEX_INIT (runtimeMutex);
- 
      /* Allocate the module hash table.  */
      module_hash_table
        = hash_new (MODULE_HASH_SIZE, (hash_func_type)hash_ptr,
--- 304,319 ----
       some data structures.  */
    if (!previous_constructors) {
  
+     __objc_msgSend = __initializing_objc_msgSend; 
+     __objc_msgSendSuper = __initializing_objc_msgSendSuper; 
+ 				/* wee need a version checking for */
+ 				/* un-initialized classes here... */
+ 
      /* Enable malloc debugging. This'll slow'er down! */
  #if defined (DEBUG) && defined (NeXT)
      malloc_debug (62);
  #endif
  
      /* Allocate the module hash table.  */
      module_hash_table
        = hash_new (MODULE_HASH_SIZE, (hash_func_type)hash_ptr,
***************
*** 348,354 ****
        class1->class_pointer->class_pointer = object_class->class_pointer; 
  
        /* Assign super class pointers */
!       if (class1->super_class) {
  	Class_t aSuperClass = objc_getClass ((char*)class1->super_class);
  
  	if (aSuperClass) {
--- 380,386 ----
        class1->class_pointer->class_pointer = object_class->class_pointer; 
  
        /* Assign super class pointers */
!       if ((((class1->info)&CLS_RTI)!=CLS_RTI) && class1->super_class) {
  	Class_t aSuperClass = objc_getClass ((char*)class1->super_class);
  
  	if (aSuperClass) {
***************
*** 362,375 ****
  
  	  /* Mark the class as initialized.  */
  	  class1->info |= CLS_RTI;
! 	} else
  	  /* Couldn't find the class's super class.  */
  	  incomplete = 1;
        }
      }
!   } else
      /* Couldn't find class Object.  */
      incomplete = 1;
  
    /* Process category information from the module.  */
    for (i = 0; i < symtab->cat_def_cnt; ++i) {
--- 394,413 ----
  
  	  /* Mark the class as initialized.  */
  	  class1->info |= CLS_RTI;
! 	} else {
  	  /* Couldn't find the class's super class.  */
  	  incomplete = 1;
+ 	  DEBUG_PRINTF("Missing superclass for %s (%s)\n",
+ 		       class1->name, (char*)(class1->super_class));
+ 	}
        }
      }
!   } else {
      /* Couldn't find class Object.  */
      incomplete = 1;
+     DEBUG_PRINTF("Missing class Object\n");
+   }
+ 
  
    /* Process category information from the module.  */
    for (i = 0; i < symtab->cat_def_cnt; ++i) {
***************
*** 396,401 ****
--- 434,440 ----
  	 be found.  Save the information.  */
        hash_add (&unclaimed_category_hash_table, category, category);
  
+       DEBUG_PRINTF("Missing class %s\n", category->class_name);
        incomplete = 1;
      }
    }
***************
*** 422,429 ****
        if (category->class_methods)
  	addMethodsToClass ((Class_t)class->class_pointer,
  			   category->class_methods);
!     } else
        incomplete = 1;
    }
  
    /* Can we finish the run time initialization? */
--- 461,471 ----
        if (category->class_methods)
  	addMethodsToClass ((Class_t)class->class_pointer,
  			   category->class_methods);
!     } else {
!       DEBUG_PRINTF("Missing class %s\n", category->class_name);
        incomplete = 1;
+     }
+ 
    }
  
    /* Can we finish the run time initialization? */
***************
*** 438,450 ****
      /* Print out class tables if debugging.  */
      DEBUG_PRINTF ("dump of class tables from objcInit\n");
      debug_dump_classes ();
!   }
  
  }
  
  
  IMP  
! objc_msgSend (id receiver, SEL sel)
  {
    /*
     * A method is always called by the compiler.  If a method wasn't
--- 480,514 ----
      /* Print out class tables if debugging.  */
      DEBUG_PRINTF ("dump of class tables from objcInit\n");
      debug_dump_classes ();
! 
!     /* initialize all classes */
!     for (node = hash_next (class_hash_table, NULL); node;
! 	 node = hash_next (class_hash_table, node)) 
!       if(!(((Class_t)node->value)->info & CLS_INITIALIZED)) 
! 	initialize_class(node->value);
! 
!     __objc_msgSend = __builtin_objc_msgSend; 
!     __objc_msgSendSuper = __builtin_objc_msgSendSuper; 
! 				/* change to the fast versions */
  
+     /* Allocate and initialize the mutex.  */
+     MUTEX_ALLOC (&runtimeMutex);
+     MUTEX_INIT (runtimeMutex);
+ 
+     MUTEX_ALLOC(&mallocMutex);
+     MUTEX_INIT(mallocMutex);
+ 
+   }
  }
  
  
+ IMP objc_msgSend (id receiver, SEL sel) {
+   return (*__objc_msgSend)(receiver,sel);
+ }
+ 
+ /* This is an cut-down messenger, which does only what is needed*/
  IMP  
! __builtin_objc_msgSend (id receiver, SEL sel)
  {
    /*
     * A method is always called by the compiler.  If a method wasn't
***************
*** 452,466 ****
     */
    IMP  imp = nil_method;
  
  
    /* The run time must be initialized at this point.
       Otherwise we get a message sent to a object with a bogus selector.  */
!   assert (initialized);
  
    /* Objective-C allows messages to be sent to a nil object.  */
    if (receiver) {
  
!     /* Check for common programmer error.  */
      if (!receiver->class_pointer) {
        fprintf (stderr, "method %s sent to deallocated object %#x\n", 
  	       sel_getName (sel), receiver);
--- 516,569 ----
     */
    IMP  imp = nil_method;
  
+   /* Objective-C allows messages to be sent to a nil object.  */
+   if (receiver) {
+     /*
+      * If we're passed a object then its class_pointer is a Class.  If
+      * we're passed a Class then its class_pointer is a MetaClass. 
+      * Therefore, searching for a instance or class method
+      * requires no special decision making here. 
+      *
+      * Look for the method. 
+      */
+     imp = get_imp (receiver->class_pointer, sel);
+ 
+     /* If the method cannot be found then perform error handling.  */
+     if (!imp)
+       imp = handle_runtime_error (receiver, sel);
+   }
+ 
+ #ifdef DEBUG
+   /* Nice debugging messages if enabled.  */
+   if (objc_trace) {
+     printf ("trace: objc_msgSend , obj=%#x, class=%s, method=%s\n",
+ 	    receiver, 
+ 	    receiver->class_pointer->name, 
+ 	    sel_getName (sel));
+     fflush (stdout);
+   }
+ #endif
+   
+   return imp;
+ }
+ 
+ IMP  
+ __initializing_objc_msgSend (id receiver, SEL sel)
+ {
+   /*
+    * A method is always called by the compiler.  If a method wasn't
+    * found then supply a default. 
+    */
+   IMP  imp = nil_method;
  
    /* The run time must be initialized at this point.
       Otherwise we get a message sent to a object with a bogus selector.  */
!   assert(initialized);
  
    /* Objective-C allows messages to be sent to a nil object.  */
    if (receiver) {
  
!     /* Check for common programmer error */
      if (!receiver->class_pointer) {
        fprintf (stderr, "method %s sent to deallocated object %#x\n", 
  	       sel_getName (sel), receiver);
***************
*** 469,475 ****
      
      /* Initialize the class if need be.  */
      if (!(receiver->class_pointer->info & CLS_INITIALIZED))
!       initialize_class (receiver->class_pointer->name);
  
      /*
       * If we're passed a object then its class_pointer is a Class.  If
--- 572,578 ----
      
      /* Initialize the class if need be.  */
      if (!(receiver->class_pointer->info & CLS_INITIALIZED))
!       initialize_class (receiver->class_pointer);
  
      /*
       * If we're passed a object then its class_pointer is a Class.  If
***************
*** 494,506 ****
  	    sel_getName (sel));
      fflush (stdout);
    }
!   
    return imp;
  }
  
  
  IMP 
! objc_msgSendSuper (Super_t super, SEL sel)
  {
    IMP	imp;
  
--- 597,616 ----
  	    sel_getName (sel));
      fflush (stdout);
    }
! 
    return imp;
  }
  
  
+ 
+ 
  IMP 
! objc_msgSendSuper (Super_t super, SEL sel) {
!   return (__objc_msgSendSuper)(super, sel);
! }
! 
! IMP 
! __initializing_objc_msgSendSuper (Super_t super, SEL sel)
  {
    IMP	imp;
  
***************
*** 508,516 ****
    assert (initialized);
  
    if (!(super->class->info & CLS_INITIALIZED))
!     initialize_class (super->class->name);
    if (!(super->receiver->class_pointer->info & CLS_INITIALIZED))
!     initialize_class (super->receiver->class_pointer->name);
  
    imp = get_imp (super->class, sel);
    
--- 618,626 ----
    assert (initialized);
  
    if (!(super->class->info & CLS_INITIALIZED))
!     initialize_class (super->class);
    if (!(super->receiver->class_pointer->info & CLS_INITIALIZED))
!     initialize_class (super->receiver->class_pointer);
  
    imp = get_imp (super->class, sel);
    
***************
*** 528,533 ****
--- 638,653 ----
    return imp;
  }
  
+ IMP 
+ __builtin_objc_msgSendSuper (Super_t super, SEL sel)
+ {
+   IMP	imp;
+   if(imp = get_imp (super->class, sel))
+     return imp;
+   else
+     return handle_runtime_error (super->receiver, sel);
+ }
+ 
  
  /*
   * This function is called by objc_msgSend or objc_msgSendSuper when a
***************
*** 634,640 ****
     *
     * No need to initialize the class.  That was done in objcInit. 
     */
!   object = (id) xcalloc (1, class->instance_size);
    object->class_pointer = class;
  
    return object;
--- 754,760 ----
     *
     * No need to initialize the class.  That was done in objcInit. 
     */
!   object = (id) __objc_xcalloc (1, class->instance_size);
    object->class_pointer = class;
  
    return object;
***************
*** 661,667 ****
    if (length < object->class_pointer->instance_size)
      abort ();
  
!   obj = (id) realloc (object, length);
    bzero ((char*)obj + object->class_pointer->instance_size,  
  	 length - object->class_pointer->instance_size);
    
--- 781,787 ----
    if (length < object->class_pointer->instance_size)
      abort ();
  
!   obj = (id) __objc_xrealloc (object, length);
    bzero ((char*)obj + object->class_pointer->instance_size,  
  	 length - object->class_pointer->instance_size);
    
***************
*** 949,958 ****
  Class_t 
  class_poseAs (Class_t impostor, Class_t super_class)
  {
!   Class_t     new_class = (Class_t) calloc (1, sizeof (Class));
!   MetaClass_t new_meta_class = (MetaClass_t) calloc (1, sizeof (MetaClass));
    node_ptr node;
!   char        *new_name = (char *) malloc (strlen (super_class->name) + 12);
  
    
    assert (new_class);
--- 1069,1078 ----
  Class_t 
  class_poseAs (Class_t impostor, Class_t super_class)
  {
!   Class_t     new_class = (Class_t) __objc_xcalloc (1, sizeof (Class));
!   MetaClass_t new_meta_class = (MetaClass_t) __objc_xcalloc (1, sizeof (MetaClass));
    node_ptr node;
!   char        *new_name = (char *) __objc_xmalloc (strlen (super_class->name) + 12);
  
    
    assert (new_class);
***************
*** 1220,1235 ****
   * is marked as initialized. 
   */
  static void		
! initialize_class (const char *name)
  {
    Method_t	method = NULL;
-   Class_t	class = objc_getClass (name);
    SEL		sel = sel_getUid ("initialize");
  
  	
    /* The class should not be initialized at this point.  */
    assert (!(class->info & CLS_INITIALIZED));
!   assert (!(class->class_pointer->info & CLS_INITIALIZED));
  
    /* Search for the +initialize method.
       Call it if it exists.  */
--- 1340,1358 ----
   * is marked as initialized. 
   */
  static void		
! initialize_class (Class_t class)
  {
    Method_t	method = NULL;
    SEL		sel = sel_getUid ("initialize");
  
  	
    /* The class should not be initialized at this point.  */
    assert (!(class->info & CLS_INITIALIZED));
!   /*assert (!(class->class_pointer->info & CLS_INITIALIZED));*/
! 
!   /* Mark the class as initialized.  */
!   class->info	|= CLS_INITIALIZED;
!   class->class_pointer->info	|= CLS_INITIALIZED;
  
    /* Search for the +initialize method.
       Call it if it exists.  */
***************
*** 1240,1254 ****
      IMP	imp;
  
      DEBUG_PRINTF ("Class: %s sending +%s\n", 
! 		  name, sel_getName (sel));
      imp = get_imp ((Class_t)class->class_pointer, sel);
      assert (imp);
      (*imp)((id)class, sel);
    }
  
-   /* Mark the class as initialized.  */
-   class->info	|= CLS_INITIALIZED;
-   class->class_pointer->info	|= CLS_INITIALIZED;
  }
  
  
--- 1363,1374 ----
      IMP	imp;
  
      DEBUG_PRINTF ("Class: %s sending +%s\n", 
! 		  class->name, sel_getName (sel));
      imp = get_imp ((Class_t)class->class_pointer, sel);
      assert (imp);
      (*imp)((id)class, sel);
    }
  
  }
  
  
diff -c ../orig/hash.c objc/hash.c
*** ../orig/hash.c	Tue Feb  9 20:20:19 1993
--- objc/hash.c	Tue Feb  9 04:07:26 1993
***************
*** 23,31 ****
     This exception does not however invalidate any other reasons why
     the executable file might be covered by the GNU General Public License.  */
  
! #include "tconfig.h"
! #include "gstddef.h"
! #include "gstdarg.h"
  #include "assert.h"
  
  #include "hash.h"
--- 23,30 ----
     This exception does not however invalidate any other reasons why
     the executable file might be covered by the GNU General Public License.  */
  
! #include "stddef.h"
! #include "stdarg.h"
  #include "assert.h"
  
  #include "hash.h"
***************
*** 53,67 ****
    assert (size);
    assert (!(size & (size - 1)));
  
!   /* Allocate the cache structure.  calloc insures
       its initialization for default values.  */
!   cache = (cache_ptr) calloc (1, sizeof (struct cache));
    assert (cache);
  
    /* Allocate the array of buckets for the cache.
!      calloc initializes all of the pointers to NULL.  */
    cache->node_table
!     = (node_ptr *) calloc (size, sizeof (node_ptr));
    assert (cache->node_table);
  
    cache->size  = size;
--- 52,66 ----
    assert (size);
    assert (!(size & (size - 1)));
  
!   /* Allocate the cache structure.  xcalloc insures
       its initialization for default values.  */
!   cache = (cache_ptr) xcalloc (1, sizeof (struct cache));
    assert (cache);
  
    /* Allocate the array of buckets for the cache.
!      xcalloc initializes all of the pointers to NULL.  */
    cache->node_table
!     = (node_ptr *) xcalloc (size, sizeof (node_ptr));
    assert (cache->node_table);
  
    cache->size  = size;
***************
*** 100,106 ****
  hash_add (cache_ptr *cachep, const void *key, void *value)
  {
    size_t indx = (*(*cachep)->hash_func)(*cachep, key);
!   node_ptr node = (node_ptr) calloc (1, sizeof (struct cache_node));
  
  
    assert (node);
--- 99,105 ----
  hash_add (cache_ptr *cachep, const void *key, void *value)
  {
    size_t indx = (*(*cachep)->hash_func)(*cachep, key);
!   node_ptr node = (node_ptr) xcalloc (1, sizeof (struct cache_node));
  
  
    assert (node);
***************
*** 252,254 ****
--- 251,256 ----
  
    return retval;
  }
+ 
+ 
+ 
diff -c ../orig/object.m objc/object.m
*** ../orig/object.m	Tue Feb  9 20:20:21 1993
--- objc/object.m	Tue Feb  9 03:45:48 1993
***************
*** 1,3 ****
--- 1,15 ----
+ /* This may look like -*- C -*- but it is really objective C */
+ 
+ /* $Log: Object.m,v $
+  * Revision 1.3  1993/02/08  20:05:15  krab
+  * Changed hash and isEqual to examine instance variables
+  *
+  * 6-Feb-1993		Kresten Krab Thorup	
+  *    Changed deepCopy
+  * 6-Feb-1993		Kresten Krab Thorup	
+  *    Changed to alloc/init scheme.  
+  */
+ 
  /* This file contains the implementation of class Object.
     Copyright (C) 1992 Free Software Foundation, Inc.
  
***************
*** 18,26 ****
  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
   
  
! #include "tconfig.h"
! #include "gstdarg.h"
! #include "object.h"
  #include "objc-proto.h"
  
  #include 
--- 30,37 ----
  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
   
  
! #include "stdarg.h"
! #include "Object.h"
  #include "objc-proto.h"
  
  #include 
***************
*** 34,61 ****
  @implementation Object
  
  
! + new
! {
!   return class_createInstance (CLASS (self));
! }
! 
  
  + free {  return nil; }
  - free {  return object_dispose (self); }
  
- 
  - copy {  return [self shallowCopy]; }
  
- 
  - shallowCopy
  {
    return object_copy (self);
  }
  
- 
  - deepCopy
  {
!   return class_createInstance ([self class]);
  }
  
  
--- 45,67 ----
  @implementation Object
  
  
! + alloc {  return class_createInstance (CLASS (self)); }
! + new   {  return [[self alloc] init]; }
! - init  {  return self; }
  
  + free {  return nil; }
  - free {  return object_dispose (self); }
  
  - copy {  return [self shallowCopy]; }
  
  - shallowCopy
  {
    return object_copy (self);
  }
  
  - deepCopy
  {
!   return object_copy (self);
  }
  
  
***************
*** 69,83 ****
  
  - (unsigned int)hash
  {
!   return (unsigned int)self; /* gak!  Not portable. */
  }
  
- 
  - (BOOL)isEqual:anObject
  {
!   return self == anObject ;
  }
  
  
  - (BOOL)isKindOf:(Class_t)aClassObject
  {
--- 75,104 ----
  
  - (unsigned int)hash
  {
!   if(isa->instance_size > sizeof(Object))
!     {
!       register unsigned cnt, res;
!       for(cnt=0, res=0; cnt < isa->instance_size; cnt++)
! 	res += ((char*)self)[cnt];
!       return res;
!     }
!   else    /* no instance variables -- use adress */
!     return ((unsigned int)self)>>3;
  }
  
  - (BOOL)isEqual:anObject
  {
!   if(self->isa != anObject->isa) 
!     return NO;
!   if(isa->instance_size != anObject->isa->instance_size)
!     return NO;
!   return bcmp(self, anObject, isa->instance_size) == 0 ? YES : NO;
  }
  
+ + (BOOL)isEqual: aClass
+ {
+   return self==aClass ? YES : NO;
+ }
  
  - (BOOL)isKindOf:(Class_t)aClassObject
  {
***************
*** 145,150 ****
--- 166,177 ----
  }
  
  
+ - perform:(SEL)aSel with:aObject with:secondObject
+ {
+   return (*((IMP)objc_msgSend (self, aSel)))(self, aSel, aObject,secondObject);
+ }
+ 
+ 
  + poseAs:(Class_t)aClassObject
  {
    return class_poseAs (self, aClassObject);
***************
*** 153,171 ****
   
  - subclassResponsibility:(SEL)aSel
  {
!   return [self error:"subclass should override %s", aSel];
  }
  
  
  - notImplemented:(SEL)aSel
  {
!   return [self error:"method %s not implemented", aSel];
  }
  
  
  - doesNotRecognize:(SEL)aSel
  {
!   return [self error:"%s does not recognize %s", [self name], aSel];
  }
  
  - error:(const char*)aString, ...
--- 180,198 ----
   
  - subclassResponsibility:(SEL)aSel
  {
!   return [self error:"subclass should override %s", sel_getName(aSel)];
  }
  
  
  - notImplemented:(SEL)aSel
  {
!   return [self error:"method %s not implemented", sel_getName(aSel)];
  }
  
  
  - doesNotRecognize:(SEL)aSel
  {
!   return [self error:"%s does not recognize %s", [self name], sel_getName(aSel)];
  }
  
  - error:(const char*)aString, ...
***************
*** 221,226 ****
--- 248,256 ----
    return self;
  }
  
+  /* This method reads the header "#\0". Finds the */
+  /* class, and checks it version.  Finally it creates a new instance */
+  /* of that class, and sends it the message -readFrom: */
  
  + readFrom:(int)aFd
  {
***************
*** 228,234 ****
    char  objName[256];
    int   len;
    
-   
    if ((len = read (aFd, &objName, strlen ("#"))) != -1)
      if (objName[0] == '#') {
        long  version;
--- 258,263 ----
***************
*** 243,264 ****
        if (len != -1)
          len = read (aFd, &version, sizeof (version));
        
!       /* No errors???
! 	 Then create a object. */
        if (len != -1) {
! 	aObj = class_createInstance (objc_getClass (objName));
!           
! 	/* If the object was 
! 	   successfully created then
! 	   tell it to dearchive
! 	   itself. */
! 	if (aObj)
  	  [aObj readFrom:aFd];
        }
      }
      
    if (len == -1)
!     [self error:"error activating object, errno=%d", errno];
    
    return aObj;
  }
--- 272,294 ----
        if (len != -1)
          len = read (aFd, &version, sizeof (version));
        
!       /* No errors??? Then create a object. */
        if (len != -1) {
! 	Class_t aClass = objc_getClass(objName);
! 	if(aClass == nil)
! 	  [self error: "readFrom: Cannot find class %s", objName];
! 	else if ([aClass version] != version)
! 	  [self error: "readFrom: Bad version: %d of class %s", version, objName];
! 
! 	if(aObj = class_createInstance (aClass))
  	  [aObj readFrom:aFd];
+ 	else
+ 	  [self error: "readFrom: Cannot create instance of class %s", aClass];
        }
      }
      
    if (len == -1)
!     [self error:"readFrom: I/O error activating object, errno=%d", errno];
    
    return aObj;
  }

Return-Path: 
Date: Wed, 10 Feb 1993 11:51:12 -0500
To: Kresten Krab Thorup , gnu-objc-runtime@prep.ai.mit.edu
From: bradcox@sitevax.gmu.edu (Brad Cox; 703 968 8229)
Subject: Re: Gnu objc runtime [comments and bug reports]
Cc: "Geoffrey S. Knauth" , rms@gnu.ai.mit.edu,
        gnu-objc-submissions@prep.ai.mit.edu

krab@iesd.auc.dk wrote:
>     # Changed isEqual so that bcmp on instances is done, instead of
>     comparing the object pointers only.  I dont know if this is the
>     right semathics, but it surely is more natural.  

There is no single *right* semantics for isEqual: at the generic Object
level. You're confusing the difference between fixing a bug and redefining
a standard.

I encourage you to undo this fix by adopting (1) the simplest to explain
(2) the smallest to implement and (3) the one discussed in my book and (4)
the one adopted in existing Object class implementations; namely that
unless overridden, equality == identity; i.e.

- isEqual: anObject { return anObject == self; }

Don't forget that unfixing isEqual: will also require unfixing hash.
--
   Brad Cox; bradcox@sitevax.gmu.edu; 703 993 1142 work 703 968 8229 home 
 George Mason Program on Social and Organizational Learning; Fairfax VA 22030


Return-Path: 
Date: Wed, 10 Feb 93 20:57:58 -0800
From: Dennis Glatting 
To: "Geoffrey S. Knauth" 
Subject: Re: [krab@iesd.auc.dk: Gnu objc runtime [comments and bug reports]]
Cc: gnu-objc-runtime@prep.ai.mit.edu
Reply-To: dennis_glatting@trirex.com

> # Changed msgSend scheme:  objc_msgSend is now a pointer
> two a function. core.c defines two messengers, one equal
> to the present doing extensively initialization
> checking, and one bare-bone with no such checks (more on
> initialization at next item) This also allows the
> programmer to do his own messengers -- fun! 

> 


Trade off.  Adds overhead to *every* message dispatch.


> When all classes have their class-relationships
> resolved, (i.e. the last time it is called), It calls
> +initialize for all classes.  (still using the heavy
> messenger)  it is not called if it has already been done if a
> +initialize method has invoked it indirectly by doing
> message passing to other objects. 

> 


This is contrary to the definition of the +initialize.  Also, I did  
this once.  There are problems.  For example, what if a +initialize  
method allocates a object of another class?  The +initialize method  
of the second class hasn't been called yet.  How is the +initialize  
method of the second class called?  By checking to see if the class  
has been initialized.  So what's the point of executing all  
+initialize methods at once?


-dpg

Return-Path: 
Date: Wed, 24 Feb 1993 09:52:42 +0100
From: Kresten Krab Thorup 
To: Bill Dudney 
In-Reply-To: <9302232343.AA02036@>
Subject: Help with the runtime
Cc: krab@iesd.auc.dk, rms@gnu.ai.mit.edu, burchard@geom.umn.edu,
        gsk@marble.com

Bill Dudney writes:
>Is there some way I can help? I dont have a very good feel for the
>state of the run time system now but I do know NeXTs run time pretty
>well and would be happy to help get GNU's up to snuff.

Since I don't think the current runtime is worth anything I have
started writing the runtime from scratch.  As the runtime is only a
2-3 thousand lines of C code, I think it would be best if I did it
alone until I have something which is close to a full runtime.  But
there are a few points where I really need help.

(1) Since we do not have a specification of the objective C language
it is my worst worry if I do it absolutely correct.  There are several
things which could be done:

   1) Writing a specification of the objective C language. 

   2) Writing a specification of the programmer/runtime interface.

Currently I use the NeXT documentation, and the existing C code to
make these matters certain.  For example, the exact semathics of
posing is still a bit unclear to me...  Should the class being posed
for be accessible in any way after the poseAs call?


(2) The type encoding format needs revision/redesign.  Stallman, Paul
and I have had some discussions on this, and if you're interested in
writing a some documentation, you're welcome.  One problem not exactly
solved yet, is how to manage translations to and from machine
independent format, and who's resplonsibility it should be to do so --
the runtime? the compiler? the code in typedstreams?.  We also need
someone to actually code things like typed streams.  This is not
critical for the core runtime, and could be done later.


(3) Whenever I or other people introduce ideas for new features or how
to implement them, take your time to evaluate them carefully, and
** answer to the gnu-objc list ** , so that we can discuss it in a wide
forum.  This is the intermediate way to handle (1).


(4) Once I get something up running, be a *critical* beta-tester.
This -- I guess -- will take a week or two before I have anything
presentable to testers.


Geoffrey:  If you think it would be a good idea, you're welcome to
post this note to the list.  Perhaps someone has more problems to add? 

Thanks,

Kresten


Statistics
 filename:           krab-runtime
 number of mails:    4
 number of writers:  3
 line count:         1426
 word count:         5455
 character count:    39580

created by Helge Hess ( helge@mdlink.de )
MDlink online service center ( www.mdlink.de )