From d4691e641ba47cb86eef80f5c879e13f9d961724 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 18 Sep 1996 05:35:50 +0000 Subject: Import of unmodified (but trimmed) gcc-2.7.2. The bigger parts of the non-i386, non-unix, and generatable files have been trimmed, but can easily be added in later if needed. gcc-2.7.2.1 will follow shortly, it's a very small delta to this and it's handy to have both available for reference for such little cost. The freebsd-specific changes will then be committed, and once the dust has settled, the bmakefiles will be committed to use this code. --- contrib/gcc/objc/Makefile | 100 +++ contrib/gcc/objc/NXConstStr.h | 38 + contrib/gcc/objc/NXConstStr.m | 36 + contrib/gcc/objc/Object.h | 124 +++ contrib/gcc/objc/Object.m | 389 ++++++++++ contrib/gcc/objc/Protocol.h | 58 ++ contrib/gcc/objc/Protocol.m | 128 ++++ contrib/gcc/objc/README | 97 +++ contrib/gcc/objc/archive.c | 1616 ++++++++++++++++++++++++++++++++++++++++ contrib/gcc/objc/class.c | 327 ++++++++ contrib/gcc/objc/encoding.c | 537 +++++++++++++ contrib/gcc/objc/encoding.h | 75 ++ contrib/gcc/objc/hash.c | 253 +++++++ contrib/gcc/objc/hash.h | 202 +++++ contrib/gcc/objc/init.c | 363 +++++++++ contrib/gcc/objc/list.h | 150 ++++ contrib/gcc/objc/makefile.dos | 56 ++ contrib/gcc/objc/misc.c | 80 ++ contrib/gcc/objc/objc-api.h | 477 ++++++++++++ contrib/gcc/objc/objc.h | 153 ++++ contrib/gcc/objc/objects.c | 92 +++ contrib/gcc/objc/runtime.h | 74 ++ contrib/gcc/objc/sarray.c | 441 +++++++++++ contrib/gcc/objc/sarray.h | 232 ++++++ contrib/gcc/objc/selector.c | 321 ++++++++ contrib/gcc/objc/sendmsg.c | 558 ++++++++++++++ contrib/gcc/objc/typedstream.h | 132 ++++ 27 files changed, 7109 insertions(+) create mode 100644 contrib/gcc/objc/Makefile create mode 100644 contrib/gcc/objc/NXConstStr.h create mode 100644 contrib/gcc/objc/NXConstStr.m create mode 100644 contrib/gcc/objc/Object.h create mode 100644 contrib/gcc/objc/Object.m create mode 100644 contrib/gcc/objc/Protocol.h create mode 100644 contrib/gcc/objc/Protocol.m create mode 100644 contrib/gcc/objc/README create mode 100644 contrib/gcc/objc/archive.c create mode 100644 contrib/gcc/objc/class.c create mode 100644 contrib/gcc/objc/encoding.c create mode 100644 contrib/gcc/objc/encoding.h create mode 100644 contrib/gcc/objc/hash.c create mode 100644 contrib/gcc/objc/hash.h create mode 100644 contrib/gcc/objc/init.c create mode 100644 contrib/gcc/objc/list.h create mode 100644 contrib/gcc/objc/makefile.dos create mode 100644 contrib/gcc/objc/misc.c create mode 100644 contrib/gcc/objc/objc-api.h create mode 100644 contrib/gcc/objc/objc.h create mode 100644 contrib/gcc/objc/objects.c create mode 100644 contrib/gcc/objc/runtime.h create mode 100644 contrib/gcc/objc/sarray.c create mode 100644 contrib/gcc/objc/sarray.h create mode 100644 contrib/gcc/objc/selector.c create mode 100644 contrib/gcc/objc/sendmsg.c create mode 100644 contrib/gcc/objc/typedstream.h (limited to 'contrib/gcc/objc') diff --git a/contrib/gcc/objc/Makefile b/contrib/gcc/objc/Makefile new file mode 100644 index 0000000..3698133 --- /dev/null +++ b/contrib/gcc/objc/Makefile @@ -0,0 +1,100 @@ +# GNU Objective C Runtime Makefile +# Copyright (C) 1993, 1995 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, 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# This makefile is run by the parent dir's makefile. +# thisdir1=`pwd`; \ +# srcdir1=`cd $(srcdir); pwd`; \ +# cd objc; \ +# $(MAKE) $(MAKEFLAGS) -f $$srcdir1/objc/Makefile libobjc.a \ +# srcdir=$$srcdir1 tooldir=$(tooldir) AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" \ +# GCC_FOR_TARGET="$$thisdir1/xgcc -B$$thisdir1/" \ +# GCC_CFLAGS="$(GCC_CFLAGS)" incinstalldir=$$thisdir1/include +# Two targets are used by ../Makefile: `all' and `mostlyclean'. + +SHELL=/bin/sh + +.SUFFIXES: .m + +OPTIMIZE= -O + +VPATH = $(srcdir)/objc + +AR = ar +AR_FLAGS = rc + +# Always search these dirs when compiling. +SUBDIR_INCLUDES = -I. -I.. -I$(srcdir) -I$(srcdir)/config + +.c.o: + $(GCC_FOR_TARGET) $(OPTIMIZE) \ + -c $(GCC_CFLAGS) $(SUBDIR_INCLUDES) $< + +.m.o: + $(GCC_FOR_TARGET) $(OPTIMIZE) -fgnu-runtime \ + -c $(GCC_CFLAGS) $(SUBDIR_INCLUDES) $< + +# If we were not invoked from the parent dir, +# invoke make in the parent dir and have reinvoke this makefile. +# That's necessary to get the right values for srcdir, etc. +all: + cd ..; $(MAKE) sublibobjc.a + +OBJC_O = hash.o sarray.o class.o sendmsg.o init.o archive.o encoding.o \ + selector.o objects.o misc.o NXConstStr.o Object.o Protocol.o + +libobjc.a: $(OBJC_O) + -rm -f libobjc.a + $(AR) rc libobjc.a $? +# ranlib is run in the parent directory's makefile. + +OBJC_H = hash.h list.h sarray.h objc.h \ + objc-api.h \ + NXConstStr.h Object.h Protocol.h encoding.h typedstream.h + +# copy objc headers to installation include directory +copy-headers: + -rm -fr $(incinstalldir)/objc + -mkdir $(incinstalldir)/objc + for file in $(OBJC_H); do \ + realfile=$(srcdir)/objc/$${file}; \ + cp $${realfile} $(incinstalldir)/objc; \ + chmod a+r $(incinstalldir)/objc/$${file}; \ + done + +mostlyclean: + -rm -f *.o libobjc.a xforward fflags +clean: mostlyclean +distclean: mostlyclean +extraclean: mostlyclean + +# For Sun VPATH. + +hash.o: hash.c +sarray.o: sarray.c +class.o: class.c +sendmsg.o: sendmsg.c +init.o: init.c +archive.o: archive.c +encoding.o: encoding.c +selector.o: selector.c +objects.o: objects.c +misc.o: misc.c +NXConstStr.o: NXConstStr.m +Object.o: Object.m +Protocol.o: Protocol.m diff --git a/contrib/gcc/objc/NXConstStr.h b/contrib/gcc/objc/NXConstStr.h new file mode 100644 index 0000000..6899c74 --- /dev/null +++ b/contrib/gcc/objc/NXConstStr.h @@ -0,0 +1,38 @@ +/* Interface for the NXConstantString class for Objective-C. + Copyright (C) 1995 Free Software Foundation, Inc. + Contributed by Pieter J. Schoenmakers + +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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef __nxconstantstring_INCLUDE_GNU +#define __nxconstantstring_INCLUDE_GNU + +#include "objc/Object.h" + +@interface NXConstantString: Object +{ + char *c_string; + unsigned int len; +} + +-(const char *) cString; +-(unsigned int) length; + +@end + +#endif diff --git a/contrib/gcc/objc/NXConstStr.m b/contrib/gcc/objc/NXConstStr.m new file mode 100644 index 0000000..d3b2117 --- /dev/null +++ b/contrib/gcc/objc/NXConstStr.m @@ -0,0 +1,36 @@ +/* Implementation of the NXConstantString class for Objective-C. + Copyright (C) 1995 Free Software Foundation, Inc. + Contributed by Pieter J. Schoenmakers + +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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "objc/NXConstStr.h" + +@implementation NXConstantString + +-(const char *) cString +{ + return (c_string); +} /* -cString */ + +-(unsigned int) length +{ + return (len); +} /* -length */ + +@end diff --git a/contrib/gcc/objc/Object.h b/contrib/gcc/objc/Object.h new file mode 100644 index 0000000..7fb8602 --- /dev/null +++ b/contrib/gcc/objc/Object.h @@ -0,0 +1,124 @@ +/* Interface for the Object class for Objective-C. + Copyright (C) 1993, 1994, 1995 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 +#include + +/* + * All classes are derived from Object. As such, + * this is the overhead tacked onto those objects. + */ +@interface Object +{ + Class 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)class; +- (Class)superClass; +- (MetaClass)metaClass; +- (const char *)name; + + /* Identifying and comparing objects */ +- self; +- (unsigned int)hash; +- (BOOL)isEqual:anObject; +- (int)compare:anotherObject; + + /* Testing object type */ +- (BOOL)isMetaClass; +- (BOOL)isClass; +- (BOOL)isInstance; + + /* Testing inheritance relationships */ +- (BOOL)isKindOf:(Class)aClassObject; +- (BOOL)isMemberOf:(Class)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 */ +- (retval_t)forward:(SEL)aSel :(arglist_t)argFrame; +- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame; + + /* Posing */ ++ poseAs:(Class)aClassObject; +- (Class)transmuteClassTo:(Class)aClassObject; + + /* Enforcing intentions */ +- subclassResponsibility:(SEL)aSel; +- notImplemented:(SEL)aSel; +- shouldNotImplement:(SEL)aSel; + + /* Error handling */ +- doesNotRecognize:(SEL)aSel; +- error:(const char *)aString, ...; + + /* Archiving */ ++ (int)version; ++ setVersion:(int)aVersion; ++ (int)streamVersion: (TypedStream*)aStream; + +- read: (TypedStream*)aStream; +- write: (TypedStream*)aStream; +- awake; + +@end + +#endif diff --git a/contrib/gcc/objc/Object.m b/contrib/gcc/objc/Object.m new file mode 100644 index 0000000..518d02a --- /dev/null +++ b/contrib/gcc/objc/Object.m @@ -0,0 +1,389 @@ +/* The implementation of class Object for Objective-C. + Copyright (C) 1993, 1994, 1995 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 +#include "objc/Object.h" +#include "objc/Protocol.h" +#include "objc/objc-api.h" + +extern void (*_objc_error)(id object, const char *format, va_list); + +extern int errno; + +#define MAX_CLASS_NAME_LEN 256 + +@implementation Object + ++ initialize +{ + return self; +} + +- init +{ + return self; +} + ++ new +{ + return [[self alloc] init]; +} + ++ alloc +{ + return class_create_instance(self); +} + +- free +{ + return object_dispose(self); +} + +- copy +{ + return [[self shallowCopy] deepen]; +} + +- shallowCopy +{ + return object_copy(self); +} + +- deepen +{ + return self; +} + +- deepCopy +{ + return [self copy]; +} + +- (Class)class +{ + return object_get_class(self); +} + +- (Class)superClass +{ + return object_get_super_class(self); +} + +- (MetaClass)metaClass +{ + return object_get_meta_class(self); +} + +- (const char *)name +{ + return object_get_class_name(self); +} + +- self +{ + return self; +} + +- (unsigned int)hash +{ + return (size_t)self; +} + +- (BOOL)isEqual:anObject +{ + return self==anObject; +} + +- (int)compare:anotherObject; +{ + if ([self isEqual:anotherObject]) + return 0; + // Ordering objects by their address is pretty useless, + // so subclasses should override this is some useful way. + else if (self > anotherObject) + return 1; + else + return -1; +} + +- (BOOL)isMetaClass +{ + return NO; +} + +- (BOOL)isClass +{ + return object_is_class(self); +} + +- (BOOL)isInstance +{ + return object_is_instance(self); +} + +- (BOOL)isKindOf:(Class)aClassObject +{ + Class class; + + for (class = self->isa; class!=Nil; class = class_get_super_class(class)) + if (class==aClassObject) + return YES; + return NO; +} + +- (BOOL)isMemberOf:(Class)aClassObject +{ + return self->isa==aClassObject; +} + +- (BOOL)isKindOfClassNamed:(const char *)aClassName +{ + Class 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; +} + +- (BOOL)isMemberOfClassNamed:(const char *)aClassName +{ + return ((aClassName!=NULL) + &&!strcmp(class_get_class_name(self->isa), aClassName)); +} + ++ (BOOL)instancesRespondTo:(SEL)aSel +{ + return class_get_instance_method(self, aSel)!=METHOD_NULL; +} + +- (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); +} + ++ (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 +// +// Modified 9/5/94 to always search the class object's protocol list, rather +// than the meta class. + ++ (BOOL) conformsTo: (Protocol*)aProtocol +{ + int i; + struct objc_protocol_list* proto_list; + id parent; + + for (proto_list = ((Class)self)->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; + } + } + + if (parent = [self superClass]) + return [parent conformsTo: aProtocol]; + else + return NO; +} + +- (BOOL) conformsTo: (Protocol*)aProtocol +{ + return [[self class] conformsTo:aProtocol]; +} + +- (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))); +} + ++ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel +{ + return ((struct objc_method_description *) + class_get_instance_method(self, aSel)); +} + +- (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))); +} + +- 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); +} + +- 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); +} + +- 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); +} + +- (retval_t)forward:(SEL)aSel :(arglist_t)argFrame +{ + return (retval_t)[self doesNotRecognize: aSel]; +} + +- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame +{ + return objc_msg_sendv(self, aSel, argFrame); +} + ++ poseAs:(Class)aClassObject +{ + return class_pose_as(self, aClassObject); +} + +- (Class)transmuteClassTo:(Class)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 old_isa = isa; + isa = aClassObject; + return old_isa; + } + return nil; +} + +- subclassResponsibility:(SEL)aSel +{ + return [self error:"subclass should override %s", sel_get_name(aSel)]; +} + +- notImplemented:(SEL)aSel +{ + return [self error:"method %s not implemented", sel_get_name(aSel)]; +} + +- shouldNotImplement:(SEL)aSel +{ + return [self error:"%s should not implement %s", + object_get_class_name(self), sel_get_name(aSel)]; +} + +- doesNotRecognize:(SEL)aSel +{ + return [self error:"%s does not recognize %s", + object_get_class_name(self), sel_get_name(aSel)]; +} + +#ifdef __alpha__ +extern size_t strlen(const char*); +#endif + +- error:(const char *)aString, ... +{ +#define FMT "error: %s (%s)\n%s\n" + char fmt[(strlen((char*)FMT)+strlen((char*)object_get_class_name(self)) + +((aString!=NULL)?strlen((char*)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 +} + ++ (int)version +{ + return class_get_version(self); +} + ++ setVersion:(int)aVersion +{ + class_set_version(self, aVersion); + return self; +} + ++ (int)streamVersion: (TypedStream*)aStream +{ + if (aStream->mode == OBJC_READONLY) + return objc_get_stream_class_version (aStream, self); + else + return class_get_version (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; +} + +- awake +{ + // [super awake]; + return self; +} + +@end diff --git a/contrib/gcc/objc/Protocol.h b/contrib/gcc/objc/Protocol.h new file mode 100644 index 0000000..c7464cf --- /dev/null +++ b/contrib/gcc/objc/Protocol.h @@ -0,0 +1,58 @@ +/* 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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/contrib/gcc/objc/Protocol.m b/contrib/gcc/objc/Protocol.m new file mode 100644 index 0000000..43ba44e --- /dev/null +++ b/contrib/gcc/objc/Protocol.m @@ -0,0 +1,128 @@ +/* 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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/contrib/gcc/objc/README b/contrib/gcc/objc/README new file mode 100644 index 0000000..70cea30 --- /dev/null +++ b/contrib/gcc/objc/README @@ -0,0 +1,97 @@ + +GNU Objective C notes +********************* + +This document is to explain what has been done, and a little about how +specific features differ from other implementations. The runtime has +been completely rewritten in gcc 2.4. The earlier runtime had several +severe bugs and was rather incomplete. The compiler has had several +new features added as well. + +This is not documentation for Objective C, it is usable to someone +who knows Objective C from somewhere else. + + +Runtime API functions +===================== + +The runtime is modeled after the NeXT Objective C runtime. That is, +most functions have semantics as it is known from the NeXT. The +names, however, have changed. All runtime API functions have names +of lowercase letters and and underscores as opposed to the +`traditional' mixed case names. + The runtime api functions are not documented as of now. +Someone offered to write it, and did it, but we were not allowed to +use it by his university (Very sad story). We have started writing +the documentation over again. This will be announced in appropriate +places when it becomes available. + + +Protocols +========= + +Protocols are now fully supported. The semantics is exactly as on the +NeXT. There is a flag to specify how protocols should be typechecked +when adopted to classes. The normal typechecker requires that all +methods in a given protocol must be implemented in the class that +adopts it -- it is not enough to inherit them. The flag +`-Wno-protocol' causes it to allow inherited methods, while +`-Wprotocols' is the default which requires them defined. + + ++initialize +=========== + +This method, if defined, is called before any other instance or class +methods of that particular class. This method is not inherited, and +is thus not called as initializer for a subclass that doesn't define +it itself. Thus, each +initialize method is called exactly once (or +never if no methods of that particular class is never called). +Besides this, it is allowed to have several +initialize methods, one +for each category. The order in which these (multiple methods) are +called is not well defined. I am not completely certain what the +semantics of this method is for other implementations, but this is +how it works for GNU Objective C. + + +Passivation/Activation/Typedstreams +=================================== + +This is supported in the style of NeXT TypedStream's. Consult the +headerfile Typedstreams.h for api functions. I (Kresten) have +rewritten it in Objective C, but this implementation is not part of +2.4, it is available from the GNU Objective C prerelease archive. + There is one difference worth noting concerning objects stored with +objc_write_object_reference (aka NXWriteObjectReference). When these +are read back in, their object is not guaranteed to be available until +the `-awake' method is called in the object that requests that object. +To objc_read_object you must pass a pointer to an id, which is valid +after exit from the function calling it (like e.g. an instance +variable). In general, you should not use objects read in until the +-awake method is called. + + +Acknowledgements +================ + +The GNU Objective C team: Geoffrey Knauth (manager), +Tom Wood (compiler) and Kresten Krab Thorup + (runtime) would like to thank a some people for +participating in the development of the present GNU Objective C. + +Paul Burchard and Andrew McCallum + has been very helpful debugging the +runtime. Eric Herring has been very helpful +cleaning up after the documentation-copyright disaster and is now +helping with the new documentation. + +Steve Naroff and Richard Stallman + has been very helpful with implementation details +in the compiler. + + +Bug Reports +=========== + +Please read the section `Submitting Bugreports' of the gcc manual +before you submit any bugs. diff --git a/contrib/gcc/objc/archive.c b/contrib/gcc/objc/archive.c new file mode 100644 index 0000000..0d55152 --- /dev/null +++ b/contrib/gcc/objc/archive.c @@ -0,0 +1,1616 @@ +/* GNU Objective C Runtime archiving + Copyright (C) 1993, 1995 Free Software Foundation, Inc. + Contributed by 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 "typedstream.h" +#include "encoding.h" + +extern int fflush(FILE*); + +#define ROUND(V, A) \ + ({ typeof(V) __v=(V); typeof(A) __a=(A); \ + __a*((__v+__a-1)/__a); }) + +#define PTR2LONG(P) (((char*)(P))-(char*)0) +#define LONG2PTR(L) (((char*)0)+(L)) + +#define __objc_fatal(format, args...) \ + { fprintf(stderr, "archiving: "); \ + fprintf(stderr, format, ## args); \ + fprintf(stderr, "\n"); abort(); } + +/* Declare some functions... */ + +static int +objc_read_class (struct objc_typed_stream* stream, Class* class); + +int objc_sizeof_type(const char* type); + +static int +objc_write_use_common (struct objc_typed_stream* stream, unsigned long key); + +static int +objc_write_register_common (struct objc_typed_stream* stream, + unsigned long key); + +static int +objc_write_class (struct objc_typed_stream* stream, + struct objc_class* class); + +const char* objc_skip_type (const char* type); + +static void __objc_finish_write_root_object(struct objc_typed_stream*); +static void __objc_finish_read_root_object(struct objc_typed_stream*); + +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&_B_VALUE) == val) + { + buf[0] = val|_B_SINT; + return 1; + } + else + { + int c, b; + + buf[0] = _B_NINT; + + for (c= sizeof(short); c != 0; c -= 1) + if (((val>>(8*(c-1)))%0x100) != 0) + break; + + buf[0] |= c; + + for (b = 1; c != 0; c--, b++) + { + buf[b] = (val >> (8*(c-1)))%0x100; + } + + return b; + } +} + +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) +{ + int sign = (val < 0); + int size = __objc_code_unsigned_short (buf, sign ? -val : val); + if (sign) + buf[0] |= _B_SIGN; + return size; +} + +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&_B_VALUE) == val) + { + buf[0] = val|_B_SINT; + return 1; + } + else + { + int c, b; + + buf[0] = _B_NINT; + + for (c= sizeof(int); c != 0; c -= 1) + if (((val>>(8*(c-1)))%0x100) != 0) + break; + + buf[0] |= c; + + for (b = 1; c != 0; c--, b++) + { + buf[b] = (val >> (8*(c-1)))%0x100; + } + + return b; + } +} + +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) +{ + int sign = (val < 0); + int size = __objc_code_unsigned_int (buf, sign ? -val : val); + if (sign) + buf[0] |= _B_SIGN; + return size; +} + +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); +} + +static __inline__ int +__objc_code_unsigned_long (unsigned char* buf, unsigned long val) +{ + if ((val&_B_VALUE) == val) + { + buf[0] = val|_B_SINT; + return 1; + } + else + { + int c, b; + + buf[0] = _B_NINT; + + for (c= sizeof(long); c != 0; c -= 1) + if (((val>>(8*(c-1)))%0x100) != 0) + break; + + buf[0] |= c; + + for (b = 1; c != 0; c--, b++) + { + buf[b] = (val >> (8*(c-1)))%0x100; + } + + return b; + } +} + +int +objc_write_unsigned_long (struct objc_typed_stream* stream, unsigned long value) +{ + unsigned char buf[sizeof(unsigned long)+1]; + int len = __objc_code_unsigned_long (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + +static __inline__ int +__objc_code_long (unsigned char* buf, long val) +{ + int sign = (val < 0); + int size = __objc_code_unsigned_long (buf, sign ? -val : val); + if (sign) + buf[0] |= _B_SIGN; + return size; +} + +int +objc_write_long (struct objc_typed_stream* stream, long value) +{ + unsigned char buf[sizeof(long)+1]; + int len = __objc_code_long (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 long key; + if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, string)))) + return objc_write_use_common (stream, key); + else + { + int length; + hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(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 long key) +{ + unsigned char buf[sizeof (unsigned long)+2]; + int len = __objc_code_unsigned_long (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 long key) +{ + unsigned char buf[sizeof (unsigned long)+2]; + int len = __objc_code_unsigned_long (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_any_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_reference (struct objc_typed_stream* stream, id object) +{ + unsigned long key; + if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object)))) + return objc_write_use_common (stream, key); + + __objc_write_extension (stream, _BX_OBJREF); + return objc_write_unsigned_long (stream, PTR2LONG (object)); +} + +int +objc_write_root_object (struct objc_typed_stream* stream, id object) +{ + int len; + if (stream->writing_root_p) + __objc_fatal ("objc_write_root_object called recursively") + else + { + stream->writing_root_p = 1; + __objc_write_extension (stream, _BX_OBJROOT); + if((len = objc_write_object (stream, object))) + __objc_finish_write_root_object(stream); + stream->writing_root_p = 0; + } + return len; +} + +int +objc_write_object (struct objc_typed_stream* stream, id object) +{ + unsigned long key; + if ((key = PTR2LONG(hash_value_for_key (stream->object_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->object_table, LONG2PTR(key=PTR2LONG(object)), object); + if ((length = objc_write_register_common (stream, key))) + return __objc_write_object (stream, object); + return length; + } +} + +#ifdef __alpha__ +extern int atoi (const char*); +extern size_t strlen(const char*); +extern size_t strcpy(char*, const char*); +#endif + +__inline__ int +__objc_write_class (struct objc_typed_stream* stream, struct objc_class* class) +{ + __objc_write_extension (stream, _BX_CLASS); + objc_write_string_atomic(stream, (char*)class->name, + strlen((char*)class->name)); + return objc_write_unsigned_long (stream, class->version); +} + + +static int +objc_write_class (struct objc_typed_stream* stream, + struct objc_class* class) +{ + unsigned long key; + if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, class)))) + return objc_write_use_common (stream, key); + else + { + int length; + hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(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; + __objc_write_extension (stream, _BX_SEL); + /* to handle NULL selectors */ + if ((SEL)0 == selector) + return objc_write_string (stream, "", 0); + sel_name = sel_get_name (selector); + return objc_write_string (stream, sel_name, strlen ((char*)sel_name)); +} + +int +objc_write_selector (struct objc_typed_stream* stream, SEL selector) +{ + const char* sel_name; + unsigned long key; + + /* to handle NULL selectors */ + if ((SEL)0 == selector) + return __objc_write_selector (stream, selector); + + sel_name = sel_get_name (selector); + if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, sel_name)))) + return objc_write_use_common (stream, key); + else + { + int length; + hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(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_long (struct objc_typed_stream* stream, long* value) +{ + unsigned char buf[sizeof(long)+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 (long)) + __objc_fatal("expected long, 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; +} + +int +__objc_read_nbyte_ulong (struct objc_typed_stream* stream, + unsigned int nbytes, unsigned long* val) +{ + int len, pos = 0; + unsigned char buf[sizeof(unsigned long)+1]; + + if (nbytes > sizeof (long)) + __objc_fatal("expected long, 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_long (struct objc_typed_stream* stream, + unsigned long* value) +{ + unsigned char buf[sizeof(unsigned long)+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_ulong (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 long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_ulong(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*)__objc_xmalloc(length+1); + if (key) + hash_add (&stream->stream_table, LONG2PTR(key), *string); + len = (*stream->read)(stream->physical, *string, length); + (*string)[length] = '\0'; + } + break; + + case _B_UCOMM: + { + char *tmp; + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + tmp = hash_value_for_key (stream->stream_table, LONG2PTR (key)); + *string = __objc_xmalloc (strlen(tmp) + 1); + strcpy (*string, tmp); + } + break; + + case _B_NSTR: + { + unsigned int nbytes = buf[0]&_B_VALUE; + len = __objc_read_nbyte_uint(stream, nbytes, &nbytes); + if (len) { + (*string) = (char*)__objc_xmalloc(nbytes+1); + if (key) + hash_add (&stream->stream_table, LONG2PTR(key), *string); + len = (*stream->read)(stream->physical, *string, nbytes); + (*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_any_uid ("read:"); + unsigned long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */ + { + len = __objc_read_nbyte_ulong(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->object_table, LONG2PTR(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_ulong(stream, (buf[0] & _B_VALUE), &key); + (*object) = hash_value_for_key (stream->object_table, LONG2PTR(key)); + } + + else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */ + { + struct objc_list* other; + len = objc_read_unsigned_long (stream, &key); + other = (struct objc_list*)hash_value_for_key (stream->object_refs, LONG2PTR(key)); + hash_add (&stream->object_refs, LONG2PTR(key), (void*)list_cons(object, other)); + } + + else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */ + { + if (key) + __objc_fatal("cannot register root object..."); + len = objc_read_object (stream, object); + __objc_finish_read_root_object (stream); + } + + 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))) + { + unsigned long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read)(stream->physical, buf, 1); + } + + if (buf[0] == (_B_EXT | _BX_CLASS)) + { + char* class_name; + unsigned long 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, LONG2PTR(key), *class); + + objc_read_unsigned_long(stream, &version); + hash_add (&stream->class_table, (*class)->name, (void*)version); + } + + else if ((buf[0]&_B_CODE) == _B_UCOMM) + { + if (key) + __objc_fatal("cannot register use upcode..."); + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + (*class) = hash_value_for_key (stream->stream_table, LONG2PTR(key)); + if (!*class) + __objc_fatal("cannot find class for key %lu", 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 long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_ulong(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); + /* To handle NULL selectors */ + if (0 == strlen(selector_name)) + { + (*selector) = (SEL)0; + return 0; + } + else + (*selector) = sel_get_any_uid(selector_name); + free (selector_name); + + /* register */ + if (key) + hash_add (&stream->stream_table, LONG2PTR(key), (void*)*selector); + } + + else if ((buf[0]&_B_CODE) == _B_UCOMM) + { + if (key) + __objc_fatal("cannot register use upcode..."); + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + (*selector) = hash_value_for_key (stream->stream_table, LONG2PTR(key)); + } + + else + __objc_fatal("expected selector, got opcode %c", buf[0]); + } + return len; +} + +/* +** 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: + return objc_write_int(stream, *(int*)data); + break; + + case _C_UINT: + return objc_write_unsigned_int(stream, *(unsigned int*)data); + break; + + case _C_LNG: + return objc_write_long(stream, *(long*)data); + break; + + case _C_ULNG: + return objc_write_unsigned_long(stream, *(unsigned long*)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; + + case _C_STRUCT_B: + { + int acc_size = 0; + int align; + while (*type != _C_STRUCT_E && *type++ != '='); /* skip "=" */ + while (*type != _C_STRUCT_E); + { + align = objc_alignof_type (type); /* padd to alignment */ + acc_size += ROUND (acc_size, align); + objc_write_type (stream, type, ((char*)data)+acc_size); + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + return 1; + } + + 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: + return objc_read_int (stream, (int*)data); + break; + + case _C_UINT: + return objc_read_unsigned_int (stream, (unsigned int*)data); + break; + + case _C_LNG: + return objc_read_long (stream, (long*)data); + break; + + case _C_ULNG: + return objc_read_unsigned_long (stream, (unsigned long*)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; + + case _C_STRUCT_B: + { + int acc_size = 0; + int align; + while (*type != _C_STRUCT_E && *type++ != '='); /* skip "=" */ + while (*type != _C_STRUCT_E); + { + align = objc_alignof_type (type); /* padd to alignment */ + acc_size += ROUND (acc_size, align); + objc_read_type (stream, type, ((char*)data)+acc_size); + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + return 1; + } + + default: + fprintf(stderr, "objc_read_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_typespec (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: + res = objc_write_int(stream, *va_arg(args, int*)); + break; + + case _C_UINT: + res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*)); + break; + + case _C_LNG: + res = objc_write_long(stream, *va_arg(args, long*)); + break; + + case _C_ULNG: + res = objc_write_unsigned_long(stream, *va_arg(args, unsigned long*)); + 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_typespec (t); + if (*t != _C_ARY_E) + __objc_fatal("expected `]', got: %s", t); + } + break; + + default: + fprintf(stderr, "objc_write_types: 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_typespec(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: + res = objc_read_int(stream, va_arg(args, int*)); + break; + + case _C_UINT: + res = objc_read_unsigned_int(stream, va_arg(args, unsigned int*)); + break; + + case _C_LNG: + res = objc_read_long(stream, va_arg(args, long*)); + break; + + case _C_ULNG: + res = objc_read_unsigned_long(stream, va_arg(args, unsigned long*)); + 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_typespec (t); + if (*t != _C_ARY_E) + __objc_fatal("expected `]', got: %s", t); + } + break; + + default: + fprintf(stderr, "objc_read_types: 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]", 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]", 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 void +__objc_free (void* p) +{ + free (p); +} + +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); + return 1; +} + +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); + return 1; +} + +static void __objc_finish_write_root_object(struct objc_typed_stream* stream) +{ + hash_delete (stream->object_table); + stream->object_table = hash_new(64, + (hash_func_type)hash_ptr, + (compare_func_type)compare_ptrs); +} + +static void __objc_finish_read_root_object(struct objc_typed_stream* stream) +{ + node_ptr node; + struct objc_list* free_list; + SEL awake_sel = sel_get_any_uid ("awake"); + + /* resolve object forward references */ + free_list = list_cons(NULL, NULL); + for (node = hash_next (stream->object_refs, NULL); node; + node = hash_next (stream->object_refs, node)) + { + struct objc_list* reflist = node->value; + const void* key = node->key; + id object = hash_value_for_key (stream->object_table, key); + while(reflist) + { + *((id*)reflist->head) = object; + if (list_find(&free_list, reflist) == NULL) + free_list = list_cons (reflist, free_list); + reflist = reflist->tail; + } + } + list_mapcar (free_list, __objc_free); + list_free (free_list); + + /* empty object reference table */ + hash_delete (stream->object_refs); + stream->object_refs = hash_new(8, (hash_func_type)hash_ptr, + (compare_func_type)compare_ptrs); + + /* call -awake for all objects read */ + if (awake_sel) + { + for (node = hash_next (stream->object_table, NULL); node; + node = hash_next (stream->object_table, node)) + { + id object = node->value; + if (__objc_responds_to (object, awake_sel)) + (*objc_msg_lookup(object, awake_sel))(object, awake_sel); + } + } + + /* empty object table */ + hash_delete (stream->object_table); + stream->object_table = hash_new(64, + (hash_func_type)hash_ptr, + (compare_func_type)compare_ptrs); +} + +/* +** Open the stream PHYSICAL in MODE +*/ + +TypedStream* +objc_open_typed_stream (FILE* physical, int mode) +{ + TypedStream* s = (TypedStream*)__objc_xmalloc(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->object_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; + s->writing_root_p = 0; + if (mode == OBJC_READONLY) + { + s->class_table = hash_new(8, (hash_func_type)hash_string, + (compare_func_type)compare_strings); + s->object_refs = hash_new(8, (hash_func_type)hash_ptr, + (compare_func_type)compare_ptrs); + 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->object_refs = 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->mode == OBJC_READONLY) + { + __objc_finish_read_root_object (stream); /* Just in case... */ + hash_delete (stream->class_table); + hash_delete (stream->object_refs); + } + + hash_delete (stream->stream_table); + hash_delete (stream->object_table); + + if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM)) + fclose ((FILE*)stream->physical); + + 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); +} + +long +objc_get_stream_class_version (TypedStream* stream, Class class) +{ + if (stream->class_table) + return PTR2LONG(hash_value_for_key (stream->class_table, class->name)); + else + return class_get_version (class); +} + diff --git a/contrib/gcc/objc/class.c b/contrib/gcc/objc/class.c new file mode 100644 index 0000000..3617a09 --- /dev/null +++ b/contrib/gcc/objc/class.c @@ -0,0 +1,327 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993, 1995 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup and 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 */ +#include "sarray.h" + +/* 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 (*_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 class) +{ + Class 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 objc_lookup_class (const char* name) +{ + Class 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 +objc_get_class (const char *name) +{ + Class 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(); +} + +MetaClass +objc_get_meta_class(const char *name) +{ + return objc_get_class(name)->class_pointer; +} + +/* This function provides a way to enumerate all the classes in the + executable. Pass *ENUM_STATE == NULL to start the enumeration. The + function will return 0 when there are no more classes. + For example: + id class; + void *es = NULL; + while ((class = objc_next_class(&es))) + ... do something with class; +*/ +Class +objc_next_class(void **enum_state) +{ + /* make sure the table is there */ + assert(__objc_class_hash); + + *(node_ptr*)enum_state = + hash_next(__objc_class_hash, *(node_ptr*)enum_state); + if (*(node_ptr*)enum_state) + return (*(node_ptr*)enum_state)->value; + return (Class)0; +} + +/* 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 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 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 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 class1 = node->value; + Class 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; + } + } +} + + + +#define CLASSOF(c) ((c)->class_pointer) + +Class +class_pose_as (Class impostor, Class super_class) +{ + node_ptr node; + Class class1; + + if (!CLS_ISRESOLV (impostor)) + __objc_resolve_class_links (); + + /* preconditions */ + assert (impostor); + assert (super_class); + assert (impostor->super_class == super_class); + assert (CLS_ISCLASS (impostor)); + assert (CLS_ISCLASS (super_class)); + assert (impostor->instance_size == super_class->instance_size); + + { + Class *subclass = &(super_class->subclass_list); + + /* move subclasses of super_class to impostor */ + while (*subclass) + { + Class nextSub = (*subclass)->sibling_class; + + if (*subclass != impostor) + { + Class sub = *subclass; + + /* classes */ + sub->sibling_class = impostor->subclass_list; + sub->super_class = impostor; + impostor->subclass_list = sub; + + /* It will happen that SUB is not a class object if it is + the top of the meta class hierarchy chain. (root + meta-class objects inherit their class object) If that is + the case... don't mess with the meta-meta class. */ + if (CLS_ISCLASS (sub)) + { + /* meta classes */ + CLASSOF (sub)->sibling_class = CLASSOF (impostor)->subclass_list; + CLASSOF (sub)->super_class = CLASSOF (impostor); + CLASSOF (impostor)->subclass_list = CLASSOF (sub); + } + } + + *subclass = nextSub; + } + + /* set subclasses of superclass to be impostor only */ + super_class->subclass_list = impostor; + CLASSOF (super_class)->subclass_list = CLASSOF (impostor); + + /* set impostor to have no sibling classes */ + impostor->sibling_class = 0; + CLASSOF (impostor)->sibling_class = 0; + } + + /* check relationship of impostor and super_class is kept. */ + assert (impostor->super_class == super_class); + assert (CLASSOF (impostor)->super_class == CLASSOF (super_class)); + + /* This is how to update the lookup table. Regardless of + what the keys of the hashtable is, change all values that are + superclass into impostor. */ + + for (node = hash_next (__objc_class_hash, NULL); node; + node = hash_next (__objc_class_hash, node)) + { + class1 = (Class)node->value; + if (class1 == super_class) + { + node->value = impostor; /* change hash table value */ + } + } + + /* next, we update the dispatch tables... */ + __objc_update_dispatch_table_for_class (CLASSOF (impostor)); + __objc_update_dispatch_table_for_class (impostor); + + return impostor; +} + + diff --git a/contrib/gcc/objc/encoding.c b/contrib/gcc/objc/encoding.c new file mode 100644 index 0000000..9620664 --- /dev/null +++ b/contrib/gcc/objc/encoding.c @@ -0,0 +1,537 @@ +/* Encoding of types for Objective C. + Copyright (C) 1993, 1995 Free Software Foundation, Inc. + Contributed by 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 "encoding.h" + +#define MAX(X, Y) \ + ({ typeof(X) __x = (X), __y = (Y); \ + (__x > __y ? __x : __y); }) + +#define MIN(X, Y) \ + ({ typeof(X) __x = (X), __y = (Y); \ + (__x < __y ? __x : __y); }) + +#define ROUND(V, A) \ + ({ typeof(V) __v=(V); typeof(A) __a=(A); \ + __a*((__v+__a-1)/__a); }) + + +static inline int +atoi (const char* str) +{ + int res = 0; + + while (isdigit (*str)) + res *= 10, res += (*str++ - '0'); + + return res; +} + +/* + return the size of an object specified by type +*/ + +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: + return sizeof(int); + break; + + case _C_UINT: + return sizeof(unsigned int); + break; + + case _C_LNG: + return sizeof(long); + break; + + case _C_ULNG: + return sizeof(unsigned long); + break; + + case _C_FLT: + return sizeof(float); + break; + + case _C_DBL: + return sizeof(double); + break; + + case _C_PTR: + case _C_ATOM: + case _C_CHARPTR: + return sizeof(char*); + break; + + case _C_ARY_B: + { + int len = atoi(type+1); + while (isdigit(*++type)); + return len*objc_aligned_size (type); + } + break; + + case _C_STRUCT_B: + { + int acc_size = 0; + int align; + while (*type != _C_STRUCT_E && *type++ != '='); /* skip "=" */ + while (*type != _C_STRUCT_E) + { + align = objc_alignof_type (type); /* padd to alignment */ + acc_size = ROUND (acc_size, align); + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + return acc_size; + } + + case _C_UNION_B: + { + int max_size = 0; + while (*type != _C_UNION_E && *type++ != '=') /* do nothing */; + while (*type != _C_UNION_E) + { + max_size = MAX (max_size, objc_sizeof_type (type)); + type = objc_skip_typespec (type); + } + return max_size; + } + + default: + abort(); + } +} + + +/* + Return the alignment of an object specified by type +*/ + +int +objc_alignof_type(const char* type) +{ + switch(*type) { + case _C_ID: + return __alignof__(id); + break; + + case _C_CLASS: + return __alignof__(Class); + break; + + case _C_SEL: + return __alignof__(SEL); + break; + + case _C_CHR: + return __alignof__(char); + break; + + case _C_UCHR: + return __alignof__(unsigned char); + break; + + case _C_SHT: + return __alignof__(short); + break; + + case _C_USHT: + return __alignof__(unsigned short); + break; + + case _C_INT: + return __alignof__(int); + break; + + case _C_UINT: + return __alignof__(unsigned int); + break; + + case _C_LNG: + return __alignof__(long); + break; + + case _C_ULNG: + return __alignof__(unsigned long); + break; + + case _C_FLT: + return __alignof__(float); + break; + + case _C_DBL: + return __alignof__(double); + break; + + case _C_ATOM: + case _C_CHARPTR: + return __alignof__(char*); + break; + + case _C_ARY_B: + while (isdigit(*++type)) /* do nothing */; + return objc_alignof_type (type); + + case _C_STRUCT_B: + { + struct { int x; double y; } fooalign; + while(*type != _C_STRUCT_E && *type++ != '=') /* do nothing */; + if (*type != _C_STRUCT_E) + return MAX (objc_alignof_type (type), __alignof__ (fooalign)); + else + return __alignof__ (fooalign); + } + + case _C_UNION_B: + { + int maxalign = 0; + while (*type != _C_UNION_E && *type++ != '=') /* do nothing */; + while (*type != _C_UNION_E) + { + maxalign = MAX (maxalign, objc_alignof_type (type)); + type = objc_skip_typespec (type); + } + return maxalign; + } + + default: + abort(); + } +} + +/* + The aligned size if the size rounded up to the nearest alignment. +*/ + +int +objc_aligned_size (const char* type) +{ + int size = objc_sizeof_type (type); + int align = objc_alignof_type (type); + return ROUND (size, align); +} + +/* + The size rounded up to the nearest integral of the wordsize, taken + to be the size of a void*. +*/ + +int +objc_promoted_size (const char* type) +{ + int size = objc_sizeof_type (type); + int wordsize = sizeof (void*); + + return ROUND (size, wordsize); +} + +/* + Skip type qualifiers. These may eventually precede typespecs + occurring in method prototype encodings. +*/ + +inline const char* +objc_skip_type_qualifiers (const char* type) +{ + while (*type == _C_CONST + || *type == _C_IN + || *type == _C_INOUT + || *type == _C_OUT + || *type == _C_BYCOPY + || *type == _C_ONEWAY) + { + type += 1; + } + return type; +} + + +/* + Skip one typespec element. If the typespec is prepended by type + qualifiers, these are skipped as well. +*/ + +const char* +objc_skip_typespec (const char* type) +{ + type = objc_skip_type_qualifiers (type); + + switch (*type) { + + case _C_ID: + /* An id may be annotated by the actual type if it is known + with the @"ClassName" syntax */ + + if (*++type != '"') + return type; + else + { + while (*++type != '"') /* do nothing */; + return type + 1; + } + + /* The following are one character type codes */ + 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: + case _C_VOID: + return ++type; + break; + + case _C_ARY_B: + /* skip digits, typespec and closing ']' */ + + while(isdigit(*++type)); + type = objc_skip_typespec(type); + if (*type == _C_ARY_E) + return ++type; + else + abort(); + + case _C_STRUCT_B: + /* skip name, and elements until closing '}' */ + + while (*type != _C_STRUCT_E && *type++ != '='); + while (*type != _C_STRUCT_E) { type = objc_skip_typespec (type); } + return ++type; + + case _C_UNION_B: + /* skip name, and elements until closing ')' */ + + while (*type != _C_UNION_E && *type++ != '='); + while (*type != _C_UNION_E) { type = objc_skip_typespec (type); } + return ++type; + + case _C_PTR: + /* Just skip the following typespec */ + + return objc_skip_typespec (++type); + + default: + abort(); + } +} + +/* + Skip an offset as part of a method encoding. This is prepended by a + '+' if the argument is passed in registers. +*/ +inline const char* +objc_skip_offset (const char* type) +{ + if (*type == '+') type++; + while(isdigit(*++type)); + return type; +} + +/* + Skip an argument specification of a method encoding. +*/ +const char* +objc_skip_argspec (const char* type) +{ + type = objc_skip_typespec (type); + type = objc_skip_offset (type); + return type; +} + +/* + Return the number of arguments that the method MTH expects. + Note that all methods need two implicit arguments `self' and + `_cmd'. +*/ +int +method_get_number_of_arguments (struct objc_method* mth) +{ + int i = 0; + const char* type = mth->method_types; + while (*type) + { + type = objc_skip_argspec (type); + i += 1; + } + return i - 1; +} + +/* + Return the size of the argument block needed on the stack to invoke + the method MTH. This may be zero, if all arguments are passed in + registers. +*/ + +int +method_get_sizeof_arguments (struct objc_method* mth) +{ + const char* type = objc_skip_typespec (mth->method_types); + return atoi (type); +} + +/* + Return a pointer to the next argument of ARGFRAME. type points to + the last argument. Typical use of this look like: + + { + char *datum, *type; + for (datum = method_get_first_argument (method, argframe, &type); + datum; datum = method_get_next_argument (argframe, &type)) + { + unsigned flags = objc_get_type_qualifiers (type); + type = objc_skip_type_qualifiers (type); + if (*type != _C_PTR) + [portal encodeData: datum ofType: type]; + else + { + if ((flags & _F_IN) == _F_IN) + [portal encodeData: *(char**)datum ofType: ++type]; + } + } + } +*/ + +char* +method_get_next_argument (arglist_t argframe, + const char **type) +{ + const char *t = objc_skip_argspec (*type); + + if (*t == '\0') + return 0; + + *type = t; + t = objc_skip_typespec (t); + + if (*t == '+') + return argframe->arg_regs + atoi (++t); + else + return argframe->arg_ptr + atoi (t); +} + +/* + Return a pointer to the value of the first argument of the method + described in M with the given argumentframe ARGFRAME. The type + is returned in TYPE. type must be passed to successive calls of + method_get_next_argument. +*/ +char* +method_get_first_argument (struct objc_method* m, + arglist_t argframe, + const char** type) +{ + *type = m->method_types; + return method_get_next_argument (argframe, type); +} + +/* + Return a pointer to the ARGth argument of the method + M from the frame ARGFRAME. The type of the argument + is returned in the value-result argument TYPE +*/ + +char* +method_get_nth_argument (struct objc_method* m, + arglist_t argframe, int arg, + const char **type) +{ + const char* t = objc_skip_argspec (m->method_types); + + if (arg > method_get_number_of_arguments (m)) + return 0; + + while (arg--) + t = objc_skip_argspec (t); + + *type = t; + t = objc_skip_typespec (t); + + if (*t == '+') + return argframe->arg_regs + atoi (++t); + else + return argframe->arg_ptr + atoi (t); +} + +unsigned +objc_get_type_qualifiers (const char* type) +{ + unsigned res = 0; + BOOL flag = YES; + + while (flag) + switch (*type++) + { + case _C_CONST: res |= _F_CONST; break; + case _C_IN: res |= _F_IN; break; + case _C_INOUT: res |= _F_INOUT; break; + case _C_OUT: res |= _F_OUT; break; + case _C_BYCOPY: res |= _F_BYCOPY; break; + case _C_ONEWAY: res |= _F_ONEWAY; break; + default: flag = NO; + } + + return res; +} diff --git a/contrib/gcc/objc/encoding.h b/contrib/gcc/objc/encoding.h new file mode 100644 index 0000000..c956034 --- /dev/null +++ b/contrib/gcc/objc/encoding.h @@ -0,0 +1,75 @@ +/* Encoding of types for Objective C. + 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 __encoding_INCLUDE_GNU +#define __encoding_INCLUDE_GNU + +#include +#include "objc/objc-api.h" + +#define _C_CONST 'r' +#define _C_IN 'n' +#define _C_INOUT 'N' +#define _C_OUT 'o' +#define _C_BYCOPY 'O' +#define _C_ONEWAY 'V' + +#define _F_CONST 0x01 +#define _F_IN 0x01 +#define _F_OUT 0x02 +#define _F_INOUT 0x03 +#define _F_BYCOPY 0x04 +#define _F_ONEWAY 0x08 + + +int objc_aligned_size (const char* type); +int objc_sizeof_type (const char* type); +int objc_alignof_type (const char* type); +int objc_aligned_size (const char* type); +int objc_promoted_size (const char* type); +const char* objc_skip_type_qualifiers (const char* type); +const char* objc_skip_typespec (const char* type); +const char* objc_skip_offset (const char* type); +const char* objc_skip_argspec (const char* type); +int method_get_number_of_arguments (struct objc_method*); +int method_get_size_of_arguments (struct objc_method*); + +char* method_get_first_argument (struct objc_method*, + arglist_t argframe, + const char** type); +char* method_get_next_argument (arglist_t argframe, + const char **type); +char* method_get_nth_argument (struct objc_method* m, + arglist_t argframe, + int arg, + const char **type); + +unsigned objc_get_type_qualifiers (const char* type); + + +#endif /* __encoding_INCLUDE_GNU */ diff --git a/contrib/gcc/objc/hash.c b/contrib/gcc/objc/hash.c new file mode 100644 index 0000000..3391274 --- /dev/null +++ b/contrib/gcc/objc/hash.c @@ -0,0 +1,253 @@ +/* Hash tables for Objective C internal structures + 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 "assert.h" + +#include "objc/hash.h" +#include "objc/objc.h" + +#include "runtime.h" /* for DEBUG_PRINTF */ + +/* These two macros determine when a hash table is full and + by how much it should be expanded respectively. + + These equations are percentages. */ +#define FULLNESS(cache) \ + ((((cache)->size * 75) / 100) <= (cache)->used) +#define EXPANSION(cache) \ + ((cache)->size * 2) + +void *__objc_xcalloc (size_t, size_t); + +cache_ptr +hash_new (unsigned int size, hash_func_type hash_func, + compare_func_type compare_func) +{ + cache_ptr cache; + + /* Pass me a value greater than 0 and a power of 2. */ + assert (size); + assert (!(size & (size - 1))); + + /* Allocate the cache structure. calloc insures + its initialization for default values. */ + cache = (cache_ptr) __objc_xcalloc (1, sizeof (struct cache)); + assert (cache); + + /* Allocate the array of buckets for the cache. + calloc initializes all of the pointers to NULL. */ + cache->node_table + = (node_ptr *) __objc_xcalloc (size, sizeof (node_ptr)); + assert (cache->node_table); + + cache->size = size; + + /* This should work for all processor architectures? */ + cache->mask = (size - 1); + + /* Store the hashing function so that codes can be computed. */ + cache->hash_func = hash_func; + + /* Store the function that compares hash keys to + determine if they are equal. */ + cache->compare_func = compare_func; + + return cache; +} + + +void +hash_delete (cache_ptr cache) +{ + node_ptr node; + + + /* Purge all key/value pairs from the table. */ + while ((node = hash_next (cache, NULL))) + hash_remove (cache, node->key); + + /* Release the array of nodes and the cache itself. */ + free (cache->node_table); + free (cache); +} + + +void +hash_add (cache_ptr *cachep, const void *key, void *value) +{ + size_t indx = (*(*cachep)->hash_func)(*cachep, key); + node_ptr node = (node_ptr) __objc_xcalloc (1, sizeof (struct cache_node)); + + + assert (node); + + /* Initialize the new node. */ + node->key = key; + node->value = value; + node->next = (*cachep)->node_table[indx]; + + /* Debugging. + Check the list for another key. */ +#ifdef DEBUG + { node_ptr node1 = (*cachep)->node_table[indx]; + + while (node1) { + + assert (node1->key != key); + node1 = node1->next; + } + } +#endif + + /* Install the node as the first element on the list. */ + (*cachep)->node_table[indx] = node; + + /* Bump the number of entries in the cache. */ + ++(*cachep)->used; + + /* Check the hash table's fullness. We're going + to expand if it is above the fullness level. */ + if (FULLNESS (*cachep)) { + + /* The hash table has reached its fullness level. Time to + expand it. + + I'm using a slow method here but is built on other + primitive functions thereby increasing its + correctness. */ + node_ptr node1 = NULL; + cache_ptr new = hash_new (EXPANSION (*cachep), + (*cachep)->hash_func, + (*cachep)->compare_func); + + DEBUG_PRINTF ("Expanding cache %#x from %d to %d\n", + *cachep, (*cachep)->size, new->size); + + /* Copy the nodes from the first hash table to the new one. */ + while ((node1 = hash_next (*cachep, node1))) + hash_add (&new, node1->key, node1->value); + + /* Trash the old cache. */ + hash_delete (*cachep); + + /* Return a pointer to the new hash table. */ + *cachep = new; + } +} + + +void +hash_remove (cache_ptr cache, const void *key) +{ + size_t indx = (*cache->hash_func)(cache, key); + node_ptr node = cache->node_table[indx]; + + + /* We assume there is an entry in the table. Error if it is not. */ + assert (node); + + /* Special case. First element is the key/value pair to be removed. */ + if ((*cache->compare_func)(node->key, key)) { + cache->node_table[indx] = node->next; + free (node); + } else { + + /* Otherwise, find the hash entry. */ + node_ptr prev = node; + BOOL removed = NO; + + do { + + if ((*cache->compare_func)(node->key, key)) { + prev->next = node->next, removed = YES; + free (node); + } else + prev = node, node = node->next; + } while (!removed && node); + assert (removed); + } + + /* Decrement the number of entries in the hash table. */ + --cache->used; +} + + +node_ptr +hash_next (cache_ptr cache, node_ptr node) +{ + /* If the scan is being started then reset the last node + visitied pointer and bucket index. */ + if (!node) + cache->last_bucket = 0; + + /* If there is a node visited last then check for another + entry in the same bucket; Otherwise step to the next bucket. */ + if (node) { + if (node->next) + /* There is a node which follows the last node + returned. Step to that node and retun it. */ + return node->next; + else + ++cache->last_bucket; + } + + /* If the list isn't exhausted then search the buckets for + other nodes. */ + if (cache->last_bucket < cache->size) { + /* Scan the remainder of the buckets looking for an entry + at the head of the list. Return the first item found. */ + while (cache->last_bucket < cache->size) + if (cache->node_table[cache->last_bucket]) + return cache->node_table[cache->last_bucket]; + else + ++cache->last_bucket; + + /* No further nodes were found in the hash table. */ + return NULL; + } else + return NULL; +} + + +/* Given KEY, return corresponding value for it in CACHE. + Return NULL if the KEY is not recorded. */ + +void * +hash_value_for_key (cache_ptr cache, const void *key) +{ + node_ptr node = cache->node_table[(*cache->hash_func)(cache, key)]; + void *retval = NULL; + + if (node) + do { + if ((*cache->compare_func)(node->key, key)) + retval = node->value; + else + node = node->next; + } while (!retval && node); + + return retval; +} diff --git a/contrib/gcc/objc/hash.h b/contrib/gcc/objc/hash.h new file mode 100644 index 0000000..7a83b08 --- /dev/null +++ b/contrib/gcc/objc/hash.h @@ -0,0 +1,202 @@ +/* Hash tables for Objective C method dispatch. + Copyright (C) 1993, 1995 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 __hash_INCLUDE_GNU +#define __hash_INCLUDE_GNU + +#include + +/* + * This data structure is used to hold items + * stored in a hash table. Each node holds + * a key/value pair. + * + * Items in the cache are really of type void *. + */ +typedef struct cache_node +{ + struct cache_node *next; /* Pointer to next entry on the list. + NULL indicates end of list. */ + const void *key; /* Key used to locate the value. Used + to locate value when more than one + key computes the same hash + value. */ + void *value; /* Value stored for the key. */ +} *node_ptr; + + +/* + * This data type is the function that computes a hash code given a key. + * Therefore, the key can be a pointer to anything and the function specific + * to the key type. + * + * Unfortunately there is a mutual data structure reference problem with this + * typedef. Therefore, to remove compiler warnings the functions passed to + * hash_new will have to be casted to this type. + */ +typedef unsigned int (*hash_func_type)(void *, const void *); + +/* + * This data type is the function that compares two hash keys and returns an + * integer greater than, equal to, or less than 0, according as the first + * parameter is lexicographically greater than, equal to, or less than the + * second. + */ + +typedef int (*compare_func_type)(const void *, const void *); + + +/* + * This data structure is the cache. + * + * It must be passed to all of the hashing routines + * (except for new). + */ +typedef struct cache +{ + /* Variables used to implement the hash itself. */ + node_ptr *node_table; /* Pointer to an array of hash nodes. */ + /* Variables used to track the size of the hash table so to determine + when to resize it. */ + unsigned int size; /* Number of buckets allocated for the hash table + (number of array entries allocated for + "node_table"). Must be a power of two. */ + unsigned int used; /* Current number of entries in the hash table. */ + unsigned int mask; /* Precomputed mask. */ + + /* Variables used to implement indexing through the hash table. */ + + unsigned int last_bucket; /* Tracks which entry in the array where + the last value was returned. */ + /* Function used to compute a hash code given a key. + This function is specified when the hash table is created. */ + hash_func_type hash_func; + /* Function used to compare two hash keys to see if they are equal. */ + compare_func_type compare_func; +} *cache_ptr; + + +/* Two important hash tables. */ +extern cache_ptr module_hash_table, class_hash_table; + +/* Allocate and initialize a hash table. */ + +cache_ptr hash_new (unsigned int size, + hash_func_type hash_func, + compare_func_type compare_func); + +/* Deallocate all of the hash nodes and the cache itself. */ + +void hash_delete (cache_ptr cache); + +/* Add the key/value pair to the hash table. If the + hash table reaches a level of fullness then it will be resized. + + assert if the key is already in the hash. */ + +void hash_add (cache_ptr *cachep, const void *key, void *value); + +/* Remove the key/value pair from the hash table. + assert if the key isn't in the table. */ + +void hash_remove (cache_ptr cache, const void *key); + +/* Used to index through the hash table. Start with NULL + to get the first entry. + + Successive calls pass the value returned previously. + ** Don't modify the hash during this operation *** + + Cache nodes are returned such that key or value can + be extracted. */ + +node_ptr hash_next (cache_ptr cache, node_ptr node); + +/* Used to return a value from a hash table using a given key. */ + +void *hash_value_for_key (cache_ptr cache, const void *key); + + +/************************************************ + + Useful hashing functions. + + Declared inline for your pleasure. + +************************************************/ + +/* Calculate a hash code by performing some + manipulation of the key pointer. (Use the lowest bits + except for those likely to be 0 due to alignment.) */ + +static inline unsigned int +hash_ptr (cache_ptr cache, const void *key) +{ + return ((size_t)key / sizeof (void *)) & cache->mask; +} + + +/* Calculate a hash code by iterating over a NULL + terminate string. */ +static inline unsigned int +hash_string (cache_ptr cache, const void *key) +{ + unsigned int ret = 0; + unsigned int ctr = 0; + + + while (*(char*)key) { + ret ^= *(char*)key++ << ctr; + ctr = (ctr + 1) % sizeof (void *); + } + + return ret & cache->mask; +} + + +/* Compare two pointers for equality. */ +static inline int +compare_ptrs (const void *k1, const void *k2) +{ + return !(k1 - k2); +} + + +/* Compare two strings. */ +static inline int +compare_strings (const void *k1, const void *k2) +{ + if (k1 == k2) + return 1; + else if (k1 == 0 || k2 == 0) + return 0; + else + return !strcmp (k1, k2); +} + + +#endif /* not __hash_INCLUDE_GNU */ diff --git a/contrib/gcc/objc/init.c b/contrib/gcc/objc/init.c new file mode 100644 index 0000000..9560dc2 --- /dev/null +++ b/contrib/gcc/objc/init.c @@ -0,0 +1,363 @@ +/* GNU Objective C Runtime initialization + Copyright (C) 1993, 1995 Free Software Foundation, Inc. + Contributed by 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 7 +#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; + +/* List of unresolved static instances. */ +static struct objc_list *uninitialized_statics; + +/* 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, struct objc_protocol_list*); + +/* This is a hook which is called by __objc_exec_class every time a class + or a category is loaded into the runtime. This may e.g. help a + dynamic loader determine the classes that have been loaded when + an object file is dynamically linked in */ +void (*_objc_load_callback)(Class class, Category* category) = 0; + +/* Is all categories/classes resolved? */ +BOOL __objc_dangling_categories = NO; + +extern SEL +__sel_register_typed_name (const char *name, const char *types, + struct objc_selector *orig); + +/* Run through the statics list, removing modules as soon as all its statics + have been initialized. */ +static void +objc_init_statics () +{ + struct objc_list **cell = &uninitialized_statics; + struct objc_static_instances **statics_in_module; + + while (*cell) + { + int module_initialized = 1; + + for (statics_in_module = (*cell)->head; + *statics_in_module; statics_in_module++) + { + struct objc_static_instances *statics = *statics_in_module; + Class class = objc_lookup_class (statics->class_name); + + if (!class) + module_initialized = 0; + /* Actually, the static's class_pointer will be NULL when we + haven't been here before. However, the comparison is to be + reminded of taking into account class posing and to think about + possible semantics... */ + else if (class != statics->instances[0]->class_pointer) + { + id *inst; + + for (inst = &statics->instances[0]; *inst; inst++) + { + (*inst)->class_pointer = class; + + /* ??? Make sure the object will not be freed. With + refcounting, invoke `-retain'. Without refcounting, do + nothing and hope that `-free' will never be invoked. */ + + /* ??? Send the object an `-initStatic' or something to + that effect now or later on? What are the semantics of + statically allocated instances, besides the trivial + NXConstantString, anyway? */ + } + } + } + if (module_initialized) + { + /* Remove this module from the uninitialized list. */ + struct objc_list *this = *cell; + *cell = this->tail; + free (this); + } + else + cell = &(*cell)->tail; + } +} /* objc_init_statics */ + +/* 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) +{ + /* Have we processed any constructors previously? This flag is 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-api.h) generated by gcc */ + Symtab_t symtab = module->symtab; + + /* 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); + + /* Replace referenced selectors from names to SEL's. */ + if (selectors) + { + for (i = 0; selectors[i].sel_id; ++i) + { + const char *name, *type; + name = (char*)selectors[i].sel_id; + type = (char*)selectors[i].sel_types; + __sel_register_typed_name (name, type, + (struct objc_selector*)&(selectors[i])); + } + } + + /* 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 class = (Class) 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) 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); + + if (_objc_load_callback) + _objc_load_callback(class, 0); + } + + /* 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 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) class->class_pointer, + category->class_methods); + + if (category->protocols) + { + __objc_init_protocols (category->protocols); + __objc_class_add_protocols (class, category->protocols); + } + + if (_objc_load_callback) + _objc_load_callback(class, category); + } + else + { + /* The object to which the category methods belong can't be found. + Save the information. */ + unclaimed_categories = list_cons(category, unclaimed_categories); + } + } + + if (module->statics) + uninitialized_statics = list_cons (module->statics, uninitialized_statics); + if (uninitialized_statics) + objc_init_statics (); + + /* Scan the unclaimed category hash. Attempt to attach any unclaimed + categories to objects. */ + for (cell = &unclaimed_categories; + *cell; + ({ if (*cell) cell = &(*cell)->tail; })) + { + Category_t category = (*cell)->head; + Class 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) class->class_pointer, + category->class_methods); + + if (category->protocols) + { + __objc_init_protocols (category->protocols); + __objc_class_add_protocols (class, category->protocols); + } + + if (_objc_load_callback) + _objc_load_callback(class, category); + } + } + + 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, (int)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; + static Class proto_class = 0; + + if (! protos) + return; + + if (!proto_class) + proto_class = objc_lookup_class("Protocol"); + + if (!proto_class) + { + unclaimed_proto_list = list_cons (protos, unclaimed_proto_list); + return; + } + +#if 0 + assert (protos->next == 0); /* only single ones allowed */ +#endif + + for(i = 0; i < protos->count; i++) + { + struct objc_protocol* aProto = protos->list[i]; + if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION) + { + /* assign class pointer */ + aProto->class_pointer = proto_class; + + /* init super protocols */ + __objc_init_protocols (aProto->protocol_list); + } + else if (protos->list[i]->class_pointer != proto_class) + { + fprintf (stderr, + "Version %d doesn't match runtime protocol version %d\n", + (int)((char*)protos->list[i]->class_pointer-(char*)0), + PROTOCOL_VERSION); + abort (); + } + } +} + +static void __objc_class_add_protocols (Class class, + struct objc_protocol_list* protos) +{ + /* Well... */ + if (! protos) + return; + + /* Add it... */ + protos->next = class->protocols; + class->protocols = protos; +} diff --git a/contrib/gcc/objc/list.h b/contrib/gcc/objc/list.h new file mode 100644 index 0000000..a59b116 --- /dev/null +++ b/contrib/gcc/objc/list.h @@ -0,0 +1,150 @@ +/* Generic single linked list to keep various information + Copyright (C) 1993, 1994 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 __GNU_OBJC_LIST_H +#define __GNU_OBJC_LIST_H +void * __objc_xrealloc (void *optr, size_t size); +void * __objc_xmalloc (size_t size); + +struct objc_list { + void *head; + struct objc_list *tail; +}; + +/* Return a cons cell produced from (head . tail) */ + +static inline struct objc_list* +list_cons(void* head, struct objc_list* tail) +{ + struct objc_list* cell; + + cell = (struct objc_list*)__objc_xmalloc(sizeof(struct objc_list)); + cell->head = head; + cell->tail = tail; + return cell; +} + +/* Return the length of a list, list_length(NULL) returns zero */ + +static inline int +list_length(struct objc_list* list) +{ + int i = 0; + while(list) + { + i += 1; + list = list->tail; + } + return i; +} + +/* Return the Nth element of LIST, where N count from zero. If N + larger than the list length, NULL is returned */ + +static inline void* +list_nth(int index, struct objc_list* list) +{ + while(index-- != 0) + { + if(list->tail) + list = list->tail; + else + return 0; + } + return list->head; +} + +/* Remove the element at the head by replacing it by its successor */ + +static inline void +list_remove_head(struct objc_list** list) +{ + if ((*list)->tail) + { + struct objc_list* tail = (*list)->tail; /* fetch next */ + *(*list) = *tail; /* copy next to list head */ + free(tail); /* free next */ + } + else /* only one element in list */ + { + free (*list); + (*list) = 0; + } +} + + +/* Remove the element with `car' set to ELEMENT */ + +static inline void +list_remove_elem(struct objc_list** list, void* elem) +{ + while (*list) { + if ((*list)->head == elem) + list_remove_head(list); + list = &((*list)->tail); + } +} + +/* Map FUNCTION over all elements in LIST */ + +static inline void +list_mapcar(struct objc_list* list, void(*function)(void*)) +{ + while(list) + { + (*function)(list->head); + list = list->tail; + } +} + +/* Return element that has ELEM as car */ + +static inline struct objc_list** +list_find(struct objc_list** list, void* elem) +{ + while(*list) + { + if ((*list)->head == elem) + return list; + list = &((*list)->tail); + } + return NULL; +} + +/* Free list (backwards recursive) */ + +static void +list_free(struct objc_list* list) +{ + if(list) + { + list_free(list->tail); + free(list); + } +} +#endif __GNU_OBJC_LIST_H diff --git a/contrib/gcc/objc/makefile.dos b/contrib/gcc/objc/makefile.dos new file mode 100644 index 0000000..5321733 --- /dev/null +++ b/contrib/gcc/objc/makefile.dos @@ -0,0 +1,56 @@ +# GNU Objective C Runtime Makefile for compiling with djgpp +# Copyright (C) 1993, 1994 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, 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# This Makefile is configured for GnuMAKE + +GCC_FOR_TARGET=gcc + +.SUFFIXES: .o .m + +OPTIMIZE = -O2 + +# Always search these dirs when compiling. +SUBDIR_INCLUDES = -I. -I.. -I../config + +.c.o: + $(GCC_FOR_TARGET) $(OPTIMIZE) \ + -c $(GCC_CFLAGS) $(SUBDIR_INCLUDES) $< + +.m.o: + $(GCC_FOR_TARGET) $(OPTIMIZE) -fgnu-runtime \ + -c $(GCC_CFLAGS) $(SUBDIR_INCLUDES) $< + +OBJC_O = hash.o sarray.o class.o sendmsg.o init.o archive.o \ + selector.o objects.o misc.o object.o protocol.o encoding.o + +libobjc.a: $(OBJC_O) + -rm -f libobjc.a + ar rc libobjc.a $(OBJC_O) + ranlib libobjc.a + +OBJC_H = hash.h list.h sarray.h objc.h \ + objc-api.h \ + object.h protocol.h mutex.h \ + typedstream.h + +mostlyclean: + -rm -f *.o libobjc.a xforward fflags +clean: mostlyclean +distclean: mostlyclean +extraclean: mostlyclean diff --git a/contrib/gcc/objc/misc.c b/contrib/gcc/objc/misc.c new file mode 100644 index 0000000..033018e --- /dev/null +++ b/contrib/gcc/objc/misc.c @@ -0,0 +1,80 @@ +/* GNU Objective C Runtime Miscellaneous + Copyright (C) 1993, 1994, 1995 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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. */ + +#ifdef __alpha__ +#include +extern int write (int, const char*, int); +extern size_t strlen (const char*); +#endif + +#include "runtime.h" + +void objc_error(id object, const char* fmt, va_list); + +void (*_objc_error)(id, const char*, va_list) = objc_error; + +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, (int)strlen((const char*)msg)); + abort(); +} + +void* +__objc_xmalloc(size_t size) +{ + void* res = (void*) malloc(size); + if(!res) + objc_fatal("Virtual memory exhausted\n"); + return res; +} + +void* +__objc_xrealloc(void* mem, size_t size) +{ + void* res = (void*) 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/contrib/gcc/objc/objc-api.h b/contrib/gcc/objc/objc-api.h new file mode 100644 index 0000000..c801033 --- /dev/null +++ b/contrib/gcc/objc/objc-api.h @@ -0,0 +1,477 @@ +/* GNU Objective-C Runtime API. + Copyright (C) 1993, 1995 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 "objc/objc.h" +#include "objc/hash.h" +#include + +/* For functions which return Method_t */ +#define METHOD_NULL (Method_t)0 + /* Boolean typedefs */ +/* +** Method descriptor returned by introspective Object methods. +** This is really just the first part of the more complete objc_method +** structure defined below and used internally by the runtime. +*/ +struct objc_method_description +{ + SEL name; /* this is a selector, not a string */ + char *types; /* type encoding */ +}; + +/* Filer types used to describe Ivars and Methods. */ +#define _C_ID '@' +#define _C_CLASS '#' +#define _C_SEL ':' +#define _C_CHR 'c' +#define _C_UCHR 'C' +#define _C_SHT 's' +#define _C_USHT 'S' +#define _C_INT 'i' +#define _C_UINT 'I' +#define _C_LNG 'l' +#define _C_ULNG 'L' +#define _C_FLT 'f' +#define _C_DBL 'd' +#define _C_BFLD 'b' +#define _C_VOID 'v' +#define _C_UNDEF '?' +#define _C_PTR '^' +#define _C_CHARPTR '*' +#define _C_ATOM '%' +#define _C_ARY_B '[' +#define _C_ARY_E ']' +#define _C_UNION_B '(' +#define _C_UNION_E ')' +#define _C_STRUCT_B '{' +#define _C_STRUCT_E '}' + + + +/* +** Set this variable nonzero to print a line describing each +** message that is sent. (this is currently disabled) +*/ +extern BOOL objc_trace; + + +/* +** Whereas a Module (defined further down) is the root (typically) of a file, +** a Symtab is the root of the class and category definitions within the +** module. +** +** A Symtab contains a variable length array of pointers to classes and +** categories defined in the module. +*/ +typedef struct objc_symtab { + unsigned long sel_ref_cnt; /* Unknown. */ + SEL refs; /* Unknown. */ + unsigned short cls_def_cnt; /* Number of classes compiled + (defined) in the module. */ + unsigned short cat_def_cnt; /* Number of categories + compiled (defined) in the + module. */ + void *defs[1]; /* Variable array of pointers. + cls_def_cnt of type Class + followed by cat_def_cnt of + type Category_t. */ +} Symtab, *Symtab_t; + + +/* For every class which happens to have statically allocated instances in + this module, one OBJC_STATIC_INSTANCES is allocated by the compiler. + INSTANCES is NULL terminated and points to all statically allocated + instances of this class. */ +struct objc_static_instances +{ + char *class_name; + id instances[0]; +}; + +/* +** The compiler generates one of these structures for each module that +** composes the executable (eg main.m). +** +** This data structure is the root of the definition tree for the module. +** +** A collect program runs between ld stages and creates a ObjC ctor array. +** That array holds a pointer to each module structure of the executable. +*/ +typedef struct objc_module { + unsigned long version; /* Compiler revision. */ + unsigned long size; /* sizeof(Module). */ + const char* name; /* Name of the file where the + module was generated. The + name includes the path. */ + + /* Pointer to a NULL terminated array of objc_static_instances. */ + struct objc_static_instances **statics; + + Symtab_t symtab; /* Pointer to the Symtab of + the module. The Symtab + holds an array of pointers to + the classes and categories + defined in the module. */ +} Module, *Module_t; + + +/* +** The compiler generates one of these structures for a class that has +** instance variables defined in its specification. +*/ +typedef struct objc_ivar* Ivar_t; +typedef struct objc_ivar_list { + int ivar_count; /* Number of structures (Ivar) + contained in the list. One + structure per instance + variable defined in the + class. */ + struct objc_ivar { + const char* ivar_name; /* Name of the instance + variable as entered in the + class definition. */ + const char* ivar_type; /* Description of the Ivar's + type. Useful for + debuggers. */ + int ivar_offset; /* Byte offset from the base + address of the instance + structure to the variable. */ + + } ivar_list[1]; /* Variable length + structure. */ +} IvarList, *IvarList_t; + + +/* +** The compiler generates one (or more) of these structures for a class that +** has methods defined in its specification. +** +** The implementation of a class can be broken into separate pieces in a file +** and categories can break them across modules. To handle this problem is a +** singly linked list of methods. +*/ +typedef struct objc_method Method; +typedef Method* Method_t; +typedef struct objc_method_list { + struct objc_method_list* method_next; /* This variable is used to link + a method list to another. It + is a singly linked list. */ + int method_count; /* Number of methods defined in + this structure. */ + struct objc_method { + SEL method_name; /* This variable is the method's + name. It is a char*. + The unique integer passed to + objc_msg_send is a char* too. + It is compared against + method_name using strcmp. */ + const char* method_types; /* Description of the method's + parameter list. Useful for + debuggers. */ + IMP method_imp; /* Address of the method in the + executable. */ + } method_list[1]; /* Variable length + structure. */ +} MethodList, *MethodList_t; + +struct objc_protocol_list { + struct objc_protocol_list *next; + int count; + Protocol *list[1]; +}; + +/* +** This is used to assure consistent access to the info field of +** classes +*/ +#ifndef HOST_BITS_PER_LONG +#define HOST_BITS_PER_LONG (sizeof(long)*8) +#endif + +#define __CLS_INFO(cls) ((cls)->info) +#define __CLS_ISINFO(cls, mask) ((__CLS_INFO(cls)&mask)==mask) +#define __CLS_SETINFO(cls, mask) (__CLS_INFO(cls) |= mask) + +/* The structure is of type MetaClass */ +#define _CLS_META 0x2L +#define CLS_ISMETA(cls) ((cls)&&__CLS_ISINFO(cls, _CLS_META)) + + +/* The structure is of type Class */ +#define _CLS_CLASS 0x1L +#define CLS_ISCLASS(cls) ((cls)&&__CLS_ISINFO(cls, _CLS_CLASS)) + +/* +** The class is initialized within the runtime. This means that +** it has had correct super and sublinks assigned +*/ +#define _CLS_RESOLV 0x8L +#define CLS_ISRESOLV(cls) __CLS_ISINFO(cls, _CLS_RESOLV) +#define CLS_SETRESOLV(cls) __CLS_SETINFO(cls, _CLS_RESOLV) + +/* +** The class has been send a +initialize message or a such is not +** defined for this class +*/ +#define _CLS_INITIALIZED 0x04L +#define CLS_ISINITIALIZED(cls) __CLS_ISINFO(cls, _CLS_INITIALIZED) +#define CLS_SETINITIALIZED(cls) __CLS_SETINFO(cls, _CLS_INITIALIZED) + +/* +** The class number of this class. This must be the same for both the +** class and it's meta class object +*/ +#define CLS_GETNUMBER(cls) (__CLS_INFO(cls) >> (HOST_BITS_PER_LONG/2)) +#define CLS_SETNUMBER(cls, num) \ + ({ (cls)->info <<= (HOST_BITS_PER_LONG/2); \ + (cls)->info >>= (HOST_BITS_PER_LONG/2); \ + __CLS_SETINFO(cls, (((unsigned long)num) << (HOST_BITS_PER_LONG/2))); }) + +/* +** The compiler generates one of these structures for each category. A class +** may have many categories and contain both instance and factory methods. +*/ +typedef struct objc_category { + const char* category_name; /* Name of the category. Name + contained in the () of the + category definition. */ + const char* class_name; /* Name of the class to which + the category belongs. */ + MethodList_t instance_methods; /* Linked list of instance + methods defined in the + category. NULL indicates no + instance methods defined. */ + MethodList_t class_methods; /* Linked list of factory + methods defined in the + category. NULL indicates no + class methods defined. */ + struct objc_protocol_list *protocols; /* List of Protocols + conformed to */ +} Category, *Category_t; + +/* +** Structure used when a message is send to a class's super class. The +** compiler generates one of these structures and passes it to +** objc_msg_super. +*/ +typedef struct objc_super { + id self; /* Id of the object sending + the message. */ + Class class; /* Object's super class. */ +} Super, *Super_t; + +IMP objc_msg_lookup_super(Super_t super, SEL sel); + +retval_t objc_msg_sendv(id, SEL, arglist_t); + + + +/* +** 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 (*_objc_lookup_class)(const char *name); + +/* +** This is a hook which is called by __objc_exec_class every time a class +** or a category is loaded into the runtime. This may e.g. help a +** dynamic loader determine the classes that have been loaded when +** an object file is dynamically linked in. +*/ +extern void (*_objc_load_callback)(Class class, Category* category); + +extern id (*_objc_object_alloc)(Class class); + +extern id (*_objc_object_copy)(id object); + +extern id (*_objc_object_dispose)(id object); + +Method_t class_get_class_method(MetaClass class, SEL aSel); + +Method_t class_get_instance_method(Class class, SEL aSel); + +Class class_pose_as(Class impostor, Class superclass); + +Class objc_get_class(const char *name); + +Class objc_lookup_class(const char *name); + +Class objc_next_class(void **enum_state); + +const char *sel_get_name(SEL selector); + +const char *sel_get_type(SEL selector); + +SEL sel_get_uid(const char *name); + +SEL sel_get_any_uid(const char *name); + +SEL sel_get_any_typed_uid(const char *name); + +SEL sel_get_typed_uid(const char *name, const char*); + +SEL sel_register_name(const char *name); + +SEL sel_register_typed_name(const char *name, const char*type); + + +BOOL sel_is_mapped (SEL aSel); + +extern id class_create_instance(Class class); + +static inline const char * +class_get_class_name(Class class) +{ + return CLS_ISCLASS(class)?class->name:((class==Nil)?"Nil":0); +} + +static inline long +class_get_instance_size(Class class) +{ + return CLS_ISCLASS(class)?class->instance_size:0; +} + +static inline MetaClass +class_get_meta_class(Class class) +{ + return CLS_ISCLASS(class)?class->class_pointer:Nil; +} + +static inline Class +class_get_super_class(Class class) +{ + return CLS_ISCLASS(class)?class->super_class:Nil; +} + +static inline int +class_get_version(Class class) +{ + return CLS_ISCLASS(class)?class->version:-1; +} + +static inline BOOL +class_is_class(Class class) +{ + return CLS_ISCLASS(class); +} + +static inline BOOL +class_is_meta_class(Class class) +{ + return CLS_ISMETA(class); +} + + +static inline void +class_set_version(Class class, long version) +{ + if (CLS_ISCLASS(class)) + class->version = version; +} + +static inline IMP +method_get_imp(Method_t method) +{ + return (method!=METHOD_NULL)?method->method_imp:(IMP)0; +} + +IMP get_imp (Class class, SEL sel); + +id object_copy(id object); + +id object_dispose(id object); + +static inline Class +object_get_class(id object) +{ + return ((object!=nil) + ? (CLS_ISCLASS(object->class_pointer) + ? object->class_pointer + : (CLS_ISMETA(object->class_pointer) + ? (Class)object + : Nil)) + : Nil); +} + +static inline const char * +object_get_class_name(id object) +{ + return ((object!=nil)?(CLS_ISCLASS(object->class_pointer) + ?object->class_pointer->name + :((Class)object)->name) + :"Nil"); +} + +static inline MetaClass +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); +} + +static inline Class +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)object)->super_class + :Nil)) + :Nil); +} + +static inline BOOL +object_is_class(id object) +{ + return CLS_ISCLASS((Class)object); +} + +static inline BOOL +object_is_instance(id object) +{ + return (object!=nil)&&CLS_ISCLASS(object->class_pointer); +} + +static inline BOOL +object_is_meta_class(id object) +{ + return CLS_ISMETA((Class)object); +} + +#endif /* not __objc_api_INCLUDE_GNU */ + + + diff --git a/contrib/gcc/objc/objc.h b/contrib/gcc/objc/objc.h new file mode 100644 index 0000000..979c5c8 --- /dev/null +++ b/contrib/gcc/objc/objc.h @@ -0,0 +1,153 @@ +/* Basic data types for Objective C. + Copyright (C) 1993, 1995 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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_INCLUDE_GNU +#define __objc_INCLUDE_GNU + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* +** Definition of the boolean type. +*/ +typedef unsigned char BOOL; +#define YES (BOOL)1 +#define NO (BOOL)0 + +/* +** Definition of a selector. Selectors themselves are not unique, but +** the sel_id is a unique identifier. +*/ +typedef const struct objc_selector +{ + void *sel_id; + const char *sel_types; +} *SEL; + +inline static BOOL +sel_eq (SEL s1, SEL s2) +{ + if (s1 == 0 || s2 == 0) + return s1 == s2; + else + return s1->sel_id == s2->sel_id; +} + + +/* +** ObjC uses this typedef for untyped instances. +*/ +typedef struct objc_object { + struct objc_class* class_pointer; +} *id; + +/* +** Definition of method type. When retrieving the implementation of a +** method, this is type of the pointer returned +*/ +typedef id (*IMP)(id, SEL, ...); + +/* +** More simple types... +*/ +#define nil (id)0 /* id of Nil instance */ +#define Nil (Class)0 /* id of Nil class */ +typedef char *STR; /* String alias */ + +/* +** The compiler generates one of these structures for each class. +** +** This structure is the definition for classes. +** +** This structure is generated by the compiler in the executable and used by +** the run-time during normal messaging operations. Therefore some members +** change type. The compiler generates "char* const" and places a string in +** the following member variables: super_class. +*/ +typedef struct objc_class *MetaClass; +typedef struct objc_class *Class; +struct objc_class { + MetaClass class_pointer; /* Pointer to the class's + meta class. */ + struct objc_class* super_class; /* Pointer to the super + class. NULL for class + Object. */ + const char* name; /* Name of the class. */ + long version; /* Unknown. */ + unsigned long info; /* Bit mask. See class masks + defined above. */ + long instance_size; /* Size in bytes of the class. + The sum of the class definition + and all super class + definitions. */ + struct objc_ivar_list* ivars; /* Pointer to a structure that + describes the instance + variables in the class + definition. NULL indicates + no instance variables. Does + not include super class + variables. */ + struct objc_method_list* methods; /* Linked list of instance + methods defined for the + class. */ + struct sarray * dtable; /* Pointer to instance + method dispatch table. */ + struct objc_class* subclass_list; /* Subclasses */ + struct objc_class* sibling_class; + + struct objc_protocol_list *protocols; /* Protocols conformed to */ +}; + +#ifndef __OBJC__ +typedef struct objc_protocol { + struct objc_class* class_pointer; + char *protocol_name; + struct objc_protocol_list *protocol_list; + struct objc_method_description_list *instance_methods, *class_methods; +} Protocol; + +#else /* __OBJC__ */ +@class Protocol; +#endif + +typedef void* retval_t; /* return value */ +typedef void(*apply_t)(void); /* function pointer */ +typedef union { + char *arg_ptr; + char arg_regs[sizeof (char*)]; +} *arglist_t; /* argument frame */ + + +IMP objc_msg_lookup(id receiver, SEL op); + +#ifdef __cplusplus +} +#endif + +#endif /* not __objc_INCLUDE_GNU */ diff --git a/contrib/gcc/objc/objects.c b/contrib/gcc/objc/objects.c new file mode 100644 index 0000000..ebaf117 --- /dev/null +++ b/contrib/gcc/objc/objects.c @@ -0,0 +1,92 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993, 1995 Free Software Foundation, Inc. + Contributed by 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 "../tconfig.h" /* include defs of bzero for target */ +#include "runtime.h" /* the kitchen sink */ + +id __objc_object_alloc(Class); +id __objc_object_dispose(id); +id __objc_object_copy(id); + +id (*_objc_object_alloc)(Class) = __objc_object_alloc; +id (*_objc_object_dispose)(id) = __objc_object_dispose; +id (*_objc_object_copy)(id) = __objc_object_copy; + +id +class_create_instance(Class class) +{ + id new = nil; + if (CLS_ISCLASS(class)) + new = (*_objc_object_alloc)(class); + if (new!=nil) + { + memset (new, 0, class->instance_size); + new->class_pointer = class; + } + return new; +} + +id +object_copy(id object) +{ + if ((object!=nil)&&CLS_ISCLASS(object->class_pointer)) + return (*_objc_object_copy)(object); + else + return nil; +} + +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; +} + +id __objc_object_alloc(Class 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); + memcpy(copy, object, object->class_pointer->instance_size); + return copy; +} + + diff --git a/contrib/gcc/objc/runtime.h b/contrib/gcc/objc/runtime.h new file mode 100644 index 0000000..0f4510f --- /dev/null +++ b/contrib/gcc/objc/runtime.h @@ -0,0 +1,74 @@ +/* GNU Objective C Runtime internal declarations + Copyright (C) 1993, 1995 Free Software Foundation, Inc. + Contributed by 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 /* for varargs and va_list's */ + +#include +#include + +#include /* so noone else will get system versions */ +#include "assert.h" + +#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 */ + +extern void __objc_add_class_to_hash(Class); /* (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); /* (objc-dispatch.c) */ +extern void __objc_resolve_class_links(); /* (objc-class.c) */ +extern void __objc_register_selectors_from_class(Class); /* (objc-sel.c) */ +extern void __objc_update_dispatch_table_for_class (Class);/* (objc-msg.c) */ +extern void class_add_method_list(Class, MethodList_t); + +extern void objc_error(id object, const char* fmt, va_list); +extern void (*_objc_error)(id, const char*, va_list); + +/* 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(format, args...) printf (format, ## args) +#else +#define DEBUG_PRINTF(format, args...) +#endif + +BOOL __objc_responds_to (id object, SEL sel); /* for internal use only! */ +SEL __sel_register_typed_name (const char*, const char*, + struct objc_selector*); + +#endif /* not __objc_runtime_INCLUDE_GNU */ + + diff --git a/contrib/gcc/objc/sarray.c b/contrib/gcc/objc/sarray.c new file mode 100644 index 0000000..9ed2196 --- /dev/null +++ b/contrib/gcc/objc/sarray.c @@ -0,0 +1,441 @@ +/* Sparse Arrays for Objective C dispatch tables + Copyright (C) 1993, 1995 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 +#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 + +#ifdef __alpha__ +const void *memcpy (void*, const void*, size_t); +void free (const void*); +#endif + +void +sarray_at_put(struct sarray* array, sidx index, void* element) +{ +#ifdef OBJC_SPARSE3 + struct sindex** the_index; +#endif + struct sbucket** the_bucket; +#ifdef OBJC_SPARSE3 + size_t ioffset; +#endif + size_t boffset; + size_t 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 /* not PRECOMPUTE_SELECTORS */ +#ifdef OBJC_SPARSE3 + ioffset = index/INDEX_CAPACITY; + boffset = (index/BUCKET_SIZE)%INDEX_SIZE; + eoffset = index%BUCKET_SIZE; +#else + boffset = index/BUCKET_SIZE; + eoffset = index%BUCKET_SIZE; +#endif +#endif /* not PRECOMPUTE_SELECTORS */ + + 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)); + memcpy(*the_index, array->empty_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)); + memcpy( *the_index,old_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)); + memcpy((void *) *the_bucket, (const void*)array->empty_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)); + memcpy( *the_bucket,old_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 + size_t num_indices = ((size-1)/(INDEX_CAPACITY))+1; +#else /* OBJC_SPARSE2 */ + size_t 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; counterempty_bucket->elems[counter] = default_element; + +#ifdef OBJC_SPARSE3 + for (counter=0; counterempty_index->buckets[counter] = arr->empty_bucket; + + for (counter=0; counterindices[counter] = arr->empty_index; + +#else /* OBJC_SPARSE2 */ + + for (counter=0; counterbuckets[counter] = arr->empty_bucket; + +#endif + + return arr; +} + + +/* Reallocate the sparse array to hold `newsize' entries */ + +void +sarray_realloc(struct sarray* array, int newsize) +{ +#ifdef OBJC_SPARSE3 + size_t old_max_index = (array->capacity-1)/INDEX_CAPACITY; + size_t new_max_index = ((newsize-1)/INDEX_CAPACITY); + size_t rounded_size = (new_max_index+1)*INDEX_CAPACITY; + +#else /* OBJC_SPARSE2 */ + size_t old_max_index = (array->capacity-1)/BUCKET_SIZE; + size_t new_max_index = ((newsize-1)/BUCKET_SIZE); + size_t 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; c2buckets[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; + } +} + + +/* Free a sparse array allocated with sarray_new */ + +void +sarray_free(struct sarray* array) { +#ifdef OBJC_SPARSE3 + size_t old_max_index = (array->capacity-1)/INDEX_CAPACITY; +#else + size_t 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; c2buckets[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 + size_t num_indices = ((oarr->capacity-1)/INDEX_CAPACITY)+1; +#else /* OBJC_SPARSE2 */ + size_t num_indices = ((oarr->capacity-1)/BUCKET_SIZE)+1; +#endif + struct sarray* arr; + + /* Allocate core array */ + arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray)); + memcpy( arr,oarr, 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); + memcpy( arr->indices,oarr->indices, + sizeof(struct sindex*)*num_indices); +#else + /* Copy bucket table */ + arr->buckets = (struct sbucket**) + __objc_xmalloc(sizeof(struct sbucket*)*num_indices); + memcpy( arr->buckets,oarr->buckets, + sizeof(struct sbucket*)*num_indices); +#endif + + idxsize += num_indices; + narrays += 1; + + return arr; +} diff --git a/contrib/gcc/objc/sarray.h b/contrib/gcc/objc/sarray.h new file mode 100644 index 0000000..a3ec7a9 --- /dev/null +++ b/contrib/gcc/objc/sarray.h @@ -0,0 +1,232 @@ +/* Sparse Arrays for Objective C dispatch tables + Copyright (C) 1993, 1995 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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_SPARSE2 /* 2-level sparse array */ +/* #define OBJC_SPARSE3 */ /* 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 + +extern int nbuckets; /* for stats */ +extern int nindices; +extern int narrays; +extern int idxsize; + +#include + +/* An unsigned integer of same size as a pointer */ +#define SIZET_BITS (sizeof(size_t)*8) + +#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< + 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 */ +#ifdef OBJC_SPARSE3 + return array-> + indices[index/INDEX_CAPACITY]-> + buckets[(index/BUCKET_SIZE)%INDEX_SIZE]-> + elems[index%BUCKET_SIZE]; +#else /* OBJC_SPARSE2 */ + return array->buckets[index/BUCKET_SIZE]->elems[index%BUCKET_SIZE]; +#endif /* not OBJC_SPARSE3 */ +#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/contrib/gcc/objc/selector.c b/contrib/gcc/objc/selector.c new file mode 100644 index 0000000..be68f4f --- /dev/null +++ b/contrib/gcc/objc/selector.c @@ -0,0 +1,321 @@ +/* GNU Objective C Runtime selector related functions + Copyright (C) 1993, 1995 Free Software Foundation, Inc. + Contributed by 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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" +#include "encoding.h" + +/* Initial selector hash table size. Value doesn't matter much */ +#define SELECTOR_HASH_SIZE 128 + +/* Tables mapping selector names to uid and opposite */ +static struct sarray* __objc_selector_array = 0; /* uid -> sel */ +static struct sarray* __objc_selector_names = 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_names = 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 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_typed_name ((const char*)method->method_name, + method->method_types); + i += 1; + } +} + + +/* Returns YES iff t1 and t2 have same method types, but we ignore + the argframe layout */ +BOOL +sel_types_match (const char* t1, const char* t2) +{ + if (!t1 || !t2) + return NO; + while (*t1 && *t2) + { + if (*t1 == '+') t1++; + if (*t2 == '+') t2++; + while (isdigit(*t1)) t1++; + while (isdigit(*t2)) t2++; + /* xxx Remove these next two lines when qualifiers are put in + all selectors, not just Protocol selectors. */ + t1 = objc_skip_type_qualifiers(t1); + t2 = objc_skip_type_qualifiers(t2); + if (!*t1 && !*t2) + return YES; + if (*t1 != *t2) + return NO; + t1++; + t2++; + } + return NO; +} + +/* return selector representing name */ +SEL +sel_get_typed_uid (const char *name, const char *types) +{ + struct objc_list *l; + sidx i; + + i = (sidx) hash_value_for_key (__objc_selector_hash, name); + if (i == 0) + return 0; + + for (l = (struct objc_list*)sarray_get (__objc_selector_array, i); + l; l = l->tail) + { + SEL s = (SEL)l->head; + if (types == 0 || s->sel_types == 0) + { + if (s->sel_types == types) + { + return s; + } + } + else if (sel_types_match (s->sel_types, types)) + { + return s; + } + } + + return 0; +} + +/* Return selector representing name; prefer a selector with non-NULL type */ +SEL +sel_get_any_typed_uid (const char *name) +{ + struct objc_list *l; + sidx i; + SEL s; + + i = (sidx) hash_value_for_key (__objc_selector_hash, name); + if (i == 0) + return 0; + + for (l = (struct objc_list*)sarray_get (__objc_selector_array, i); + l; l = l->tail) + { + s = (SEL) l->head; + if (s->sel_types) + return s; + } + + return s; +} + +/* return selector representing name */ +SEL +sel_get_any_uid (const char *name) +{ + struct objc_list *l; + sidx i; + + i = (sidx) hash_value_for_key (__objc_selector_hash, name); + if (soffset_decode (i) == 0) + return 0; + + l = (struct objc_list*)sarray_get (__objc_selector_array, i); + if (l == 0) + return 0; + + return (SEL)l->head; +} + +/* return selector representing name */ +SEL +sel_get_uid (const char *name) +{ + return sel_register_typed_name (name, 0); +} + +/* Get name of selector. If selector is unknown, the empty string "" + is returned */ +const char* +sel_get_name (SEL selector) +{ + if ((soffset_decode((sidx)selector->sel_id) > 0) + && (soffset_decode((sidx)selector->sel_id) <= __objc_selector_max_index)) + return sarray_get (__objc_selector_names, (sidx) selector->sel_id); + else + return 0; +} + +BOOL +sel_is_mapped (SEL selector) +{ + unsigned int idx = soffset_decode ((sidx)selector->sel_id); + return ((idx > 0) && (idx <= __objc_selector_max_index)); +} + + +const char* +sel_get_type (SEL selector) +{ + if (selector) + return selector->sel_types; + else + return 0; +} + +/* The uninstalled dispatch table */ +extern struct sarray* __objc_uninstalled_dtable; + +/* Store the passed selector name in the selector record and return its + selector value (value returned by sel_get_uid). */ +SEL +__sel_register_typed_name (const char *name, const char *types, + struct objc_selector *orig) +{ + struct objc_selector* j; + sidx i; + struct objc_list *l; + + i = (sidx) hash_value_for_key (__objc_selector_hash, name); + if (soffset_decode (i) != 0) + { + for (l = (struct objc_list*)sarray_get (__objc_selector_array, i); + l; l = l->tail) + { + SEL s = (SEL)l->head; + if (types == 0 || s->sel_types == 0) + { + if (s->sel_types == types) + { + if (orig) + { + orig->sel_id = (void*)i; + return orig; + } + else + return s; + } + } + else if (!strcmp (s->sel_types, types)) + { + if (orig) + { + orig->sel_id = (void*)i; + return orig; + } + else + return s; + } + } + if (orig) + j = orig; + else + j = __objc_xmalloc (sizeof (struct objc_selector)); + + j->sel_id = (void*)i; + j->sel_types = (const char*)types; + l = (struct objc_list*)sarray_get (__objc_selector_array, i); + } + else + { + __objc_selector_max_index += 1; + i = soffset_encode(__objc_selector_max_index); + if (orig) + j = orig; + else + j = __objc_xmalloc (sizeof (struct objc_selector)); + + j->sel_id = (void*)i; + j->sel_types = (const char*)types; + l = 0; + } + + DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types, + soffset_decode (i)); + + { + int is_new = (l == 0); + l = list_cons ((void*)j, l); + sarray_at_put_safe (__objc_selector_names, i, (void *) name); + sarray_at_put_safe (__objc_selector_array, i, (void *) l); + if (is_new) + hash_add (&__objc_selector_hash, (void *) name, (void *) i); + } + + sarray_realloc(__objc_uninstalled_dtable, __objc_selector_max_index+1); + + return (SEL) j; +} + +SEL +sel_register_name (const char *name) +{ + return __sel_register_typed_name (name, 0, 0); +} + +SEL +sel_register_typed_name (const char *name, const char *type) +{ + return __sel_register_typed_name (name, type, 0); +} + diff --git a/contrib/gcc/objc/sendmsg.c b/contrib/gcc/objc/sendmsg.c new file mode 100644 index 0000000..79d4a6b --- /dev/null +++ b/contrib/gcc/objc/sendmsg.c @@ -0,0 +1,558 @@ +/* GNU Objective C Runtime message lookup + Copyright (C) 1993, 1995 Free Software Foundation, Inc. + Contributed by 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 "../tconfig.h" +#include "runtime.h" +#include "sarray.h" +#include "encoding.h" + +/* this is how we hack STRUCT_VALUE to be 1 or 0 */ +#define gen_rtx(args...) 1 +#define rtx int + +#if STRUCT_VALUE == 0 +#define INVISIBLE_STRUCT_RETURN 1 +#else +#define INVISIBLE_STRUCT_RETURN 0 +#endif + +/* The uninstalled dispatch table */ +struct sarray* __objc_uninstalled_dtable = 0; + +/* Send +initialize to class */ +static void __objc_send_initialize(Class); + +static void __objc_install_dispatch_table_for_class (Class); + +/* Forward declare some functions */ +static void __objc_init_install_dtable(id, SEL); +static id __objc_word_forward(id, SEL, ...); +typedef struct { id many[8]; } __big; +#if INVISIBLE_STRUCT_RETURN +static __big +#else +static id +#endif +__objc_block_forward(id, SEL, ...); +static Method_t search_for_method_in_hierarchy (Class 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 class, SEL sel) +{ + IMP impl; + void* res = sarray_get (class->dtable, (size_t) sel->sel_id); + if(res == __objc_init_install_dtable) + { + __objc_install_dispatch_table_for_class (class); + res = sarray_get (class->dtable, (size_t) sel->sel_id); + } + if (res == 0) + { + const char *t = sel->sel_types; + if (t && (*t == '[' || *t == '(' || *t == '{')) + res = (IMP)__objc_block_forward; + else + res = (IMP)__objc_word_forward; + } + return res; +} + +__inline__ BOOL +__objc_responds_to (id object, SEL sel) +{ + void* res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id); + if(res == __objc_init_install_dtable) + { + __objc_install_dispatch_table_for_class (object->class_pointer); + res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id); + } + return (res != 0); +} + +/* 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) +{ + IMP result; + if(receiver) + { + result = sarray_get(receiver->class_pointer->dtable, (sidx)op->sel_id); + if (result == 0) + { + const char *t = op->sel_types; + if (t && (*t == '[' || *t == '(' || *t == '{')) + result = (IMP)__objc_block_forward; + else + result = (IMP)__objc_word_forward; + } + return result; + } + 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; +} + +int method_get_sizeof_arguments (Method*); + +retval_t +objc_msg_sendv(id object, SEL op, arglist_t arg_frame) +{ + Method* m = class_get_instance_method(object->class_pointer, op); + const char *type; + *((id*)method_get_first_argument (m, arg_frame, &type)) = object; + *((SEL*)method_get_next_argument (arg_frame, &type)) = op; + return __builtin_apply((apply_t)m->method_imp, + arg_frame, + method_get_sizeof_arguments (m)); +} + +void __objc_init_dispatch_tables() +{ + __objc_uninstalled_dtable + = sarray_new(200, __objc_init_install_dtable); +} + +/* 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__ already_initialized; + IMP imp; + void* args; + void* result; + + /* 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 already_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)receiver)); + assert(CLS_ISMETA(receiver->class_pointer)); + + /* Install real dtable for factory methods */ + __objc_install_dispatch_table_for_class (receiver->class_pointer); + + if (strcmp (sel_get_name (op), "initialize")) + __objc_send_initialize((Class)receiver); + else + CLS_SETINITIALIZED((Class)receiver); + } + +already_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); + if (result) + __builtin_return (result); + else + return; + +} + +/* 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 class) +{ + assert(__objc_uninstalled_dtable); + class->dtable = __objc_uninstalled_dtable; +} + +/* Send +initialize to class if not already done */ +static void __objc_send_initialize(Class class) +{ + /* 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); + + { + SEL op = sel_register_name ("initialize"); + Class tmpclass = class; + IMP imp = 0; + + while (!imp && tmpclass) { + MethodList_t method_list = tmpclass->class_pointer->methods; + + while(!imp && method_list) { + int i; + Method_t method; + + for (i=0;imethod_count;i++) { + method = &(method_list->method_list[i]); + if (method->method_name->sel_id == op->sel_id) { + imp = method->method_imp; + break; + } + } + + method_list = method_list->method_next; + + } + + tmpclass = tmpclass->super_class; + } + if (imp) + (*imp)((id)class, op); + + } + } +} + +static void +__objc_install_dispatch_table_for_class (Class class) +{ + Class super; + MethodList_t mlist; + int counter; + + /* If the class has not yet had it's class links resolved, we must + re-compute all class links */ + if(!CLS_ISRESOLV(class)) + __objc_resolve_class_links(); + + super = class->super_class; + + if (super != 0 && (super->dtable == __objc_uninstalled_dtable)) + __objc_install_dispatch_table_for_class (super); + + /* Allocate dtable if necessary */ + if (super == 0) + { + class->dtable = sarray_new (__objc_selector_max_index, 0); + } + 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_safe (class->dtable, + (sidx) method->method_name->sel_id, + method->method_imp); + counter -= 1; + } + } +} + +void __objc_update_dispatch_table_for_class (Class class) +{ + Class next; + + /* not yet installed -- skip it */ + if (class->dtable == __objc_uninstalled_dtable) + return; + + sarray_free (class->dtable); /* release memory */ + __objc_install_premature_dtable (class); /* someone might require it... */ + __objc_install_dispatch_table_for_class (class); /* could have been lazy... */ + + 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 right away, and their selectors are made into + SEL's by the function __objc_register_selectors_from_class. */ +void +class_add_method_list (Class class, MethodList_t list) +{ + int i; + static SEL initialize_sel = 0; + if (!initialize_sel) + initialize_sel = sel_register_name ("initialize"); + + /* 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 transmogrified to SEL's */ + method->method_name = + sel_register_typed_name ((const char*)method->method_name, + method->method_types); + + if (search_for_method_in_list (class->methods, method->method_name) + && method->method_name->sel_id != initialize_sel->sel_id) + { + /* 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 class, SEL op) +{ + return search_for_method_in_hierarchy(class, op); +} + +Method_t +class_get_class_method(MetaClass 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 cls, SEL sel) +{ + Method_t method = NULL; + Class 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->sel_id == op->sel_id) + return method; + } + + /* The method wasn't found. Follow the link to the next list of + methods. */ + method_list = method_list->method_next; + } + + return NULL; +} + +static retval_t __objc_forward (id object, SEL sel, arglist_t args); + +static id +__objc_word_forward (id rcv, SEL op, ...) +{ + void *args, *res; + + args = __builtin_apply_args (); + res = __objc_forward (rcv, op, args); + if (res) + __builtin_return (res); + else + return res; +} + +#if INVISIBLE_STRUCT_RETURN +static __big +#else +static id +#endif +__objc_block_forward (id rcv, SEL op, ...) +{ + void *args, *res; + + args = __builtin_apply_args (); + res = __objc_forward (rcv, op, args); + if (res) + __builtin_return (res); +} + + +/* This function is installed in the dispatch table for all methods which are + not implemented. Thus, it is called when a selector is not recognized. */ +static retval_t +__objc_forward (id object, SEL sel, arglist_t args) +{ + IMP imp; + static SEL frwd_sel = 0; + SEL err_sel; + + /* first try if the object understands forward:: */ + if (!frwd_sel) + frwd_sel = sel_get_any_uid("forward::"); + + if (__objc_responds_to (object, frwd_sel)) + { + imp = get_imp(object->class_pointer, frwd_sel); + return (*imp)(object, frwd_sel, sel, args); + } + + /* If the object recognizes the doesNotRecognize: method then we're going + to send it. */ + err_sel = sel_get_any_uid ("doesNotRecognize:"); + if (__objc_responds_to (object, err_sel)) + { + imp = get_imp (object->class_pointer, err_sel); + return (*imp) (object, err_sel, sel); + } + + /* The object doesn't recognize the method. Check for responding to + error:. If it does then sent it. */ + { + size_t strlen (const char*); + char msg[256 + strlen ((const char*)sel_get_name (sel)) + + strlen ((const char*)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_any_uid ("error:"); + if (__objc_responds_to (object, err_sel)) + { + imp = get_imp (object->class_pointer, err_sel); + return (*imp) (object, sel_get_any_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 (); + } +} + +void __objc_print_dtable_stats() +{ + int total = 0; + printf("memory usage: (%s)\n", +#ifdef OBJC_SPARSE2 + "2-level sparse arrays" +#else + "3-level sparse arrays" +#endif + ); + + printf("arrays: %d = %ld bytes\n", narrays, (int)narrays*sizeof(struct sarray)); + total += narrays*sizeof(struct sarray); + printf("buckets: %d = %ld bytes\n", nbuckets, (int)nbuckets*sizeof(struct sbucket)); + total += nbuckets*sizeof(struct sbucket); + + printf("idxtables: %d = %ld bytes\n", idxsize, (int)idxsize*sizeof(void*)); + total += idxsize*sizeof(void*); + printf("-----------------------------------\n"); + printf("total: %d bytes\n", total); + printf("===================================\n"); +} + + + diff --git a/contrib/gcc/objc/typedstream.h b/contrib/gcc/objc/typedstream.h new file mode 100644 index 0000000..50bd654 --- /dev/null +++ b/contrib/gcc/objc/typedstream.h @@ -0,0 +1,132 @@ +/* GNU Objective-C Typed Streams interface. + Copyright (C) 1993, 1995 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, 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 __typedstream_INCLUDE_GNU +#define __typedstream_INCLUDE_GNU + +#include "objc/objc.h" +#include "objc/hash.h" +#include + +typedef int (*objc_typed_read_func)(void*, char*, int); +typedef int (*objc_typed_write_func)(void*, const char*, int); +typedef int (*objc_typed_flush_func)(void*); +typedef int (*objc_typed_eof_func)(void*); + +#define OBJC_READONLY 0x01 +#define OBJC_WRITEONLY 0x02 + +#define OBJC_MANAGED_STREAM 0x01 +#define OBJC_FILE_STREAM 0x02 +#define OBJC_MEMORY_STREAM 0x04 + +#define OBJC_TYPED_STREAM_VERSION 0x01 + +typedef struct objc_typed_stream { + void* physical; + cache_ptr object_table; /* read/written objects */ + cache_ptr stream_table; /* other read/written but shared things.. */ + cache_ptr class_table; /* class version mapping */ + cache_ptr object_refs; /* forward references */ + int mode; /* OBJC_READONLY or OBJC_WRITEONLY */ + int type; /* MANAGED, FILE, MEMORY etc bit string */ + int version; /* version used when writing */ + int writing_root_p; + objc_typed_read_func read; + objc_typed_write_func write; + objc_typed_eof_func eof; + objc_typed_flush_func flush; +} TypedStream; + +/* opcode masks */ +#define _B_VALUE 0x1fU +#define _B_CODE 0xe0U +#define _B_SIGN 0x10U +#define _B_NUMBER 0x0fU + +/* standard opcodes */ +#define _B_INVALID 0x00U +#define _B_SINT 0x20U +#define _B_NINT 0x40U +#define _B_SSTR 0x60U +#define _B_NSTR 0x80U +#define _B_RCOMM 0xa0U +#define _B_UCOMM 0xc0U +#define _B_EXT 0xe0U + +/* eXtension opcodes */ +#define _BX_OBJECT 0x00U +#define _BX_CLASS 0x01U +#define _BX_SEL 0x02U +#define _BX_OBJREF 0x03U +#define _BX_OBJROOT 0x04U +#define _BX_EXT 0x1fU + +/* +** Read and write objects as specified by TYPE. All the `last' +** arguments are pointers to the objects to read/write. +*/ + +int objc_write_type (TypedStream* stream, const char* type, const void* data); +int objc_read_type (TypedStream* stream, const char* type, void* data); + +int objc_write_types (TypedStream* stream, const char* type, ...); +int objc_read_types (TypedStream* stream, const char* type, ...); + +int objc_write_object_reference (TypedStream* stream, id object); +int objc_write_root_object (TypedStream* stream, id object); + +long objc_get_stream_class_version (TypedStream* stream, Class class); + + +/* +** Convenience functions +*/ + +int objc_write_array (TypedStream* stream, const char* type, + int count, const void* data); +int objc_read_array (TypedStream* stream, const char* type, + int count, void* data); + +int objc_write_object (TypedStream* stream, id object); +int objc_read_object (TypedStream* stream, id* object); + + + +/* +** Open a typed stream for reading or writing. MODE may be either of +** OBJC_READONLY or OBJC_WRITEONLY. +*/ + +TypedStream* objc_open_typed_stream (FILE* physical, int mode); +TypedStream* objc_open_typed_stream_for_file (const char* file_name, int mode); + +void objc_close_typed_stream (TypedStream* stream); + +BOOL objc_end_of_typed_stream (TypedStream* stream); +void objc_flush_typed_stream (TypedStream* stream); + +#endif /* not __typedstream_INCLUDE_GNU */ -- cgit v1.1