Initial revision
authorTom Wood <wood@gnu.org>
Sat, 10 Apr 1993 01:05:19 +0000 (01:05 +0000)
committerTom Wood <wood@gnu.org>
Sat, 10 Apr 1993 01:05:19 +0000 (01:05 +0000)
From-SVN: r4077

15 files changed:
gcc/objc/Object.h [new file with mode: 0644]
gcc/objc/Object.m [new file with mode: 0644]
gcc/objc/Protocol.h [new file with mode: 0644]
gcc/objc/Protocol.m [new file with mode: 0644]
gcc/objc/archive.c [new file with mode: 0644]
gcc/objc/class.c [new file with mode: 0644]
gcc/objc/init.c [new file with mode: 0644]
gcc/objc/misc.c [new file with mode: 0644]
gcc/objc/objc-api.h [new file with mode: 0644]
gcc/objc/objects.c [new file with mode: 0644]
gcc/objc/runtime.h [new file with mode: 0644]
gcc/objc/sarray.c [new file with mode: 0644]
gcc/objc/sarray.h [new file with mode: 0644]
gcc/objc/selector.c [new file with mode: 0644]
gcc/objc/sendmsg.c [new file with mode: 0644]

diff --git a/gcc/objc/Object.h b/gcc/objc/Object.h
new file mode 100644 (file)
index 0000000..33e10bc
--- /dev/null
@@ -0,0 +1,121 @@
+/* Interface for the Object class for Objective-C.
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+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
+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. */
+
+#ifndef __object_INCLUDE_GNU
+#define __object_INCLUDE_GNU
+
+#include <objc/objc.h>
+
+/*
+ * All classes are derived from Object.  As such,
+ * this is the overhead tacked onto those objects.
+ */
+@interface Object
+{
+    Class_t    isa;    /* A pointer to the instance's class structure */
+}
+
+        /* Initializing classes and instances */
++ initialize;
+- init;
+
+        /* Creating, freeing, and copying instances */
++ new;
++ alloc;
+- free;
+- copy;
+- shallowCopy;
+- deepen;
+- deepCopy;
+
+        /* Identifying classes */
+- (Class_t)class;
+- (Class_t)superClass;
+- (MetaClass_t)metaClass;
+- (const char *)name;
+
+        /* Identifying and comparing objects */
+- self;
+- (unsigned int)hash;
+- (BOOL)isEqual:anObject;
+
+        /* Testing object type */
+- (BOOL)isMetaClass;
+- (BOOL)isClass;
+- (BOOL)isInstance;
+
+        /* Testing inheritance relationships */
+- (BOOL)isKindOf:(Class_t)aClassObject;
+- (BOOL)isMemberOf:(Class_t)aClassObject;
+- (BOOL)isKindOfClassNamed:(const char *)aClassName;
+- (BOOL)isMemberOfClassNamed:(const char *)aClassName;
+
+        /* Testing class functionality */
++ (BOOL)instancesRespondTo:(SEL)aSel;
+- (BOOL)respondsTo:(SEL)aSel;
+
+       /* Testing protocol conformance */
+- (BOOL)conformsTo:(Protocol*)aProtocol;
+
+        /* Introspection */
++ (IMP)instanceMethodFor:(SEL)aSel;
+- (IMP)methodFor:(SEL)aSel;
++ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel;
+- (struct objc_method_description *)descriptionForMethod:(SEL)aSel;
+
+        /* Sending messages determined at run time */
+- perform:(SEL)aSel;
+- perform:(SEL)aSel with:anObject;
+- perform:(SEL)aSel with:anObject1 with:anObject2;
+
+        /* Forwarding */
+- forward:(SEL)aSel :(arglist_t)argFrame;
+- performv:(SEL)aSel :(arglist_t)argFrame;
+
+        /* Posing */
++ poseAs:(Class_t)aClassObject;
+- (Class_t)transmuteClassTo:(Class_t)aClassObject;
+
+        /* Enforcing intentions */
+- subclassResponsibility:(SEL)aSel;
+- notImplemented:(SEL)aSel;
+
+        /* Error handling */
+- doesNotRecognize:(SEL)aSel;
+- error:(const char *)aString, ...;
+
+        /* Archiving */
++ (int)version;
++ setVersion:(int)aVersion;
+
+- read: (TypedStream*)aStream;
+- write: (TypedStream*)aStream;
+
++ read: (TypedStream*)aStream;
++ write: (TypedStream*)aStream;
+
+@end
+
+#endif
diff --git a/gcc/objc/Object.m b/gcc/objc/Object.m
new file mode 100644 (file)
index 0000000..330c9a8
--- /dev/null
@@ -0,0 +1,454 @@
+/* The implementation of class Object for Objective-C.
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+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
+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 <objc/Object.h>
+#include <objc/Protocol.h>
+#include <objc/objc-api.h>
+#include <objc/objc-archive.h>
+
+extern int strlen(const char *);
+extern int strcmp(const char *, const char *);
+extern int read(int, void *, int);
+extern int write(int, const void *, int);
+extern int errno;
+
+#define MAX_CLASS_NAME_LEN 256
+
+@implementation Object
+
+// Initialize a class
+// often overridden by subclasses
++ initialize
+{
+  return self;
+}
+
+// Initialize an instance
+// this method does not apply to class objects
+// often overridden by subclasses (should call superclass version)
+- init
+{
+  return self;
+}
+
+// Create and initialize an instance of a class
+// not usually overridden by subclasses (should call superclass version)
++ new
+{
+  return [[self alloc] init];
+}
+
+// Creates an instance of a class
+// should NOT be overridden by subclasses
++ alloc
+{
+  return class_create_instance(self);
+}
+
+// Free an instance
+// this method does not apply to class objects
+// often overridden by subclasses (should call superclass version)
+- free
+{
+  return object_dispose(self);
+}
+
+// Create a copy of the receiving instance
+// this method does not apply to class objects
+// not usually overridden by subclasses
+- copy
+{
+  return [[self shallowCopy] deepen];
+}
+
+// Creates a copy of only the receiving instance
+// this method does not apply to class objects
+// should NOT be overridden by subclasses
+- shallowCopy
+{
+  return object_copy(self);
+}
+
+// Deepens a shallow copy of an instance
+// this method does not apply to class objects
+// often overridden by subclasses (should call superclass version)
+- deepen
+{
+  return self;
+}
+
+// Creates a recursive copy of the receiving instance
+// this method does not apply to class objects
+// may be overridden by subclasses
+// Not correct, but included for compatibility with Stepstone
+- deepCopy
+{
+  return [self copy];
+}
+
+// Return the class object or the class of an instance
+// not usually overridden by subclasses
+- (Class_t)class
+{
+  return object_get_class(self);
+}
+
+// Return the superclass of a class or instance
+// not usually overridden by subclasses
+- (Class_t)superClass
+{
+  return object_get_super_class(self);
+}
+
+// Return the metaclass of a class or instance
+// not usually overridden by subclasses
+- (MetaClass_t)metaClass
+{
+  return object_get_meta_class(self);
+}
+
+// Return the character string name of a class or an instance's class
+// not usually overridden by subclasses
+- (const char *)name
+{
+  return object_get_class_name(self);
+}
+
+// Return the receiving class or instance object
+// not usually overridden by subclasses
+- self
+{
+  return self;
+}
+
+// Return a hash value for a class or instance object
+// not usually overridden by subclasses
+- (unsigned int)hash
+{
+  return (unsigned int)self;
+}
+
+// Indicates if anObject is the receiving class or instance object
+// not usually overridden by subclasses
+- (BOOL)isEqual:anObject
+{
+  return self==anObject;
+}
+
+// Indicates if the receiver is a metaclass object
+// should NOT be overridden by subclasses
+- (BOOL)isMetaClass
+{
+  return NO;
+}
+
+// Indicates if the receiver is a class object
+// should NOT be overridden by subclasses
+- (BOOL)isClass
+{
+  return object_is_class(self);
+}
+
+// Indicates if the receiver is an instance object
+// should NOT be overridden by subclasses
+- (BOOL)isInstance
+{
+  return object_is_instance(self);
+}
+
+// Indicates if the receiver is a type of aClassObject
+// not usually overridden by subclasses
+- (BOOL)isKindOf:(Class_t)aClassObject
+{
+  Class_t class;
+
+  for (class = self->isa; class!=Nil; class = class_get_super_class(class))
+    if (class==aClassObject)
+      return YES;
+  return NO;
+}
+
+// Indicates if the receiver is a member of the aClassObject class
+// not usually overridden by subclasses
+- (BOOL)isMemberOf:(Class_t)aClassObject
+{
+  return self->isa==aClassObject;
+}
+
+// Indicates if the receiver is a type of the class named aClassName
+// not usually overridden by subclasses
+- (BOOL)isKindOfClassNamed:(const char *)aClassName
+{
+  Class_t class;
+
+  if (aClassName!=NULL)
+    for (class = self->isa; class!=Nil; class = class_get_super_class(class))
+      if (!strcmp(class_get_class_name(class), aClassName))
+        return YES;
+  return NO;
+}
+
+// Indicates if the receiver is a member of the class named aClassName
+// not usually overridden by subclasses
+- (BOOL)isMemberOfClassNamed:(const char *)aClassName
+{
+  return ((aClassName!=NULL)
+          &&!strcmp(class_get_class_name(self->isa), aClassName));
+}
+
+// Indicates if instances of a class respond to the message aSel
+// not usually overridden by subclasses
++ (BOOL)instancesRespondTo:(SEL)aSel
+{
+  return class_get_instance_method(self, aSel)!=METHOD_NULL;
+}
+
+// Indicates if the receiving class or instance responds to the message aSel
+// not usually overridden by subclasses
+- (BOOL)respondsTo:(SEL)aSel
+{
+  return ((object_is_instance(self)
+           ?class_get_instance_method(self->isa, aSel)
+           :class_get_class_method(self->isa, aSel))!=METHOD_NULL);
+}
+
+// Returns the address of a class's instance method
+// not usually overridden by subclasses
++ (IMP)instanceMethodFor:(SEL)aSel
+{
+  return method_get_imp(class_get_instance_method(self, aSel));
+}
+
+// Indicates if the receiving class or instance conforms to the given protocol
+// not usually overridden by subclasses
+- (BOOL) conformsTo: (Protocol*)aProtocol
+{
+  int i;
+  struct objc_protocol_list* proto_list;
+
+  for (proto_list = isa->protocols;
+       proto_list; proto_list = proto_list->next)
+    {
+      for (i=0; i < proto_list->count; i++)
+      {
+        if ([proto_list->list[i] conformsTo: aProtocol])
+          return YES;
+      }
+    }
+
+  return NO;
+}
+
+
+// Returns the address of a class's class or an instance's instance method
+// not usually overridden by subclasses
+- (IMP)methodFor:(SEL)aSel
+{
+  return (method_get_imp(object_is_instance(self)
+                         ?class_get_instance_method(self->isa, aSel)
+                         :class_get_class_method(self->isa, aSel)));
+}
+
+// Returns a method description for a class's instance method aSel
+// not usually overridden by subclasses
++ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel
+{
+  return ((struct objc_method_description *)
+           class_get_instance_method(self, aSel));
+}
+
+// Returns a description for a class's class or an instance's instance method
+// not usually overridden by subclasses
+- (struct objc_method_description *)descriptionForMethod:(SEL)aSel
+{
+  return ((struct objc_method_description *)
+           (object_is_instance(self)
+            ?class_get_instance_method(self->isa, aSel)
+            :class_get_class_method(self->isa, aSel)));
+}
+
+// Sends the message aSel, which takes no parameters, to the receiver
+// not usually overridden by subclasses
+- perform:(SEL)aSel
+{
+  IMP msg = objc_msg_lookup(self, aSel);
+  if (!msg)
+    return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
+  return (*msg)(self, aSel);
+}
+
+// Sends the message aSel, which takes one id parameter, to the receiver
+// not usually overridden by subclasses
+- perform:(SEL)aSel with:anObject
+{
+  IMP msg = objc_msg_lookup(self, aSel);
+  if (!msg)
+    return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
+  return (*msg)(self, aSel, anObject);
+}
+
+// Sends the message aSel, which takes two id parameters, to the receiver
+// not usually overridden by subclasses
+- perform:(SEL)aSel with:anObject1 with:anObject2
+{
+  IMP msg = objc_msg_lookup(self, aSel);
+  if (!msg)
+    return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
+  return (*msg)(self, aSel, anObject1, anObject2);
+}
+
+// Forwards a message to which a class or instance object does not respond
+// may be overridden by subclasses
+- forward:(SEL)aSel :(arglist_t)argFrame
+{
+  return [self doesNotRecognize: aSel];
+}
+
+// Sends a message aSel, of arbitrary arguments, to the receiver
+// should NOT be overridden by subclasses
+- performv:(SEL)aSel :(arglist_t)argFrame
+{
+  return objc_msg_sendv(self, aSel, method_get_argsize(0), argFrame);
+}
+
+// Instructs the runtime system that the receiver is to pose for aClassObject
+// not usually overridden by subclasses
++ poseAs:(Class_t)aClassObject
+{
+  return class_pose_as(self, aClassObject);
+}
+
+// Changes the receiver's class to be aClassObject
+// this method does not apply to class objects
+// not usually overridden by subclasses
+- (Class_t)transmuteClassTo:(Class_t)aClassObject
+{
+  if (object_is_instance(self))
+    if (class_is_class(aClassObject))
+      if (class_get_instance_size(aClassObject)==class_get_instance_size(isa))
+        if ([self isKindOf:aClassObject])
+          {
+            Class_t old_isa = isa;
+            isa = aClassObject;
+            return old_isa;
+          }
+  return nil;
+}
+
+// Indicates that a subclass did not override a class or instance message
+//   it was supposed to have overridden
+// not usually overridden by subclasses
+- subclassResponsibility:(SEL)aSel
+{
+  return [self error:"subclass should override %s", sel_get_name(aSel)];
+}
+
+// Indicates that a class or instance method has not been implemented
+// may be overridden by subclasses
+- notImplemented:(SEL)aSel
+{
+  return [self error:"method %s not implemented", sel_get_name(aSel)];
+}
+
+// Reports that a class or instance does not recognize the message aSel
+// not usually overridden by subclasses
+- doesNotRecognize:(SEL)aSel
+{
+  return [self error:"%s does not recognize %s",
+                     object_get_class_name(self), sel_get_name(aSel)];
+}
+
+// Reports an error
+// not usually overridden by subclasses
+- error:(const char *)aString, ...
+{
+#define FMT "error: %s (%s)\n%s\n"
+  char fmt[(strlen(FMT)+strlen(object_get_class_name(self))
+            +((aString!=NULL)?strlen(aString):0)+8)];
+  va_list ap;
+
+  sprintf(fmt, FMT, object_get_class_name(self),
+                    object_is_instance(self)?"instance":"class",
+                    (aString!=NULL)?aString:"");
+  va_start(ap, aString);
+  (*_objc_error)(self, fmt, ap);
+  va_end(ap);
+  return nil;
+#undef FMT
+}
+
+// Returns the class's version number
+// not usually overridden by subclasses
++ (int)version
+{
+  return class_get_version(self);
+}
+
+// Sets the class's version number
+// not usually overridden by subclasses
++ setVersion:(int)aVersion
+{
+  class_set_version(self, aVersion);
+  return self;
+}
+
+// These are used to write or read the instance variables 
+// declared in this particular part of the object.  Subclasses
+// should extend these, by calling [super read/write: aStream]
+// before doing their own archiving.  These methods are private, in
+// the sense that they should only be called from subclasses.
+
+- read: (TypedStream*)aStream
+{
+  // [super read: aStream];  
+  return self;
+}
+
+- write: (TypedStream*)aStream
+{
+  // [super write: aStream];
+  return self;
+}
+
+// These are used to read or write class information, such as static
+// variables used in that class.  The version number of the class being 
+// read can be obtained from 
+//     objc_typed_stream_class_version(stream, class_name)  
+
++ write: (TypedStream*)aStream
+{
+  // [super write: aStream];
+  return self;
+}
+
++ read: (TypedStream*)aStream
+{
+  // [super read: aStream];
+  return self;
+}
+
+
+
+@end
diff --git a/gcc/objc/Protocol.h b/gcc/objc/Protocol.h
new file mode 100644 (file)
index 0000000..1b26bcb
--- /dev/null
@@ -0,0 +1,57 @@
+/* Declare the class Protocol for Objective C programs.
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+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.  */
+
+#ifndef __Protocol_INCLUDE_GNU
+#define __Protocol_INCLUDE_GNU
+
+#include <objc/Object.h>       
+
+@interface Protocol : Object
+{
+@private
+        char *protocol_name;
+        struct objc_protocol_list *protocol_list;
+        struct objc_method_description_list *instance_methods, *class_methods; 
+}
+
+/* Obtaining attributes intrinsic to the protocol */
+
+- (const char *)name;
+
+/* Testing protocol conformance */
+
+- (BOOL) conformsTo: (Protocol *)aProtocolObject;
+
+/* Looking up information specific to a protocol */
+
+- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel;
+- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel;
+
+@end
+
+
+
+
+#endif __Protocol_INCLUDE_GNU
diff --git a/gcc/objc/Protocol.m b/gcc/objc/Protocol.m
new file mode 100644 (file)
index 0000000..f4999bc
--- /dev/null
@@ -0,0 +1,127 @@
+/* This file contains the implementation of class Protocol.
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+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 <objc/Protocol.h>
+#include <objc/objc-api.h>
+
+/* Method description list */
+struct objc_method_description_list {
+        int count;
+        struct objc_method_description list[1];
+};
+
+
+@implementation Protocol
+{
+@private
+        char *protocol_name;
+        struct objc_protocol_list *protocol_list;
+        struct objc_method_description_list *instance_methods, *class_methods; 
+}
+
+/* Obtaining attributes intrinsic to the protocol */
+
+- (const char *)name
+{
+  return protocol_name;
+}
+
+/* Testing protocol conformance */
+
+- (BOOL) conformsTo: (Protocol *)aProtocolObject
+{
+  int i;
+  struct objc_protocol_list* proto_list;
+
+  if (!strcmp(aProtocolObject->protocol_name, self->protocol_name))
+    return YES;
+
+  for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
+    {
+      for (i=0; i < proto_list->count; i++)
+       {
+         if ([proto_list->list[i] conformsTo: aProtocolObject])
+           return YES;
+       }
+    }
+
+  return NO;
+}
+
+/* Looking up information specific to a protocol */
+
+- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel
+{
+  int i;
+  struct objc_protocol_list* proto_list;
+  const char* name = sel_get_name (aSel);
+  struct objc_method_description *result;
+
+  for (i = 0; i < instance_methods->count; i++)
+    {
+      if (!strcmp ((char*)instance_methods->list[i].name, name))
+       return &(instance_methods->list[i]);
+    }
+
+  for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
+    {
+      for (i=0; i < proto_list->count; i++)
+       {
+         if ((result = [proto_list->list[i]
+                        descriptionForInstanceMethod: aSel]))
+           return result;
+       }
+    }
+
+  return NULL;
+}
+
+- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel;
+{
+  int i;
+  struct objc_protocol_list* proto_list;
+  const char* name = sel_get_name (aSel);
+  struct objc_method_description *result;
+
+  for (i = 0; i < class_methods->count; i++)
+    {
+      if (!strcmp ((char*)class_methods->list[i].name, name))
+       return &(class_methods->list[i]);
+    }
+
+  for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
+    {
+      for (i=0; i < proto_list->count; i++)
+       {
+         if ((result = [proto_list->list[i]
+                        descriptionForClassMethod: aSel]))
+           return result;
+       }
+    }
+
+  return NULL;
+}
+
+@end
diff --git a/gcc/objc/archive.c b/gcc/objc/archive.c
new file mode 100644 (file)
index 0000000..8398984
--- /dev/null
@@ -0,0 +1,1378 @@
+/* GNU Objective C Runtime archiving
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+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.  */
+
+/*
+** Note: This version assumes that int and longs are both 32bit.
+**       Most API function are in the bottom of this file.
+*/
+
+#include "runtime.h"
+#include <objc/objc-archive.h>
+
+#define __objc_fatal(format, args...) \
+ { fprintf(stderr, "archining: "); \
+   fprintf(stderr, format, ## args); \
+   fprintf(stderr, "\n"); abort(); }
+
+/* Declare some functions... */
+
+static int
+objc_read_class (struct objc_typed_stream* stream, Class** class);
+
+static int
+objc_sizeof_type(const char* type);
+
+static int
+objc_write_use_common (struct objc_typed_stream* stream, unsigned int key);
+
+static int
+objc_write_register_common (struct objc_typed_stream* stream,
+                           unsigned int key);
+
+static int 
+objc_write_class (struct objc_typed_stream* stream,
+                        struct objc_class* class);
+
+static const char*
+__objc_skip_type (const char* type);
+
+static __inline__ int
+__objc_code_unsigned_char (unsigned char* buf, unsigned char val)
+{
+  if ((val&_B_VALUE) == val)
+    {
+      buf[0] = val|_B_SINT;
+      return 1;
+    }
+  else
+    {
+      buf[0] = _B_NINT|0x01;
+      buf[1] = val;
+      return 2;
+    }
+}
+
+int
+objc_write_unsigned_char (struct objc_typed_stream* stream,
+                         unsigned char value)
+{
+  unsigned char buf[sizeof (unsigned char)+1];
+  int len = __objc_code_unsigned_char (buf, value);
+  return (*stream->write)(stream->physical, buf, len);
+}
+
+static __inline__ int
+__objc_code_char (unsigned char* buf, char val)
+{
+  if (val >= 0)
+    return __objc_code_unsigned_char (buf, val);
+  else
+    {
+      buf[0] = _B_NINT|_B_SIGN|0x01;
+      buf[1] = -val;
+      return 2;
+    }
+}
+
+int
+objc_write_char (struct objc_typed_stream* stream, char value)
+{
+  unsigned char buf[sizeof (char)+1];
+  int len = __objc_code_char (buf, value);
+  return (*stream->write)(stream->physical, buf, len);
+}
+
+static __inline__ int
+__objc_code_unsigned_short (unsigned char* buf, unsigned short val)
+{
+  if (val <= 0xffU)
+    return __objc_code_unsigned_char (buf, val);
+
+  else 
+    {
+      buf[0] = _B_NINT|0x02;
+      buf[1] = val/0x100;
+      buf[2] = val%0x100;
+      return 3;
+    }
+}
+
+int
+objc_write_unsigned_short (struct objc_typed_stream* stream, unsigned short value)
+{
+  unsigned char buf[sizeof (unsigned short)+1];
+  int len = __objc_code_unsigned_short (buf, value);
+  return (*stream->write)(stream->physical, buf, len);
+}
+      
+static __inline__ int
+__objc_code_short (unsigned char* buf, short val)
+{
+  if (val > 0)
+    return __objc_code_unsigned_short (buf, val);
+
+  if (val > -0x7f)             /* val > -128 */
+    return __objc_code_char (buf, val);
+
+  else 
+    {
+      int len = __objc_code_unsigned_short (buf, -val);
+      buf[0] |= _B_SIGN;
+      return len;
+    }
+}
+
+int
+objc_write_short (struct objc_typed_stream* stream, short value)
+{
+  unsigned char buf[sizeof (short)+1];
+  int len = __objc_code_short (buf, value);
+  return (*stream->write)(stream->physical, buf, len);
+}
+      
+
+static __inline__ int
+__objc_code_unsigned_int (unsigned char* buf, unsigned int val)
+{
+  if (val < 0x10000)
+    return __objc_code_unsigned_short (buf, val%0x10000);
+
+  else if (val < 0x1000000)
+    {
+      buf[0] = _B_NINT|3;
+      buf[1] = val/0x10000;
+      buf[2] = (val%0x10000)/0x100;
+      buf[3] = val%0x100;
+      return 4;
+    }
+
+  else 
+    {
+      buf[0] = _B_NINT|4;
+      buf[1] = val/0x1000000;
+      buf[2] = (val%0x1000000)/0x10000;
+      buf[3] = (val%0x10000)/0x100;
+      buf[4] = val%0x100;
+      return 5;
+    }
+}
+
+int
+objc_write_unsigned_int (struct objc_typed_stream* stream, unsigned int value)
+{
+  unsigned char buf[sizeof(unsigned int)+1];
+  int len = __objc_code_unsigned_int (buf, value);
+  return (*stream->write)(stream->physical, buf, len);
+}
+
+static __inline__ int
+__objc_code_int (unsigned char* buf, int val)
+{
+  if (val >= 0)
+    return __objc_code_unsigned_int (buf, val);
+
+  if (val > -0x7f)
+    return __objc_code_char (buf, val);
+
+  else 
+    {
+      int len = __objc_code_unsigned_int (buf, -val);
+      buf[0] |= _B_SIGN;
+      return len;
+    }
+}
+
+int
+objc_write_int (struct objc_typed_stream* stream, int value)
+{
+  unsigned char buf[sizeof(int)+1];
+  int len = __objc_code_int (buf, value);
+  return (*stream->write)(stream->physical, buf, len);
+}
+
+int
+objc_write_string (struct objc_typed_stream* stream,
+                  const unsigned char* string, unsigned int nbytes)
+{
+  unsigned char buf[sizeof(unsigned int)+1];
+  int len = __objc_code_unsigned_int (buf, nbytes);
+  
+  if ((buf[0]&_B_CODE) == _B_SINT)
+    buf[0] = (buf[0]&_B_VALUE)|_B_SSTR;
+
+  else /* _B_NINT */
+    buf[0] = (buf[0]&_B_VALUE)|_B_NSTR;
+
+  if ((*stream->write)(stream->physical, buf, len) != 0)
+    return (*stream->write)(stream->physical, string, nbytes);
+  else
+    return 0;
+}
+
+int
+objc_write_string_atomic (struct objc_typed_stream* stream,
+                         unsigned char* string, unsigned int nbytes)
+{
+  unsigned int key;
+  if ((key = (unsigned int)hash_value_for_key (stream->stream_table, string)))
+    return objc_write_use_common (stream, key);
+  else
+    {
+      int length;
+      hash_add (&stream->stream_table, (void*)key=(unsigned int)string, string);
+      if ((length = objc_write_register_common (stream, key)))
+       return objc_write_string (stream, string, nbytes);
+      return length;
+    }
+}
+
+static int
+objc_write_register_common (struct objc_typed_stream* stream, unsigned int key)
+{
+  unsigned char buf[sizeof (unsigned int)+2];
+  int len = __objc_code_unsigned_int (buf+1, key);
+  if (len == 1)
+    {
+      buf[0] = _B_RCOMM|0x01;
+      buf[1] &= _B_VALUE;
+      return (*stream->write)(stream->physical, buf, len+1);
+    }
+  else
+    {
+      buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
+      return (*stream->write)(stream->physical, buf+1, len);
+    }
+}
+
+static int
+objc_write_use_common (struct objc_typed_stream* stream, unsigned int key)
+{
+  unsigned char buf[sizeof (unsigned int)+2];
+  int len = __objc_code_unsigned_int (buf+1, key);
+  if (len == 1)
+    {
+      buf[0] = _B_UCOMM|0x01;
+      buf[1] &= _B_VALUE;
+      return (*stream->write)(stream->physical, buf, 2);
+    }
+  else
+    {
+      buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
+      return (*stream->write)(stream->physical, buf+1, len);
+    }
+}
+
+static __inline__ int
+__objc_write_extension (struct objc_typed_stream* stream, unsigned char code)
+{
+  if (code <= _B_VALUE)
+    {
+      unsigned char buf = code|_B_EXT;
+      return (*stream->write)(stream->physical, &buf, 1);
+    }
+  else 
+    abort();
+}
+
+__inline__ int
+__objc_write_object (struct objc_typed_stream* stream, id object)
+{
+  unsigned char buf = '\0';
+  SEL write_sel = sel_get_uid ("write:");
+  if (object)
+    {
+      __objc_write_extension (stream, _BX_OBJECT);
+      objc_write_class (stream, object->class_pointer);
+      (*objc_msg_lookup(object, write_sel))(object, write_sel, stream);
+      return (*stream->write)(stream->physical, &buf, 1);
+    }
+  else
+    return objc_write_use_common(stream, 0);
+}
+
+int 
+objc_write_object (struct objc_typed_stream* stream, id object)
+{
+  unsigned int key;
+  if ((key = (unsigned int)hash_value_for_key (stream->stream_table, object)))
+    return objc_write_use_common (stream, key);
+
+  else if (object == nil)
+    return objc_write_use_common(stream, 0);
+
+  else
+    {
+      int length;
+      hash_add (&stream->stream_table, (void*)key=(unsigned int)object, object);
+      if ((length = objc_write_register_common (stream, key)))
+       return __objc_write_object (stream, object);
+      return length;
+    }
+}
+
+__inline__ int
+__objc_write_class (struct objc_typed_stream* stream, struct objc_class* class)
+{
+  unsigned char buf = '\0';
+  SEL write_sel = sel_get_uid ("write:");
+  __objc_write_extension (stream, _BX_CLASS);
+  objc_write_string_atomic(stream, (char*)class->name,
+                          strlen(class->name));
+  objc_write_unsigned_int (stream, CLS_GETNUMBER(class));
+  (*objc_msg_lookup(class, write_sel))(class, write_sel, stream);
+  return (*stream->write)(stream->physical, &buf, 1);
+}
+
+
+static int 
+objc_write_class (struct objc_typed_stream* stream,
+                        struct objc_class* class)
+{
+  unsigned int key;
+  if ((key = (unsigned int)hash_value_for_key (stream->stream_table, class)))
+    return objc_write_use_common (stream, key);
+  else
+    {
+      int length;
+      hash_add (&stream->stream_table, (void*)key=(unsigned int)class, class);
+      if ((length = objc_write_register_common (stream, key)))
+       return __objc_write_class (stream, class);
+      return length;
+    }
+}
+
+
+__inline__ int 
+__objc_write_selector (struct objc_typed_stream* stream, SEL selector)
+{
+  const char* sel_name = sel_get_name (selector);
+  __objc_write_extension (stream, _BX_SEL);
+  return objc_write_string (stream, sel_name, strlen(sel_name));
+}
+
+int 
+objc_write_selector (struct objc_typed_stream* stream, SEL selector)
+{
+  const char* sel_name = sel_get_name (selector);
+  unsigned int key;
+  if ((key = (unsigned int)hash_value_for_key (stream->stream_table, sel_name)))
+    return objc_write_use_common (stream, key);
+  else
+    {
+      int length;
+      hash_add (&stream->stream_table, (void*)key=(unsigned int)sel_name, (char*)sel_name);
+      if ((length = objc_write_register_common (stream, key)))
+       return __objc_write_selector (stream, selector);
+      return length;
+    }
+}
+
+
+
+/*
+** Read operations 
+*/
+
+__inline__ int
+objc_read_char (struct objc_typed_stream* stream, char* val)
+{
+  unsigned char buf;
+  int len;
+  len = (*stream->read)(stream->physical, &buf, 1);
+  if (len != 0)
+    {
+      if ((buf & _B_CODE) == _B_SINT)
+       (*val) = (buf & _B_VALUE);
+
+      else if ((buf & _B_NUMBER) == 1)
+       {
+         len = (*stream->read)(stream->physical, val, 1);
+         if (buf&_B_SIGN)
+           (*val) = -1*(*val);
+       }
+
+      else
+       __objc_fatal("expected 8bit signed int, got %dbit int",
+                    (int)(buf&_B_NUMBER)*8);
+    }
+  return len;
+}
+
+
+__inline__ int
+objc_read_unsigned_char (struct objc_typed_stream* stream, unsigned char* val)
+{
+  unsigned char buf;
+  int len;
+  if ((len = (*stream->read)(stream->physical, &buf, 1)))
+    {
+      if ((buf & _B_CODE) == _B_SINT)
+       (*val) = (buf & _B_VALUE);
+
+      else if ((buf & _B_NUMBER) == 1)
+       len = (*stream->read)(stream->physical, val, 1);
+
+      else
+       __objc_fatal("expected 8bit unsigned int, got %dbit int",
+                    (int)(buf&_B_NUMBER)*8);
+    }
+  return len;
+}
+
+__inline__ int
+objc_read_short (struct objc_typed_stream* stream, short* value)
+{
+  unsigned char buf[sizeof(short)+1];
+  int len;
+  if ((len = (*stream->read)(stream->physical, buf, 1)))
+    {
+      if ((buf[0] & _B_CODE) == _B_SINT)
+       (*value) = (buf[0] & _B_VALUE);
+
+      else
+       {
+         int pos = 1;
+         int nbytes = buf[0] & _B_NUMBER;
+         if (nbytes > sizeof (short))
+           __objc_fatal("expected short, got bigger (%dbits)", nbytes*8);
+         len = (*stream->read)(stream->physical, buf+1, nbytes);
+         (*value) = 0;
+         while (pos <= nbytes)
+           (*value) = ((*value)*0x100) + buf[pos++];
+         if (buf[0] & _B_SIGN)
+           (*value) = -(*value);
+       }
+    }
+  return len;
+}
+
+__inline__ int
+objc_read_unsigned_short (struct objc_typed_stream* stream,
+                         unsigned short* value)
+{
+  unsigned char buf[sizeof(unsigned short)+1];
+  int len;
+  if ((len = (*stream->read)(stream->physical, buf, 1)))
+    {
+      if ((buf[0] & _B_CODE) == _B_SINT)
+       (*value) = (buf[0] & _B_VALUE);
+
+      else
+       {
+         int pos = 1;
+         int nbytes = buf[0] & _B_NUMBER;
+         if (nbytes > sizeof (short))
+           __objc_fatal("expected short, got int or bigger");
+         len = (*stream->read)(stream->physical, buf+1, nbytes);
+         (*value) = 0;
+         while (pos <= nbytes)
+           (*value) = ((*value)*0x100) + buf[pos++];
+       }
+    }
+  return len;
+}
+
+
+__inline__ int
+objc_read_int (struct objc_typed_stream* stream, int* value)
+{
+  unsigned char buf[sizeof(int)+1];
+  int len;
+  if ((len = (*stream->read)(stream->physical, buf, 1)))
+    {
+      if ((buf[0] & _B_CODE) == _B_SINT)
+       (*value) = (buf[0] & _B_VALUE);
+
+      else
+       {
+         int pos = 1;
+         int nbytes = buf[0] & _B_NUMBER;
+         if (nbytes > sizeof (int))
+           __objc_fatal("expected int, got bigger");
+         len = (*stream->read)(stream->physical, buf+1, nbytes);
+         (*value) = 0;
+         while (pos <= nbytes)
+           (*value) = ((*value)*0x100) + buf[pos++];
+         if (buf[0] & _B_SIGN)
+           (*value) = -(*value);
+       }
+    }
+  return len;
+}
+
+__inline__ int
+__objc_read_nbyte_uint (struct objc_typed_stream* stream,
+                      unsigned int nbytes, unsigned int* val)
+{
+  int len, pos = 0;
+  unsigned char buf[sizeof(unsigned int)+1];
+
+  if (nbytes > sizeof (int))
+    __objc_fatal("expected int, got bigger");
+
+  len = (*stream->read)(stream->physical, buf, nbytes);
+  (*val) = 0;
+  while (pos < nbytes)
+    (*val) = ((*val)*0x100) + buf[pos++];
+  return len;
+}
+  
+
+__inline__ int
+objc_read_unsigned_int (struct objc_typed_stream* stream,
+                       unsigned int* value)
+{
+  unsigned char buf[sizeof(unsigned int)+1];
+  int len;
+  if ((len = (*stream->read)(stream->physical, buf, 1)))
+    {
+      if ((buf[0] & _B_CODE) == _B_SINT)
+       (*value) = (buf[0] & _B_VALUE);
+
+      else
+       len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value);
+
+    }
+  return len;
+}
+
+__inline__ int
+objc_read_string (struct objc_typed_stream* stream,
+                 char** string)
+{
+  unsigned char buf[sizeof(unsigned int)+1];
+  int len;
+  if ((len = (*stream->read)(stream->physical, buf, 1)))
+    {
+      unsigned int key = 0;
+
+      if ((buf[0]&_B_CODE) == _B_RCOMM)        /* register following */
+       {
+         len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+         len = (*stream->read)(stream->physical, buf, 1);
+       }
+
+      switch (buf[0]&_B_CODE) {
+      case _B_SSTR:
+       {
+         int length = buf[0]&_B_VALUE;
+         (*string) = (char*)malloc(length+1);
+         if (key)
+           hash_add (&stream->stream_table, (void*)key, *string);
+         len = (*stream->read)(stream->physical, *string, length);
+         (*string)[length] = '\0';
+       }
+       break;
+
+      case _B_UCOMM:
+       {
+         len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+         (*string) = hash_value_for_key (stream->stream_table, (void*)key);
+       }
+       break;
+
+      case _B_NSTR:
+       {
+         unsigned int nbytes = buf[0]&_B_VALUE;
+         len = __objc_read_nbyte_uint(stream, nbytes, &nbytes);
+         if (len) {
+           (*string) = (char*)malloc(nbytes);
+           if (key)
+             hash_add (&stream->stream_table, (void*)key, *string);
+           len = (*stream->read)(stream->physical, *string, buf[0]&_B_VALUE);
+           (*string)[nbytes] = '\0';
+         }
+       }
+       break;
+       
+      default:
+       __objc_fatal("expected string, got opcode %c\n", (buf[0]&_B_CODE));
+      }
+    }
+
+  return len;
+}
+
+
+int
+objc_read_object (struct objc_typed_stream* stream, id* object)
+{
+  unsigned char buf[sizeof (unsigned int)];
+  int len;
+  if ((len = (*stream->read)(stream->physical, buf, 1)))
+    {
+      SEL read_sel = sel_get_uid ("read:");
+      unsigned int key = 0;
+
+      if ((buf[0]&_B_CODE) == _B_RCOMM)        /* register common */
+       {
+         len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+         len = (*stream->read)(stream->physical, buf, 1);
+       }
+
+      if (buf[0] == (_B_EXT | _BX_OBJECT))
+       {
+         Class* class;
+
+         /* get class */
+         len = objc_read_class (stream, &class);
+
+         /* create instance */
+         (*object) = class_create_instance(class);
+
+         /* register? */
+         if (key)
+           hash_add (&stream->stream_table, (void*)key, *object);
+
+         /* send -read: */
+         if (__objc_responds_to (*object, read_sel))
+           (*get_imp(class, read_sel))(*object, read_sel, stream);
+
+         /* check null-byte */
+         len = (*stream->read)(stream->physical, buf, 1);
+         if (buf[0] != '\0')
+           __objc_fatal("expected null-byte, got opcode %c", buf[0]);
+       }
+
+      else if ((buf[0]&_B_CODE) == _B_UCOMM)
+       {
+         if (key)
+           __objc_fatal("cannot register use upcode...");
+         len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+         (*object) = hash_value_for_key (stream->stream_table, (void*)key);
+       }
+
+      else
+       __objc_fatal("expected object, got opcode %c", buf[0]);
+    }
+  return len;
+}
+
+static int
+objc_read_class (struct objc_typed_stream* stream, Class** class)
+{
+  unsigned char buf[sizeof (unsigned int)];
+  int len;
+  if ((len = (*stream->read)(stream->physical, buf, 1)))
+    {
+      SEL read_sel = sel_get_uid ("read:");
+      unsigned int key = 0;
+
+      if ((buf[0]&_B_CODE) == _B_RCOMM)        /* register following */
+       {
+         len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+         len = (*stream->read)(stream->physical, buf, 1);
+       }
+
+      if (buf[0] == (_B_EXT | _BX_CLASS))
+       {
+         char* class_name;
+         int version;
+
+         /* get class */
+         len = objc_read_string (stream, &class_name);
+         (*class) = objc_get_class(class_name);
+         free (class_name);
+
+         /* register */
+         if (key)
+           hash_add (&stream->stream_table, (void*)key, *class);
+
+         /* call +read: */
+         (*objc_msg_lookup(*class, read_sel))(*class, read_sel, stream);
+
+         objc_read_unsigned_int(stream, &version);
+         hash_add (&stream->class_table, (*class)->name, (void*)version);
+
+         /* check null-byte */
+         len = (*stream->read)(stream->physical, buf, 1);
+         if (buf[0] != '\0')
+           __objc_fatal("expected null-byte, got opcode %c", buf[0]);
+       }
+
+      else if ((buf[0]&_B_CODE) == _B_UCOMM)
+       {
+         if (key)
+           __objc_fatal("cannot register use upcode...");
+         len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+         (*class) = hash_value_for_key (stream->stream_table, (void*)key);
+         if (!*class)
+           __objc_fatal("cannot find class for key %x", key);
+       }
+
+      else
+       __objc_fatal("expected class, got opcode %c", buf[0]);
+    }
+  return len;
+}
+
+int
+objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
+{
+  unsigned char buf[sizeof (unsigned int)];
+  int len;
+  if ((len = (*stream->read)(stream->physical, buf, 1)))
+    {
+      unsigned int key = 0;
+
+      if ((buf[0]&_B_CODE) == _B_RCOMM)        /* register following */
+       {
+         len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+         len = (*stream->read)(stream->physical, buf, 1);
+       }
+
+      if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
+       {
+         char* selector_name;
+
+         /* get selector */
+         len = objc_read_string (stream, &selector_name);
+         (*selector) = sel_get_uid(selector_name);
+         free (selector_name);
+
+         /* register */
+         if (key)
+           hash_add (&stream->stream_table, (void*)key, *selector);
+       }
+
+      else if ((buf[0]&_B_CODE) == _B_UCOMM)
+       {
+         if (key)
+           __objc_fatal("cannot register use upcode...");
+         len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+         (*selector) = hash_value_for_key (stream->stream_table, (void*)key);
+       }
+
+      else
+       __objc_fatal("expected selector, got opcode %c", buf[0]);
+    }
+  return len;
+}
+
+static int
+objc_sizeof_type(const char* type)
+{
+  switch(*type) {
+  case _C_ID: return sizeof(id);
+    break;
+
+  case _C_CLASS:
+    return sizeof(Class*);
+    break;
+
+  case _C_SEL:
+    return sizeof(SEL);
+    break;
+
+  case _C_CHR:
+    return sizeof(char);
+    break;
+    
+  case _C_UCHR:
+    return sizeof(unsigned char);
+    break;
+
+  case _C_SHT:
+    return sizeof(short);
+    break;
+
+  case _C_USHT:
+    return sizeof(unsigned short);
+    break;
+
+  case _C_INT:
+  case _C_LNG:
+    return sizeof(int);
+    break;
+
+  case _C_UINT:
+  case _C_ULNG:
+    return sizeof(unsigned int);
+    break;
+
+  case _C_ATOM:
+  case _C_CHARPTR:
+    return sizeof(char*);
+    break;
+
+  default:
+    fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
+    abort();
+  }
+}
+
+
+static const char*
+__objc_skip_type (const char* type)
+{
+  switch (*type) {
+  case _C_ID:
+  case _C_CLASS:
+  case _C_SEL:
+  case _C_CHR:
+  case _C_UCHR:
+  case _C_CHARPTR:
+  case _C_ATOM:
+  case _C_SHT:
+  case _C_USHT:
+  case _C_INT:
+  case _C_UINT:
+  case _C_LNG:
+  case _C_ULNG:
+  case _C_FLT:
+  case _C_DBL:
+    return ++type;
+    break;
+
+  case _C_ARY_B:
+    while(isdigit(*++type));
+    type = __objc_skip_type(type);
+    if (*type == _C_ARY_E)
+      return ++type;
+    else
+      __objc_fatal("cannot parse typespec: %s", type);
+    break;
+
+  default:
+    fprintf(stderr, "objc_read_types: cannot parse typespec: %s\n", type);
+    abort();
+  }
+}
+
+/*
+** USER LEVEL FUNCTIONS
+*/
+
+/*
+** Write one object, encoded in TYPE and pointed to by DATA to the
+** typed stream STREAM.  
+*/
+
+int
+objc_write_type(TypedStream* stream, const char* type, const void* data)
+{
+  switch(*type) {
+  case _C_ID:
+    return objc_write_object (stream, *(id*)data);
+    break;
+
+  case _C_CLASS:
+    return objc_write_class (stream, *(Class**)data);
+    break;
+
+  case _C_SEL:
+    return objc_write_selector (stream, *(SEL*)data);
+    break;
+
+  case _C_CHR:
+    return objc_write_char(stream, *(char*)data);
+    break;
+    
+  case _C_UCHR:
+    return objc_write_unsigned_char(stream, *(unsigned char*)data);
+    break;
+
+  case _C_SHT:
+    return objc_write_short(stream, *(short*)data);
+    break;
+
+  case _C_USHT:
+    return objc_write_unsigned_short(stream, *(unsigned short*)data);
+    break;
+
+  case _C_INT:
+  case _C_LNG:
+    return objc_write_int(stream, *(int*)data);
+    break;
+
+  case _C_UINT:
+  case _C_ULNG:
+    return objc_write_unsigned_int(stream, *(unsigned int*)data);
+    break;
+
+  case _C_CHARPTR:
+    return objc_write_string (stream, (char*)data, strlen((char*)data));
+    break;
+
+  case _C_ATOM:
+    return objc_write_string_atomic (stream, (char*)data, strlen((char*)data));
+    break;
+
+  case _C_ARY_B:
+    {
+      int len = atoi(type+1);
+      while (isdigit(*++type));
+      return objc_write_array (stream, type, len, data);
+    }
+    break; 
+
+  default:
+    fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
+    abort();
+  }
+}
+
+/*
+** Read one object, encoded in TYPE and pointed to by DATA to the
+** typed stream STREAM.  DATA specifies the address of the types to
+** read.  Expected type is checked against the type actually present
+** on the stream. 
+*/
+
+int
+objc_read_type(TypedStream* stream, const char* type, void* data)
+{
+  char c;
+  switch(c = *type) {
+  case _C_ID:
+    return objc_read_object (stream, (id*)data);
+    break;
+
+  case _C_CLASS:
+    return objc_read_class (stream, (Class**)data);
+    break;
+
+  case _C_SEL:
+    return objc_read_selector (stream, (SEL*)data);
+    break;
+
+  case _C_CHR:
+    return objc_read_char (stream, (char*)data);
+    break;
+    
+  case _C_UCHR:
+    return objc_read_unsigned_char (stream, (unsigned char*)data);
+    break;
+
+  case _C_SHT:
+    return objc_read_short (stream, (short*)data);
+    break;
+
+  case _C_USHT:
+    return objc_read_unsigned_short (stream, (unsigned short*)data);
+    break;
+
+  case _C_INT:
+  case _C_LNG:
+    return objc_read_int (stream, (int*)data);
+    break;
+
+  case _C_UINT:
+  case _C_ULNG:
+    return objc_read_unsigned_int (stream, (unsigned int*)data);
+    break;
+
+  case _C_CHARPTR:
+  case _C_ATOM:
+    return objc_read_string (stream, (char**)data);
+    break;
+
+  case _C_ARY_B:
+    {
+      int len = atoi(type+1);
+      while (isdigit(*++type));
+      return objc_read_array (stream, type, len, data);
+    }
+    break; 
+
+  default:
+    fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
+    abort();
+  }
+}
+
+/*
+** Write the object specified by the template TYPE to STREAM.  Last
+** arguments specify addresses of values to be written.  It might 
+** seem surprising to specify values by address, but this is extremely
+** convenient for copy-paste with objc_read_types calls.  A more
+** down-to-the-earth cause for this passing of addresses is that values
+** of arbitrary size is not well supported in ANSI C for functions with
+** variable number of arguments.
+*/
+
+int 
+objc_write_types (TypedStream* stream, const char* type, ...)
+{
+  va_list args;
+  const char *c;
+  int res = 0;
+
+  va_start(args, type);
+
+  for (c = type; *c; c = __objc_skip_type (c))
+    {
+      switch(*c) {
+      case _C_ID:
+       res = objc_write_object (stream, *va_arg (args, id*));
+       break;
+
+      case _C_CLASS:
+       res = objc_write_class (stream, *va_arg(args, Class**));
+       break;
+
+      case _C_SEL:
+       res = objc_write_selector (stream, *va_arg(args, SEL*));
+       break;
+       
+      case _C_CHR:
+       res = objc_write_char (stream, *va_arg (args, char*));
+       break;
+       
+      case _C_UCHR:
+       res = objc_write_unsigned_char (stream,
+                                       *va_arg (args, unsigned char*));
+       break;
+       
+      case _C_SHT:
+       res = objc_write_short (stream, *va_arg(args, short*));
+       break;
+
+      case _C_USHT:
+       res = objc_write_unsigned_short (stream,
+                                        *va_arg(args, unsigned short*));
+       break;
+
+      case _C_INT:
+      case _C_LNG:
+       res = objc_write_int(stream, *va_arg(args, int*));
+       break;
+       
+      case _C_UINT:
+      case _C_ULNG:
+       res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*));
+       break;
+
+      case _C_CHARPTR:
+       {
+         char* str = va_arg(args, char*);
+         res = objc_write_string (stream, str, strlen(str));
+       }
+       break;
+
+      case _C_ATOM:
+       {
+         char* str = va_arg(args, char*);
+         res = objc_write_string_atomic (stream, str, strlen(str));
+       }
+       break;
+
+      case _C_ARY_B:
+       {
+         int len = atoi(c+1);
+         const char* t = c;
+         while (isdigit(*++t));
+         res = objc_write_array (stream, t, len, va_arg(args, void*));
+         t = __objc_skip_type (t);
+         if (*t != _C_ARY_E)
+           __objc_fatal("expected `]', got: %s", t);
+       }
+       break; 
+       
+      default:
+       fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
+       abort();
+      }
+    }
+  va_end(args);
+  return res;
+}
+
+
+/* 
+** Last arguments specify addresses of values to be read.  Expected
+** type is checked against the type actually present on the stream. 
+*/
+
+int 
+objc_read_types(TypedStream* stream, const char* type, ...)
+{
+  va_list args;
+  const char *c;
+  int res = 0;
+
+  va_start(args, type);
+
+  for (c = type; *c; c = __objc_skip_type(c))
+    {
+      switch(*c) {
+      case _C_ID:
+       res = objc_read_object(stream, va_arg(args, id*));
+       break;
+
+      case _C_CLASS:
+       res = objc_read_class(stream, va_arg(args, Class**));
+       break;
+
+      case _C_SEL:
+       res = objc_read_selector(stream, va_arg(args, SEL*));
+       break;
+       
+      case _C_CHR:
+       res = objc_read_char(stream, va_arg(args, char*));
+       break;
+       
+      case _C_UCHR:
+       res = objc_read_unsigned_char(stream, va_arg(args, unsigned char*));
+       break;
+       
+      case _C_SHT:
+       res = objc_read_short(stream, va_arg(args, short*));
+       break;
+
+      case _C_USHT:
+       res = objc_read_unsigned_short(stream, va_arg(args, unsigned short*));
+       break;
+
+      case _C_INT:
+      case _C_LNG:
+       res = objc_read_int(stream, va_arg(args, int*));
+       break;
+       
+      case _C_UINT:
+      case _C_ULNG:
+       res = objc_read_unsigned_int(stream, va_arg(args, unsigned int*));
+       break;
+
+      case _C_CHARPTR:
+      case _C_ATOM:
+       {
+         char** str = va_arg(args, char**);
+         res = objc_read_string (stream, str);
+       }
+       break;
+
+      case _C_ARY_B:
+       {
+         int len = atoi(c+1);
+         const char* t = c;
+         while (isdigit(*++t));
+         res = objc_read_array (stream, t, len, va_arg(args, void*));
+         t = __objc_skip_type (t);
+         if (*t != _C_ARY_E)
+           __objc_fatal("expected `]', got: %s", t);
+       }
+       break; 
+       
+      default:
+       fprintf(stderr, "objc_read_type: cannot parse typespec: %s\n", type);
+       abort();
+      }
+    }
+  va_end(args);
+  return res;
+}
+
+/*
+** Write an array of COUNT elements of TYPE from the memory address DATA.
+** This is equivalent of objc_write_type (stream, "[N<type>]", data)
+*/
+
+int
+objc_write_array (TypedStream* stream, const char* type,
+                 int count, const void* data)
+{
+  int off = objc_sizeof_type(type);
+  const char* where = data;
+
+  while (count-- > 0)
+    {
+      objc_write_type(stream, type, where);
+      where += off;
+    }
+  return 1;
+}
+
+/*
+** Read an array of COUNT elements of TYPE into the memory address
+** DATA.  The memory pointed to by data is supposed to be allocated
+** by the callee.  This is equivalent of 
+**   objc_read_type (stream, "[N<type>]", data)
+*/
+
+int
+objc_read_array (TypedStream* stream, const char* type,
+                int count, void* data)
+{
+  int off = objc_sizeof_type(type);
+  char* where = (char*)data;
+
+  while (count-- > 0)
+    {
+      objc_read_type(stream, type, where);
+      where += off;
+    }
+  return 1;
+}
+
+static int 
+__objc_fread(FILE* file, char* data, int len)
+{
+  return fread(data, len, 1, file);
+}
+
+static int 
+__objc_fwrite(FILE* file, char* data, int len)
+{
+  return fwrite(data, len, 1, file);
+}
+
+static int
+__objc_feof(FILE* file)
+{
+  return feof(file);
+}
+
+static int 
+__objc_no_write(FILE* file, char* data, int len)
+{
+  __objc_fatal ("TypedStream not open for writing");
+}
+
+static int 
+__objc_no_read(FILE* file, char* data, int len)
+{
+  __objc_fatal ("TypedStream not open for reading");
+}
+
+static int
+__objc_read_typed_stream_signature (TypedStream* stream)
+{
+  char buffer[80];
+  int pos = 0;
+  do
+    (*stream->read)(stream->physical, buffer+pos, 1);
+  while (buffer[pos++] != '\0');
+  sscanf (buffer, "GNU TypedStream %d", &stream->version);
+  if (stream->version != OBJC_TYPED_STREAM_VERSION)
+    __objc_fatal ("cannot handle TypedStream version %d", stream->version);
+}
+
+static int
+__objc_write_typed_stream_signature (TypedStream* stream)
+{
+  char buffer[80];
+  sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
+  stream->version = OBJC_TYPED_STREAM_VERSION;
+  (*stream->write)(stream->physical, buffer, strlen(buffer)+1);
+}
+
+/*
+** Open the stream PHYSICAL in MODE
+*/
+
+TypedStream* 
+objc_open_typed_stream (FILE* physical, int mode)
+{
+  int fflush(FILE*);
+
+  TypedStream* s = (TypedStream*)malloc(sizeof(TypedStream));
+
+  s->mode = mode;
+  s->physical = physical;
+  s->stream_table = hash_new(64,
+                            (hash_func_type)hash_ptr,
+                            (compare_func_type)compare_ptrs);
+  s->eof = (objc_typed_eof_func)__objc_feof;
+  s->flush = (objc_typed_flush_func)fflush;
+  if (mode == OBJC_READONLY)
+    {
+      s->class_table = hash_new(8, (hash_func_type)hash_string,
+                               (compare_func_type)compare_strings);
+      s->read = (objc_typed_read_func)__objc_fread;
+      s->write = (objc_typed_write_func)__objc_no_write;
+      __objc_read_typed_stream_signature (s);
+    }
+  else if (mode == OBJC_WRITEONLY)
+    {
+      s->class_table = 0;
+      s->read = (objc_typed_read_func)__objc_no_read;
+      s->write = (objc_typed_write_func)__objc_fwrite;
+      __objc_write_typed_stream_signature (s);
+    }      
+  else
+    {
+      objc_close_typed_stream (s);
+      return NULL;
+    }
+  s->type = OBJC_FILE_STREAM;
+  return s;
+}
+
+/*
+** Open the file named by FILE_NAME in MODE
+*/
+
+TypedStream*
+objc_open_typed_stream_for_file (const char* file_name, int mode)
+{
+  FILE* file = NULL;
+  TypedStream* s;
+
+  if (mode == OBJC_READONLY)
+    file = fopen (file_name, "r");
+  else
+    file = fopen (file_name, "w");
+
+  if (file)
+    {
+      s = objc_open_typed_stream (file, mode);
+      if (s)
+       s->type |= OBJC_MANAGED_STREAM;
+      return s;
+    }
+  else
+    return NULL;
+}
+
+/*
+** Close STREAM freeing the structure it self.  If it was opened with 
+** objc_open_typed_stream_for_file, the file will also be closed.
+*/
+
+void
+objc_close_typed_stream (TypedStream* stream)
+{
+  if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
+    fclose ((FILE*)stream->physical);
+  hash_delete (stream->stream_table);
+  if (stream->mode == OBJC_READONLY)
+    hash_delete (stream->class_table);
+  free (stream);
+}
+
+BOOL
+objc_end_of_typed_stream (TypedStream* stream)
+{
+  return (*stream->eof)(stream->physical);
+}
+
+void
+objc_flush_typed_stream (TypedStream* stream)
+{
+  (*stream->flush)(stream->physical);
+}
+
diff --git a/gcc/objc/class.c b/gcc/objc/class.c
new file mode 100644 (file)
index 0000000..a5feef5
--- /dev/null
@@ -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
diff --git a/gcc/objc/init.c b/gcc/objc/init.c
new file mode 100644 (file)
index 0000000..eb31f24
--- /dev/null
@@ -0,0 +1,272 @@
+/* GNU Objective C Runtime initialization 
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+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 version number of this runtime.  This must match the number 
+   defined in gcc (objc-act.c) */
+#define OBJC_VERSION 5
+#define PROTOCOL_VERSION 2
+
+/* This list contains all modules currently loaded into the runtime */
+static struct objc_list* __objc_module_list = 0;
+
+/* This list contains all proto_list's not yet assigned class links */
+static struct objc_list* unclaimed_proto_list = 0;
+
+/* Check compiler vs runtime version */
+static void init_check_module_version(Module_t);
+
+/* Assign isa links to protos */
+static void __objc_init_protocols (struct objc_protocol_list* protos);
+
+/* Add protocol to class */
+static void __objc_class_add_protocols (Class_t, struct objc_protocol_list*);
+
+/* Is all categories/classes resolved? */
+BOOL __objc_dangling_categories = NO;
+
+/* This function is called by constructor functions generated for each
+   module compiled.  (_GLOBAL_$I$...) The purpose of this function is to
+   gather the module pointers so that they may be processed by the
+   initialization routines as soon as possible */
+
+void
+__objc_exec_class (Module_t module)
+{
+  /* Has we processed any constructors previously?  This flag used to 
+     indicate that some global data structures need to be built.  */ 
+  static BOOL previous_constructors = 0;
+
+  static struct objc_list* unclaimed_categories = 0;
+
+  /* The symbol table (defined in objc.h) generated by gcc */
+  Symtab_t symtab = module->symtab;
+
+  /* Pointer to the class Object class object */
+  Class_t object_class;
+
+  /* Entry used to traverse hash lists */
+  struct objc_list** cell;
+
+  /* The table of selector references for this module */
+  SEL *selectors = symtab->refs; 
+
+  /* dummy counter */
+  int i;
+
+  DEBUG_PRINTF ("received module: %s\n", module->name);
+  /* check gcc version */
+  init_check_module_version(module);
+
+  /* On the first call of this routine, initialize some data structures.  */
+  if (!previous_constructors)
+    {
+      __objc_init_selector_tables();
+      __objc_init_class_tables();
+      __objc_init_dispatch_tables();
+      previous_constructors = 1;
+    }
+
+  /* Save the module pointer for later processing. (not currently used) */
+  __objc_module_list = list_cons(module, __objc_module_list);
+
+  /* Parse the classes in the load module and gather selector information.  */
+  DEBUG_PRINTF ("gathering selectors from module: %s\n", module->name);
+  for (i = 0; i < symtab->cls_def_cnt; ++i)
+    {
+      Class_t class = (Class_t) symtab->defs[i];
+
+      /* Make sure we have what we think.  */
+      assert (CLS_ISCLASS(class));
+      assert (CLS_ISMETA(class->class_pointer));
+      DEBUG_PRINTF ("phase 1, processing class: %s\n", class->name);
+
+      /* Store the class in the class table and assign class numbers.  */
+      __objc_add_class_to_hash (class);
+
+      /* Register all of the selectors in the class and meta class.  */
+      __objc_register_selectors_from_class (class);
+      __objc_register_selectors_from_class ((Class_t) class->class_pointer);
+
+      /* Install the fake dispatch tables */
+      __objc_install_premature_dtable(class);
+      __objc_install_premature_dtable(class->class_pointer);
+
+      if (class->protocols)
+       __objc_init_protocols (class->protocols);
+   }
+
+  /* Replace referenced selectors from names to SEL's.  */
+  for (i = 0; selectors[i]; ++i)
+    selectors[i] = sel_register_name ((const char *) selectors[i]);
+
+  /* Process category information from the module.  */
+  for (i = 0; i < symtab->cat_def_cnt; ++i)
+    {
+      Category_t category = symtab->defs[i + symtab->cls_def_cnt];
+      Class_t class = objc_lookup_class (category->class_name);
+      
+      /* If the class for the category exists then append its methods.  */
+      if (class)
+       {
+
+         DEBUG_PRINTF ("processing categories from (module,object): %s, %s\n",
+                       module->name,
+                       class->name);
+
+         /* Do instance methods.  */
+         if (category->instance_methods)
+           class_add_method_list (class, category->instance_methods);
+
+         /* Do class methods.  */
+         if (category->class_methods)
+           class_add_method_list ((Class_t) class->class_pointer, 
+                                  category->class_methods);
+
+         if (category->protocols)
+           {
+             __objc_init_protocols (category->protocols);
+             __objc_class_add_protocols (class, category->protocols);
+           }
+
+       }
+      else
+       {
+         /* The object to which the category methods belong can't be found.
+            Save the information.  */
+         unclaimed_categories = list_cons(category, unclaimed_categories);
+       }
+    }
+
+  /* Scan the unclaimed category hash.  Attempt to attach any unclaimed
+     categories to objects.  */
+  for (cell = &unclaimed_categories;
+       *cell;
+       *cell && (cell = &(*cell)->tail))
+    {
+      Category_t category = (*cell)->head;
+      Class_t class = objc_lookup_class (category->class_name);
+      
+      if (class)
+       {
+         DEBUG_PRINTF ("attaching stored categories to object: %s\n",
+                       class->name);
+         
+         list_remove_head (cell);
+         
+         if (category->instance_methods)
+           class_add_method_list (class, category->instance_methods);
+         
+         if (category->class_methods)
+           class_add_method_list ((Class_t) class->class_pointer,
+                                  category->class_methods);
+         
+         if (category->protocols)
+           {
+             __objc_init_protocols (category->protocols);
+             __objc_class_add_protocols (class, category->protocols);
+           }
+         
+       }
+    }
+  
+  if (unclaimed_proto_list && objc_lookup_class ("Protocol"))
+    {
+      list_mapcar (unclaimed_proto_list,(void(*)(void*))__objc_init_protocols);
+      list_free (unclaimed_proto_list);
+      unclaimed_proto_list = 0;
+    }
+
+}
+
+/* Sanity check the version of gcc used to compile `module'*/
+static void init_check_module_version(Module_t module)
+{
+  if ((module->version != OBJC_VERSION) || (module->size != sizeof (Module)))
+    {
+      fprintf (stderr, "Module %s version %d doesn't match runtime %d\n",
+              module->name, module->version, OBJC_VERSION);
+      if(module->version > OBJC_VERSION)
+       fprintf (stderr, "Runtime (libobjc.a) is out of date\n");
+      else if (module->version < OBJC_VERSION)
+       fprintf (stderr, "Compiler (gcc) is out of date\n");
+      else
+       fprintf (stderr, "Objective C internal error -- bad Module size\n");
+      abort ();
+    }
+}
+
+static void
+__objc_init_protocols (struct objc_protocol_list* protos)
+{
+  int i;
+  Class_t proto_class;
+
+  if (! protos)
+    return;
+
+  proto_class = objc_lookup_class("Protocol");
+
+  if (proto_class == 0 && ! list_find (&unclaimed_proto_list, protos))
+    {
+      unclaimed_proto_list = list_cons (protos, unclaimed_proto_list);
+      return;
+    }
+
+  assert (protos->next == 0);  /* only single ones allowed */
+
+  for(i = 0; i < protos->count; i++)
+    {
+      if (((int)((id)protos->list[i])->class_pointer) == PROTOCOL_VERSION)
+       ((id)protos->list[i])->class_pointer = proto_class;
+      else
+       {
+         fprintf (stderr,
+                  "Version %d doesn't protocol version %d\n",
+                  ((int)((id)protos->list[i])->class_pointer),
+                  PROTOCOL_VERSION);
+         abort ();
+       }
+    }
+}
+
+static void __objc_class_add_protocols (Class_t class,
+                                       struct objc_protocol_list* protos)
+{
+#ifndef NeXT_OBJC              /* force class Protocol to be linked in */
+  extern char* __objc_class_name_Protocol;
+  char* x = __objc_class_name_Protocol;
+#endif
+
+  /* Well... */
+  if (! protos)
+    return;
+
+  /* Add it... */
+  protos->next = class->protocols;
+  class->protocols = protos;
+}
diff --git a/gcc/objc/misc.c b/gcc/objc/misc.c
new file mode 100644 (file)
index 0000000..53adc82
--- /dev/null
@@ -0,0 +1,78 @@
+/* GNU Objective C Runtime Miscellanious 
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+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"
+
+void* malloc(size_t);
+void* realloc(void*, size_t);
+
+void objc_error(id object, const char* fmt, va_list);
+
+void (*_objc_error)(id, const char*, va_list) = objc_error;
+/* id (*_objc_object_alloc)(Class_t) = 0; */
+/* id (*_objc_object_dispose)(id)    = 0; */
+/* id (*_objc_object_copy)(id)       = 0; */
+
+void
+objc_error(id object, const char* fmt, va_list ap)
+{
+  vfprintf (stderr, fmt, ap);
+  abort ();
+}
+
+volatile void
+objc_fatal(const char* msg)
+{
+  write(2, msg, strlen(msg));
+  abort();
+}
+
+void*
+__objc_xmalloc(size_t size)
+{
+  void* res = malloc(size);
+  if(!res)
+    objc_fatal("Virtual memory exhausted\n");
+  return res;
+}
+
+void*
+__objc_xrealloc(void* mem, size_t size)
+{
+  void* res = realloc(mem, size);
+  if(!res)
+    objc_fatal("Virtual memory exhausted\n");
+  return res;
+}
+
+void*
+__objc_xcalloc(size_t nelem, size_t size)
+{
+  void* res = (void*)calloc(nelem, size);
+  if(!res)
+    objc_fatal("Virtual memory exhausted\n");
+  return res;
+}
diff --git a/gcc/objc/objc-api.h b/gcc/objc/objc-api.h
new file mode 100644 (file)
index 0000000..ff2b3f2
--- /dev/null
@@ -0,0 +1,440 @@
+/* GNU Objective-C Runtime API.
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+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
+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. */
+
+#ifndef __objc_api_INCLUDE_GNU
+#define __objc_api_INCLUDE_GNU
+
+#include <stdlib.h>
+#include <objc/objc.h>
+
+static const ARGSIZE = 96;             /* for `method_get_argsize()' */
+
+/*
+** Points to the function that the runtime system calls to handle
+** an error.  By default, it prints formatted error messages to the
+** standard error stream and calls abort to produce a core file.
+** The function is guaranteed to be passed a valid object and a
+** non-NULL format string.
+*/
+extern void (*_objc_error)(id object, const char *format, va_list args);
+
+/*
+** This is a hook which is called by objc_lookup_class and
+** objc_get_class if the runtime is not able to find the class.
+** This may e.g. try to load in the class using dynamic loading.
+** The function is guaranteed to be passed a non-NULL name string.
+*/
+extern Class_t (*_objc_lookup_class)(const char *name);
+
+/*
+** Points to the function that the runtime system calls to allocate
+** memory for new instances.  Called through class_create_instance(),
+** this function should return a valid block of memory of at least
+** class_get_instance_size() bytes, or nil upon failure.  The
+** function is guaranteed to be passed a valid class object.
+*/
+extern id (*_objc_object_alloc)(Class_t class);
+
+/*
+** Points to the function that the runtime system calls to create
+** an exact copy of an object.  Called through object_copy(), this
+** function should return a new instance of object's class created
+** by class_create_instance() which is bit-identical to object, or
+** nil upon failure.  The function is guaranteed to be passed a
+** valid instance object.
+*/
+extern id (*_objc_object_copy)(id object);
+
+/*
+** Points to the function that the runtime system calls to free
+** instances.  Called through object_dispose(), this function
+** should free the memory pointed to by object and return nil.
+** This function is not responsible for freeing memory pointed
+** to by any of the object's instance variables.  The function
+** is guaranteed to be passed a valid instance object.
+*/
+extern id (*_objc_object_dispose)(id object);
+
+/*
+** Searches for a class method specified by aSel, starting with the
+** metaclass class and proceeding up the class hierarchy, until either
+** the method is found or the root class has been examined.  Returns
+** a pointer to the method's Method structure if found.  Returns the
+** value METHOD_NULL if the method is not found, class is not a
+** metaclass object, or aSel is not a valid selector.
+*/
+Method_t class_get_class_method(MetaClass_t class, SEL aSel);
+
+/*
+** Searches for an instance method specified by aSel, starting with
+** the class class and proceeding up the class hierarchy, until either
+** the method is found or the root class has been examined.  Returns
+** a pointer to the method's Method structure if found.  Returns the
+** value METHOD_NULL if the method is not found, class is not a class
+** object, or aSel is not a valid selector.
+*/
+Method_t class_get_instance_method(Class_t class, SEL aSel);
+
+/*
+** Causes impostor to pose as its superclass.  Messages sent to the
+** superclass will actually be sent to the posing class.  Instance
+** variables may not be declared in the posing class.  The posing
+** class can add new methods to the class or override existing methods
+** in the superclass.  Returns non-nil on success.  Returns nil if
+** either of impostor or superclass are not class objects, impostor is
+** not a subclass of superclass, or upon some other error.
+*/
+Class_t class_pose_as(Class_t impostor, Class_t superclass);
+
+/*
+** Returns 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);
+
+/*
+** Returns 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);
+
+/*
+** Returns the method name associated with selector, or NULL
+** if selector is not defined.
+*/
+const char *sel_get_name(SEL selector);
+
+/*
+** Returns the selector associated with the method name name.  If name
+** has not been defined or name is NULL, 0 is returned.
+*/
+SEL sel_get_uid(const char *name);
+
+/*
+** Registers a selector for name and returns the new selector.  If
+** name is NULL or the empty string (""), 0 is returned.
+*/
+SEL sel_register_name(const char *name);
+
+/*
+** Indicate if aSel is a valid selector.  This is not a safe
+** operation, and it should really never be nessecary to use.
+*/
+BOOL sel_is_mapped (SEL aSel);
+
+/*******************************************************************/
+/*                                                                 */
+/* Internal __inline functions                                     */
+/*                                                                 */
+/*******************************************************************/
+
+/*
+** Allocates memory for a new object of class class by calling the
+** function specified by the variable _objc_object_alloc if non-zero,
+** otherwise uses a default method.  Then, initializes the object's
+** isa instance variable to class, and returns the new object.
+** Returns nil if the memory could not be allocated or class is not
+** a class object.
+*/
+extern inline id
+class_create_instance(Class_t class)
+{
+  id new = nil;
+  if (CLS_ISCLASS(class))
+    new = (_objc_object_alloc
+           ?(*_objc_object_alloc)(class)
+           :(id)malloc(class->instance_size));
+  if (new!=nil)
+    new->class_pointer = class;
+  return new;
+}
+
+/*
+** Returns name of the class class or empty string if class is not
+** a class object.  If class is Nil, the string "Nil" is returned.
+*/
+static inline const char *
+class_get_class_name(Class_t class)
+{
+  return CLS_ISCLASS(class)?class->name:((class==Nil)?"Nil":0);
+}
+
+/*
+** Returns the size of an instance of class class in bytes, or 0 if
+** class is not a class.  The size of an instance is at least 4 bytes.
+*/
+static inline long
+class_get_instance_size(Class_t class)
+{
+  return CLS_ISCLASS(class)?class->instance_size:0;
+}
+
+/*
+** Returns a pointer to class's metaclass, or Nil if class is not a
+** class.
+*/
+static inline MetaClass_t
+class_get_meta_class(Class_t class)
+{
+  return CLS_ISCLASS(class)?class->class_pointer:Nil;
+}
+
+/*
+** Returns a pointer to class's superclass, or Nil if class is not a
+** class.  Note that the superclass of Object is Nil.
+*/
+static inline Class_t
+class_get_super_class(Class_t class)
+{
+  return CLS_ISCLASS(class)?class->super_class:Nil;
+}
+
+/*
+** Returns the version number for the class, or -1 if class is not a
+** class.
+*/
+static inline int
+class_get_version(Class_t class)
+{
+  return CLS_ISCLASS(class)?class->version:-1;
+}
+
+/*
+** Returns YES if class is a class, or NO if not.
+*/
+static inline BOOL
+class_is_class(Class_t class)
+{
+  return CLS_ISCLASS(class);
+}
+
+/*
+** Returns YES if class is a metaclass, or NO if not.
+*/
+static inline BOOL
+class_is_meta_class(Class_t class)
+{
+  return CLS_ISMETA(class);
+}
+
+
+/*
+** Sets the version number of class class.  Does nothing if class is
+** not a class.
+*/
+static inline void
+class_set_version(Class_t class, long version)
+{
+  if (CLS_ISCLASS(class))
+    class->version = version;
+}
+
+/*
+** Returns the size in bytes of the argument frame to a method.  Since
+** at least two parameters (self and _cmd) are sent to each method, this
+** value will be at least 8.  If method is not a valid method, 0 is
+** returned.
+** 
+** Currently, the frame size info is only reliable on a NeXT, so until
+** we get this fixed, we'll use a value which is most possibly large
+** enough. You can possibly reduce this value (96) on anything but a
+** Sparc if you don't return structs from the methods forwarded to.
+*/
+static inline unsigned int
+method_get_argsize(Method_t method)
+{
+  return ARGSIZE;              /* This was a magic number (96)... */
+}
+
+/*
+** Returns a pointer to the implementation of method method.  If method
+** is not a method, NULL is returned.
+*/
+static inline IMP
+method_get_imp(Method_t method)
+{
+  return (method!=METHOD_NULL)?method->method_imp:(IMP)0;
+}
+
+/*
+** Returns the implementation (pointer to function) of the method
+** identified by a (class, selector) pair.  Use this, and *not* 
+** objc_msg_lookup, since objc_msg_lookup may eventually return a
+** pointer to an internal function which does lazy initialization...
+*/
+IMP get_imp (Class_t class, SEL sel);
+
+/*
+** Creates a new instance object that's an exact copy of object by
+** calling the function pointed to by the variable _objc_object_copy if
+** non-zero, otherwise uses a default method.  Returns the new object.
+** Returns nil if object is not an instance object, memory for the new
+** object could not be allocated, or some other error occurred.
+*/
+extern inline id
+object_copy(id object)
+{
+  if ((object!=nil)&&CLS_ISCLASS(object->class_pointer))
+    {
+      if (_objc_object_copy)
+        return (*_objc_object_copy)(object);
+      else
+        {
+          id copy = class_create_instance(object->class_pointer);
+          if (copy!=nil)
+            bcopy(object, copy, object->class_pointer->instance_size);
+          return copy;
+        }
+      return nil;
+    }
+}
+
+/*
+** Frees the memory occupied by object by calling the function pointed
+** to by the variable _objc_object_dispose if non-zero, otherwise uses
+** a default method.  Always returns nil.  If object is not an instance
+** object, does nothing.
+*/
+extern inline id
+object_dispose(id object)
+{
+  if ((object!=nil)&&CLS_ISCLASS(object->class_pointer))
+    {
+      if (_objc_object_dispose)
+        (*_objc_object_dispose)(object);
+      else
+        free(object);
+    }
+  return nil;
+}
+
+/*
+** Returns the class of an object.  If object is an instance, this is
+** its class object.  If object is a class object, returns object (this
+** is arguably not correct, but is implemented this way for compatibility
+** with NeXT (and Stepstone?)).  If object is a metaclass object, or
+** object is nil, returns Nil.
+*/
+static inline Class_t
+object_get_class(id object)
+{
+  return ((object!=nil)
+         ? (CLS_ISCLASS(object->class_pointer)
+            ? object->class_pointer
+            : (CLS_ISMETA(object->class_pointer)
+               ? (Class_t)object
+               : Nil))
+         : Nil);
+}
+
+/*
+** Returns the name of the class of object.  If object is an instace,
+** this is the name of its class.  If object is a class or a metaclass,
+** returns its name.  If object is nil, returns "Nil".
+*/
+static inline const char *
+object_get_class_name(id object)
+{
+  return ((object!=nil)?(CLS_ISCLASS(object->class_pointer)
+                         ?object->class_pointer->name
+                         :((Class_t)object)->name)
+                       :"Nil");
+}
+
+/*
+** Returns the metaclass of an object.  If object is an instance or a
+** class, this is the metaclass object for it.  If object is a metaclass
+** object, or object is nil, returns Nil.
+*/
+static inline MetaClass_t
+object_get_meta_class(id object)
+{
+  return ((object!=nil)?(CLS_ISCLASS(object->class_pointer)
+                         ?object->class_pointer->class_pointer
+                         :(CLS_ISMETA(object->class_pointer)
+                           ?object->class_pointer
+                           :Nil))
+                       :Nil);
+}
+
+/*
+** Returns the superclass of object.  If object is an instance or
+** a class, this is its superclass-object for it.  If object is a
+** metaclass-object or nil, this is Nil.
+*/
+static inline Class_t
+object_get_super_class(id object)
+{
+  return ((object!=nil)?(CLS_ISCLASS(object->class_pointer)
+                         ?object->class_pointer->super_class
+                         :(CLS_ISMETA(object->class_pointer)
+                           ?((Class_t)object)->super_class
+                           :Nil))
+                       :Nil);
+}
+
+/*
+** YES if object is a class, NO if not.
+*/
+static inline BOOL
+object_is_class(id object)
+{
+  return CLS_ISCLASS((Class_t)object);
+}
+
+/*
+** YES if object is an instance, NO if not.
+*/
+static inline BOOL
+object_is_instance(id object)
+{
+  return (object!=nil)&&CLS_ISCLASS(object->class_pointer);
+}
+
+/*
+** YES if object is a metaclass, NO if not.
+*/
+static inline BOOL
+object_is_meta_class(id object)
+{
+  return CLS_ISMETA((Class_t)object);
+}
+
+/*
+** Functions used for archiving.  This is not documented yet!
+*/
+
+TypedStream* new_typed_stream(FILE* physical);
+void free_typed_stream(TypedStream* stream);
+
+void objc_write_object(TypedStream* stream, id object);
+int objc_read_object(TypedStream* stream, id *object);
+
+void objc_write_type(TypedStream* stream, const char* type, const void* data);
+void objc_read_type(TypedStream* stream, const char* type, void* data);
+
+#endif /* not __objc_api_INCLUDE_GNU */
diff --git a/gcc/objc/objects.c b/gcc/objc/objects.c
new file mode 100644 (file)
index 0000000..a8f1a3b
--- /dev/null
@@ -0,0 +1,75 @@
+/* GNU Objective C Runtime class related functions
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+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 */
+
+id __objc_object_alloc(Class_t);
+id __objc_object_dispose(id);
+id __objc_object_copy(id);
+
+id (*_objc_object_alloc)(Class_t) = __objc_object_alloc;
+id (*_objc_object_dispose)(id)    = __objc_object_dispose;
+id (*_objc_object_copy)(id)       = __objc_object_copy;
+
+id
+class_create_instance(Class_t class)
+{
+  id res = (*_objc_object_alloc)(class);
+  res->class_pointer = class;
+  return res;
+}
+
+id 
+object_copy(id object)
+{
+  return (*_objc_object_copy)(object);
+}
+
+id 
+object_dispose(id object)
+{
+  return (*_objc_object_dispose)(object);
+}
+
+id __objc_object_alloc(Class_t class)
+{
+  return (id)__objc_xmalloc(class->instance_size);
+}
+
+id __objc_object_dispose(id object) 
+{
+  free(object);
+  return 0;
+}
+
+id __objc_object_copy(id object)
+{
+  id copy = class_create_instance(object->class_pointer);
+  bcopy(object, copy, object->class_pointer->instance_size);
+  return copy;
+}
+
+
diff --git a/gcc/objc/runtime.h b/gcc/objc/runtime.h
new file mode 100644 (file)
index 0000000..6f2a550
--- /dev/null
@@ -0,0 +1,71 @@
+/* GNU Objective C Runtime internal declarations
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+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.  */
+
+#ifndef __objc_runtime_INCLUDE_GNU
+#define __objc_runtime_INCLUDE_GNU
+
+#include <objc/objc.h>         /* core data types */
+#include <objc/objc-api.h>     /* runtime api functions */
+
+#include <objc/hash.h>         /* hash structures */
+#include <objc/list.h>         /* linear lists */
+
+#include <stdio.h>             /* argh! I hate this */
+#include <stdarg.h>            /* for varargs and va_list's */
+#include <stdlib.h>
+
+#include <assert.h>
+
+extern void __objc_add_class_to_hash(Class_t); /* (objc-class.c) */
+extern void __objc_init_selector_tables();     /* (objc-sel.c) */
+extern void __objc_init_class_tables();     /* (objc-class.c) */
+extern void __objc_init_dispatch_tables();     /* (objc-dispatch.c) */
+extern void __objc_install_premature_dtable(Class_t); /* (objc-dispatch.c) */
+extern void __objc_resolve_class_links(); /* (objc-class.c) */
+extern void __objc_register_selectors_from_class(Class_t); /* (objc-sel.c) */
+extern void __objc_update_dispatch_table_for_class (Class_t);/* (objc-msg.c) */
+
+/* True when class links has been resolved */     
+extern BOOL __objc_class_links_resolved;
+
+/* Number of selectors stored in each of the selector  tables */
+extern int __objc_selector_max_index;
+
+#ifdef DEBUG
+#define DEBUG_PRINTF printf
+#else
+#define DEBUG_PRINTF
+#endif 
+
+
+/* standard functions */
+int bcopy(void*, void*, size_t);
+int vprintf(const char*, va_list);
+
+
+#endif /* not __objc_runtime_INCLUDE_GNU */
+
+
diff --git a/gcc/objc/sarray.c b/gcc/objc/sarray.c
new file mode 100644 (file)
index 0000000..8bab62c
--- /dev/null
@@ -0,0 +1,428 @@
+/* Sparse Arrays for Objective C dispatch tables
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+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 <objc/sarray.h>
+#include <stdio.h>
+#include "assert.h"
+
+int nbuckets = 0;
+int nindices = 0;
+int narrays = 0;
+int idxsize = 0;
+
+#ifdef OBJC_SPARSE2
+const char* __objc_sparse2_id = "2 level sparse indices";
+#endif
+
+#ifdef OBJC_SPARSE3
+const char* __objc_sparse3_id = "3 level sparse indices";
+#endif
+
+void
+sarray_at_put(struct sarray* array, sidx index, void* element)
+{
+  struct sindex** the_index;
+  struct sbucket** the_bucket;
+#ifdef OBJC_SPARSE3
+  unsigned int ioffset;
+#endif
+  unsigned int boffset;
+  unsigned int eoffset;
+#ifdef PRECOMPUTE_SELECTORS
+  union sofftype xx; 
+  xx.idx = index;
+#ifdef OBJC_SPARSE3
+  ioffset = xx.off.ioffset;
+#endif
+  boffset = xx.off.boffset;
+  eoffset = xx.off.eoffset;
+#else
+  ioffset = index/INDEX_CAPACITY;
+  boffset = (index/BUCKET_SIZE)%INDEX_SIZE;
+  eoffset = index%BUCKET_SIZE;
+#endif
+
+  assert(soffset_decode(index) < array->capacity); /* Range check */
+
+#ifdef OBJC_SPARSE3
+  the_index = &(array->indices[ioffset]);
+  the_bucket = &((*the_index)->buckets[boffset]);
+#else
+  the_bucket = &(array->buckets[boffset]);
+#endif
+  
+  if ((*the_bucket)->elems[eoffset] == element)
+    return;            /* great! we just avoided a lazy copy */
+
+#ifdef OBJC_SPARSE3
+
+  /* First, perform lazy copy/allocation of index if needed */
+
+  if ((*the_index) == array->empty_index) {
+
+    /* The index was previously empty, allocate a new */
+    *the_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex));
+    bcopy(array->empty_index, *the_index, sizeof(struct sindex));
+    (*the_index)->version = array->version;
+    the_bucket = &((*the_index)->buckets[boffset]);
+    nindices += 1;
+    
+  } else if ((*the_index)->version != array->version) {
+
+    /* This index must be lazy copied */
+    struct sindex* old_index = *the_index;
+    *the_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex));
+    bcopy(old_index, *the_index, sizeof(struct sindex));
+    (*the_index)->version = array->version;
+    the_bucket = &((*the_index)->buckets[boffset]);
+    nindices += 1;
+    
+  }
+
+#endif /* OBJC_SPARSE3 */
+
+  /* next, perform lazy allocation/copy of the bucket if needed */
+
+  if ((*the_bucket) == array->empty_bucket) {
+
+    /* The bucket was previously empty (or something like that), */
+    /* allocate a new.  This is the effect of `lazy' allocation */  
+    *the_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket));
+    bcopy(array->empty_bucket, *the_bucket, sizeof(struct sbucket));
+    (*the_bucket)->version = array->version;
+    nbuckets += 1;
+
+  } else if ((*the_bucket)->version != array->version) {
+
+    /* Perform lazy copy. */
+    struct sbucket* old_bucket = *the_bucket;
+    *the_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket));
+    bcopy(old_bucket, *the_bucket, sizeof(struct sbucket));
+    (*the_bucket)->version = array->version;
+    nbuckets += 1;
+
+  }
+  (*the_bucket)->elems[eoffset] = element;
+}
+
+void
+sarray_at_put_safe(struct sarray* array, sidx index, void* element)
+{
+  if(soffset_decode(index) >= array->capacity)
+    sarray_realloc(array, soffset_decode(index)+1);
+  sarray_at_put(array, index, element);
+}
+
+struct sarray* 
+sarray_new (int size, void* default_element)
+{
+#ifdef OBJC_SPARSE3
+  unsigned num_indices = ((size-1)/(INDEX_CAPACITY))+1;
+#else /* OBJC_SPARSE2 */
+  unsigned num_indices = ((size-1)/BUCKET_SIZE)+1;
+#endif
+  int counter;
+  struct sarray* arr;
+
+  assert(size > 0);
+
+  /* Allocate core array */
+  arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray));
+  arr->version = 0;
+  narrays  += 1;
+  
+  /* Initialize members */
+#ifdef OBJC_SPARSE3
+  arr->capacity = num_indices*INDEX_CAPACITY;
+  arr->indices = (struct sindex**) 
+    __objc_xmalloc(sizeof(struct sindex*)*num_indices);
+  idxsize  += num_indices;
+
+  arr->empty_index = (struct sindex*) __objc_xmalloc(sizeof(struct sindex));
+  arr->empty_index->version = 0;
+  nindices += 1;
+
+#else /* OBJC_SPARSE2 */
+  arr->capacity = num_indices*BUCKET_SIZE;
+  arr->buckets = (struct sbucket**) 
+    __objc_xmalloc(sizeof(struct sbucket*)*num_indices);
+  idxsize  += num_indices;
+
+#endif
+
+  arr->empty_bucket = (struct sbucket*) __objc_xmalloc(sizeof(struct sbucket));
+  arr->empty_bucket->version = 0;
+  nbuckets += 1;
+
+  arr->ref_count = 1;
+  arr->is_copy_of = (struct sarray*)0;
+  
+  for (counter=0; counter<BUCKET_SIZE; counter++)
+    arr->empty_bucket->elems[counter] = default_element;
+
+#ifdef OBJC_SPARSE3
+  for (counter=0; counter<INDEX_SIZE; counter++)
+    arr->empty_index->buckets[counter] = arr->empty_bucket;
+
+  for (counter=0; counter<num_indices; counter++)
+    arr->indices[counter] = arr->empty_index;
+
+#else /* OBJC_SPARSE2 */
+
+  for (counter=0; counter<num_indices; counter++)
+    arr->buckets[counter] = arr->empty_bucket;
+
+#endif
+
+  return arr;
+}
+\f
+
+/* Reallocate the sparse array to hold `newsize' entries */
+
+void 
+sarray_realloc(struct sarray* array, int newsize)
+{
+#ifdef OBJC_SPARSE3
+  int old_max_index = (array->capacity-1)/INDEX_CAPACITY;
+  int new_max_index = ((newsize-1)/INDEX_CAPACITY);
+  int rounded_size = (new_max_index+1)*INDEX_CAPACITY;
+
+#else /* OBJC_SPARSE2 */
+  int old_max_index = (array->capacity-1)/BUCKET_SIZE;
+  int new_max_index = ((newsize-1)/BUCKET_SIZE);
+  int rounded_size = (new_max_index+1)*BUCKET_SIZE;
+
+#endif
+
+  int counter;
+
+  assert(newsize > 0);
+
+  /* The size is the same, just ignore the request */
+  if(rounded_size == array->capacity)
+    return;
+
+  assert(array->ref_count == 1);       /* stop if lazy copied... */
+
+  if(rounded_size < array->capacity) 
+    {
+      /* update capacity */
+      array->capacity = rounded_size;
+
+      /* free buckets above new_max_index */
+      for(counter = old_max_index; counter > new_max_index; counter-- ) {
+#ifdef OBJC_SPARSE3
+       struct sindex* idx = array->indices[counter];
+       if((idx != array->empty_index) && (idx->version == array->version)) {
+         int c2; 
+         for(c2=0; c2<INDEX_SIZE; c2++) {
+           struct sbucket* bkt = idx->buckets[c2];
+           if((bkt != array->empty_bucket) && (bkt->version == array->version))
+             {
+               free(bkt);
+               nbuckets -= 1;
+             }
+         }
+         free(idx);
+         nindices -= 1;
+       }
+#else /* OBJC_SPARSE2 */
+       struct sbucket* bkt = array->buckets[counter];
+       if ((bkt != array->empty_bucket) && (bkt->version == array->version))
+         {
+           free(bkt);
+           nbuckets -= 1;
+         }
+#endif
+      }
+         
+#ifdef OBJC_SPARSE3
+      /* realloc to free the space above new_max_index */
+      array->indices = (struct sindex**)
+       __objc_xrealloc(array->indices, 
+                       (new_max_index+1)*sizeof(struct sindex*));
+#else /* OBJC_SPARSE2 */
+      array->buckets = (struct sbucket**)
+       __objc_xrealloc(array->buckets, 
+                       (new_max_index+1)*sizeof(struct sbucket*));
+#endif      
+      idxsize -= (old_max_index-new_max_index);
+
+      return;
+    }
+
+  /* We are asked to extend the array -- reallocate the bucket table, */
+  /* and insert empty_bucket in newly allocated places. */
+  if(rounded_size > array->capacity) 
+    {
+      /* update capacity */
+      array->capacity = rounded_size;
+
+#ifdef OBJC_SPARSE3
+      /* realloc to make room in table above old_max_index */
+      array->indices = (struct sindex**)
+       __objc_xrealloc(array->indices, 
+                       (new_max_index+1)*sizeof(struct sindex*));
+
+      /* reset entries above old_max_index to empty_bucket */
+      for(counter = old_max_index+1; counter <= new_max_index; counter++)
+       array->indices[counter] = array->empty_index;
+
+#else /* OBJC_SPARSE2 */
+
+      /* realloc to make room in table above old_max_index */
+      array->buckets = (struct sbucket**)
+       __objc_xrealloc(array->buckets, 
+                       (new_max_index+1)*sizeof(struct sbucket*));
+
+      /* reset entries above old_max_index to empty_bucket */
+      for(counter = old_max_index+1; counter <= new_max_index; counter++)
+       array->buckets[counter] = array->empty_bucket;
+
+#endif
+      idxsize += (new_max_index-old_max_index);
+      return;
+    }
+}
+\f
+
+/* Free a sparse array allocated with sarray_new */
+
+void 
+sarray_free(struct sarray* array) {
+#ifdef OBJC_SPARSE3
+  unsigned int old_max_index = (array->capacity-1)/INDEX_CAPACITY;
+#else
+  unsigned int old_max_index = (array->capacity-1)/BUCKET_SIZE;
+#endif
+  int counter = 0;
+
+  assert(array->ref_count != 0);       /* Freed multiple times!!! */
+
+  if(--(array->ref_count) != 0)        /* There exists copies of me */
+    return;
+
+  if((array->is_copy_of) && ((array->is_copy_of->ref_count - 1) == 0))
+    sarray_free(array->is_copy_of);
+
+  /* Free all entries that do not point to empty_bucket */
+  for(counter = 0; counter <= old_max_index; counter++ ) {
+#ifdef OBJC_SPARSE3
+    struct sindex* idx = array->indices[counter];
+    if((idx != array->empty_index) && (idx->version == array->version)) {
+      int c2; 
+      for(c2=0; c2<INDEX_SIZE; c2++) {
+       struct sbucket* bkt = idx->buckets[c2];
+       if((bkt != array->empty_bucket) && (bkt->version == array->version))
+         {
+           free(bkt);
+           nbuckets -= 1;
+         }
+      }
+      free(idx);
+      nindices -= 1;
+    }
+#else /* OBJC_SPARSE2 */
+    struct sbucket* bkt = array->buckets[counter];
+    if ((bkt != array->empty_bucket) && (bkt->version == array->version))
+      {
+       free(bkt);
+       nbuckets -= 1;
+      }
+#endif
+  }
+       
+#ifdef OBJC_SPARSE3  
+  /* free empty_index */
+  if(array->empty_index->version == array->version) {
+    free(array->empty_index);
+    nindices -= 1;
+  }
+#endif
+
+  /* free empty_bucket */
+  if(array->empty_bucket->version == array->version) {
+    free(array->empty_bucket);
+    nbuckets -= 1;
+  }
+
+#ifdef OBJC_SPARSE3
+  /* free bucket table */
+  free(array->indices);
+  idxsize -= (old_max_index+1);
+
+#else
+  /* free bucket table */
+  free(array->buckets);
+  idxsize -= (old_max_index+1);
+
+#endif
+
+  /* free array */
+  free(array);
+  narrays -= 1;
+}
+
+/* This is a lazy copy.  Only the core of the structure is actually */
+/* copied.   */
+
+struct sarray* 
+sarray_lazy_copy(struct sarray* oarr)
+{
+#ifdef OBJC_SPARSE3
+  unsigned num_indices = ((oarr->capacity-1)/INDEX_CAPACITY)+1;
+#else /* OBJC_SPARSE2 */
+  unsigned num_indices = ((oarr->capacity-1)/BUCKET_SIZE)+1;
+#endif
+  struct sarray* arr;
+
+  /* Allocate core array */
+  arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray));
+  bcopy(oarr, arr, sizeof(struct sarray));
+  arr->version = oarr->version + 1;
+  arr->is_copy_of = oarr;
+  oarr->ref_count += 1;
+  arr->ref_count = 1;
+  
+#ifdef OBJC_SPARSE3
+  /* Copy bucket table */
+  arr->indices = (struct sindex**) 
+    __objc_xmalloc(sizeof(struct sindex*)*num_indices);
+  bcopy(oarr->indices, arr->indices, 
+       sizeof(struct sindex*)*num_indices);
+#else 
+  /* Copy bucket table */
+  arr->buckets = (struct sbucket**) 
+    __objc_xmalloc(sizeof(struct sbucket*)*num_indices);
+  bcopy(oarr->buckets, arr->buckets, 
+       sizeof(struct sbucket*)*num_indices);
+#endif
+
+  idxsize += num_indices;
+  narrays += 1;
+
+  return arr;
+}
diff --git a/gcc/objc/sarray.h b/gcc/objc/sarray.h
new file mode 100644 (file)
index 0000000..b222957
--- /dev/null
@@ -0,0 +1,224 @@
+/* Sparse Arrays for Objective C dispatch tables
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+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.  */
+
+#ifndef __sarray_INCLUDE_GNU
+#define __sarray_INCLUDE_GNU
+
+#define OBJC_SPARSE3           /* 2-level sparse array */
+/* #define OBJC_SPARSE2 */      /* 3-level sparse array */
+
+#ifdef OBJC_SPARSE2
+extern const char* __objc_sparse2_id;
+#endif
+
+#ifdef OBJC_SPARSE3
+extern const char* __objc_sparse3_id;
+#endif
+
+#include <stddef.h>
+
+extern int nbuckets;           /* for stats */
+extern int nindices;
+extern int narrays;
+extern int idxsize;
+
+#include <assert.h>
+
+#if defined(sparc) || defined(OBJC_SPARSE2)
+#define PRECOMPUTE_SELECTORS
+#endif
+
+#ifdef OBJC_SPARSE3
+
+/* Buckets are 8 words each */
+#define BUCKET_BITS 3
+#define BUCKET_SIZE (1<<BUCKET_BITS)
+#define BUCKET_MASK (BUCKET_SIZE-1)
+
+/* Indices are 16 words each */
+#define INDEX_BITS 4
+#define INDEX_SIZE (1<<INDEX_BITS)
+#define INDEX_MASK (INDEX_SIZE-1)
+
+#define INDEX_CAPACITY (BUCKET_SIZE*INDEX_SIZE)
+
+#else /* OBJC_SPARSE2 */
+
+/* Buckets are 32 words each */
+#define BUCKET_BITS 5
+#define BUCKET_SIZE (1<<BUCKET_BITS)
+#define BUCKET_MASK (BUCKET_SIZE-1)
+
+#endif /* OBJC_SPARSE2 */
+
+typedef unsigned int sidx;
+
+#ifdef PRECOMPUTE_SELECTORS
+
+struct soffset {
+#ifdef OBJC_SPARSE3
+  unsigned char unused;
+  unsigned char eoffset;
+  unsigned char boffset;
+  unsigned char ioffset;
+#else /* OBJC_SPARSE2 */
+#ifdef sparc
+  unsigned int boffset : 30 - BUCKET_BITS;
+  unsigned int eoffset : BUCKET_BITS;
+  unsigned int unused  : 2;
+#else
+  unsigned short boffset;
+  unsigned short eoffset;
+#endif
+#endif /* OBJC_SPARSE2 */
+};
+
+union sofftype {
+  struct soffset off;
+  sidx idx;
+};
+
+#endif /* not PRECOMPUTE_SELECTORS */
+
+void * __objc_xrealloc (void *optr, size_t size);
+void * __objc_xmalloc (size_t size);
+
+struct sbucket {
+  void* elems[BUCKET_SIZE];    /* elements stored in array */
+  short version;                       /* used for copy-on-write */
+};
+
+#ifdef OBJC_SPARSE3
+
+struct sindex {
+  struct sbucket* buckets[INDEX_SIZE];
+  short version;
+};
+
+#endif /* OBJC_SPARSE3 */
+
+struct sarray {
+#ifdef OBJC_SPARSE3
+  struct sindex** indices;
+  struct sindex* empty_index;
+#else /* OBJC_SPARSE2 */
+  struct sbucket** buckets;
+#endif  /* OBJC_SPARSE2 */
+  struct sbucket* empty_bucket;
+  short version;
+  short ref_count;
+  struct sarray* is_copy_of;
+  int capacity;
+};
+
+struct sarray* sarray_new(int, void* default_element);
+void sarray_free(struct sarray*);
+struct sarray* sarray_lazy_copy(struct sarray*);
+struct sarray* sarray_hard_copy(struct sarray*); /* ... like the name? */
+void sarray_realloc(struct sarray*, int new_size);
+void sarray_at_put(struct sarray*, sidx index, void* elem);
+void sarray_at_put_safe(struct sarray*, sidx index, void* elem);
+\f
+
+#ifdef PRECOMPUTE_SELECTORS
+/* Transform soffset values to ints and vica verca */
+static inline unsigned int
+soffset_decode(sidx index)
+{
+  union sofftype x;
+  x.idx = index;
+#ifdef OBJC_SPARSE3
+  return x.off.eoffset
+    + (x.off.boffset*BUCKET_SIZE)
+      + (x.off.ioffset*INDEX_CAPACITY);
+#else /* OBJC_SPARSE2 */
+  return x.off.eoffset + (x.off.boffset*BUCKET_SIZE);
+#endif /* OBJC_SPARSE2 */
+}
+
+static inline sidx
+soffset_encode(unsigned int offset)
+{
+  union sofftype x;
+  x.off.eoffset = offset%BUCKET_SIZE;
+#ifdef OBJC_SPARSE3
+  x.off.boffset = (offset/BUCKET_SIZE)%INDEX_SIZE;
+  x.off.ioffset = offset/INDEX_CAPACITY;
+#else /* OBJC_SPARSE2 */
+  x.off.boffset = offset/BUCKET_SIZE;
+#endif
+  return (sidx)x.idx;
+}
+
+#else /* not PRECOMPUTE_SELECTORS */
+
+static inline unsigned int
+soffset_decode(sidx index)
+{
+  return index;
+}
+
+static inline sidx
+soffset_encode(unsigned int offset)
+{
+  return offset;
+}
+#endif /* not PRECOMPUTE_SELECTORS */
+
+/* Get element from the Sparse array `array' at offset `index' */
+
+static inline void* sarray_get(struct sarray* array, sidx index)
+{
+#ifdef PRECOMPUTE_SELECTORS
+  union sofftype x;
+  x.idx = index;
+#ifdef OBJC_SPARSE3
+  return 
+    array->
+      indices[x.off.ioffset]->
+       buckets[x.off.boffset]->
+         elems[x.off.eoffset];
+#else /* OBJC_SPARSE2 */
+  return array->buckets[x.off.boffset]->elems[x.off.eoffset];
+#endif /* OBJC_SPARSE2 */
+#else /* not PRECOMPUTE_SELECTORS */
+  return array->
+    indices[index/INDEX_CAPACITY]->
+      buckets[(index/BUCKET_SIZE)%INDEX_SIZE]->
+       elems[index%BUCKET_SIZE];
+#endif /* not PRECOMPUTE_SELECTORS */
+}
+
+static inline void* sarray_get_safe(struct sarray* array, sidx index)
+{
+  if(soffset_decode(index) < array->capacity)
+    return sarray_get(array, index);
+  else
+    return (array->empty_bucket->elems[0]);
+}
+
+#endif /* __sarray_INCLUDE_GNU */
diff --git a/gcc/objc/selector.c b/gcc/objc/selector.c
new file mode 100644 (file)
index 0000000..44a73f6
--- /dev/null
@@ -0,0 +1,143 @@
+/* GNU Objective C Runtime selector related functions
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+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"
+#include <objc/sarray.h>
+
+/* Initial selector hash table size. Value doesnt matter much */
+#define SELECTOR_HASH_SIZE 128
+
+/* Tables mapping selector names to uid and opposite */
+static struct sarray* __objc_selector_array = 0; /* uid -> name */
+static cache_ptr      __objc_selector_hash  = 0; /* name -> uid */
+
+static void register_selectors_from_list(MethodList_t);
+
+/* Number of selectors stored in each of the above tables */
+int __objc_selector_max_index = 0;
+
+void __objc_init_selector_tables()
+{
+  __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
+  __objc_selector_hash
+    = hash_new (SELECTOR_HASH_SIZE,
+               (hash_func_type) hash_string,
+               (compare_func_type) compare_strings);
+}  
+
+/* This routine is given a class and records all of the methods in its class
+   structure in the record table.  */
+void
+__objc_register_selectors_from_class (Class_t class)
+{
+  MethodList_t method_list;
+
+  method_list = class->methods;
+  while (method_list)
+    {
+      register_selectors_from_list (method_list);
+      method_list = method_list->method_next;
+    }
+}
+
+
+/* This routine is given a list of methods and records each of the methods in
+   the record table.  This is the routine that does the actual recording
+   work.
+
+   This one is only called for Class objects.  For categories,
+   class_add_method_list is called.
+   */
+static void
+register_selectors_from_list (MethodList_t method_list)
+{
+  int i = 0;
+  while (i < method_list->method_count)
+    {
+      Method_t method = &method_list->method_list[i];
+      method->method_name = sel_register_name ((char*)method->method_name);
+      i += 1;
+    }
+}
+
+/* return selector representing name */
+SEL
+sel_get_uid (const char *name)
+{
+  return (SEL) hash_value_for_key (__objc_selector_hash, name);
+}
+
+/* Get name of selector.  If selector is unknown, the empty string "" 
+   is returned */ 
+const char*
+sel_get_name (SEL selector)
+{
+  if ((soffset_decode((unsigned)selector) > 0)
+      && (soffset_decode((unsigned)selector) <= __objc_selector_max_index))
+    return sarray_get (__objc_selector_array, (sidx) selector);
+  else
+    return NULL;
+}
+
+BOOL
+sel_is_mapped (SEL selector)
+{
+  unsigned int idx = soffset_decode ((sidx)selector);
+  return ((idx > 0) && (idx <= __objc_selector_max_index));
+}
+
+#ifdef OBJC_SPARSE_LOOKUP
+/* The uninstalled dispatch table */
+extern struct sarray* __objc_uninstalled_dtable;
+#endif
+
+/* Store the passed selector name in the selector record and return its
+   selector value (value returned by sel_get_uid). */
+SEL
+sel_register_name (const char *sel)
+{
+  SEL j;
+  sidx i;
+
+  if ((j = sel_get_uid ((const char *) sel)))
+    return j;
+
+  /* Save the selector name.  */
+  __objc_selector_max_index += 1;
+  i = soffset_encode(__objc_selector_max_index);
+
+  DEBUG_PRINTF ("Record selector %s as: %#x\n", sel, i);
+
+  sarray_at_put_safe (__objc_selector_array, i, (void *) sel);
+  hash_add (&__objc_selector_hash, (void *) sel, (void *) i);
+
+#ifdef OBJC_SPARSE_LOOKUP
+  sarray_realloc(__objc_uninstalled_dtable, __objc_selector_max_index+1);
+#endif
+
+  return (SEL) i;
+}
+
diff --git a/gcc/objc/sendmsg.c b/gcc/objc/sendmsg.c
new file mode 100644 (file)
index 0000000..90688a5
--- /dev/null
@@ -0,0 +1,574 @@
+/* GNU Objective C Runtime message lookup 
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+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"
+
+#ifdef OBJC_SPARSE_LOOKUP
+const char* __objc_sparse_lookup_id = "Method lookup uses sparse arrays";
+#endif
+
+#ifdef OBJC_HASH_LOOKUP
+const char* __objc_hash_lookup_id = "Method lookup uses hash caching";
+#endif
+
+#ifdef OBJC_HASH_LOOKUP
+#include <objc/cache.h>
+#endif
+
+#ifdef OBJC_SPARSE_LOOKUP
+/* The uninstalled dispatch table */
+struct sarray* __objc_uninstalled_dtable = 0;
+#endif
+
+/* Send +initialize to class */
+static void __objc_send_initialize(Class_t);
+
+static void __objc_install_dispatch_table_for_class (Class_t);
+
+/* Forward declare some functions */
+#ifdef OBJC_SPARSE_LOOKUP
+static void __objc_init_install_dtable(id, SEL);
+#endif
+static id __objc_missing_method(id, SEL, ...);
+static Method_t search_for_method_in_hierarchy (Class_t class, SEL sel);
+static Method_t search_for_method_in_list(MethodList_t list, SEL op);
+id nil_method(id, SEL, ...);
+
+id
+nil_method(id receiver, SEL op, ...)
+{
+  return receiver;
+}
+
+/* Given a class and selector, return the selector's implementation.  */
+__inline__ IMP
+get_imp (Class_t class, SEL sel)
+{
+#ifdef OBJC_SPARSE_LOOKUP
+  void* res = sarray_get (class->dtable, (unsigned int) sel);
+  if(res == __objc_init_install_dtable)
+    __objc_install_dispatch_table_for_class (class);
+  return sarray_get (class->dtable, (unsigned int) sel);
+#else
+  return cache_get (class, sel);
+#endif
+}
+
+/* This is the lookup function.  All entries in the table are either a 
+   valid method *or* one of `__objc_missing_method' which calls
+   forward:: etc, or `__objc_init_install_dtable' which installs the
+   real dtable */
+__inline__ IMP
+objc_msg_lookup(id receiver, SEL op)
+{
+  if(receiver)
+#ifdef OBJC_HASH_LOOKUP
+    return cache_get(receiver->class_pointer, op);
+#else
+    return sarray_get(receiver->class_pointer->dtable, (sidx)op);
+#endif
+  else
+    return nil_method;
+}
+
+IMP
+objc_msg_lookup_super (Super_t super, SEL sel)
+{
+  if (super->self)
+    return get_imp (super->class, sel);
+  else
+    return nil_method;
+}
+
+retval_t
+objc_msg_sendv(id object, SEL op, size_t frame_size, arglist_t arg_frame)
+{
+#ifdef __objc_frame_receiver
+  __objc_frame_receiver(arg_frame) = object;
+  __objc_frame_selector(arg_frame) = op;
+  return __builtin_apply((apply_t)get_imp(object->class_pointer, op),
+                        arg_frame,
+                        frame_size);
+#else
+#warning performv:: will not work
+  (*_objc_error)(object, "objc_msg_sendv (performv::) not supported\n", 0);
+  return 0;
+#endif
+}
+
+void __objc_init_dispatch_tables()
+{
+#ifdef OBJC_SPARSE_LOOKUP  
+  __objc_uninstalled_dtable
+    = sarray_new(200, __objc_init_install_dtable);
+#endif
+}
+
+#ifdef OBJC_SPARSE_LOOKUP
+/* This one is a bit hairy.  This function is installed in the 
+   premature dispatch table, and thus called once for each class,
+   namely when the very first message is send to it.  */
+
+static void __objc_init_install_dtable(id receiver, SEL op)
+{
+  __label__ allready_initialized;
+  IMP imp;
+  void* args;
+  void* result;
+
+  /* If the class has not yet had it's class links resolved, we must 
+     re-compute all class links */
+  if(!CLS_ISRESOLV(receiver->class_pointer))
+    __objc_resolve_class_links();
+
+  /* This may happen, if the programmer has taken the address of a 
+     method before the dtable was initialized... too bad for him! */
+  if(receiver->class_pointer->dtable != __objc_uninstalled_dtable)
+    goto allready_initialized;
+
+  if(CLS_ISCLASS(receiver->class_pointer))
+    {
+      /* receiver is an ordinary object */
+      assert(CLS_ISCLASS(receiver->class_pointer));
+
+      /* install instance methods table */
+      __objc_install_dispatch_table_for_class (receiver->class_pointer);
+
+      /* call +initialize -- this will in turn install the factory 
+        dispatch table if not already done :-) */
+      __objc_send_initialize(receiver->class_pointer);
+    }
+  else
+    {
+      /* receiver is a class object */
+      assert(CLS_ISCLASS((Class_t)receiver));
+      assert(CLS_ISMETA(receiver->class_pointer));
+
+      /* Install real dtable for factory methods */
+      __objc_install_dispatch_table_for_class (receiver->class_pointer);
+      
+      if(op != sel_get_uid ("initialize"))
+       __objc_send_initialize((Class_t)receiver);
+      else
+       CLS_SETINITIALIZED((Class_t)receiver);
+    }
+
+allready_initialized:
+  
+  /* Get real method for this in newly installed dtable */
+  imp = get_imp(receiver->class_pointer, op);
+
+  args = __builtin_apply_args();
+  result = __builtin_apply((apply_t)imp, args, 96);
+  __builtin_return (result);
+  
+}
+#endif
+
+/* Install dummy table for class which causes the first message to
+   that class (or instances hereof) to be initialized properly */
+void __objc_install_premature_dtable(Class_t class)
+{
+#ifdef OBJC_SPARSE_LOOKUP
+  assert(__objc_uninstalled_dtable);
+  class->dtable = __objc_uninstalled_dtable;
+#else
+  class->cache = (Cache_t)__objc_xcalloc(1, sizeof(Cache));
+#endif
+}   
+
+/* Send +initialize to class if not already done */
+static void __objc_send_initialize(Class_t class)
+{
+  Method_t m;
+  IMP imp;
+
+  /* This *must* be a class object */
+  assert(CLS_ISCLASS(class));
+  assert(!CLS_ISMETA(class));
+
+  if (!CLS_ISINITIALIZED(class))
+    {
+      CLS_SETINITIALIZED(class);
+      CLS_SETINITIALIZED(class->class_pointer);
+      
+      if(class->super_class)
+       __objc_send_initialize(class->super_class);
+  
+      m = search_for_method_in_list(class->class_pointer->methods,
+                                   sel_get_uid("initialize"));
+      if(m != NULL)
+        {
+          CLS_SETINITIALIZED(class);
+          (*m->method_imp) ((id) class, sel_get_uid("initialize"));
+        }
+    }
+}  
+
+static void
+__objc_install_dispatch_table_for_class (Class_t class)
+{
+#ifdef OBJC_SPARSE_LOOKUP
+  Class_t super = class->super_class;
+  MethodList_t mlist;
+  int counter;
+
+  if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
+    __objc_install_dispatch_table_for_class (super);
+
+  /* Allocate dtable if nessecary */
+  if (super == 0)
+    {
+      class->dtable = sarray_new (__objc_selector_max_index,
+                                 __objc_missing_method);
+    }
+  else
+    class->dtable = sarray_lazy_copy (super->dtable);
+
+  for (mlist = class->methods; mlist; mlist = mlist->method_next)
+    {
+      counter = mlist->method_count - 1;
+      while (counter >= 0)
+        {
+          Method_t method = &(mlist->method_list[counter]);
+         sarray_at_put (class->dtable,
+                        (sidx) method->method_name,
+                        method->method_imp);
+          counter -= 1;
+        }
+    }
+#endif
+}
+
+void __objc_update_dispatch_table_for_class (Class_t class)
+{
+  Class_t next;
+#ifdef OBJC_SPARSE_LOOKUP
+  struct sarray* save;
+#else
+  Cache_t save;
+#endif
+
+  /* not yet installed -- skip it */
+#ifdef OBJC_SPARSE_LOOKUP
+  if (class->dtable == __objc_uninstalled_dtable) 
+#else
+  if (class->cache->mask == 0)
+#endif
+    return;
+
+#ifdef OBJC_SPARSE_LOOKUP
+  save = class->dtable;
+  __objc_install_premature_dtable (class);
+  sarray_free (save);
+
+#else
+  save = class->cache;
+  __objc_install_premature_dtable (class);
+  free(save);
+
+#endif
+
+  if (class->subclass_list)    /* Traverse subclasses */
+    for (next = class->subclass_list; next; next = next->sibling_class)
+      __objc_update_dispatch_table_for_class (next);
+}
+
+
+/* This function adds a method list to a class.  This function is
+   typically called by another function specific to the run-time.  As
+   such this function does not worry about thread safe issued.
+
+   This one is only called for categories. Class objects have their
+   methods installed rightaway, and their selectors are made into
+   SEL's by the function __objc_register_selectors_from_class. */ 
+void
+class_add_method_list (Class_t class, MethodList_t list)
+{
+  int i;
+
+  /* Passing of a linked list is not allowed.  Do multiple calls.  */
+  assert (!list->method_next);
+
+  /* Check for duplicates.  */
+  for (i = 0; i < list->method_count; ++i)
+    {
+      Method_t method = &list->method_list[i];
+
+      if (method->method_name)  /* Sometimes these are NULL */
+       {
+         /* This is where selector names are transmogriffed to SEL's */
+         method->method_name = sel_register_name ((char*)method->method_name);
+
+         if (search_for_method_in_list (class->methods, method->method_name))
+           {
+             /* Duplication. Print a error message an change the method name
+                to NULL. */
+             fprintf (stderr, "attempt to add a existing method: %s\n",
+                      sel_get_name(method->method_name));
+             method->method_name = 0;
+           }
+       }
+    }
+
+  /* Add the methods to the class's method list.  */
+  list->method_next = class->methods;
+  class->methods = list;
+}
+
+
+Method_t
+class_get_instance_method(Class_t class, SEL op)
+{
+  return search_for_method_in_hierarchy(class, op);
+}
+
+Method_t
+class_get_class_method(MetaClass_t class, SEL op)
+{
+  return search_for_method_in_hierarchy(class, op);
+}
+
+
+/* Search for a method starting from the current class up its hierarchy.
+   Return a pointer to the method's method structure if found.  NULL
+   otherwise. */   
+
+static Method_t
+search_for_method_in_hierarchy (Class_t cls, SEL sel)
+{
+  Method_t method = NULL;
+  Class_t class;
+
+  if (! sel_is_mapped (sel))
+    return NULL;
+
+  /* Scan the method list of the class.  If the method isn't found in the
+     list then step to its super class. */
+  for (class = cls; ((! method) && class); class = class->super_class)
+    method = search_for_method_in_list (class->methods, sel);
+
+  return method;
+}
+
+
+
+/* Given a linked list of method and a method's name.  Search for the named
+   method's method structure.  Return a pointer to the method's method
+   structure if found.  NULL otherwise. */  
+static Method_t
+search_for_method_in_list (MethodList_t list, SEL op)
+{
+  MethodList_t method_list = list;
+
+  if (! sel_is_mapped (op))
+    return NULL;
+
+  /* If not found then we'll search the list.  */
+  while (method_list)
+    {
+      int i;
+
+      /* Search the method list.  */
+      for (i = 0; i < method_list->method_count; ++i)
+        {
+          Method_t method = &method_list->method_list[i];
+
+          if (method->method_name)
+            if (method->method_name == op)
+              return method;
+        }
+
+      /* The method wasn't found.  Follow the link to the next list of
+         methods.  */
+      method_list = method_list->method_next;
+    }
+
+  return NULL;
+}
+
+
+/* This fuction is installed in the dispatch table for all methods which are
+   not implemented.  Thus, it is called when a selector is not recognized. */
+static id
+__objc_missing_method (id object, SEL sel, ...)
+{
+  IMP imp;
+  SEL frwd_sel;
+  SEL err_sel;
+
+  /* first try if the object understands forward:: */
+  frwd_sel = sel_get_uid("forward::");
+  imp = get_imp(object->class_pointer, frwd_sel);
+  if(imp != __objc_missing_method)
+    {
+      void *result, *args = __builtin_apply_args();
+      result = (*imp)(object, frwd_sel, sel, args);
+      __builtin_return(result);
+    }
+
+  /* If the object recognizes the doesNotRecognize: method then we're going
+     to send it. */
+  err_sel = sel_get_uid ("doesNotRecognize:");
+  imp = get_imp (object->class_pointer, err_sel);
+  if (imp != __objc_missing_method)
+    {
+      return (*imp) (object, err_sel, sel);
+    }
+  
+  /* The object doesn't recognize the method.  Check for responding to
+     error:.  If it does then sent it. */
+  {
+    char msg[256 + strlen (sel_get_name (sel))
+             + strlen (object->class_pointer->name)];
+
+    sprintf (msg, "(%s) %s does not recognize %s",
+            (CLS_ISMETA(object->class_pointer)
+             ? "class"
+             : "instance" ),
+             object->class_pointer->name, sel_get_name (sel));
+
+    err_sel = sel_get_uid ("error:");
+    imp = get_imp (object->class_pointer, err_sel);
+    if (imp != __objc_missing_method)
+      return (*imp) (object, sel_get_uid ("error:"), msg);
+
+    /* The object doesn't respond to doesNotRecognize: or error:;  Therefore,
+       a default action is taken. */
+    fprintf (stderr, "fatal: %s\n", msg);
+    abort ();
+  }
+}
+
+int __objc_print_dtable_stats()
+{
+  int total = 0;
+  printf("memory usage: (%s)\n",
+#ifdef OBJC_SPARSE_LOOKUP
+#ifdef OBJC_SPARSE2
+        "2-level sparse arrays"
+#else
+        "3-level sparse arrays"
+#endif
+#else
+        "hash-cache"
+#endif
+        );
+
+#ifdef OBJC_SPARSE_LOOKUP
+  printf("arrays: %d = %d bytes\n", narrays, narrays*sizeof(struct sarray));
+  total += narrays*sizeof(struct sarray);
+#ifdef OBJC_SPARSE3
+  printf("indices: %d = %d bytes\n", nindices, nindices*sizeof(struct sindex));
+  total += nindices*sizeof(struct sindex);
+#endif
+  printf("buckets: %d = %d bytes\n", nbuckets, nbuckets*sizeof(struct sbucket));
+  total += nbuckets*sizeof(struct sbucket);
+
+  printf("idxtables: %d = %d bytes\n", idxsize, idxsize*sizeof(void*));
+  total += idxsize*sizeof(void*);
+#else /* HASH_LOOKUP */
+  total = __objc_class_hash_tables_size ();
+#endif
+  printf("-----------------------------------\n");
+  printf("total: %d bytes\n", total);
+  printf("===================================\n");
+  }
+
+#ifdef OBJC_HASH_LOOKUP
+static Cache_t __objc_cache_insert(Cache_t cache, SEL op, IMP imp);
+
+static Cache_t
+__objc_double_cache(Cache_t cache)
+{
+  int i;
+  Cache_t newc = (Cache_t)__objc_xcalloc(1, sizeof(Cache)
+                                        +(sizeof(Cache)*2*(cache->mask+1)));
+  newc->occupied = cache->occupied;
+  newc->mask = ((cache->mask)<<1) | 1;
+  for(i=0; i <= cache->mask; i++)
+    newc = __objc_cache_insert(newc,
+                              cache->buckets[i].method_selector,
+                              cache->buckets[i].method_imp);
+  free(cache);
+  return newc;
+}
+
+
+static Cache_t
+__objc_cache_insert(Cache_t cache, SEL op, IMP imp)
+{
+  int index = ((unsigned int)op)&(cache)->mask;
+
+  if(op == 0)
+    return cache;
+
+  do
+    {
+      if((cache)->buckets[index].method_selector == 0)
+       {
+         (cache)->buckets[index].method_selector = op;
+         (cache)->buckets[index].method_imp = imp;
+         (cache)->occupied += 1;
+         return cache;
+       }
+    }
+  while (--index >= 0);
+    
+  cache = __objc_double_cache(cache);
+  return __objc_cache_insert(cache, op, imp);
+}
+
+void* 
+__objc_cache_miss(Class_t class, SEL op) 
+{
+  Method_t m;
+  Cache_t cache = class->cache;
+  
+  if(!CLS_ISRESOLV(class))
+    __objc_resolve_class_links();
+
+  m = search_for_method_in_hierarchy(class, op);
+
+  if(!CLS_ISINITIALIZED(class))
+    if(CLS_ISMETA(class))
+      __objc_send_initialize(objc_get_class(class->name));
+    else
+      __objc_send_initialize(class);
+
+  if(m == NULL)
+    return __objc_missing_method;
+
+  if((cache->occupied+2)*2 > cache->mask)
+    class->cache = __objc_double_cache(cache);
+  
+  class->cache = __objc_cache_insert(class->cache, op, m->method_imp);
+  return m->method_imp;
+}
+
+#endif
+
+