diff options
| author | svn2git <svn2git@FreeBSD.org> | 1994-05-01 08:00:00 +0000 |
|---|---|---|
| committer | svn2git <svn2git@FreeBSD.org> | 1994-05-01 08:00:00 +0000 |
| commit | a16f65c7d117419bd266c28a1901ef129a337569 (patch) | |
| tree | 2626602f66dc3551e7a7c7bc9ad763c3bc7ab40a /gnu/usr.bin/cc/libobjc | |
| parent | 8503f4f13f77abf7adc8f7e329c6f9c1d52b6a20 (diff) | |
Release FreeBSD 1.1upstream/1.1.0_cvsrelease/1.1.0_cvs
This commit was manufactured to restore the state of the 1.1-RELEASE image.
Releases prior to 5.3-RELEASE are omitting the secure/ and crypto/ subdirs.
Diffstat (limited to 'gnu/usr.bin/cc/libobjc')
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/Makefile | 31 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/Object.h | 121 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/Object.m | 358 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/Protocol.h | 57 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/Protocol.m | 127 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/archive.c | 1492 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/class.c | 350 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/gstdarg.h | 156 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/hash.c | 250 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/hash.h | 200 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/init.c | 275 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/list.h | 145 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/misc.c | 72 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/objc-api.h | 450 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/objc.h | 185 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/objects.c | 91 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/runtime.h | 73 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/sarray.c | 435 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/sarray.h | 235 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/selector.c | 139 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/sendmsg.c | 471 | ||||
| -rw-r--r-- | gnu/usr.bin/cc/libobjc/typedstream.h | 132 |
22 files changed, 5845 insertions, 0 deletions
diff --git a/gnu/usr.bin/cc/libobjc/Makefile b/gnu/usr.bin/cc/libobjc/Makefile new file mode 100644 index 000000000000..a5903126bdca --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/Makefile @@ -0,0 +1,31 @@ +LIB= objc +CC= gcc + +NOPROFILE=no + +CFLAGS+= -I${.CURDIR} -I${.CURDIR}/.. -I${.CURDIR}/../lib + +SRCS = hash.c sarray.c class.c sendmsg.c init.c archive.c \ + selector.c objects.c misc.c Object.m Protocol.m + +OBJC_HDRS = hash.h list.h sarray.h objc.h \ + objc-api.h \ + Object.h Protocol.h \ + typedstream.h + +OBJC_HDR_DESTDIR = ${DESTDIR}/usr/include/objc + +beforeinstall: + @-if [ ! -d ${OBJC_HDR_DESTDIR} ]; then \ + mkdir ${OBJC_HDR_DESTDIR}; \ + chown ${BINOWN}.${BINGRP} ${OBJC_HDR_DESTDIR}; \ + chmod 755 ${OBJC_HDR_DESTDIR}; \ + fi + @echo installing includes into objc + @-for file in ${OBJC_HDRS}; do \ + cmp -s ${.CURDIR}/$$file ${OBJC_HDR_DESTDIR}/$$file || \ + install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/$$file \ + ${OBJC_HDR_DESTDIR}/$$file; \ + done + +.include <bsd.lib.mk> diff --git a/gnu/usr.bin/cc/libobjc/Object.h b/gnu/usr.bin/cc/libobjc/Object.h new file mode 100644 index 000000000000..917fed55a877 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/Object.h @@ -0,0 +1,121 @@ +/* Interface for the Object class for Objective-C. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#ifndef __object_INCLUDE_GNU +#define __object_INCLUDE_GNU + +#include <objc/objc.h> +#include <objc/typedstream.h> + +/* + * 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; + + /* 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 */ +- forward:(SEL)aSel :(arglist_t)argFrame; +- performv:(SEL)aSel :(arglist_t)argFrame; + + /* Posing */ ++ poseAs:(Class*)aClassObject; +- (Class*)transmuteClassTo:(Class*)aClassObject; + + /* Enforcing intentions */ +- subclassResponsibility:(SEL)aSel; +- notImplemented:(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/gnu/usr.bin/cc/libobjc/Object.m b/gnu/usr.bin/cc/libobjc/Object.m new file mode 100644 index 000000000000..79bbdd8d7251 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/Object.m @@ -0,0 +1,358 @@ +/* The implementation of class Object for Objective-C. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#include "objc/Object.h" +#include "objc/Protocol.h" +#include "objc/objc-api.h" + +#include "gstdarg.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; +} + +- (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 +- (BOOL) conformsTo: (Protocol*)aProtocol +{ + int i; + struct objc_protocol_list* proto_list; + + for (proto_list = isa->protocols; + proto_list; proto_list = proto_list->next) + { + for (i=0; i < proto_list->count; i++) + { + if ([proto_list->list[i] conformsTo: aProtocol]) + return YES; + } + } + + if ([self superClass]) + return [[self superClass] conformsTo: aProtocol]; + else + return NO; +} + +- (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); +} + +- forward:(SEL)aSel :(arglist_t)argFrame +{ + return [self doesNotRecognize: aSel]; +} + +- performv:(SEL)aSel :(arglist_t)argFrame +{ + return objc_msg_sendv(self, aSel, method_get_argsize(0), 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)]; +} + +- doesNotRecognize:(SEL)aSel +{ + return [self error:"%s does not recognize %s", + object_get_class_name(self), sel_get_name(aSel)]; +} + +- 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 +{ +#ifndef __alpha__ + if (aStream->mode == OBJC_READONLY) + return objc_get_stream_class_version (aStream, self); + else +#endif + 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/gnu/usr.bin/cc/libobjc/Protocol.h b/gnu/usr.bin/cc/libobjc/Protocol.h new file mode 100644 index 000000000000..6a38b4838c0c --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/Protocol.h @@ -0,0 +1,57 @@ +/* Declare the class Protocol for Objective C programs. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __Protocol_INCLUDE_GNU +#define __Protocol_INCLUDE_GNU + +#include "objc/Object.h" + +@interface Protocol : Object +{ +@private + char *protocol_name; + struct objc_protocol_list *protocol_list; + struct objc_method_description_list *instance_methods, *class_methods; +} + +/* Obtaining attributes intrinsic to the protocol */ + +- (const char *)name; + +/* Testing protocol conformance */ + +- (BOOL) conformsTo: (Protocol *)aProtocolObject; + +/* Looking up information specific to a protocol */ + +- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel; +- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel; + +@end + + + + +#endif __Protocol_INCLUDE_GNU diff --git a/gnu/usr.bin/cc/libobjc/Protocol.m b/gnu/usr.bin/cc/libobjc/Protocol.m new file mode 100644 index 000000000000..38963d0d4bfd --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/Protocol.m @@ -0,0 +1,127 @@ +/* This file contains the implementation of class Protocol. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "objc/Protocol.h" +#include "objc/objc-api.h" + +/* Method description list */ +struct objc_method_description_list { + int count; + struct objc_method_description list[1]; +}; + + +@implementation Protocol +{ +@private + char *protocol_name; + struct objc_protocol_list *protocol_list; + struct objc_method_description_list *instance_methods, *class_methods; +} + +/* Obtaining attributes intrinsic to the protocol */ + +- (const char *)name +{ + return protocol_name; +} + +/* Testing protocol conformance */ + +- (BOOL) conformsTo: (Protocol *)aProtocolObject +{ + int i; + struct objc_protocol_list* proto_list; + + if (!strcmp(aProtocolObject->protocol_name, self->protocol_name)) + return YES; + + for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) + { + for (i=0; i < proto_list->count; i++) + { + if ([proto_list->list[i] conformsTo: aProtocolObject]) + return YES; + } + } + + return NO; +} + +/* Looking up information specific to a protocol */ + +- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel +{ + int i; + struct objc_protocol_list* proto_list; + const char* name = sel_get_name (aSel); + struct objc_method_description *result; + + for (i = 0; i < instance_methods->count; i++) + { + if (!strcmp ((char*)instance_methods->list[i].name, name)) + return &(instance_methods->list[i]); + } + + for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) + { + for (i=0; i < proto_list->count; i++) + { + if ((result = [proto_list->list[i] + descriptionForInstanceMethod: aSel])) + return result; + } + } + + return NULL; +} + +- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel; +{ + int i; + struct objc_protocol_list* proto_list; + const char* name = sel_get_name (aSel); + struct objc_method_description *result; + + for (i = 0; i < class_methods->count; i++) + { + if (!strcmp ((char*)class_methods->list[i].name, name)) + return &(class_methods->list[i]); + } + + for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) + { + for (i=0; i < proto_list->count; i++) + { + if ((result = [proto_list->list[i] + descriptionForClassMethod: aSel])) + return result; + } + } + + return NULL; +} + +@end diff --git a/gnu/usr.bin/cc/libobjc/archive.c b/gnu/usr.bin/cc/libobjc/archive.c new file mode 100644 index 000000000000..867b74977f3b --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/archive.c @@ -0,0 +1,1492 @@ +/* GNU Objective C Runtime archiving + Copyright (C) 1993 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + +You should have received a copy of the GNU General Public License along with + GNU CC; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +/* +** Note: This version assumes that int and longs are both 32bit. +*/ + +#ifndef __alpha__ + +#include "runtime.h" +#include "typedstream.h" + +#define __objc_fatal(format, args...) \ + { fprintf(stderr, "archining: "); \ + fprintf(stderr, format, ## args); \ + fprintf(stderr, "\n"); abort(); } + +/* Declare some functions... */ + +static int +objc_read_class (struct objc_typed_stream* stream, Class** class); + +static int +objc_sizeof_type(const char* type); + +static int +objc_write_use_common (struct objc_typed_stream* stream, unsigned int key); + +static int +objc_write_register_common (struct objc_typed_stream* stream, + unsigned int key); + +static int +objc_write_class (struct objc_typed_stream* stream, + struct objc_class* class); + +static const char* +__objc_skip_type (const char* type); + +static 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 <= 0xffU) + return __objc_code_unsigned_char (buf, val); + + else + { + buf[0] = _B_NINT|0x02; + buf[1] = val/0x100; + buf[2] = val%0x100; + return 3; + } +} + +int +objc_write_unsigned_short (struct objc_typed_stream* stream, unsigned short value) +{ + unsigned char buf[sizeof (unsigned short)+1]; + int len = __objc_code_unsigned_short (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + +static __inline__ int +__objc_code_short (unsigned char* buf, short val) +{ + if (val > 0) + return __objc_code_unsigned_short (buf, val); + + if (val > -0x7f) /* val > -128 */ + return __objc_code_char (buf, val); + + else + { + int len = __objc_code_unsigned_short (buf, -val); + buf[0] |= _B_SIGN; + return len; + } +} + +int +objc_write_short (struct objc_typed_stream* stream, short value) +{ + unsigned char buf[sizeof (short)+1]; + int len = __objc_code_short (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + + +static __inline__ int +__objc_code_unsigned_int (unsigned char* buf, unsigned int val) +{ + if (val < 0x10000) + return __objc_code_unsigned_short (buf, val%0x10000); + + else if (val < 0x1000000) + { + buf[0] = _B_NINT|3; + buf[1] = val/0x10000; + buf[2] = (val%0x10000)/0x100; + buf[3] = val%0x100; + return 4; + } + + else + { + buf[0] = _B_NINT|4; + buf[1] = val/0x1000000; + buf[2] = (val%0x1000000)/0x10000; + buf[3] = (val%0x10000)/0x100; + buf[4] = val%0x100; + return 5; + } +} + +int +objc_write_unsigned_int (struct objc_typed_stream* stream, unsigned int value) +{ + unsigned char buf[sizeof(unsigned int)+1]; + int len = __objc_code_unsigned_int (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + +static __inline__ int +__objc_code_int (unsigned char* buf, int val) +{ + if (val >= 0) + return __objc_code_unsigned_int (buf, val); + + if (val > -0x7f) + return __objc_code_char (buf, val); + + else + { + int len = __objc_code_unsigned_int (buf, -val); + buf[0] |= _B_SIGN; + return len; + } +} + +int +objc_write_int (struct objc_typed_stream* stream, int value) +{ + unsigned char buf[sizeof(int)+1]; + int len = __objc_code_int (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + +int +objc_write_string (struct objc_typed_stream* stream, + const unsigned char* string, unsigned int nbytes) +{ + unsigned char buf[sizeof(unsigned int)+1]; + int len = __objc_code_unsigned_int (buf, nbytes); + + if ((buf[0]&_B_CODE) == _B_SINT) + buf[0] = (buf[0]&_B_VALUE)|_B_SSTR; + + else /* _B_NINT */ + buf[0] = (buf[0]&_B_VALUE)|_B_NSTR; + + if ((*stream->write)(stream->physical, buf, len) != 0) + return (*stream->write)(stream->physical, string, nbytes); + else + return 0; +} + +int +objc_write_string_atomic (struct objc_typed_stream* stream, + unsigned char* string, unsigned int nbytes) +{ + unsigned int key; + if ((key = (unsigned int)hash_value_for_key (stream->stream_table, string))) + return objc_write_use_common (stream, key); + else + { + int length; + hash_add (&stream->stream_table, (void*)key=(unsigned int)string, string); + if ((length = objc_write_register_common (stream, key))) + return objc_write_string (stream, string, nbytes); + return length; + } +} + +static int +objc_write_register_common (struct objc_typed_stream* stream, unsigned int key) +{ + unsigned char buf[sizeof (unsigned int)+2]; + int len = __objc_code_unsigned_int (buf+1, key); + if (len == 1) + { + buf[0] = _B_RCOMM|0x01; + buf[1] &= _B_VALUE; + return (*stream->write)(stream->physical, buf, len+1); + } + else + { + buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM; + return (*stream->write)(stream->physical, buf+1, len); + } +} + +static int +objc_write_use_common (struct objc_typed_stream* stream, unsigned int key) +{ + unsigned char buf[sizeof (unsigned int)+2]; + int len = __objc_code_unsigned_int (buf+1, key); + if (len == 1) + { + buf[0] = _B_UCOMM|0x01; + buf[1] &= _B_VALUE; + return (*stream->write)(stream->physical, buf, 2); + } + else + { + buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM; + return (*stream->write)(stream->physical, buf+1, len); + } +} + +static __inline__ int +__objc_write_extension (struct objc_typed_stream* stream, unsigned char code) +{ + if (code <= _B_VALUE) + { + unsigned char buf = code|_B_EXT; + return (*stream->write)(stream->physical, &buf, 1); + } + else + abort(); +} + +__inline__ int +__objc_write_object (struct objc_typed_stream* stream, id object) +{ + unsigned char buf = '\0'; + SEL write_sel = sel_get_uid ("write:"); + if (object) + { + __objc_write_extension (stream, _BX_OBJECT); + objc_write_class (stream, object->class_pointer); + (*objc_msg_lookup(object, write_sel))(object, write_sel, stream); + return (*stream->write)(stream->physical, &buf, 1); + } + else + return objc_write_use_common(stream, 0); +} + +int +objc_write_object_reference (struct objc_typed_stream* stream, id object) +{ + unsigned int key; + if ((key = (unsigned int)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_int (stream, (unsigned int)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 int key; + if ((key = (unsigned int)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, (void*)key=(unsigned int)object, object); + if ((length = objc_write_register_common (stream, key))) + return __objc_write_object (stream, object); + return length; + } +} + +__inline__ int +__objc_write_class (struct objc_typed_stream* stream, struct objc_class* class) +{ + __objc_write_extension (stream, _BX_CLASS); + objc_write_string_atomic(stream, (char*)class->name, + strlen((char*)class->name)); + return objc_write_unsigned_int (stream, CLS_GETNUMBER(class)); +} + + +static int +objc_write_class (struct objc_typed_stream* stream, + struct objc_class* class) +{ + unsigned int key; + if ((key = (unsigned int)hash_value_for_key (stream->stream_table, class))) + return objc_write_use_common (stream, key); + else + { + int length; + hash_add (&stream->stream_table, (void*)key=(unsigned int)class, class); + if ((length = objc_write_register_common (stream, key))) + return __objc_write_class (stream, class); + return length; + } +} + + +__inline__ int +__objc_write_selector (struct objc_typed_stream* stream, SEL selector) +{ + const char* sel_name = sel_get_name (selector); + __objc_write_extension (stream, _BX_SEL); + return objc_write_string (stream, sel_name, strlen ((char*)sel_name)); +} + +int +objc_write_selector (struct objc_typed_stream* stream, SEL selector) +{ + const char* sel_name = sel_get_name (selector); + unsigned int key; + if ((key = (unsigned int)hash_value_for_key (stream->stream_table, sel_name))) + return objc_write_use_common (stream, key); + else + { + int length; + hash_add (&stream->stream_table, (void*)key=(unsigned int)sel_name, (char*)sel_name); + if ((length = objc_write_register_common (stream, key))) + return __objc_write_selector (stream, selector); + return length; + } +} + + + +/* +** Read operations +*/ + +__inline__ int +objc_read_char (struct objc_typed_stream* stream, char* val) +{ + unsigned char buf; + int len; + len = (*stream->read)(stream->physical, &buf, 1); + if (len != 0) + { + if ((buf & _B_CODE) == _B_SINT) + (*val) = (buf & _B_VALUE); + + else if ((buf & _B_NUMBER) == 1) + { + len = (*stream->read)(stream->physical, val, 1); + if (buf&_B_SIGN) + (*val) = -1*(*val); + } + + else + __objc_fatal("expected 8bit signed int, got %dbit int", + (int)(buf&_B_NUMBER)*8); + } + return len; +} + + +__inline__ int +objc_read_unsigned_char (struct objc_typed_stream* stream, unsigned char* val) +{ + unsigned char buf; + int len; + if ((len = (*stream->read)(stream->physical, &buf, 1))) + { + if ((buf & _B_CODE) == _B_SINT) + (*val) = (buf & _B_VALUE); + + else if ((buf & _B_NUMBER) == 1) + len = (*stream->read)(stream->physical, val, 1); + + else + __objc_fatal("expected 8bit unsigned int, got %dbit int", + (int)(buf&_B_NUMBER)*8); + } + return len; +} + +__inline__ int +objc_read_short (struct objc_typed_stream* stream, short* value) +{ + unsigned char buf[sizeof(short)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + { + int pos = 1; + int nbytes = buf[0] & _B_NUMBER; + if (nbytes > sizeof (short)) + __objc_fatal("expected short, got bigger (%dbits)", nbytes*8); + len = (*stream->read)(stream->physical, buf+1, nbytes); + (*value) = 0; + while (pos <= nbytes) + (*value) = ((*value)*0x100) + buf[pos++]; + if (buf[0] & _B_SIGN) + (*value) = -(*value); + } + } + return len; +} + +__inline__ int +objc_read_unsigned_short (struct objc_typed_stream* stream, + unsigned short* value) +{ + unsigned char buf[sizeof(unsigned short)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + { + int pos = 1; + int nbytes = buf[0] & _B_NUMBER; + if (nbytes > sizeof (short)) + __objc_fatal("expected short, got int or bigger"); + len = (*stream->read)(stream->physical, buf+1, nbytes); + (*value) = 0; + while (pos <= nbytes) + (*value) = ((*value)*0x100) + buf[pos++]; + } + } + return len; +} + + +__inline__ int +objc_read_int (struct objc_typed_stream* stream, int* value) +{ + unsigned char buf[sizeof(int)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + { + int pos = 1; + int nbytes = buf[0] & _B_NUMBER; + if (nbytes > sizeof (int)) + __objc_fatal("expected int, got bigger"); + len = (*stream->read)(stream->physical, buf+1, nbytes); + (*value) = 0; + while (pos <= nbytes) + (*value) = ((*value)*0x100) + buf[pos++]; + if (buf[0] & _B_SIGN) + (*value) = -(*value); + } + } + return len; +} + +__inline__ int +__objc_read_nbyte_uint (struct objc_typed_stream* stream, + unsigned int nbytes, unsigned int* val) +{ + int len, pos = 0; + unsigned char buf[sizeof(unsigned int)+1]; + + if (nbytes > sizeof (int)) + __objc_fatal("expected int, got bigger"); + + len = (*stream->read)(stream->physical, buf, nbytes); + (*val) = 0; + while (pos < nbytes) + (*val) = ((*val)*0x100) + buf[pos++]; + return len; +} + + +__inline__ int +objc_read_unsigned_int (struct objc_typed_stream* stream, + unsigned int* value) +{ + unsigned char buf[sizeof(unsigned int)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value); + + } + return len; +} + +__inline__ int +objc_read_string (struct objc_typed_stream* stream, + char** string) +{ + unsigned char buf[sizeof(unsigned int)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + unsigned int key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read)(stream->physical, buf, 1); + } + + switch (buf[0]&_B_CODE) { + case _B_SSTR: + { + int length = buf[0]&_B_VALUE; + (*string) = (char*)__objc_xmalloc(length+1); + if (key) + hash_add (&stream->stream_table, (void*)key, *string); + len = (*stream->read)(stream->physical, *string, length); + (*string)[length] = '\0'; + } + break; + + case _B_UCOMM: + { + len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key); + (*string) = hash_value_for_key (stream->stream_table, (void*)key); + } + break; + + case _B_NSTR: + { + unsigned int nbytes = buf[0]&_B_VALUE; + len = __objc_read_nbyte_uint(stream, nbytes, &nbytes); + if (len) { + (*string) = (char*)__objc_xmalloc(nbytes); + if (key) + hash_add (&stream->stream_table, (void*)key, *string); + len = (*stream->read)(stream->physical, *string, buf[0]&_B_VALUE); + (*string)[nbytes] = '\0'; + } + } + break; + + default: + __objc_fatal("expected string, got opcode %c\n", (buf[0]&_B_CODE)); + } + } + + return len; +} + + +int +objc_read_object (struct objc_typed_stream* stream, id* object) +{ + unsigned char buf[sizeof (unsigned int)]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + SEL read_sel = sel_get_uid ("read:"); + unsigned int key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */ + { + len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read)(stream->physical, buf, 1); + } + + if (buf[0] == (_B_EXT | _BX_OBJECT)) + { + Class* class; + + /* get class */ + len = objc_read_class (stream, &class); + + /* create instance */ + (*object) = class_create_instance(class); + + /* register? */ + if (key) + hash_add (&stream->object_table, (void*)key, *object); + + /* send -read: */ + if (__objc_responds_to (*object, read_sel)) + (*get_imp(class, read_sel))(*object, read_sel, stream); + + /* check null-byte */ + len = (*stream->read)(stream->physical, buf, 1); + if (buf[0] != '\0') + __objc_fatal("expected null-byte, got opcode %c", buf[0]); + } + + else if ((buf[0]&_B_CODE) == _B_UCOMM) + { + if (key) + __objc_fatal("cannot register use upcode..."); + len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key); + (*object) = hash_value_for_key (stream->object_table, (void*)key); + } + + else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */ + { + struct objc_list* other; + len = objc_read_unsigned_int (stream, &key); + other = (struct objc_list*)hash_value_for_key (stream->object_refs, (void*)key); + hash_add (&stream->object_refs, (void*)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 int key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read)(stream->physical, buf, 1); + } + + if (buf[0] == (_B_EXT | _BX_CLASS)) + { + char* class_name; + int version; + + /* get class */ + len = objc_read_string (stream, &class_name); + (*class) = objc_get_class(class_name); + free (class_name); + + /* register */ + if (key) + hash_add (&stream->stream_table, (void*)key, *class); + + objc_read_unsigned_int(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_uint(stream, (buf[0] & _B_VALUE), &key); + (*class) = hash_value_for_key (stream->stream_table, (void*)key); + if (!*class) + __objc_fatal("cannot find class for key %x", key); + } + + else + __objc_fatal("expected class, got opcode %c", buf[0]); + } + return len; +} + +int +objc_read_selector (struct objc_typed_stream* stream, SEL* selector) +{ + unsigned char buf[sizeof (unsigned int)]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + unsigned int key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read)(stream->physical, buf, 1); + } + + if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */ + { + char* selector_name; + + /* get selector */ + len = objc_read_string (stream, &selector_name); + (*selector) = sel_get_uid(selector_name); + free (selector_name); + + /* register */ + if (key) + hash_add (&stream->stream_table, (void*)key, *selector); + } + + else if ((buf[0]&_B_CODE) == _B_UCOMM) + { + if (key) + __objc_fatal("cannot register use upcode..."); + len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key); + (*selector) = hash_value_for_key (stream->stream_table, (void*)key); + } + + else + __objc_fatal("expected selector, got opcode %c", buf[0]); + } + return len; +} + +static int +objc_sizeof_type(const char* type) +{ + switch(*type) { + case _C_ID: return sizeof(id); + break; + + case _C_CLASS: + return sizeof(Class*); + break; + + case _C_SEL: + return sizeof(SEL); + break; + + case _C_CHR: + return sizeof(char); + break; + + case _C_UCHR: + return sizeof(unsigned char); + break; + + case _C_SHT: + return sizeof(short); + break; + + case _C_USHT: + return sizeof(unsigned short); + break; + + case _C_INT: + case _C_LNG: + return sizeof(int); + break; + + case _C_UINT: + case _C_ULNG: + return sizeof(unsigned int); + break; + + case _C_ATOM: + case _C_CHARPTR: + return sizeof(char*); + break; + + default: + fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type); + abort(); + } +} + + +static const char* +__objc_skip_type (const char* type) +{ + switch (*type) { + case _C_ID: + case _C_CLASS: + case _C_SEL: + case _C_CHR: + case _C_UCHR: + case _C_CHARPTR: + case _C_ATOM: + case _C_SHT: + case _C_USHT: + case _C_INT: + case _C_UINT: + case _C_LNG: + case _C_ULNG: + case _C_FLT: + case _C_DBL: + return ++type; + break; + + case _C_ARY_B: + while(isdigit(*++type)); + type = __objc_skip_type(type); + if (*type == _C_ARY_E) + return ++type; + else + __objc_fatal("cannot parse typespec: %s", type); + break; + + default: + fprintf(stderr, "objc_read_types: cannot parse typespec: %s\n", type); + abort(); + } +} + +/* +** USER LEVEL FUNCTIONS +*/ + +/* +** Write one object, encoded in TYPE and pointed to by DATA to the +** typed stream STREAM. +*/ + +int +objc_write_type(TypedStream* stream, const char* type, const void* data) +{ + switch(*type) { + case _C_ID: + return objc_write_object (stream, *(id*)data); + break; + + case _C_CLASS: + return objc_write_class (stream, *(Class**)data); + break; + + case _C_SEL: + return objc_write_selector (stream, *(SEL*)data); + break; + + case _C_CHR: + return objc_write_char(stream, *(char*)data); + break; + + case _C_UCHR: + return objc_write_unsigned_char(stream, *(unsigned char*)data); + break; + + case _C_SHT: + return objc_write_short(stream, *(short*)data); + break; + + case _C_USHT: + return objc_write_unsigned_short(stream, *(unsigned short*)data); + break; + + case _C_INT: + case _C_LNG: + return objc_write_int(stream, *(int*)data); + break; + + case _C_UINT: + case _C_ULNG: + return objc_write_unsigned_int(stream, *(unsigned int*)data); + break; + + case _C_CHARPTR: + return objc_write_string (stream, (char*)data, strlen((char*)data)); + break; + + case _C_ATOM: + return objc_write_string_atomic (stream, (char*)data, strlen((char*)data)); + break; + + case _C_ARY_B: + { + int len = atoi(type+1); + while (isdigit(*++type)); + return objc_write_array (stream, type, len, data); + } + break; + + default: + fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type); + abort(); + } +} + +/* +** Read one object, encoded in TYPE and pointed to by DATA to the +** typed stream STREAM. DATA specifies the address of the types to +** read. Expected type is checked against the type actually present +** on the stream. +*/ + +int +objc_read_type(TypedStream* stream, const char* type, void* data) +{ + char c; + switch(c = *type) { + case _C_ID: + return objc_read_object (stream, (id*)data); + break; + + case _C_CLASS: + return objc_read_class (stream, (Class**)data); + break; + + case _C_SEL: + return objc_read_selector (stream, (SEL*)data); + break; + + case _C_CHR: + return objc_read_char (stream, (char*)data); + break; + + case _C_UCHR: + return objc_read_unsigned_char (stream, (unsigned char*)data); + break; + + case _C_SHT: + return objc_read_short (stream, (short*)data); + break; + + case _C_USHT: + return objc_read_unsigned_short (stream, (unsigned short*)data); + break; + + case _C_INT: + case _C_LNG: + return objc_read_int (stream, (int*)data); + break; + + case _C_UINT: + case _C_ULNG: + return objc_read_unsigned_int (stream, (unsigned int*)data); + break; + + case _C_CHARPTR: + case _C_ATOM: + return objc_read_string (stream, (char**)data); + break; + + case _C_ARY_B: + { + int len = atoi(type+1); + while (isdigit(*++type)); + return objc_read_array (stream, type, len, data); + } + break; + + default: + fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type); + abort(); + } +} + +/* +** Write the object specified by the template TYPE to STREAM. Last +** arguments specify addresses of values to be written. It might +** seem surprising to specify values by address, but this is extremely +** convenient for copy-paste with objc_read_types calls. A more +** down-to-the-earth cause for this passing of addresses is that values +** of arbitrary size is not well supported in ANSI C for functions with +** variable number of arguments. +*/ + +int +objc_write_types (TypedStream* stream, const char* type, ...) +{ + va_list args; + const char *c; + int res = 0; + + va_start(args, type); + + for (c = type; *c; c = __objc_skip_type (c)) + { + switch(*c) { + case _C_ID: + res = objc_write_object (stream, *va_arg (args, id*)); + break; + + case _C_CLASS: + res = objc_write_class (stream, *va_arg(args, Class**)); + break; + + case _C_SEL: + res = objc_write_selector (stream, *va_arg(args, SEL*)); + break; + + case _C_CHR: + res = objc_write_char (stream, *va_arg (args, char*)); + break; + + case _C_UCHR: + res = objc_write_unsigned_char (stream, + *va_arg (args, unsigned char*)); + break; + + case _C_SHT: + res = objc_write_short (stream, *va_arg(args, short*)); + break; + + case _C_USHT: + res = objc_write_unsigned_short (stream, + *va_arg(args, unsigned short*)); + break; + + case _C_INT: + case _C_LNG: + res = objc_write_int(stream, *va_arg(args, int*)); + break; + + case _C_UINT: + case _C_ULNG: + res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*)); + break; + + case _C_CHARPTR: + { + char* str = va_arg(args, char*); + res = objc_write_string (stream, str, strlen(str)); + } + break; + + case _C_ATOM: + { + char* str = va_arg(args, char*); + res = objc_write_string_atomic (stream, str, strlen(str)); + } + break; + + case _C_ARY_B: + { + int len = atoi(c+1); + const char* t = c; + while (isdigit(*++t)); + res = objc_write_array (stream, t, len, va_arg(args, void*)); + t = __objc_skip_type (t); + if (*t != _C_ARY_E) + __objc_fatal("expected `]', got: %s", t); + } + break; + + default: + fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type); + abort(); + } + } + va_end(args); + return res; +} + + +/* +** Last arguments specify addresses of values to be read. Expected +** type is checked against the type actually present on the stream. +*/ + +int +objc_read_types(TypedStream* stream, const char* type, ...) +{ + va_list args; + const char *c; + int res = 0; + + va_start(args, type); + + for (c = type; *c; c = __objc_skip_type(c)) + { + switch(*c) { + case _C_ID: + res = objc_read_object(stream, va_arg(args, id*)); + break; + + case _C_CLASS: + res = objc_read_class(stream, va_arg(args, Class**)); + break; + + case _C_SEL: + res = objc_read_selector(stream, va_arg(args, SEL*)); + break; + + case _C_CHR: + res = objc_read_char(stream, va_arg(args, char*)); + break; + + case _C_UCHR: + res = objc_read_unsigned_char(stream, va_arg(args, unsigned char*)); + break; + + case _C_SHT: + res = objc_read_short(stream, va_arg(args, short*)); + break; + + case _C_USHT: + res = objc_read_unsigned_short(stream, va_arg(args, unsigned short*)); + break; + + case _C_INT: + case _C_LNG: + res = objc_read_int(stream, va_arg(args, int*)); + break; + + case _C_UINT: + case _C_ULNG: + res = objc_read_unsigned_int(stream, va_arg(args, unsigned int*)); + break; + + case _C_CHARPTR: + case _C_ATOM: + { + char** str = va_arg(args, char**); + res = objc_read_string (stream, str); + } + break; + + case _C_ARY_B: + { + int len = atoi(c+1); + const char* t = c; + while (isdigit(*++t)); + res = objc_read_array (stream, t, len, va_arg(args, void*)); + t = __objc_skip_type (t); + if (*t != _C_ARY_E) + __objc_fatal("expected `]', got: %s", t); + } + break; + + default: + fprintf(stderr, "objc_read_type: cannot parse typespec: %s\n", type); + abort(); + } + } + va_end(args); + return res; +} + +/* +** Write an array of COUNT elements of TYPE from the memory address DATA. +** This is equivalent of objc_write_type (stream, "[N<type>]", data) +*/ + +int +objc_write_array (TypedStream* stream, const char* type, + int count, const void* data) +{ + int off = objc_sizeof_type(type); + const char* where = data; + + while (count-- > 0) + { + objc_write_type(stream, type, where); + where += off; + } + return 1; +} + +/* +** Read an array of COUNT elements of TYPE into the memory address +** DATA. The memory pointed to by data is supposed to be allocated +** by the callee. This is equivalent of +** objc_read_type (stream, "[N<type>]", data) +*/ + +int +objc_read_array (TypedStream* stream, const char* type, + int count, void* data) +{ + int off = objc_sizeof_type(type); + char* where = (char*)data; + + while (count-- > 0) + { + objc_read_type(stream, type, where); + where += off; + } + return 1; +} + +static int +__objc_fread(FILE* file, char* data, int len) +{ + return fread(data, len, 1, file); +} + +static int +__objc_fwrite(FILE* file, char* data, int len) +{ + return fwrite(data, len, 1, file); +} + +static int +__objc_feof(FILE* file) +{ + return feof(file); +} + +static int +__objc_no_write(FILE* file, char* data, int len) +{ + __objc_fatal ("TypedStream not open for writing"); +} + +static int +__objc_no_read(FILE* file, char* data, int len) +{ + __objc_fatal ("TypedStream not open for reading"); +} + +static int +__objc_read_typed_stream_signature (TypedStream* stream) +{ + char buffer[80]; + int pos = 0; + do + (*stream->read)(stream->physical, buffer+pos, 1); + while (buffer[pos++] != '\0'); + sscanf (buffer, "GNU TypedStream %d", &stream->version); + if (stream->version != OBJC_TYPED_STREAM_VERSION) + __objc_fatal ("cannot handle TypedStream version %d", stream->version); + 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; + SEL awake_sel = sel_get_uid ("awake"); + + /* resolve object forward references */ + 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; + reflist = reflist->tail; + } + list_free (node->value); + } + + /* 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) +{ + int fflush(FILE*); + + 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); +} + +int +objc_get_stream_class_version (TypedStream* stream, Class* class) +{ + if (stream->class_table) + return (int) hash_value_for_key (stream->class_table, class->name); + else + return class_get_version (class); +} + +#endif /* __alpha__ */ diff --git a/gnu/usr.bin/cc/libobjc/class.c b/gnu/usr.bin/cc/libobjc/class.c new file mode 100644 index 000000000000..c9af0eb1bbf2 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/class.c @@ -0,0 +1,350 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup, Dennis Glatting + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + +You should have received a copy of the GNU General Public License along with + GNU CC; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" /* the kitchen sink */ + + +/* The table of classname->class. Used for objc_lookup_class and friends */ +static cache_ptr __objc_class_hash = 0; + +/* This is a hook which is called by objc_get_class and + objc_lookup_class if the runtime is not able to find the class. + This may e.g. try to load in the class using dynamic loading */ +Class* (*_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(); +} + + +/* 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; + } + } +} + + +/* This is a incomplete implementation of posing. This function does the + bulk of the work but does not initialize the class method caches. That is + a run-time specific operation. + +I implement posing by hiding SUPER_CLASS, creating new class and meta class + structures, initializing it with IMPOSTOR, and changing it such that it is + identified as SUPER_CLASS. SUPER_CLASS remains in the hierarchy but is + inaccessible by the means. The class hierarchy is then re arranged such + that all of the subclasses of SUPER_CLASS now inherit from the new class + structures -- except the impostor itself. The only dramatic effect on the + application is that subclasses of SUPER_CLASS cannot do a [ .... + super_class ] and expect their real super class. */ +Class* +class_pose_as (Class* impostor, Class* super_class) +{ + Class* new_class = (Class*) __objc_xcalloc (1, sizeof (Class)); + MetaClass* new_meta_class = + (MetaClass*) __objc_xmalloc(sizeof (MetaClass)); + char *new_name = (char *)__objc_xmalloc ((size_t)strlen ((char*)super_class->name) + 12); + + /* We must know the state of the hierachy. Do initial setup if needed */ + if(!CLS_ISRESOLV(impostor)) + __objc_resolve_class_links(); + + assert (new_class); + assert (new_meta_class); + assert (new_name); + + assert (CLS_ISCLASS(impostor)); + assert (CLS_ISCLASS(super_class)); + + assert (impostor->instance_size == super_class->instance_size); + + /* Create the impostor class. */ + new_class->class_pointer = new_meta_class; + new_class->super_class = super_class; + new_class->name = super_class->name; + new_class->version = super_class->version; + new_class->info = super_class->info; + new_class->instance_size = super_class->instance_size; + new_class->ivars = super_class->ivars; + new_class->methods = impostor->methods; + new_class->dtable = impostor->dtable; + + /* Create the impostor meta class. */ + new_meta_class->class_pointer = super_class->class_pointer->class_pointer; + new_meta_class->super_class = super_class->class_pointer->super_class; + new_meta_class->name = super_class->class_pointer->name; + new_meta_class->version = super_class->class_pointer->version; + new_meta_class->info = super_class->class_pointer->info; + new_meta_class->instance_size = super_class->class_pointer->instance_size; + new_meta_class->ivars = super_class->class_pointer->ivars; + new_meta_class->methods = impostor->class_pointer->methods; + new_meta_class->dtable = impostor->class_pointer->dtable; + + /* Now change super/subclass links of all related classes. This is rather + complex, since we have both super_class link, and subclass_list for the + involved classes. */ + { + Class* *classpp; + MetaClass* *metaclasspp; + + /* Remove impostor from subclass list of super_class */ + for (classpp = &(super_class->subclass_list); + *classpp; + classpp = &((*classpp)->sibling_class)) + { + if (*classpp == impostor) + *classpp = (*classpp)->sibling_class; + if (*classpp == 0) + break; + } + + /* Do the same for the meta classes */ + + for (metaclasspp = &(super_class->class_pointer->subclass_list); + *metaclasspp; + metaclasspp = &((*metaclasspp)->sibling_class)) + { + if (*metaclasspp == impostor->class_pointer) + *metaclasspp = (*metaclasspp)->sibling_class; + if (*metaclasspp == 0) + break; + } + + /* From the loop above, classpp now points to the sibling_class entry */ + /* of the last element in the list of subclasses for super_class */ + + /* Append the subclass list of impostor to the subclass list of */ + /* superclass, and excange those two and set subclass of */ + /* super_class to be impostor only */ + + *classpp = impostor->subclass_list; + new_class->subclass_list = super_class->subclass_list; + super_class->subclass_list = new_class; + new_class->sibling_class = 0; + + /* Do the same thing for the meta classes */ + *metaclasspp = impostor->class_pointer->subclass_list; + new_meta_class->subclass_list = super_class->class_pointer->subclass_list; + super_class->class_pointer->subclass_list = new_meta_class; + new_meta_class->sibling_class = 0; + + /* Update superclass links for all subclasses of new_class */ + for (classpp = &(new_class->subclass_list); *classpp; + classpp = &((*classpp)->sibling_class)) + (*classpp)->super_class = new_class; + + for (metaclasspp = &(new_meta_class->subclass_list); *metaclasspp; + metaclasspp = &((*metaclasspp)->sibling_class)) + (*metaclasspp)->super_class = new_meta_class; + + } + + /* Delete the class from the hash table, change its name so that it can no + longer be found, then place it back into the hash table using its new + name. + + Don't worry about the class number. It is already assigned. + memory is lost with the hash key.) */ + hash_remove (__objc_class_hash, super_class->name); + sprintf (new_name, "%s*", super_class->name); + super_class->name = new_name; + super_class->class_pointer->name = new_name; + hash_add (&__objc_class_hash, super_class->name, super_class); + + /* Place the impostor class in class hash table and assign it a class + number. */ + __objc_add_class_to_hash (new_class); + + /* Now update dispatch tables for new_class and it's subclasses */ + __objc_update_dispatch_table_for_class ((Class*) new_meta_class); + __objc_update_dispatch_table_for_class (new_class); + + return new_class; +} + diff --git a/gnu/usr.bin/cc/libobjc/gstdarg.h b/gnu/usr.bin/cc/libobjc/gstdarg.h new file mode 100644 index 000000000000..dfa734ba39c6 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/gstdarg.h @@ -0,0 +1,156 @@ +/* stdarg.h for GNU. + Note that the type used in va_arg is supposed to match the + actual type **after default promotions**. + Thus, va_arg (..., short) is not valid. */ + +#ifndef _STDARG_H +#ifndef _ANSI_STDARG_H_ +#ifndef __need___va_list +#define _STDARG_H +#define _ANSI_STDARG_H_ +#endif /* not __need___va_list */ +#undef __need___va_list + +#ifndef __GNUC__ +/* Use the system's macros with the system's compiler. + This is relevant only when building GCC with some other compiler. */ +#include <stdarg.h> +#else +#ifdef __clipper__ +#include <va-clipper.h> +#else +#ifdef __m88k__ +#include <va-m88k.h> +#else +#ifdef __i860__ +#include <va-i860.h> +#else +#ifdef __hppa__ +#include <va-pa.h> +#else +#ifdef __mips__ +#include <va-mips.h> +#else +#ifdef __sparc__ +#include <va-sparc.h> +#else +#ifdef __i960__ +#include <va-i960.h> +#else +#ifdef __alpha__ +#include <va-alpha.h> +#else + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +#if defined(__svr4__) || defined(_AIX) || defined(_M_UNIX) +typedef char *__gnuc_va_list; +#else +typedef void *__gnuc_va_list; +#endif +#endif + +/* Define the standard macros for the user, + if this invocation was from the user program. */ +#ifdef _STDARG_H + +/* Amount of space required in an argument list for an arg of type TYPE. + TYPE may alternatively be an expression whose type is used. */ + +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) + +#define va_start(AP, LASTARG) \ + (AP = ((__gnuc_va_list) __builtin_next_arg ())) + +#undef va_end +void va_end (__gnuc_va_list); /* Defined in libgcc.a */ +#define va_end(AP) + +/* We cast to void * and then to TYPE * because this avoids + a warning about increasing the alignment requirement. */ + +#if defined (__arm__) || defined (__i386__) || defined (__ns32000__) || defined (__vax__) +/* This is for little-endian machines; small args are padded upward. */ +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE)))) +#else /* big-endian */ +/* This is for big-endian machines; small args are padded downward. */ +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - ((sizeof (TYPE) < 4 \ + ? sizeof (TYPE) \ + : __va_rounded_size (TYPE)))))) +#endif /* big-endian */ +#endif /* _STDARG_H */ + +#endif /* not alpha */ +#endif /* not i960 */ +#endif /* not sparc */ +#endif /* not mips */ +#endif /* not hppa */ +#endif /* not i860 */ +#endif /* not m88k */ +#endif /* not clipper */ + +#ifdef _STDARG_H +/* Define va_list, if desired, from __gnuc_va_list. */ +/* We deliberately do not define va_list when called from + stdio.h, because ANSI C says that stdio.h is not supposed to define + va_list. stdio.h needs to have access to that data type, + but must not use that name. It should use the name __gnuc_va_list, + which is safe because it is reserved for the implementation. */ + +#ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */ +#undef _VA_LIST +#endif + +#ifdef _BSD_VA_LIST +#undef _BSD_VA_LIST +#endif + +#ifdef __svr4__ +/* SVR4.2 uses _VA_LIST for an internal alias for va_list, + so we must avoid testing it and setting it here. + SVR4 uses _VA_LIST as a flag in stdarg.h, but we should + have no conflict with that. */ +#ifndef _VA_LIST_ +#define _VA_LIST_ +#ifdef __i860__ +#ifndef _VA_LIST +#define _VA_LIST va_list +#endif +#endif /* __i860__ */ +typedef __gnuc_va_list va_list; +#endif /* _VA_LIST_ */ +#else /* not __svr4__ */ + +/* The macro _VA_LIST_ is the same thing used by this file in Ultrix. + But on BSD NET2 we must not test or define or undef it. + (Note that the comments in NET 2's ansi.h + are incorrect for _VA_LIST_--see stdio.h!) */ +#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) +/* The macro _VA_LIST is used in SCO Unix 3.2. */ +#ifndef _VA_LIST +/* The macro _VA_LIST_T_H is used in the Bull dpx2 */ +#ifndef _VA_LIST_T_H +#define _VA_LIST_T_H +#if !(defined (__BSD_NET2__) || defined (____386BSD____)) +#define _VA_LIST_ +#endif +#define _VA_LIST +typedef __gnuc_va_list va_list; +#endif /* not _VA_LIST_T_H */ +#endif /* not _VA_LIST */ +#endif /* not _VA_LIST_ */ + +#endif /* not __svr4__ */ + +#endif /* _STDARG_H */ + +#endif /* __GNUC__ */ +#endif /* not _ANSI_STDARG_H_ */ +#endif /* not _STDARG_H */ diff --git a/gnu/usr.bin/cc/libobjc/hash.c b/gnu/usr.bin/cc/libobjc/hash.c new file mode 100644 index 000000000000..2226a2630b16 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/hash.c @@ -0,0 +1,250 @@ +/* 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "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) + +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/gnu/usr.bin/cc/libobjc/hash.h b/gnu/usr.bin/cc/libobjc/hash.h new file mode 100644 index 000000000000..e054e7d03aa9 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/hash.h @@ -0,0 +1,200 @@ +/* Hash tables for Objective C method dispatch. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + + +#ifndef __hash_INCLUDE_GNU +#define __hash_INCLUDE_GNU + +#ifdef IN_GCC +#include "gstddef.h" +#else +#include "stddef.h" +#endif + +/* + * 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 lexico-graphically 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 fullnes 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) +{ + return !strcmp (k1, k2); +} + + +#endif /* not __hash_INCLUDE_GNU */ diff --git a/gnu/usr.bin/cc/libobjc/init.c b/gnu/usr.bin/cc/libobjc/init.c new file mode 100644 index 000000000000..220d7d23e648 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/init.c @@ -0,0 +1,275 @@ +/* GNU Objective C Runtime initialization + Copyright (C) 1993 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + +You should have received a copy of the GNU General Public License along with + GNU CC; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" + +/* The version number of this runtime. This must match the number + defined in gcc (objc-act.c) */ +#define OBJC_VERSION 5 +#define PROTOCOL_VERSION 2 + +/* This list contains all modules currently loaded into the runtime */ +static struct objc_list* __objc_module_list = 0; + +/* This list contains all proto_list's not yet assigned class links */ +static struct objc_list* unclaimed_proto_list = 0; + +/* Check compiler vs runtime version */ +static void init_check_module_version(Module_t); + +/* Assign isa links to protos */ +static void __objc_init_protocols (struct objc_protocol_list* protos); + +/* Add protocol to class */ +static void __objc_class_add_protocols (Class*, struct objc_protocol_list*); + +/* Is all categories/classes resolved? */ +BOOL __objc_dangling_categories = NO; + +/* This function is called by constructor functions generated for each + module compiled. (_GLOBAL_$I$...) The purpose of this function is to + gather the module pointers so that they may be processed by the + initialization routines as soon as possible */ + +void +__objc_exec_class (Module_t module) +{ + /* Has we processed any constructors previously? This flag used to + indicate that some global data structures need to be built. */ + static BOOL previous_constructors = 0; + + static struct objc_list* unclaimed_categories = 0; + + /* The symbol table (defined in objc.h) generated by gcc */ + Symtab_t symtab = module->symtab; + + /* Entry used to traverse hash lists */ + struct objc_list** cell; + + /* The table of selector references for this module */ + SEL *selectors = symtab->refs; + + /* dummy counter */ + int i; + + DEBUG_PRINTF ("received module: %s\n", module->name); + /* check gcc version */ + init_check_module_version(module); + + /* On the first call of this routine, initialize some data structures. */ + if (!previous_constructors) + { + __objc_init_selector_tables(); + __objc_init_class_tables(); + __objc_init_dispatch_tables(); + previous_constructors = 1; + } + + /* Save the module pointer for later processing. (not currently used) */ + __objc_module_list = list_cons(module, __objc_module_list); + + /* Parse the classes in the load module and gather selector information. */ + DEBUG_PRINTF ("gathering selectors from module: %s\n", module->name); + for (i = 0; i < symtab->cls_def_cnt; ++i) + { + Class* 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); + } + + /* Replace referenced selectors from names to SEL's. */ + if (selectors) + { + for (i = 0; selectors[i]; ++i) + selectors[i] = sel_register_name ((const char *) selectors[i]); + } + + /* Process category information from the module. */ + for (i = 0; i < symtab->cat_def_cnt; ++i) + { + Category_t category = symtab->defs[i + symtab->cls_def_cnt]; + Class* 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); + } + + } + else + { + /* The object to which the category methods belong can't be found. + Save the information. */ + unclaimed_categories = list_cons(category, unclaimed_categories); + } + } + + /* Scan the unclaimed category hash. Attempt to attach any unclaimed + categories to objects. */ + for (cell = &unclaimed_categories; + *cell; + *cell && ((cell = &(*cell)->tail))) + { + Category_t category = (*cell)->head; + Class* 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 (unclaimed_proto_list && objc_lookup_class ("Protocol")) + { + list_mapcar (unclaimed_proto_list,(void(*)(void*))__objc_init_protocols); + list_free (unclaimed_proto_list); + unclaimed_proto_list = 0; + } + +} + +/* Sanity check the version of gcc used to compile `module'*/ +static void init_check_module_version(Module_t module) +{ + if ((module->version != OBJC_VERSION) || (module->size != sizeof (Module))) + { + fprintf (stderr, "Module %s version %d doesn't match runtime %d\n", + module->name, module->version, OBJC_VERSION); + if(module->version > OBJC_VERSION) + fprintf (stderr, "Runtime (libobjc.a) is out of date\n"); + else if (module->version < OBJC_VERSION) + fprintf (stderr, "Compiler (gcc) is out of date\n"); + else + fprintf (stderr, "Objective C internal error -- bad Module size\n"); + abort (); + } +} + +static void +__objc_init_protocols (struct objc_protocol_list* protos) +{ + int i; + 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; + } + + assert (protos->next == 0); /* only single ones allowed */ + + 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", + ((size_t)protos->list[i]->class_pointer), + 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/gnu/usr.bin/cc/libobjc/list.h b/gnu/usr.bin/cc/libobjc/list.h new file mode 100644 index 000000000000..37d7caed15b9 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/list.h @@ -0,0 +1,145 @@ +/* Generic single linked list to keep various information + Copyright (C) 1993 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + +You should have received a copy of the GNU General Public License along with + GNU CC; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +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); + } +} diff --git a/gnu/usr.bin/cc/libobjc/misc.c b/gnu/usr.bin/cc/libobjc/misc.c new file mode 100644 index 000000000000..6b6b34298225 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/misc.c @@ -0,0 +1,72 @@ +/* GNU Objective C Runtime Miscellanious + Copyright (C) 1993 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + +You should have received a copy of the GNU General Public License along with + GNU CC; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" + +void 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, (size_t)strlen((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/gnu/usr.bin/cc/libobjc/objc-api.h b/gnu/usr.bin/cc/libobjc/objc-api.h new file mode 100644 index 000000000000..1a5756d6d14c --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/objc-api.h @@ -0,0 +1,450 @@ +/* GNU Objective-C Runtime API. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#ifndef __objc_api_INCLUDE_GNU +#define __objc_api_INCLUDE_GNU + +#include "objc/objc.h" +#include "objc/hash.h" +#include <stdio.h> + +/* 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; + + +/* +** 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. */ + 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) \ + ({ assert(CLS_GETNUMBER(cls)==0); \ + __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, size_t, arglist_t); + + + +static const ARGSIZE = 96; /* for `method_get_argsize()' */ + +/* +** 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); + +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); + +const char *sel_get_name(SEL selector); + +SEL sel_get_uid(const char *name); + +SEL sel_register_name(const char *name); + +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 unsigned int +method_get_argsize(Method_t method) +{ + return ARGSIZE; /* This was a magic number (96)... */ +} + +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/gnu/usr.bin/cc/libobjc/objc.h b/gnu/usr.bin/cc/libobjc/objc.h new file mode 100644 index 000000000000..4bb9da361dec --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/objc.h @@ -0,0 +1,185 @@ +/* Basic data types for Objective C. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __objc_INCLUDE_GNU +#define __objc_INCLUDE_GNU + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef IN_GCC +#include "gstddef.h" +#else +#include "stddef.h" +#endif + +/* +** Definition of the boolean type. +*/ +typedef char BOOL; +#define YES (BOOL)1 +#define NO (BOOL)0 + +/* +** Definition of a selector. Selectors are really of type unsigned int. +** The runtime does this mapping from SEL's to names internally in the +** sel_... operations. You should never use the fact that it is actually +** an integer, since other Objective-C implementations use other conventions. +*/ +typedef void* SEL; + +/* +** 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 + +@class Protocol; +#endif + +typedef void* retval_t; /* return value */ +typedef void(*apply_t)(void); /* function pointer */ + +#if defined(REG_ARGS) || defined(STACK_ARGS) + +typedef struct { + char* arg_pointer; +#ifdef STRUCT_RETURN + void* struct_return; +#endif +#ifdef REG_ARGS + void* regs[2]; +#endif +} *arglist_t; + +#ifdef REG_ARGS +#define __objc_frame_receiver(FRAME) (FRAME)->regs[0] +#define __objc_frame_selector(FRAME) ((SEL)(FRAME)->regs[1]) + +#else +#define __objc_frame_receiver(FRAME) ((id*)(FRAME)->arg_pointer)[0] +#define __objc_frame_selector(FRAME) ((SEL*)(FRAME)->arg_pointer)[1] +#endif +#else + +typedef void* arglist_t; + +#endif + +#if defined(__OBJC__) + +#include "objc/sarray.h" + +static id nil_method(id rcv, SEL op, ...) { return rcv; } + +extern __inline__ IMP +objc_msg_lookup(id receiver, SEL op) +{ + if(receiver) + return sarray_get(receiver->class_pointer->dtable, (size_t) op); + else + return nil_method; +} + +#else + +IMP objc_msg_lookup(id receiver, SEL op); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* not __objc_INCLUDE_GNU */ diff --git a/gnu/usr.bin/cc/libobjc/objects.c b/gnu/usr.bin/cc/libobjc/objects.c new file mode 100644 index 000000000000..bd7a47e90523 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/objects.c @@ -0,0 +1,91 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + +You should have received a copy of the GNU General Public License along with + GNU CC; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" /* the kitchen sink */ + +id __objc_object_alloc(Class*); +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) + { + bzero (new, 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/gnu/usr.bin/cc/libobjc/runtime.h b/gnu/usr.bin/cc/libobjc/runtime.h new file mode 100644 index 000000000000..cd9de6ac63f0 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/runtime.h @@ -0,0 +1,73 @@ +/* GNU Objective C Runtime internal declarations + Copyright (C) 1993 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + +You should have received a copy of the GNU General Public License along with + GNU CC; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#ifndef __objc_runtime_INCLUDE_GNU +#define __objc_runtime_INCLUDE_GNU + +#include "gstdarg.h" /* for varargs and va_list's */ + +#include <stdio.h> +#include <ctype.h> + +#include "gstddef.h" /* 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 printf +#else +#define DEBUG_PRINTF +#endif + +BOOL __objc_responds_to (id object, SEL sel); /* for internal use only! */ + +#endif /* not __objc_runtime_INCLUDE_GNU */ + + diff --git a/gnu/usr.bin/cc/libobjc/sarray.c b/gnu/usr.bin/cc/libobjc/sarray.c new file mode 100644 index 000000000000..e3b322ae0099 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/sarray.c @@ -0,0 +1,435 @@ +/* Sparse Arrays for Objective C dispatch tables + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "objc/sarray.h" +#include <stdio.h> +#include "assert.h" + +int nbuckets = 0; +int nindices = 0; +int narrays = 0; +int idxsize = 0; + +#ifdef OBJC_SPARSE2 +const char* __objc_sparse2_id = "2 level sparse indices"; +#endif + +#ifdef OBJC_SPARSE3 +const char* __objc_sparse3_id = "3 level sparse indices"; +#endif + +void +sarray_at_put(struct sarray* array, sidx index, void* element) +{ +#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( *the_bucket,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; counter<BUCKET_SIZE; counter++) + arr->empty_bucket->elems[counter] = default_element; + +#ifdef OBJC_SPARSE3 + for (counter=0; counter<INDEX_SIZE; counter++) + arr->empty_index->buckets[counter] = arr->empty_bucket; + + for (counter=0; counter<num_indices; counter++) + arr->indices[counter] = arr->empty_index; + +#else /* OBJC_SPARSE2 */ + + for (counter=0; counter<num_indices; counter++) + arr->buckets[counter] = arr->empty_bucket; + +#endif + + return arr; +} + + +/* Reallocate the sparse array to hold `newsize' entries */ + +void +sarray_realloc(struct sarray* array, int newsize) +{ +#ifdef OBJC_SPARSE3 + int old_max_index = (array->capacity-1)/INDEX_CAPACITY; + int new_max_index = ((newsize-1)/INDEX_CAPACITY); + int rounded_size = (new_max_index+1)*INDEX_CAPACITY; + +#else /* OBJC_SPARSE2 */ + int old_max_index = (array->capacity-1)/BUCKET_SIZE; + int new_max_index = ((newsize-1)/BUCKET_SIZE); + int rounded_size = (new_max_index+1)*BUCKET_SIZE; + +#endif + + int counter; + + assert(newsize > 0); + + /* The size is the same, just ignore the request */ + if(rounded_size == array->capacity) + return; + + assert(array->ref_count == 1); /* stop if lazy copied... */ + + if(rounded_size < array->capacity) + { + /* update capacity */ + array->capacity = rounded_size; + + /* free buckets above new_max_index */ + for(counter = old_max_index; counter > new_max_index; counter-- ) { +#ifdef OBJC_SPARSE3 + struct sindex* idx = array->indices[counter]; + if((idx != array->empty_index) && (idx->version == array->version)) { + int c2; + for(c2=0; c2<INDEX_SIZE; c2++) { + struct sbucket* bkt = idx->buckets[c2]; + if((bkt != array->empty_bucket) && (bkt->version == array->version)) + { + free(bkt); + nbuckets -= 1; + } + } + free(idx); + nindices -= 1; + } +#else /* OBJC_SPARSE2 */ + struct sbucket* bkt = array->buckets[counter]; + if ((bkt != array->empty_bucket) && (bkt->version == array->version)) + { + free(bkt); + nbuckets -= 1; + } +#endif + } + +#ifdef OBJC_SPARSE3 + /* realloc to free the space above new_max_index */ + array->indices = (struct sindex**) + __objc_xrealloc(array->indices, + (new_max_index+1)*sizeof(struct sindex*)); +#else /* OBJC_SPARSE2 */ + array->buckets = (struct sbucket**) + __objc_xrealloc(array->buckets, + (new_max_index+1)*sizeof(struct sbucket*)); +#endif + idxsize -= (old_max_index-new_max_index); + + return; + } + + /* We are asked to extend the array -- reallocate the bucket table, */ + /* and insert empty_bucket in newly allocated places. */ + if(rounded_size > array->capacity) + { + /* update capacity */ + array->capacity = rounded_size; + +#ifdef OBJC_SPARSE3 + /* realloc to make room in table above old_max_index */ + array->indices = (struct sindex**) + __objc_xrealloc(array->indices, + (new_max_index+1)*sizeof(struct sindex*)); + + /* reset entries above old_max_index to empty_bucket */ + for(counter = old_max_index+1; counter <= new_max_index; counter++) + array->indices[counter] = array->empty_index; + +#else /* OBJC_SPARSE2 */ + + /* realloc to make room in table above old_max_index */ + array->buckets = (struct sbucket**) + __objc_xrealloc(array->buckets, + (new_max_index+1)*sizeof(struct sbucket*)); + + /* reset entries above old_max_index to empty_bucket */ + for(counter = old_max_index+1; counter <= new_max_index; counter++) + array->buckets[counter] = array->empty_bucket; + +#endif + idxsize += (new_max_index-old_max_index); + return; + } +} + + +/* 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; c2<INDEX_SIZE; c2++) { + struct sbucket* bkt = idx->buckets[c2]; + if((bkt != array->empty_bucket) && (bkt->version == array->version)) + { + free(bkt); + nbuckets -= 1; + } + } + free(idx); + nindices -= 1; + } +#else /* OBJC_SPARSE2 */ + struct sbucket* bkt = array->buckets[counter]; + if ((bkt != array->empty_bucket) && (bkt->version == array->version)) + { + free(bkt); + nbuckets -= 1; + } +#endif + } + +#ifdef OBJC_SPARSE3 + /* free empty_index */ + if(array->empty_index->version == array->version) { + free(array->empty_index); + nindices -= 1; + } +#endif + + /* free empty_bucket */ + if(array->empty_bucket->version == array->version) { + free(array->empty_bucket); + nbuckets -= 1; + } + +#ifdef OBJC_SPARSE3 + /* free bucket table */ + free(array->indices); + idxsize -= (old_max_index+1); + +#else + /* free bucket table */ + free(array->buckets); + idxsize -= (old_max_index+1); + +#endif + + /* free array */ + free(array); + narrays -= 1; +} + +/* This is a lazy copy. Only the core of the structure is actually */ +/* copied. */ + +struct sarray* +sarray_lazy_copy(struct sarray* oarr) +{ +#ifdef OBJC_SPARSE3 + 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/gnu/usr.bin/cc/libobjc/sarray.h b/gnu/usr.bin/cc/libobjc/sarray.h new file mode 100644 index 000000000000..05d28cea8b0c --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/sarray.h @@ -0,0 +1,235 @@ +/* Sparse Arrays for Objective C dispatch tables + Copyright (C) 1993 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __sarray_INCLUDE_GNU +#define __sarray_INCLUDE_GNU + +#define OBJC_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 + +#ifdef IN_GCC +#include "gstddef.h" +#else +#include "stddef.h" +#endif + +extern int nbuckets; /* for stats */ +extern int nindices; +extern int narrays; +extern int idxsize; + +#include <assert.h> + +/* 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<<BUCKET_BITS) +#define BUCKET_MASK (BUCKET_SIZE-1) + +/* Indices are 16 words each */ +#define INDEX_BITS 4 +#define INDEX_SIZE (1<<INDEX_BITS) +#define INDEX_MASK (INDEX_SIZE-1) + +#define INDEX_CAPACITY (BUCKET_SIZE*INDEX_SIZE) + +#else /* OBJC_SPARSE2 */ + +/* Buckets are 32 words each */ +#define BUCKET_BITS 5 +#define BUCKET_SIZE (1<<BUCKET_BITS) +#define BUCKET_MASK (BUCKET_SIZE-1) + +#endif /* OBJC_SPARSE2 */ + +typedef size_t sidx; + +#ifdef PRECOMPUTE_SELECTORS + +struct soffset { +#ifdef OBJC_SPARSE3 + unsigned int unused : SIZET_BITS/4; + unsigned int eoffset : SIZET_BITS/4; + unsigned int boffset : SIZET_BITS/4; + unsigned int ioffset : SIZET_BITS/4; +#else /* OBJC_SPARSE2 */ +#ifdef sparc + unsigned int boffset : (SIZET_BITS - 2) - BUCKET_BITS; + unsigned int eoffset : BUCKET_BITS; + unsigned int unused : 2; +#else + unsigned int boffset : SIZET_BITS/2; + unsigned int eoffset : SIZET_BITS/2; +#endif +#endif /* OBJC_SPARSE2 */ +}; + +union sofftype { + struct soffset off; + sidx idx; +}; + +#endif /* not PRECOMPUTE_SELECTORS */ + +void * __objc_xrealloc (void *optr, size_t size); +void * __objc_xmalloc (size_t size); + +struct sbucket { + void* elems[BUCKET_SIZE]; /* elements stored in array */ + short version; /* used for copy-on-write */ +}; + +#ifdef OBJC_SPARSE3 + +struct sindex { + struct sbucket* buckets[INDEX_SIZE]; + short version; +}; + +#endif /* OBJC_SPARSE3 */ + +struct sarray { +#ifdef OBJC_SPARSE3 + struct sindex** indices; + struct sindex* empty_index; +#else /* OBJC_SPARSE2 */ + struct sbucket** buckets; +#endif /* OBJC_SPARSE2 */ + struct sbucket* empty_bucket; + short version; + short ref_count; + struct sarray* is_copy_of; + int capacity; +}; + +struct sarray* sarray_new(int, void* default_element); +void sarray_free(struct sarray*); +struct sarray* sarray_lazy_copy(struct sarray*); +struct sarray* sarray_hard_copy(struct sarray*); /* ... like the name? */ +void sarray_realloc(struct sarray*, int new_size); +void sarray_at_put(struct sarray*, sidx index, void* elem); +void sarray_at_put_safe(struct sarray*, sidx index, void* elem); + + +#ifdef PRECOMPUTE_SELECTORS +/* Transform soffset values to ints and vica verca */ +static inline unsigned int +soffset_decode(sidx index) +{ + union sofftype x; + x.idx = index; +#ifdef OBJC_SPARSE3 + return x.off.eoffset + + (x.off.boffset*BUCKET_SIZE) + + (x.off.ioffset*INDEX_CAPACITY); +#else /* OBJC_SPARSE2 */ + return x.off.eoffset + (x.off.boffset*BUCKET_SIZE); +#endif /* OBJC_SPARSE2 */ +} + +static inline sidx +soffset_encode(size_t offset) +{ + union sofftype x; + x.off.eoffset = offset%BUCKET_SIZE; +#ifdef OBJC_SPARSE3 + x.off.boffset = (offset/BUCKET_SIZE)%INDEX_SIZE; + x.off.ioffset = offset/INDEX_CAPACITY; +#else /* OBJC_SPARSE2 */ + x.off.boffset = offset/BUCKET_SIZE; +#endif + return (sidx)x.idx; +} + +#else /* not PRECOMPUTE_SELECTORS */ + +static inline size_t +soffset_decode(sidx index) +{ + return index; +} + +static inline sidx +soffset_encode(size_t offset) +{ + return offset; +} +#endif /* not PRECOMPUTE_SELECTORS */ + +/* Get element from the Sparse array `array' at offset `index' */ + +static inline void* sarray_get(struct sarray* array, sidx index) +{ +#ifdef PRECOMPUTE_SELECTORS + union sofftype x; + x.idx = index; +#ifdef OBJC_SPARSE3 + return + array-> + indices[x.off.ioffset]-> + buckets[x.off.boffset]-> + elems[x.off.eoffset]; +#else /* OBJC_SPARSE2 */ + return array->buckets[x.off.boffset]->elems[x.off.eoffset]; +#endif /* OBJC_SPARSE2 */ +#else /* not PRECOMPUTE_SELECTORS */ +#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/gnu/usr.bin/cc/libobjc/selector.c b/gnu/usr.bin/cc/libobjc/selector.c new file mode 100644 index 000000000000..40bc7a338c32 --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/selector.c @@ -0,0 +1,139 @@ +/* GNU Objective C Runtime selector related functions + Copyright (C) 1993 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + +You should have received a copy of the GNU General Public License along with + GNU CC; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" +#include "objc/sarray.h" + +/* Initial selector hash table size. Value doesnt matter much */ +#define SELECTOR_HASH_SIZE 128 + +/* Tables mapping selector names to uid and opposite */ +static struct sarray* __objc_selector_array = 0; /* uid -> name */ +static cache_ptr __objc_selector_hash = 0; /* name -> uid */ + +static void register_selectors_from_list(MethodList_t); + +/* Number of selectors stored in each of the above tables */ +int __objc_selector_max_index = 0; + +void __objc_init_selector_tables() +{ + __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0); + __objc_selector_hash + = hash_new (SELECTOR_HASH_SIZE, + (hash_func_type) hash_string, + (compare_func_type) compare_strings); +} + +/* This routine is given a class and records all of the methods in its class + structure in the record table. */ +void +__objc_register_selectors_from_class (Class* class) +{ + MethodList_t method_list; + + method_list = class->methods; + while (method_list) + { + register_selectors_from_list (method_list); + method_list = method_list->method_next; + } +} + + +/* This routine is given a list of methods and records each of the methods in + the record table. This is the routine that does the actual recording + work. + + This one is only called for Class objects. For categories, + class_add_method_list is called. + */ +static void +register_selectors_from_list (MethodList_t method_list) +{ + int i = 0; + while (i < method_list->method_count) + { + Method_t method = &method_list->method_list[i]; + method->method_name = sel_register_name ((char*)method->method_name); + i += 1; + } +} + +/* return selector representing name */ +SEL +sel_get_uid (const char *name) +{ + return (SEL) hash_value_for_key (__objc_selector_hash, name); +} + +/* Get name of selector. If selector is unknown, the empty string "" + is returned */ +const char* +sel_get_name (SEL selector) +{ + if ((soffset_decode((sidx)selector) > 0) + && (soffset_decode((sidx)selector) <= __objc_selector_max_index)) + return sarray_get (__objc_selector_array, (sidx) selector); + else + return NULL; +} + +BOOL +sel_is_mapped (SEL selector) +{ + unsigned int idx = soffset_decode ((sidx)selector); + return ((idx > 0) && (idx <= __objc_selector_max_index)); +} + +/* 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_name (const char *sel) +{ + SEL j; + sidx i; + + if ((j = sel_get_uid ((const char *) sel))) + return j; + + /* Save the selector name. */ + __objc_selector_max_index += 1; + i = soffset_encode(__objc_selector_max_index); + + DEBUG_PRINTF ("Record selector %s as: %#x\n", sel, i); + + sarray_at_put_safe (__objc_selector_array, i, (void *) sel); + hash_add (&__objc_selector_hash, (void *) sel, (void *) i); + + sarray_realloc(__objc_uninstalled_dtable, __objc_selector_max_index+1); + + return (SEL) i; +} + diff --git a/gnu/usr.bin/cc/libobjc/sendmsg.c b/gnu/usr.bin/cc/libobjc/sendmsg.c new file mode 100644 index 000000000000..e2c52ba4c71f --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/sendmsg.c @@ -0,0 +1,471 @@ +/* GNU Objective C Runtime message lookup + Copyright (C) 1993 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + +You should have received a copy of the GNU General Public License along with + GNU CC; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" +#include "sarray.h" + +/* 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_missing_method(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) +{ + void* res = sarray_get (class->dtable, (size_t) sel); + if(res == __objc_init_install_dtable) + __objc_install_dispatch_table_for_class (class); + return sarray_get (class->dtable, (size_t) sel); +} + +__inline__ BOOL +__objc_responds_to (id object, SEL sel) +{ + return get_imp (object->class_pointer, sel) != __objc_missing_method; +} + +/* This is the lookup function. All entries in the table are either a + valid method *or* one of `__objc_missing_method' which calls + forward:: etc, or `__objc_init_install_dtable' which installs the + real dtable */ +__inline__ IMP +objc_msg_lookup(id receiver, SEL op) +{ + if(receiver) + return sarray_get(receiver->class_pointer->dtable, (sidx)op); + else + return nil_method; +} + +IMP +objc_msg_lookup_super (Super_t super, SEL sel) +{ + if (super->self) + return get_imp (super->class, sel); + else + return nil_method; +} + +retval_t +objc_msg_sendv(id object, SEL op, size_t frame_size, arglist_t arg_frame) +{ +#ifdef __objc_frame_receiver + __objc_frame_receiver(arg_frame) = object; + __objc_frame_selector(arg_frame) = op; + return __builtin_apply((apply_t)get_imp(object->class_pointer, op), + arg_frame, + frame_size); +#else +#warning performv:: will not work + va_list nothing; + (*_objc_error)(object, "objc_msg_sendv (performv::) not supported\n", nothing); + return 0; +#endif +} + +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__ allready_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 allready_initialized; + + if(CLS_ISCLASS(receiver->class_pointer)) + { + /* receiver is an ordinary object */ + assert(CLS_ISCLASS(receiver->class_pointer)); + + /* install instance methods table */ + __objc_install_dispatch_table_for_class (receiver->class_pointer); + + /* call +initialize -- this will in turn install the factory + dispatch table if not already done :-) */ + __objc_send_initialize(receiver->class_pointer); + } + else + { + /* receiver is a class object */ + assert(CLS_ISCLASS((Class*)receiver)); + assert(CLS_ISMETA(receiver->class_pointer)); + + /* Install real dtable for factory methods */ + __objc_install_dispatch_table_for_class (receiver->class_pointer); + + if(op != sel_get_uid ("initialize")) + __objc_send_initialize((Class*)receiver); + else + CLS_SETINITIALIZED((Class*)receiver); + } + +allready_initialized: + + /* Get real method for this in newly installed dtable */ + imp = get_imp(receiver->class_pointer, op); + + args = __builtin_apply_args(); + result = __builtin_apply((apply_t)imp, args, 96); + __builtin_return (result); + +} + +/* 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) +{ + Method_t m; + + /* 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); + + { + MethodList_t method_list = class->class_pointer->methods; + SEL op = sel_register_name ("initialize"); + + /* 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 == op) + (*method->method_imp)((id) class, op); + } + + /* The method wasn't found. Follow the link to the next list of + methods. */ + method_list = method_list->method_next; + } + } + } +} + +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 nessecary */ + if (super == 0) + { + class->dtable = sarray_new (__objc_selector_max_index, + __objc_missing_method); + } + else + class->dtable = sarray_lazy_copy (super->dtable); + + for (mlist = class->methods; mlist; mlist = mlist->method_next) + { + counter = mlist->method_count - 1; + while (counter >= 0) + { + Method_t method = &(mlist->method_list[counter]); + sarray_at_put (class->dtable, + (sidx) method->method_name, + method->method_imp); + counter -= 1; + } + } +} + +void __objc_update_dispatch_table_for_class (Class* class) +{ + Class* next; + struct sarray* save; + + /* not yet installed -- skip it */ + if (class->dtable == __objc_uninstalled_dtable) + return; + + save = class->dtable; + __objc_install_premature_dtable (class); + sarray_free (save); + + + if (class->subclass_list) /* Traverse subclasses */ + for (next = class->subclass_list; next; next = next->sibling_class) + __objc_update_dispatch_table_for_class (next); +} + + +/* This function adds a method list to a class. This function is + typically called by another function specific to the run-time. As + such this function does not worry about thread safe issued. + + This one is only called for categories. Class objects have their + methods installed rightaway, and their selectors are made into + SEL's by the function __objc_register_selectors_from_class. */ +void +class_add_method_list (Class* 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 transmogriffed to SEL's */ + method->method_name = sel_register_name ((char*)method->method_name); + + if (search_for_method_in_list (class->methods, method->method_name) + && method->method_name != initialize_sel) + { + /* 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 == op) + return method; + } + + /* The method wasn't found. Follow the link to the next list of + methods. */ + method_list = method_list->method_next; + } + + return NULL; +} + + +/* This fuction is installed in the dispatch table for all methods which are + not implemented. Thus, it is called when a selector is not recognized. */ +static id +__objc_missing_method (id object, SEL sel, ...) +{ + IMP imp; + SEL frwd_sel; + SEL err_sel; + + /* first try if the object understands forward:: */ + frwd_sel = sel_get_uid("forward::"); + imp = get_imp(object->class_pointer, frwd_sel); + if(imp != __objc_missing_method) + { + void *result, *args = __builtin_apply_args(); + result = (*imp)(object, frwd_sel, sel, args); + __builtin_return(result); + } + + /* If the object recognizes the doesNotRecognize: method then we're going + to send it. */ + err_sel = sel_get_uid ("doesNotRecognize:"); + imp = get_imp (object->class_pointer, err_sel); + if (imp != __objc_missing_method) + { + return (*imp) (object, err_sel, sel); + } + + /* The object doesn't recognize the method. Check for responding to + error:. If it does then sent it. */ + { + char msg[256 + strlen ((char*)sel_get_name (sel)) + + strlen ((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_uid ("error:"); + imp = get_imp (object->class_pointer, err_sel); + if (imp != __objc_missing_method) + return (*imp) (object, sel_get_uid ("error:"), msg); + + /* The object doesn't respond to doesNotRecognize: or error:; Therefore, + a default action is taken. */ + fprintf (stderr, "fatal: %s\n", msg); + abort (); + } +} + +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 = %d bytes\n", narrays, narrays*sizeof(struct sarray)); + total += narrays*sizeof(struct sarray); + printf("buckets: %d = %d bytes\n", nbuckets, nbuckets*sizeof(struct sbucket)); + total += nbuckets*sizeof(struct sbucket); + + printf("idxtables: %d = %d bytes\n", idxsize, idxsize*sizeof(void*)); + total += idxsize*sizeof(void*); + printf("-----------------------------------\n"); + printf("total: %d bytes\n", total); + printf("===================================\n"); +} + + + diff --git a/gnu/usr.bin/cc/libobjc/typedstream.h b/gnu/usr.bin/cc/libobjc/typedstream.h new file mode 100644 index 000000000000..1650bf55de6b --- /dev/null +++ b/gnu/usr.bin/cc/libobjc/typedstream.h @@ -0,0 +1,132 @@ +/* GNU Objective-C Typed Streams interface. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#ifndef __typedstream_INCLUDE_GNU +#define __typedstream_INCLUDE_GNU + +#include "objc/objc.h" +#include "objc/hash.h" +#include <stdio.h> + +#ifndef __alpha__ /* alpha is currently not supported */ + +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); + +int objc_get_stream_class_version (TypedStream* stream, Class* class); + + +/* +** Convenience funtions +*/ + +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); + +/* +** 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 /* __alpha__ */ + +#endif /* not __typedstream_INCLUDE_GNU */ |
