1998-09-21 Ben Elliston <bje@cygnus.com>

* New directory.  Moved files from ../gcc/objc.

From-SVN: r22514
This commit is contained in:
Ben Elliston 1998-09-21 01:22:07 +00:00 committed by Ben Elliston
parent 2325c774f8
commit 88e17b57eb
44 changed files with 12625 additions and 0 deletions

4
libobjc/ChangeLog Normal file
View File

@ -0,0 +1,4 @@
1998-09-21 Ben Elliston <bje@cygnus.com>
* New directory. Moved files from ../gcc/objc.

44
libobjc/NXConstStr.h Normal file
View File

@ -0,0 +1,44 @@
/* Interface for the NXConstantString class for Objective-C.
Copyright (C) 1995 Free Software Foundation, Inc.
Contributed by Pieter J. Schoenmakers <tiggr@es.ele.tue.nl>
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#ifndef __nxconstantstring_INCLUDE_GNU
#define __nxconstantstring_INCLUDE_GNU
#include "objc/Object.h"
@interface NXConstantString: Object
{
char *c_string;
unsigned int len;
}
-(const char *) cString;
-(unsigned int) length;
@end
#endif

42
libobjc/NXConstStr.m Normal file
View File

@ -0,0 +1,42 @@
/* Implementation of the NXConstantString class for Objective-C.
Copyright (C) 1995 Free Software Foundation, Inc.
Contributed by Pieter J. Schoenmakers <tiggr@es.ele.tue.nl>
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#include "objc/NXConstStr.h"
@implementation NXConstantString
-(const char *) cString
{
return (c_string);
} /* -cString */
-(unsigned int) length
{
return (len);
} /* -length */
@end

124
libobjc/Object.h Normal file
View File

@ -0,0 +1,124 @@
/* Interface for the Object class for Objective-C.
Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled
with GCC to produce an executable, this does not cause the resulting
executable to be covered by the GNU General Public License. This
exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public License. */
#ifndef __object_INCLUDE_GNU
#define __object_INCLUDE_GNU
#include <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;
- (int)compare:anotherObject;
/* Testing object type */
- (BOOL)isMetaClass;
- (BOOL)isClass;
- (BOOL)isInstance;
/* Testing inheritance relationships */
- (BOOL)isKindOf:(Class)aClassObject;
- (BOOL)isMemberOf:(Class)aClassObject;
- (BOOL)isKindOfClassNamed:(const char *)aClassName;
- (BOOL)isMemberOfClassNamed:(const char *)aClassName;
/* Testing class functionality */
+ (BOOL)instancesRespondTo:(SEL)aSel;
- (BOOL)respondsTo:(SEL)aSel;
/* Testing protocol conformance */
- (BOOL)conformsTo:(Protocol*)aProtocol;
/* Introspection */
+ (IMP)instanceMethodFor:(SEL)aSel;
- (IMP)methodFor:(SEL)aSel;
+ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel;
- (struct objc_method_description *)descriptionForMethod:(SEL)aSel;
/* Sending messages determined at run time */
- perform:(SEL)aSel;
- perform:(SEL)aSel with:anObject;
- perform:(SEL)aSel with:anObject1 with:anObject2;
/* Forwarding */
- (retval_t)forward:(SEL)aSel :(arglist_t)argFrame;
- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame;
/* Posing */
+ poseAs:(Class)aClassObject;
- (Class)transmuteClassTo:(Class)aClassObject;
/* Enforcing intentions */
- subclassResponsibility:(SEL)aSel;
- notImplemented:(SEL)aSel;
- shouldNotImplement:(SEL)aSel;
/* Error handling */
- doesNotRecognize:(SEL)aSel;
- error:(const char *)aString, ...;
/* Archiving */
+ (int)version;
+ setVersion:(int)aVersion;
+ (int)streamVersion: (TypedStream*)aStream;
- read: (TypedStream*)aStream;
- write: (TypedStream*)aStream;
- awake;
@end
#endif

387
libobjc/Object.m Normal file
View File

@ -0,0 +1,387 @@
/* The implementation of class Object for Objective-C.
Copyright (C) 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled
with GCC to produce an executable, this does not cause the resulting
executable to be covered by the GNU General Public License. This
exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public License. */
#include <stdarg.h>
#include "objc/Object.h"
#include "objc/Protocol.h"
#include "objc/objc-api.h"
extern int errno;
#define MAX_CLASS_NAME_LEN 256
@implementation Object
+ initialize
{
return self;
}
- init
{
return self;
}
+ new
{
return [[self alloc] init];
}
+ alloc
{
return class_create_instance(self);
}
- free
{
return object_dispose(self);
}
- copy
{
return [[self shallowCopy] deepen];
}
- shallowCopy
{
return object_copy(self);
}
- deepen
{
return self;
}
- deepCopy
{
return [self copy];
}
- (Class)class
{
return object_get_class(self);
}
- (Class)superClass
{
return object_get_super_class(self);
}
- (MetaClass)metaClass
{
return object_get_meta_class(self);
}
- (const char *)name
{
return object_get_class_name(self);
}
- self
{
return self;
}
- (unsigned int)hash
{
return (size_t)self;
}
- (BOOL)isEqual:anObject
{
return self==anObject;
}
- (int)compare:anotherObject;
{
if ([self isEqual:anotherObject])
return 0;
// Ordering objects by their address is pretty useless,
// so subclasses should override this is some useful way.
else if (self > anotherObject)
return 1;
else
return -1;
}
- (BOOL)isMetaClass
{
return NO;
}
- (BOOL)isClass
{
return object_is_class(self);
}
- (BOOL)isInstance
{
return object_is_instance(self);
}
- (BOOL)isKindOf:(Class)aClassObject
{
Class class;
for (class = self->isa; class!=Nil; class = class_get_super_class(class))
if (class==aClassObject)
return YES;
return NO;
}
- (BOOL)isMemberOf:(Class)aClassObject
{
return self->isa==aClassObject;
}
- (BOOL)isKindOfClassNamed:(const char *)aClassName
{
Class class;
if (aClassName!=NULL)
for (class = self->isa; class!=Nil; class = class_get_super_class(class))
if (!strcmp(class_get_class_name(class), aClassName))
return YES;
return NO;
}
- (BOOL)isMemberOfClassNamed:(const char *)aClassName
{
return ((aClassName!=NULL)
&&!strcmp(class_get_class_name(self->isa), aClassName));
}
+ (BOOL)instancesRespondTo:(SEL)aSel
{
return class_get_instance_method(self, aSel)!=METHOD_NULL;
}
- (BOOL)respondsTo:(SEL)aSel
{
return ((object_is_instance(self)
?class_get_instance_method(self->isa, aSel)
:class_get_class_method(self->isa, aSel))!=METHOD_NULL);
}
+ (IMP)instanceMethodFor:(SEL)aSel
{
return method_get_imp(class_get_instance_method(self, aSel));
}
// Indicates if the receiving class or instance conforms to the given protocol
// not usually overridden by subclasses
//
// Modified 9/5/94 to always search the class object's protocol list, rather
// than the meta class.
+ (BOOL) conformsTo: (Protocol*)aProtocol
{
int i;
struct objc_protocol_list* proto_list;
id parent;
for (proto_list = ((Class)self)->protocols;
proto_list; proto_list = proto_list->next)
{
for (i=0; i < proto_list->count; i++)
{
if ([proto_list->list[i] conformsTo: aProtocol])
return YES;
}
}
if ((parent = [self superClass]))
return [parent conformsTo: aProtocol];
else
return NO;
}
- (BOOL) conformsTo: (Protocol*)aProtocol
{
return [[self class] conformsTo:aProtocol];
}
- (IMP)methodFor:(SEL)aSel
{
return (method_get_imp(object_is_instance(self)
?class_get_instance_method(self->isa, aSel)
:class_get_class_method(self->isa, aSel)));
}
+ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel
{
return ((struct objc_method_description *)
class_get_instance_method(self, aSel));
}
- (struct objc_method_description *)descriptionForMethod:(SEL)aSel
{
return ((struct objc_method_description *)
(object_is_instance(self)
?class_get_instance_method(self->isa, aSel)
:class_get_class_method(self->isa, aSel)));
}
- perform:(SEL)aSel
{
IMP msg = objc_msg_lookup(self, aSel);
if (!msg)
return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
return (*msg)(self, aSel);
}
- perform:(SEL)aSel with:anObject
{
IMP msg = objc_msg_lookup(self, aSel);
if (!msg)
return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
return (*msg)(self, aSel, anObject);
}
- perform:(SEL)aSel with:anObject1 with:anObject2
{
IMP msg = objc_msg_lookup(self, aSel);
if (!msg)
return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
return (*msg)(self, aSel, anObject1, anObject2);
}
- (retval_t)forward:(SEL)aSel :(arglist_t)argFrame
{
return (retval_t)[self doesNotRecognize: aSel];
}
- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame
{
return objc_msg_sendv(self, aSel, argFrame);
}
+ poseAs:(Class)aClassObject
{
return class_pose_as(self, aClassObject);
}
- (Class)transmuteClassTo:(Class)aClassObject
{
if (object_is_instance(self))
if (class_is_class(aClassObject))
if (class_get_instance_size(aClassObject)==class_get_instance_size(isa))
if ([self isKindOf:aClassObject])
{
Class old_isa = isa;
isa = aClassObject;
return old_isa;
}
return nil;
}
- subclassResponsibility:(SEL)aSel
{
return [self error:"subclass should override %s", sel_get_name(aSel)];
}
- notImplemented:(SEL)aSel
{
return [self error:"method %s not implemented", sel_get_name(aSel)];
}
- shouldNotImplement:(SEL)aSel
{
return [self error:"%s should not implement %s",
object_get_class_name(self), sel_get_name(aSel)];
}
- doesNotRecognize:(SEL)aSel
{
return [self error:"%s does not recognize %s",
object_get_class_name(self), sel_get_name(aSel)];
}
#ifdef __alpha__
extern size_t strlen(const char*);
#endif
- error:(const char *)aString, ...
{
#define FMT "error: %s (%s)\n%s\n"
char fmt[(strlen((char*)FMT)+strlen((char*)object_get_class_name(self))
+((aString!=NULL)?strlen((char*)aString):0)+8)];
va_list ap;
sprintf(fmt, FMT, object_get_class_name(self),
object_is_instance(self)?"instance":"class",
(aString!=NULL)?aString:"");
va_start(ap, aString);
objc_verror(self, OBJC_ERR_UNKNOWN, fmt, ap);
va_end(ap);
return nil;
#undef FMT
}
+ (int)version
{
return class_get_version(self);
}
+ setVersion:(int)aVersion
{
class_set_version(self, aVersion);
return self;
}
+ (int)streamVersion: (TypedStream*)aStream
{
if (aStream->mode == OBJC_READONLY)
return objc_get_stream_class_version (aStream, self);
else
return class_get_version (self);
}
// These are used to write or read the instance variables
// declared in this particular part of the object. Subclasses
// should extend these, by calling [super read/write: aStream]
// before doing their own archiving. These methods are private, in
// the sense that they should only be called from subclasses.
- read: (TypedStream*)aStream
{
// [super read: aStream];
return self;
}
- write: (TypedStream*)aStream
{
// [super write: aStream];
return self;
}
- awake
{
// [super awake];
return self;
}
@end

58
libobjc/Protocol.h Normal file
View File

@ -0,0 +1,58 @@
/* Declare the class Protocol for Objective C programs.
Copyright (C) 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#ifndef __Protocol_INCLUDE_GNU
#define __Protocol_INCLUDE_GNU
#include "objc/Object.h"
@interface Protocol : Object
{
@private
char *protocol_name;
struct objc_protocol_list *protocol_list;
struct objc_method_description_list *instance_methods, *class_methods;
}
/* Obtaining attributes intrinsic to the protocol */
- (const char *)name;
/* Testing protocol conformance */
- (BOOL) conformsTo: (Protocol *)aProtocolObject;
/* Looking up information specific to a protocol */
- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel;
- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel;
@end
#endif __Protocol_INCLUDE_GNU

128
libobjc/Protocol.m Normal file
View File

@ -0,0 +1,128 @@
/* This file contains the implementation of class Protocol.
Copyright (C) 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#include "objc/Protocol.h"
#include "objc/objc-api.h"
/* Method description list */
struct objc_method_description_list {
int count;
struct objc_method_description list[1];
};
@implementation Protocol
{
@private
char *protocol_name;
struct objc_protocol_list *protocol_list;
struct objc_method_description_list *instance_methods, *class_methods;
}
/* Obtaining attributes intrinsic to the protocol */
- (const char *)name
{
return protocol_name;
}
/* Testing protocol conformance */
- (BOOL) conformsTo: (Protocol *)aProtocolObject
{
int i;
struct objc_protocol_list* proto_list;
if (!strcmp(aProtocolObject->protocol_name, self->protocol_name))
return YES;
for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
{
for (i=0; i < proto_list->count; i++)
{
if ([proto_list->list[i] conformsTo: aProtocolObject])
return YES;
}
}
return NO;
}
/* Looking up information specific to a protocol */
- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel
{
int i;
struct objc_protocol_list* proto_list;
const char* name = sel_get_name (aSel);
struct objc_method_description *result;
for (i = 0; i < instance_methods->count; i++)
{
if (!strcmp ((char*)instance_methods->list[i].name, name))
return &(instance_methods->list[i]);
}
for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
{
for (i=0; i < proto_list->count; i++)
{
if ((result = [proto_list->list[i]
descriptionForInstanceMethod: aSel]))
return result;
}
}
return NULL;
}
- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel;
{
int i;
struct objc_protocol_list* proto_list;
const char* name = sel_get_name (aSel);
struct objc_method_description *result;
for (i = 0; i < class_methods->count; i++)
{
if (!strcmp ((char*)class_methods->list[i].name, name))
return &(class_methods->list[i]);
}
for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
{
for (i=0; i < proto_list->count; i++)
{
if ((result = [proto_list->list[i]
descriptionForClassMethod: aSel]))
return result;
}
}
return NULL;
}
@end

1651
libobjc/archive.c Normal file

File diff suppressed because it is too large Load Diff

358
libobjc/class.c Normal file
View File

@ -0,0 +1,358 @@
/* GNU Objective C Runtime class related functions
Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup and Dennis Glatting.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include "runtime.h" /* the kitchen sink */
#include "sarray.h"
/* The table of classname->class. Used for objc_lookup_class and friends */
static cache_ptr __objc_class_hash = 0; /* !T:MUTEX */
/* 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; /* !T:SAFE */
/* True when class links has been resolved */
BOOL __objc_class_links_resolved = NO; /* !T:UNUSED */
/* 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_mutex_lock(__objc_runtime_mutex);
__objc_class_hash
= hash_new (CLASS_HASH_SIZE,
(hash_func_type) hash_string,
(compare_func_type) compare_strings);
objc_mutex_unlock(__objc_runtime_mutex);
}
/* 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;
objc_mutex_lock(__objc_runtime_mutex);
/* 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);
}
objc_mutex_unlock(__objc_runtime_mutex);
}
/* 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;
objc_mutex_lock(__objc_runtime_mutex);
/* Make sure the class hash table exists. */
assert (__objc_class_hash);
class = hash_value_for_key (__objc_class_hash, name);
objc_mutex_unlock(__objc_runtime_mutex);
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;
objc_mutex_lock(__objc_runtime_mutex);
/* Make sure the class hash table exists. */
assert (__objc_class_hash);
class = hash_value_for_key (__objc_class_hash, name);
objc_mutex_unlock(__objc_runtime_mutex);
if (class)
return class;
if (_objc_lookup_class)
class = (*_objc_lookup_class)(name);
if(class)
return class;
objc_error(nil, OBJC_ERR_BAD_CLASS,
"objc runtime: cannot find class %s\n", name);
return 0;
}
MetaClass
objc_get_meta_class(const char *name)
{
return objc_get_class(name)->class_pointer;
}
/* This function provides a way to enumerate all the classes in the
executable. Pass *ENUM_STATE == NULL to start the enumeration. The
function will return 0 when there are no more classes.
For example:
id class;
void *es = NULL;
while ((class = objc_next_class(&es)))
... do something with class;
*/
Class
objc_next_class(void **enum_state)
{
objc_mutex_lock(__objc_runtime_mutex);
/* make sure the table is there */
assert(__objc_class_hash);
*(node_ptr*)enum_state =
hash_next(__objc_class_hash, *(node_ptr*)enum_state);
objc_mutex_unlock(__objc_runtime_mutex);
if (*(node_ptr*)enum_state)
return (*(node_ptr*)enum_state)->value;
return (Class)0;
}
/* Resolve super/subclass links for all classes. The only thing we
can be sure of is that the class_pointer for class objects point
to the right meta class objects */
void __objc_resolve_class_links()
{
node_ptr node;
Class object_class = objc_get_class ("Object");
assert(object_class);
objc_mutex_lock(__objc_runtime_mutex);
/* 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;
}
}
objc_mutex_unlock(__objc_runtime_mutex);
}
#define CLASSOF(c) ((c)->class_pointer)
Class
class_pose_as (Class impostor, Class super_class)
{
node_ptr node;
Class class1;
if (!CLS_ISRESOLV (impostor))
__objc_resolve_class_links ();
/* preconditions */
assert (impostor);
assert (super_class);
assert (impostor->super_class == super_class);
assert (CLS_ISCLASS (impostor));
assert (CLS_ISCLASS (super_class));
assert (impostor->instance_size == super_class->instance_size);
{
Class *subclass = &(super_class->subclass_list);
/* move subclasses of super_class to impostor */
while (*subclass)
{
Class nextSub = (*subclass)->sibling_class;
if (*subclass != impostor)
{
Class sub = *subclass;
/* classes */
sub->sibling_class = impostor->subclass_list;
sub->super_class = impostor;
impostor->subclass_list = sub;
/* It will happen that SUB is not a class object if it is
the top of the meta class hierarchy chain. (root
meta-class objects inherit their class object) If that is
the case... don't mess with the meta-meta class. */
if (CLS_ISCLASS (sub))
{
/* meta classes */
CLASSOF (sub)->sibling_class =
CLASSOF (impostor)->subclass_list;
CLASSOF (sub)->super_class = CLASSOF (impostor);
CLASSOF (impostor)->subclass_list = CLASSOF (sub);
}
}
*subclass = nextSub;
}
/* set subclasses of superclass to be impostor only */
super_class->subclass_list = impostor;
CLASSOF (super_class)->subclass_list = CLASSOF (impostor);
/* set impostor to have no sibling classes */
impostor->sibling_class = 0;
CLASSOF (impostor)->sibling_class = 0;
}
/* check relationship of impostor and super_class is kept. */
assert (impostor->super_class == super_class);
assert (CLASSOF (impostor)->super_class == CLASSOF (super_class));
/* This is how to update the lookup table. Regardless of
what the keys of the hashtable is, change all values that are
superclass into impostor. */
objc_mutex_lock(__objc_runtime_mutex);
for (node = hash_next (__objc_class_hash, NULL); node;
node = hash_next (__objc_class_hash, node))
{
class1 = (Class)node->value;
if (class1 == super_class)
{
node->value = impostor; /* change hash table value */
}
}
objc_mutex_unlock(__objc_runtime_mutex);
/* next, we update the dispatch tables... */
__objc_update_dispatch_table_for_class (CLASSOF (impostor));
__objc_update_dispatch_table_for_class (impostor);
return impostor;
}

912
libobjc/encoding.c Normal file
View File

@ -0,0 +1,912 @@
/* Encoding of types for Objective C.
Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
Bitfield support by Ovidiu Predescu
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#include "tconfig.h"
#include "objc-api.h"
#include "encoding.h"
#define MAX(X, Y) \
({ typeof(X) __x = (X), __y = (Y); \
(__x > __y ? __x : __y); })
#define MIN(X, Y) \
({ typeof(X) __x = (X), __y = (Y); \
(__x < __y ? __x : __y); })
#define ROUND(V, A) \
({ typeof(V) __v=(V); typeof(A) __a=(A); \
__a*((__v+__a-1)/__a); })
/* Various hacks for objc_layout_record. These are used by the target
macros. */
#define TREE_CODE(TYPE) *TYPE
#define RECORD_TYPE _C_STRUCT_B
#define UNION_TYPE _C_UNION_B
#define QUAL_UNION_TYPE _C_UNION_B
#define TYPE_FIELDS(TYPE) objc_skip_typespec (TYPE)
#define DECL_MODE(TYPE) *(TYPE)
#define DFmode _C_DBL
static inline int
atoi (const char* str)
{
int res = 0;
while (isdigit (*str))
res *= 10, res += (*str++ - '0');
return res;
}
/*
return the size of an object specified by type
*/
int
objc_sizeof_type (const char* type)
{
/* Skip the variable name if any */
if (*type == '"')
{
for (type++; *type++ != '"';)
/* do nothing */;
}
switch(*type) {
case _C_ID:
return sizeof(id);
break;
case _C_CLASS:
return sizeof(Class);
break;
case _C_SEL:
return sizeof(SEL);
break;
case _C_CHR:
return sizeof(char);
break;
case _C_UCHR:
return sizeof(unsigned char);
break;
case _C_SHT:
return sizeof(short);
break;
case _C_USHT:
return sizeof(unsigned short);
break;
case _C_INT:
return sizeof(int);
break;
case _C_UINT:
return sizeof(unsigned int);
break;
case _C_LNG:
return sizeof(long);
break;
case _C_ULNG:
return sizeof(unsigned long);
break;
case _C_LNG_LNG:
return sizeof(long long);
break;
case _C_ULNG_LNG:
return sizeof(unsigned long long);
break;
case _C_FLT:
return sizeof(float);
break;
case _C_DBL:
return sizeof(double);
break;
case _C_VOID:
return sizeof(void);
break;
case _C_PTR:
case _C_ATOM:
case _C_CHARPTR:
return sizeof(char*);
break;
case _C_ARY_B:
{
int len = atoi(type+1);
while (isdigit(*++type));
return len*objc_aligned_size (type);
}
break;
case _C_BFLD:
{
/* The new encoding of bitfields is: b 'position' 'type' 'size' */
int position, size;
int startByte, endByte;
position = atoi (type + 1);
while (isdigit (*++type));
size = atoi (type + 1);
startByte = position / BITS_PER_UNIT;
endByte = (position + size) / BITS_PER_UNIT;
return endByte - startByte;
}
case _C_STRUCT_B:
{
struct objc_struct_layout layout;
unsigned int size;
objc_layout_structure (type, &layout);
while (objc_layout_structure_next_member (&layout))
/* do nothing */ ;
objc_layout_finish_structure (&layout, &size, NULL);
return size;
}
case _C_UNION_B:
{
int max_size = 0;
while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
while (*type != _C_UNION_E)
{
/* Skip the variable name if any */
if (*type == '"')
{
for (type++; *type++ != '"';)
/* do nothing */;
}
max_size = MAX (max_size, objc_sizeof_type (type));
type = objc_skip_typespec (type);
}
return max_size;
}
default:
{
objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type);
return 0;
}
}
}
/*
Return the alignment of an object specified by type
*/
int
objc_alignof_type(const char* type)
{
/* Skip the variable name if any */
if (*type == '"')
{
for (type++; *type++ != '"';)
/* do nothing */;
}
switch(*type) {
case _C_ID:
return __alignof__(id);
break;
case _C_CLASS:
return __alignof__(Class);
break;
case _C_SEL:
return __alignof__(SEL);
break;
case _C_CHR:
return __alignof__(char);
break;
case _C_UCHR:
return __alignof__(unsigned char);
break;
case _C_SHT:
return __alignof__(short);
break;
case _C_USHT:
return __alignof__(unsigned short);
break;
case _C_INT:
return __alignof__(int);
break;
case _C_UINT:
return __alignof__(unsigned int);
break;
case _C_LNG:
return __alignof__(long);
break;
case _C_ULNG:
return __alignof__(unsigned long);
break;
case _C_LNG_LNG:
return __alignof__(long long);
break;
case _C_ULNG_LNG:
return __alignof__(unsigned long long);
break;
case _C_FLT:
return __alignof__(float);
break;
case _C_DBL:
return __alignof__(double);
break;
case _C_PTR:
case _C_ATOM:
case _C_CHARPTR:
return __alignof__(char*);
break;
case _C_ARY_B:
while (isdigit(*++type)) /* do nothing */;
return objc_alignof_type (type);
case _C_STRUCT_B:
{
struct objc_struct_layout layout;
unsigned int align;
objc_layout_structure (type, &layout);
while (objc_layout_structure_next_member (&layout))
/* do nothing */;
objc_layout_finish_structure (&layout, NULL, &align);
return align;
}
case _C_UNION_B:
{
int maxalign = 0;
while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
while (*type != _C_UNION_E)
{
/* Skip the variable name if any */
if (*type == '"')
{
for (type++; *type++ != '"';)
/* do nothing */;
}
maxalign = MAX (maxalign, objc_alignof_type (type));
type = objc_skip_typespec (type);
}
return maxalign;
}
default:
{
objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type);
return 0;
}
}
}
/*
The aligned size if the size rounded up to the nearest alignment.
*/
int
objc_aligned_size (const char* type)
{
int size, align;
/* Skip the variable name */
if (*type == '"')
{
for (type++; *type++ != '"';)
/* do nothing */;
}
size = objc_sizeof_type (type);
align = objc_alignof_type (type);
return ROUND (size, align);
}
/*
The size rounded up to the nearest integral of the wordsize, taken
to be the size of a void*.
*/
int
objc_promoted_size (const char* type)
{
int size, wordsize;
/* Skip the variable name */
if (*type == '"')
{
for (type++; *type++ != '"';)
/* do nothing */;
}
size = objc_sizeof_type (type);
wordsize = sizeof (void*);
return ROUND (size, wordsize);
}
/*
Skip type qualifiers. These may eventually precede typespecs
occurring in method prototype encodings.
*/
inline const char*
objc_skip_type_qualifiers (const char* type)
{
while (*type == _C_CONST
|| *type == _C_IN
|| *type == _C_INOUT
|| *type == _C_OUT
|| *type == _C_BYCOPY
|| *type == _C_ONEWAY
|| *type == _C_GCINVISIBLE)
{
type += 1;
}
return type;
}
/*
Skip one typespec element. If the typespec is prepended by type
qualifiers, these are skipped as well.
*/
const char*
objc_skip_typespec (const char* type)
{
/* Skip the variable name if any */
if (*type == '"')
{
for (type++; *type++ != '"';)
/* do nothing */;
}
type = objc_skip_type_qualifiers (type);
switch (*type) {
case _C_ID:
/* An id may be annotated by the actual type if it is known
with the @"ClassName" syntax */
if (*++type != '"')
return type;
else
{
while (*++type != '"') /* do nothing */;
return type + 1;
}
/* The following are one character type codes */
case _C_CLASS:
case _C_SEL:
case _C_CHR:
case _C_UCHR:
case _C_CHARPTR:
case _C_ATOM:
case _C_SHT:
case _C_USHT:
case _C_INT:
case _C_UINT:
case _C_LNG:
case _C_ULNG:
case _C_LNG_LNG:
case _C_ULNG_LNG:
case _C_FLT:
case _C_DBL:
case _C_VOID:
case _C_UNDEF:
return ++type;
break;
case _C_ARY_B:
/* skip digits, typespec and closing ']' */
while(isdigit(*++type));
type = objc_skip_typespec(type);
if (*type == _C_ARY_E)
return ++type;
else
{
objc_error(nil, OBJC_ERR_BAD_TYPE, "bad array type %s\n", type);
return 0;
}
case _C_BFLD:
/* The new encoding of bitfields is: b 'position' 'type' 'size' */
while (isdigit (*++type)); /* skip position */
while (isdigit (*++type)); /* skip type and size */
return type;
case _C_STRUCT_B:
/* skip name, and elements until closing '}' */
while (*type != _C_STRUCT_E && *type++ != '=');
while (*type != _C_STRUCT_E) { type = objc_skip_typespec (type); }
return ++type;
case _C_UNION_B:
/* skip name, and elements until closing ')' */
while (*type != _C_UNION_E && *type++ != '=');
while (*type != _C_UNION_E) { type = objc_skip_typespec (type); }
return ++type;
case _C_PTR:
/* Just skip the following typespec */
return objc_skip_typespec (++type);
default:
{
objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type);
return 0;
}
}
}
/*
Skip an offset as part of a method encoding. This is prepended by a
'+' if the argument is passed in registers.
*/
inline const char*
objc_skip_offset (const char* type)
{
if (*type == '+') type++;
while(isdigit(*++type));
return type;
}
/*
Skip an argument specification of a method encoding.
*/
const char*
objc_skip_argspec (const char* type)
{
type = objc_skip_typespec (type);
type = objc_skip_offset (type);
return type;
}
/*
Return the number of arguments that the method MTH expects.
Note that all methods need two implicit arguments `self' and
`_cmd'.
*/
int
method_get_number_of_arguments (struct objc_method* mth)
{
int i = 0;
const char* type = mth->method_types;
while (*type)
{
type = objc_skip_argspec (type);
i += 1;
}
return i - 1;
}
/*
Return the size of the argument block needed on the stack to invoke
the method MTH. This may be zero, if all arguments are passed in
registers.
*/
int
method_get_sizeof_arguments (struct objc_method* mth)
{
const char* type = objc_skip_typespec (mth->method_types);
return atoi (type);
}
/*
Return a pointer to the next argument of ARGFRAME. type points to
the last argument. Typical use of this look like:
{
char *datum, *type;
for (datum = method_get_first_argument (method, argframe, &type);
datum; datum = method_get_next_argument (argframe, &type))
{
unsigned flags = objc_get_type_qualifiers (type);
type = objc_skip_type_qualifiers (type);
if (*type != _C_PTR)
[portal encodeData: datum ofType: type];
else
{
if ((flags & _F_IN) == _F_IN)
[portal encodeData: *(char**)datum ofType: ++type];
}
}
}
*/
char*
method_get_next_argument (arglist_t argframe,
const char **type)
{
const char *t = objc_skip_argspec (*type);
if (*t == '\0')
return 0;
*type = t;
t = objc_skip_typespec (t);
if (*t == '+')
return argframe->arg_regs + atoi (++t);
else
return argframe->arg_ptr + atoi (t);
}
/*
Return a pointer to the value of the first argument of the method
described in M with the given argumentframe ARGFRAME. The type
is returned in TYPE. type must be passed to successive calls of
method_get_next_argument.
*/
char*
method_get_first_argument (struct objc_method* m,
arglist_t argframe,
const char** type)
{
*type = m->method_types;
return method_get_next_argument (argframe, type);
}
/*
Return a pointer to the ARGth argument of the method
M from the frame ARGFRAME. The type of the argument
is returned in the value-result argument TYPE
*/
char*
method_get_nth_argument (struct objc_method* m,
arglist_t argframe, int arg,
const char **type)
{
const char* t = objc_skip_argspec (m->method_types);
if (arg > method_get_number_of_arguments (m))
return 0;
while (arg--)
t = objc_skip_argspec (t);
*type = t;
t = objc_skip_typespec (t);
if (*t == '+')
return argframe->arg_regs + atoi (++t);
else
return argframe->arg_ptr + atoi (t);
}
unsigned
objc_get_type_qualifiers (const char* type)
{
unsigned res = 0;
BOOL flag = YES;
while (flag)
switch (*type++)
{
case _C_CONST: res |= _F_CONST; break;
case _C_IN: res |= _F_IN; break;
case _C_INOUT: res |= _F_INOUT; break;
case _C_OUT: res |= _F_OUT; break;
case _C_BYCOPY: res |= _F_BYCOPY; break;
case _C_ONEWAY: res |= _F_ONEWAY; break;
case _C_GCINVISIBLE: res |= _F_GCINVISIBLE; break;
default: flag = NO;
}
return res;
}
/* The following three functions can be used to determine how a
structure is laid out by the compiler. For example:
struct objc_struct_layout layout;
int i;
objc_layout_structure (type, &layout);
while (objc_layout_structure_next_member (&layout))
{
int position, align;
const char *type;
objc_layout_structure_get_info (&layout, &position, &align, &type);
printf ("element %d has offset %d, alignment %d\n",
i++, position, align);
}
These functions are used by objc_sizeof_type and objc_alignof_type
functions to compute the size and alignment of structures. The
previous method of computing the size and alignment of a structure
was not working on some architectures, particulary on AIX, and in
the presence of bitfields inside the structure. */
void
objc_layout_structure (const char *type,
struct objc_struct_layout *layout)
{
const char *ntype;
if (*type++ != _C_STRUCT_B)
{
objc_error(nil, OBJC_ERR_BAD_TYPE,
"record type expected in objc_layout_structure, got %s\n",
type);
}
layout->original_type = type;
/* Skip "<name>=" if any. Avoid embedded structures and unions. */
ntype = type;
while (*ntype != _C_STRUCT_E && *ntype != _C_STRUCT_B && *ntype != _C_UNION_B
&& *ntype++ != '=')
/* do nothing */;
/* If there's a "<name>=", ntype - 1 points to '='; skip the the name */
if (*(ntype - 1) == '=')
type = ntype;
layout->type = type;
layout->prev_type = NULL;
layout->record_size = 0;
layout->record_align = BITS_PER_UNIT;
#ifdef STRUCTURE_SIZE_BOUNDARY
layout->record_align = MAX (layout->record_align, STRUCTURE_SIZE_BOUNDARY);
#endif
}
BOOL
objc_layout_structure_next_member (struct objc_struct_layout *layout)
{
register int known_align = layout->record_size;
register int desired_align = 0;
/* The following are used only if the field is a bitfield */
register const char *bfld_type;
register int bfld_type_size, bfld_type_align, bfld_field_size;
/* The current type without the type qualifiers */
const char *type;
#if 1
if (layout->prev_type == NULL)
{
layout->prev_type = layout->type;
layout->type = objc_skip_typespec (layout->prev_type);
return YES;
}
#endif
/* Add the size of the previous field to the size of the record. */
if (layout->prev_type)
{
type = objc_skip_type_qualifiers (layout->prev_type);
if (*type != _C_BFLD)
layout->record_size += objc_sizeof_type (type) * BITS_PER_UNIT;
else {
desired_align = 1;
/* Get the bitfield's type */
for (bfld_type = type + 1;
isdigit(*bfld_type);
bfld_type++)
/* do nothing */;
bfld_type_size = objc_sizeof_type (bfld_type) * BITS_PER_UNIT;
bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT;
bfld_field_size = atoi (objc_skip_typespec (bfld_type));
layout->record_size += bfld_field_size;
}
}
if (*layout->type == _C_STRUCT_E)
return NO;
/* Skip the variable name if any */
if (*layout->type == '"')
{
for (layout->type++; *layout->type++ != '"';)
/* do nothing */;
}
type = objc_skip_type_qualifiers (layout->type);
if (*type != _C_BFLD)
desired_align = objc_alignof_type(type) * BITS_PER_UNIT;
else
{
desired_align = 1;
/* Skip the bitfield's offset */
for (bfld_type = type + 1; isdigit(*bfld_type); bfld_type++)
/* do nothing */;
bfld_type_size = objc_sizeof_type (bfld_type) * BITS_PER_UNIT;
bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT;
bfld_field_size = atoi (objc_skip_typespec (bfld_type));
}
#ifdef BIGGEST_FIELD_ALIGNMENT
desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT);
#endif
#ifdef ADJUST_FIELD_ALIGN
desired_align = ADJUST_FIELD_ALIGN (type, desired_align);
#endif
/* Record must have at least as much alignment as any field.
Otherwise, the alignment of the field within the record
is meaningless. */
#ifndef PCC_BITFIELD_TYPE_MATTERS
layout->record_align = MAX (layout->record_align, desired_align);
#else
if (*type == _C_BFLD)
{
/* For these machines, a zero-length field does not
affect the alignment of the structure as a whole.
It does, however, affect the alignment of the next field
within the structure. */
if (bfld_field_size)
layout->record_align = MAX (layout->record_align, desired_align);
else
desired_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT;
/* A named bit field of declared type `int'
forces the entire structure to have `int' alignment.
Q1: How is encoded this thing and how to check for it?
Q2: How to determine maximum_field_alignment at runtime? */
/* if (DECL_NAME (field) != 0) */
{
int type_align = bfld_type_align;
#if 0
if (maximum_field_alignment != 0)
type_align = MIN (type_align, maximum_field_alignment);
else if (DECL_PACKED (field))
type_align = MIN (type_align, BITS_PER_UNIT);
#endif
layout->record_align = MAX (layout->record_align, type_align);
}
}
else
layout->record_align = MAX (layout->record_align, desired_align);
#endif
/* Does this field automatically have alignment it needs
by virtue of the fields that precede it and the record's
own alignment? */
if (*type == _C_BFLD)
layout->record_size = atoi (type + 1);
else if (layout->record_size % desired_align != 0)
{
/* No, we need to skip space before this field.
Bump the cumulative size to multiple of field alignment. */
layout->record_size = ROUND (layout->record_size, desired_align);
}
/* Jump to the next field in record. */
layout->prev_type = layout->type;
layout->type = objc_skip_typespec (layout->type); /* skip component */
return YES;
}
void objc_layout_finish_structure (struct objc_struct_layout *layout,
unsigned int *size,
unsigned int *align)
{
if (layout->type && *layout->type == _C_STRUCT_E)
{
/* Work out the alignment of the record as one expression and store
in the record type. Round it up to a multiple of the record's
alignment. */
#ifdef ROUND_TYPE_ALIGN
layout->record_align = ROUND_TYPE_ALIGN (layout->original_type,
1,
layout->record_align);
#else
layout->record_align = MAX (1, layout->record_align);
#endif
#ifdef ROUND_TYPE_SIZE
layout->record_size = ROUND_TYPE_SIZE (layout->original_type,
layout->record_size,
layout->record_align);
#else
/* Round the size up to be a multiple of the required alignment */
layout->record_size = ROUND (layout->record_size, layout->record_align);
#endif
layout->type = NULL;
}
if (size)
*size = layout->record_size / BITS_PER_UNIT;
if (align)
*align = layout->record_align / BITS_PER_UNIT;
}
void objc_layout_structure_get_info (struct objc_struct_layout *layout,
unsigned int *offset,
unsigned int *align,
const char **type)
{
if (offset)
*offset = layout->record_size / BITS_PER_UNIT;
if (align)
*align = layout->record_align / BITS_PER_UNIT;
if (type)
*type = layout->prev_type;
}

97
libobjc/encoding.h Normal file
View File

@ -0,0 +1,97 @@
/* Encoding of types for Objective C.
Copyright (C) 1993, 1997 Free Software Foundation, Inc.
Author: Kresten Krab Thorup
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#ifndef __encoding_INCLUDE_GNU
#define __encoding_INCLUDE_GNU
#include <ctype.h>
#include "objc/objc-api.h"
#define _C_CONST 'r'
#define _C_IN 'n'
#define _C_INOUT 'N'
#define _C_OUT 'o'
#define _C_BYCOPY 'O'
#define _C_ONEWAY 'V'
#define _C_GCINVISIBLE '!'
#define _F_CONST 0x01
#define _F_IN 0x01
#define _F_OUT 0x02
#define _F_INOUT 0x03
#define _F_BYCOPY 0x04
#define _F_ONEWAY 0x08
#define _F_GCINVISIBLE 0x10
int objc_aligned_size (const char* type);
int objc_sizeof_type (const char* type);
int objc_alignof_type (const char* type);
int objc_aligned_size (const char* type);
int objc_promoted_size (const char* type);
const char* objc_skip_type_qualifiers (const char* type);
const char* objc_skip_typespec (const char* type);
const char* objc_skip_offset (const char* type);
const char* objc_skip_argspec (const char* type);
int method_get_number_of_arguments (struct objc_method*);
int method_get_sizeof_arguments (struct objc_method*);
char* method_get_first_argument (struct objc_method*,
arglist_t argframe,
const char** type);
char* method_get_next_argument (arglist_t argframe,
const char **type);
char* method_get_nth_argument (struct objc_method* m,
arglist_t argframe,
int arg,
const char **type);
unsigned objc_get_type_qualifiers (const char* type);
struct objc_struct_layout
{
const char *original_type;
const char *type;
const char *prev_type;
unsigned int record_size;
unsigned int record_align;
};
void objc_layout_structure (const char *type,
struct objc_struct_layout *layout);
BOOL objc_layout_structure_next_member (struct objc_struct_layout *layout);
void objc_layout_finish_structure (struct objc_struct_layout *layout,
unsigned int *size,
unsigned int *align);
void objc_layout_structure_get_info (struct objc_struct_layout *layout,
unsigned int *offset,
unsigned int *align,
const char **type);
#endif /* __encoding_INCLUDE_GNU */

458
libobjc/gc.c Normal file
View File

@ -0,0 +1,458 @@
/* Basic data types for Objective C.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Ovidiu Predescu.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#include "../tconfig.h"
#include "objc.h"
#include "encoding.h"
#include <assert.h>
#include <string.h>
#if OBJC_WITH_GC
#include <gc.h>
/* gc_typed.h uses the following but doesn't declare them */
typedef GC_word word;
typedef GC_signed_word signed_word;
#if BITS_PER_WORD == 32
# define LOGWL 5
# define modWORDSZ(n) ((n) & 0x1f) /* n mod size of word */
#endif
#if BITS_PER_WORD == 64
# define LOGWL 6
# define modWORDSZ(n) ((n) & 0x3f) /* n mod size of word */
#endif
#define divWORDSZ(n) ((n) >> LOGWL) /* divide n by size of word */
#include <gc_typed.h>
/* The following functions set up in `mask` the corresponding pointers.
The offset is incremented with the size of the type. */
#define ROUND(V, A) \
({ typeof(V) __v=(V); typeof(A) __a=(A); \
__a*((__v+__a-1)/__a); })
#define SET_BIT_FOR_OFFSET(mask, offset) \
GC_set_bit(mask, offset / sizeof (void*))
/* Some prototypes */
static void
__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset);
static void
__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset);
static void
__objc_gc_setup_array (GC_bitmap mask, const char *type, int offset)
{
int i, len = atoi(type + 1);
while (isdigit(*++type))
/* do nothing */; /* skip the size of the array */
switch (*type) {
case _C_ARY_B:
for (i = 0; i < len; i++)
__objc_gc_setup_array (mask, type, offset);
break;
case _C_STRUCT_B:
for (i = 0; i < len; i++)
__objc_gc_setup_struct (mask, type, offset);
break;
case _C_UNION_B:
for (i = 0; i < len; i++)
__objc_gc_setup_union (mask, type, offset);
break;
default:
break;
}
}
static void
__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset)
{
struct objc_struct_layout layout;
unsigned int position;
const char *mtype;
objc_layout_structure (type, &layout);
while (objc_layout_structure_next_member (&layout))
{
BOOL gc_invisible = NO;
objc_layout_structure_get_info (&layout, &position, NULL, &mtype);
/* Skip the variable name */
if (*mtype == '"')
{
for (mtype++; *mtype++ != '"';)
/* do nothing */;
}
if (*mtype == _C_GCINVISIBLE)
{
gc_invisible = YES;
mtype++;
}
/* Add to position the offset of this structure */
position += offset;
switch (*mtype) {
case _C_ID:
case _C_CLASS:
case _C_SEL:
case _C_PTR:
case _C_CHARPTR:
case _C_ATOM:
if (!gc_invisible)
SET_BIT_FOR_OFFSET(mask, position);
break;
case _C_ARY_B:
__objc_gc_setup_array (mask, mtype, position);
break;
case _C_STRUCT_B:
__objc_gc_setup_struct (mask, mtype, position);
break;
case _C_UNION_B:
__objc_gc_setup_union (mask, mtype, position);
break;
default:
break;
}
}
}
static void
__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset)
{
/* Sub-optimal, quick implementation: assume the union is made of
pointers, set up the mask accordingly. */
int i, size, align;
/* Skip the variable name */
if (*type == '"')
{
for (type++; *type++ != '"';)
/* do nothing */;
}
size = objc_sizeof_type (type);
align = objc_alignof_type (type);
offset = ROUND(offset, align);
for (i = 0; i < size; i += sizeof (void*))
{
SET_BIT_FOR_OFFSET(mask, offset);
offset += sizeof (void*);
}
}
/* Iterates over the types in the structure that represents the class
encoding and sets the bits in mask according to each ivar type. */
static void
__objc_gc_type_description_from_type (GC_bitmap mask, const char *type)
{
struct objc_struct_layout layout;
unsigned int offset, align;
const char *ivar_type;
objc_layout_structure (type, &layout);
while (objc_layout_structure_next_member (&layout))
{
BOOL gc_invisible = NO;
objc_layout_structure_get_info (&layout, &offset, &align, &ivar_type);
/* Skip the variable name */
if (*ivar_type == '"')
{
for (ivar_type++; *ivar_type++ != '"';)
/* do nothing */;
}
if (*ivar_type == _C_GCINVISIBLE)
{
gc_invisible = YES;
ivar_type++;
}
switch (*ivar_type) {
case _C_ID:
case _C_CLASS:
case _C_SEL:
case _C_PTR:
case _C_CHARPTR:
if (!gc_invisible)
SET_BIT_FOR_OFFSET(mask, offset);
break;
case _C_ARY_B:
__objc_gc_setup_array (mask, ivar_type, offset);
break;
case _C_STRUCT_B:
__objc_gc_setup_struct (mask, ivar_type, offset);
break;
case _C_UNION_B:
__objc_gc_setup_union (mask, ivar_type, offset);
break;
default:
break;
}
}
}
/* Computes in *type the full type encoding of this class including
its super classes. '*size' gives the total number of bytes allocated
into *type, '*current' the number of bytes used so far by the
encoding. */
static void
__objc_class_structure_encoding (Class class, char **type, int *size,
int *current)
{
int i, ivar_count;
struct objc_ivar_list* ivars;
if (!class)
{
strcat (*type, "{");
*current++;
return;
}
/* Add the type encodings of the super classes */
__objc_class_structure_encoding (class->super_class, type, size, current);
ivars = class->ivars;
if (!ivars)
return;
ivar_count = ivars->ivar_count;
for (i = 0; i < ivar_count; i++)
{
struct objc_ivar *ivar = &(ivars->ivar_list[i]);
const char *ivar_type = ivar->ivar_type;
int len = strlen (ivar_type);
if (*current + len + 1 >= *size)
{
/* Increase the size of the encoding string so that it
contains this ivar's type. */
*size = ROUND(*current + len + 1, 10);
*type = objc_realloc (*type, *size);
}
strcat (*type + *current, ivar_type);
*current += len;
}
}
/* Allocates the memory that will hold the type description for class
and calls the __objc_class_structure_encoding that generates this
value. */
void
__objc_generate_gc_type_description (Class class)
{
GC_bitmap mask;
int bits_no, size;
int type_size = 10, current;
char *class_structure_type;
if (!CLS_ISCLASS(class))
return;
/* We have to create a mask in which each bit counts for a pointer member.
We take into consideration all the non-pointer instance variables and we
round them up to the alignment. */
/* The number of bits in the mask is the size of an instance in bytes divided
by the size of a pointer. */
bits_no = (ROUND(class_get_instance_size (class), sizeof(void*))
/ sizeof (void*));
size = ROUND(bits_no, BITS_PER_WORD) / BITS_PER_WORD;
mask = objc_atomic_malloc (size * sizeof (int));
memset (mask, 0, size * sizeof (int));
class_structure_type = objc_atomic_malloc (type_size);
*class_structure_type = current = 0;
__objc_class_structure_encoding (class, &class_structure_type,
&type_size, &current);
if (current + 1 == type_size)
class_structure_type = objc_realloc (class_structure_type, ++type_size);
strcat (class_structure_type + current, "}");
// printf ("type description for '%s' is %s\n", class->name, class_structure_type);
__objc_gc_type_description_from_type (mask, class_structure_type);
objc_free (class_structure_type);
#define DEBUG 1
#ifdef DEBUG
printf (" mask for '%s', type '%s' (bits %d, mask size %d) is:",
class_structure_type, class->name, bits_no, size);
{
int i;
for (i = 0; i < size; i++)
printf (" %lx", mask[i]);
}
puts ("");
#endif
class->gc_object_type = (void*)GC_make_descriptor (mask, bits_no);
}
/* Returns YES if type denotes a pointer type, NO otherwise */
static inline BOOL
__objc_ivar_pointer (const char *type)
{
type = objc_skip_type_qualifiers (type);
return (*type == _C_ID
|| *type == _C_CLASS
|| *type == _C_SEL
|| *type == _C_PTR
|| *type == _C_CHARPTR
|| *type == _C_ATOM);
}
/* Mark the instance variable whose name is given by ivarname as a
weak pointer (a pointer hidden to the garbage collector) if
gc_invisible is true. If gc_invisible is false it unmarks the
instance variable and makes it a normal pointer, visible to the
garbage collector.
This operation only makes sense on instance variables that are
pointers. */
void
class_ivar_set_gcinvisible (Class class, const char* ivarname,
BOOL gc_invisible)
{
int i, ivar_count;
struct objc_ivar_list* ivars;
if (!class || !ivarname)
return;
ivars = class->ivars;
if (!ivars)
return;
ivar_count = ivars->ivar_count;
for (i = 0; i < ivar_count; i++)
{
struct objc_ivar *ivar = &(ivars->ivar_list[i]);
const char *type;
if (!ivar->ivar_name || strcmp (ivar->ivar_name, ivarname))
continue;
assert (ivar->ivar_type);
type = ivar->ivar_type;
/* Skip the variable name */
if (*type == '"')
{
for (type++; *type++ != '"';)
/* do nothing */;
}
if (*type == _C_GCINVISIBLE)
{
char *new_type;
if (gc_invisible || !__objc_ivar_pointer (type))
return; /* The type of the variable already matches the
requested gc_invisible type */
/* The variable is gc_invisible and we have to reverse it */
new_type = objc_atomic_malloc (strlen (ivar->ivar_type));
strncpy (new_type, ivar->ivar_type,
(size_t)(type - ivar->ivar_type));
strcat (new_type, type + 1);
ivar->ivar_type = new_type;
}
else
{
char *new_type;
if (!gc_invisible || !__objc_ivar_pointer (type))
return; /* The type of the variable already matches the
requested gc_invisible type */
/* The variable is gc visible and we have to make it gc_invisible */
new_type = objc_malloc (strlen (ivar->ivar_type) + 2);
strncpy (new_type, ivar->ivar_type,
(size_t)(type - ivar->ivar_type));
strcat (new_type, "!");
strcat (new_type, type);
ivar->ivar_type = new_type;
}
__objc_generate_gc_type_description (class);
return;
}
/* Search the instance variable in the superclasses */
class_ivar_set_gcinvisible (class->super_class, ivarname, gc_invisible);
}
#else /* !OBJC_WITH_GC */
void
__objc_generate_gc_type_description (Class class)
{
}
void class_ivar_set_gcinvisible (Class class,
const char* ivarname,
BOOL gc_invisible)
{
}
#endif /* OBJC_WITH_GC */

283
libobjc/hash.c Normal file
View File

@ -0,0 +1,283 @@
/* Hash tables for Objective C internal structures
Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#include "assert.h"
#include "objc/hash.h"
#include "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_calloc (1, sizeof (struct cache));
assert (cache);
/* Allocate the array of buckets for the cache.
calloc initializes all of the pointers to NULL. */
cache->node_table
= (node_ptr *) objc_calloc (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;
node_ptr next_node;
unsigned int i;
/* Purge all key/value pairs from the table. */
/* Step through the nodes one by one and remove every node WITHOUT
using hash_next. this makes hash_delete much more efficient. */
for (i = 0;i < cache->size;i++) {
if ((node = cache->node_table[i])) {
/* an entry in the hash table has been found, now step through the
nodes next in the list and free them. */
while ((next_node = node->next)) {
hash_remove (cache,node->key);
node = next_node;
}
hash_remove (cache,node->key);
}
}
/* Release the array of nodes and the cache itself. */
objc_free(cache->node_table);
objc_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_calloc (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;
objc_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;
objc_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;
break;
} else
node = node->next;
} while (!retval && node);
return retval;
}
/* Given KEY, return YES if it exists in the CACHE.
Return NO if it does not */
BOOL
hash_is_key_in_hash (cache_ptr cache, const void *key)
{
node_ptr node = cache->node_table[(*cache->hash_func)(cache, key)];
if (node)
do {
if ((*cache->compare_func)(node->key, key))
return YES;
else
node = node->next;
} while (node);
return NO;
}

206
libobjc/hash.h Normal file
View File

@ -0,0 +1,206 @@
/* Hash tables for Objective C method dispatch.
Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#ifndef __hash_INCLUDE_GNU
#define __hash_INCLUDE_GNU
#include <stddef.h>
#include <objc/objc.h>
/*
* This data structure is used to hold items
* stored in a hash table. Each node holds
* a key/value pair.
*
* Items in the cache are really of type void *.
*/
typedef struct cache_node
{
struct cache_node *next; /* Pointer to next entry on the list.
NULL indicates end of list. */
const void *key; /* Key used to locate the value. Used
to locate value when more than one
key computes the same hash
value. */
void *value; /* Value stored for the key. */
} *node_ptr;
/*
* This data type is the function that computes a hash code given a key.
* Therefore, the key can be a pointer to anything and the function specific
* to the key type.
*
* Unfortunately there is a mutual data structure reference problem with this
* typedef. Therefore, to remove compiler warnings the functions passed to
* hash_new will have to be casted to this type.
*/
typedef unsigned int (*hash_func_type)(void *, const void *);
/*
* This data type is the function that compares two hash keys and returns an
* integer greater than, equal to, or less than 0, according as the first
* parameter is lexicographically greater than, equal to, or less than the
* second.
*/
typedef int (*compare_func_type)(const void *, const void *);
/*
* This data structure is the cache.
*
* It must be passed to all of the hashing routines
* (except for new).
*/
typedef struct cache
{
/* Variables used to implement the hash itself. */
node_ptr *node_table; /* Pointer to an array of hash nodes. */
/* Variables used to track the size of the hash table so to determine
when to resize it. */
unsigned int size; /* Number of buckets allocated for the hash table
(number of array entries allocated for
"node_table"). Must be a power of two. */
unsigned int used; /* Current number of entries in the hash table. */
unsigned int mask; /* Precomputed mask. */
/* Variables used to implement indexing through the hash table. */
unsigned int last_bucket; /* Tracks which entry in the array where
the last value was returned. */
/* Function used to compute a hash code given a key.
This function is specified when the hash table is created. */
hash_func_type hash_func;
/* Function used to compare two hash keys to see if they are equal. */
compare_func_type compare_func;
} *cache_ptr;
/* Two important hash tables. */
extern cache_ptr module_hash_table, class_hash_table;
/* Allocate and initialize a hash table. */
cache_ptr hash_new (unsigned int size,
hash_func_type hash_func,
compare_func_type compare_func);
/* Deallocate all of the hash nodes and the cache itself. */
void hash_delete (cache_ptr cache);
/* Add the key/value pair to the hash table. If the
hash table reaches a level of fullness then it will be resized.
assert if the key is already in the hash. */
void hash_add (cache_ptr *cachep, const void *key, void *value);
/* Remove the key/value pair from the hash table.
assert if the key isn't in the table. */
void hash_remove (cache_ptr cache, const void *key);
/* Used to index through the hash table. Start with NULL
to get the first entry.
Successive calls pass the value returned previously.
** Don't modify the hash during this operation ***
Cache nodes are returned such that key or value can
be extracted. */
node_ptr hash_next (cache_ptr cache, node_ptr node);
/* Used to return a value from a hash table using a given key. */
void *hash_value_for_key (cache_ptr cache, const void *key);
/* Used to determine if the given key exists in the hash table */
BOOL hash_is_key_in_hash (cache_ptr cache, const void *key);
/************************************************
Useful hashing functions.
Declared inline for your pleasure.
************************************************/
/* Calculate a hash code by performing some
manipulation of the key pointer. (Use the lowest bits
except for those likely to be 0 due to alignment.) */
static inline unsigned int
hash_ptr (cache_ptr cache, const void *key)
{
return ((size_t)key / sizeof (void *)) & cache->mask;
}
/* Calculate a hash code by iterating over a NULL
terminate string. */
static inline unsigned int
hash_string (cache_ptr cache, const void *key)
{
unsigned int ret = 0;
unsigned int ctr = 0;
while (*(char*)key) {
ret ^= *(char*)key++ << ctr;
ctr = (ctr + 1) % sizeof (void *);
}
return ret & cache->mask;
}
/* Compare two pointers for equality. */
static inline int
compare_ptrs (const void *k1, const void *k2)
{
return !(k1 - k2);
}
/* Compare two strings. */
static inline int
compare_strings (const void *k1, const void *k2)
{
if (k1 == k2)
return 1;
else if (k1 == 0 || k2 == 0)
return 0;
else
return !strcmp (k1, k2);
}
#endif /* not __hash_INCLUDE_GNU */

834
libobjc/init.c Normal file
View File

@ -0,0 +1,834 @@
/* GNU Objective C Runtime initialization
Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
+load support contributed by Ovidiu Predescu <ovidiu@net-community.com>
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include "runtime.h"
/* The version number of this runtime. This must match the number
defined in gcc (objc-act.c) */
#define OBJC_VERSION 8
#define PROTOCOL_VERSION 2
/* This list contains all modules currently loaded into the runtime */
static struct objc_list* __objc_module_list = 0; /* !T:MUTEX */
/* This list contains all proto_list's not yet assigned class links */
static struct objc_list* unclaimed_proto_list = 0; /* !T:MUTEX */
/* List of unresolved static instances. */
static struct objc_list *uninitialized_statics = 0; /* !T:MUTEX */
/* Global runtime "write" mutex. */
objc_mutex_t __objc_runtime_mutex = 0;
/* Number of threads that are alive. */
int __objc_runtime_threads_alive = 1; /* !T:MUTEX */
/* Check compiler vs runtime version */
static void init_check_module_version (Module_t);
/* Assign isa links to protos */
static void __objc_init_protocols (struct objc_protocol_list* protos);
/* Add protocol to class */
static void __objc_class_add_protocols (Class, struct objc_protocol_list*);
/* This is a hook which is called by __objc_exec_class every time a class
or a category is loaded into the runtime. This may e.g. help a
dynamic loader determine the classes that have been loaded when
an object file is dynamically linked in */
void (*_objc_load_callback)(Class class, Category* category); /* !T:SAFE */
/* Is all categories/classes resolved? */
BOOL __objc_dangling_categories = NO; /* !T:UNUSED */
extern SEL
__sel_register_typed_name (const char *name, const char *types,
struct objc_selector *orig, BOOL is_const);
/* Sends +load to all classes and categories in certain situations. */
static void objc_send_load (void);
/* Inserts all the classes defined in module in a tree of classes that
resembles the class hierarchy. This tree is traversed in preorder and the
classes in its nodes receive the +load message if these methods were not
executed before. The algorithm ensures that when the +load method of a class
is executed all the superclasses have been already received the +load
message. */
static void __objc_create_classes_tree (Module_t module);
static void __objc_call_callback (Module_t module);
/* A special version that works only before the classes are completely
installed in the runtime. */
static BOOL class_is_subclass_of_class (Class class, Class superclass);
typedef struct objc_class_tree {
Class class;
struct objc_list *subclasses; /* `head' is pointer to an objc_class_tree */
} objc_class_tree;
/* This is a linked list of objc_class_tree trees. The head of these trees
are root classes (their super class is Nil). These different trees
represent different class hierarchies. */
static struct objc_list *__objc_class_tree_list = NULL;
/* Keeps the +load methods who have been already executed. This hash should
not be destroyed during the execution of the program. */
static cache_ptr __objc_load_methods = NULL;
/* Creates a tree of classes whose topmost class is directly inherited from
`upper' and the bottom class in this tree is `bottom_class'. The classes
in this tree are super classes of `bottom_class'. `subclasses' member
of each tree node point to the next subclass tree node. */
static objc_class_tree *
create_tree_of_subclasses_inherited_from (Class bottom_class, Class upper)
{
Class superclass = bottom_class->super_class ?
objc_lookup_class ((char*)bottom_class->super_class)
: Nil;
objc_class_tree *tree, *prev;
DEBUG_PRINTF ("create_tree_of_subclasses_inherited_from:");
DEBUG_PRINTF ("bottom_class = %s, upper = %s\n",
(bottom_class ? bottom_class->name : NULL),
(upper ? upper->name : NULL));
tree = prev = objc_calloc (1, sizeof (objc_class_tree));
prev->class = bottom_class;
while (superclass != upper)
{
tree = objc_calloc (1, sizeof (objc_class_tree));
tree->class = superclass;
tree->subclasses = list_cons (prev, tree->subclasses);
superclass = (superclass->super_class ?
objc_lookup_class ((char*)superclass->super_class)
: Nil);
prev = tree;
}
return tree;
}
/* Insert the `class' into the proper place in the `tree' class hierarchy. This
function returns a new tree if the class has been successfully inserted into
the tree or NULL if the class is not part of the classes hierarchy described
by `tree'. This function is private to objc_tree_insert_class(), you should
not call it directly. */
static objc_class_tree *
__objc_tree_insert_class (objc_class_tree *tree, Class class)
{
DEBUG_PRINTF ("__objc_tree_insert_class: tree = %x, class = %s\n",
tree, class->name);
if (tree == NULL)
return create_tree_of_subclasses_inherited_from (class, NULL);
else if (class == tree->class)
{
/* `class' has been already inserted */
DEBUG_PRINTF ("1. class %s was previously inserted\n", class->name);
return tree;
}
else if ((class->super_class ?
objc_lookup_class ((char*)class->super_class)
: Nil)
== tree->class)
{
/* If class is a direct subclass of tree->class then add class to the
list of subclasses. First check to see if it wasn't already
inserted. */
struct objc_list *list = tree->subclasses;
objc_class_tree *node;
while (list)
{
/* Class has been already inserted; do nothing just return
the tree. */
if (((objc_class_tree*)list->head)->class == class)
{
DEBUG_PRINTF ("2. class %s was previously inserted\n",
class->name);
return tree;
}
list = list->tail;
}
/* Create a new node class and insert it into the list of subclasses */
node = objc_calloc (1, sizeof (objc_class_tree));
node->class = class;
tree->subclasses = list_cons (node, tree->subclasses);
DEBUG_PRINTF ("3. class %s inserted\n", class->name);
return tree;
}
else
{
/* The class is not a direct subclass of tree->class. Search for class's
superclasses in the list of subclasses. */
struct objc_list *subclasses = tree->subclasses;
/* Precondition: the class must be a subclass of tree->class; otherwise
return NULL to indicate our caller that it must take the next tree. */
if (!class_is_subclass_of_class (class, tree->class))
return NULL;
for (; subclasses != NULL; subclasses = subclasses->tail)
{
Class aClass = ((objc_class_tree*)(subclasses->head))->class;
if (class_is_subclass_of_class (class, aClass))
{
/* If we found one of class's superclasses we insert the class
into its subtree and return the original tree since nothing
has been changed. */
subclasses->head
= __objc_tree_insert_class (subclasses->head, class);
DEBUG_PRINTF ("4. class %s inserted\n", class->name);
return tree;
}
}
/* We haven't found a subclass of `class' in the `subclasses' list.
Create a new tree of classes whose topmost class is a direct subclass
of tree->class. */
{
objc_class_tree *new_tree
= create_tree_of_subclasses_inherited_from (class, tree->class);
tree->subclasses = list_cons (new_tree, tree->subclasses);
DEBUG_PRINTF ("5. class %s inserted\n", class->name);
return tree;
}
}
}
/* This function inserts `class' in the right tree hierarchy classes. */
static void
objc_tree_insert_class (Class class)
{
struct objc_list *list_node;
objc_class_tree *tree;
list_node = __objc_class_tree_list;
while (list_node)
{
tree = __objc_tree_insert_class (list_node->head, class);
if (tree)
{
list_node->head = tree;
break;
}
else
list_node = list_node->tail;
}
/* If the list was finished but the class hasn't been inserted, insert it
here. */
if (!list_node)
{
__objc_class_tree_list = list_cons (NULL, __objc_class_tree_list);
__objc_class_tree_list->head = __objc_tree_insert_class (NULL, class);
}
}
/* Traverse tree in preorder. Used to send +load. */
static void
objc_preorder_traverse (objc_class_tree *tree,
int level,
void (*function)(objc_class_tree*, int))
{
struct objc_list *node;
(*function) (tree, level);
for (node = tree->subclasses; node; node = node->tail)
objc_preorder_traverse (node->head, level + 1, function);
}
/* Traverse tree in postorder. Used to destroy a tree. */
static void
objc_postorder_traverse (objc_class_tree *tree,
int level,
void (*function)(objc_class_tree*, int))
{
struct objc_list *node;
for (node = tree->subclasses; node; node = node->tail)
objc_postorder_traverse (node->head, level + 1, function);
(*function) (tree, level);
}
/* Used to print a tree class hierarchy. */
#ifdef DEBUG
static void
__objc_tree_print (objc_class_tree *tree, int level)
{
int i;
for (i = 0; i < level; i++)
printf (" ");
printf ("%s\n", tree->class->name);
}
#endif
/* Walks on a linked list of methods in the reverse order and executes all
the methods corresponding to `op' selector. Walking in the reverse order
assures the +load of class is executed first and then +load of categories
because of the way in which categories are added to the class methods. */
static void
__objc_send_message_in_list (MethodList_t method_list, Class class, SEL op)
{
int i;
if (!method_list)
return;
/* First execute the `op' message in the following method lists */
__objc_send_message_in_list (method_list->method_next, class, op);
/* Search the method list. */
for (i = 0; i < method_list->method_count; i++)
{
Method_t mth = &method_list->method_list[i];
if (mth->method_name && sel_eq (mth->method_name, op)
&& !hash_is_key_in_hash (__objc_load_methods, mth->method_name))
{
/* The method was found and wasn't previously executed. */
(*mth->method_imp) ((id)class, mth->method_name);
/* Add this method into the +load hash table */
hash_add (&__objc_load_methods, mth->method_imp, mth->method_imp);
DEBUG_PRINTF ("sending +load in class: %s\n", class->name);
break;
}
}
}
static void
__objc_send_load (objc_class_tree *tree, int level)
{
static SEL load_sel = 0;
Class class = tree->class;
MethodList_t method_list = class->class_pointer->methods;
if (!load_sel)
load_sel = sel_register_name ("load");
__objc_send_message_in_list (method_list, class, load_sel);
}
static void
__objc_destroy_class_tree_node (objc_class_tree *tree, int level)
{
objc_free (tree);
}
/* This is used to check if the relationship between two classes before the
runtime completely installs the classes. */
static BOOL
class_is_subclass_of_class (Class class, Class superclass)
{
for (; class != Nil;)
{
if (class == superclass)
return YES;
class = (class->super_class ?
objc_lookup_class ((char*)class->super_class)
: Nil);
}
return NO;
}
/* This list contains all the classes in the runtime system for whom their
superclasses are not yet know to the runtime. */
static struct objc_list* unresolved_classes = 0;
/* Static function used to reference the Object and NXConstantString classes.
*/
static void
__objc_force_linking (void)
{
extern void __objc_linking (void);
__objc_linking ();
/* Call the function to avoid compiler warning */
__objc_force_linking ();
}
/* Run through the statics list, removing modules as soon as all its statics
have been initialized. */
static void
objc_init_statics (void)
{
struct objc_list **cell = &uninitialized_statics;
struct objc_static_instances **statics_in_module;
objc_mutex_lock(__objc_runtime_mutex);
while (*cell)
{
int module_initialized = 1;
for (statics_in_module = (*cell)->head;
*statics_in_module; statics_in_module++)
{
struct objc_static_instances *statics = *statics_in_module;
Class class = objc_lookup_class (statics->class_name);
if (!class)
module_initialized = 0;
/* Actually, the static's class_pointer will be NULL when we
haven't been here before. However, the comparison is to be
reminded of taking into account class posing and to think about
possible semantics... */
else if (class != statics->instances[0]->class_pointer)
{
id *inst;
for (inst = &statics->instances[0]; *inst; inst++)
{
(*inst)->class_pointer = class;
/* ??? Make sure the object will not be freed. With
refcounting, invoke `-retain'. Without refcounting, do
nothing and hope that `-free' will never be invoked. */
/* ??? Send the object an `-initStatic' or something to
that effect now or later on? What are the semantics of
statically allocated instances, besides the trivial
NXConstantString, anyway? */
}
}
}
if (module_initialized)
{
/* Remove this module from the uninitialized list. */
struct objc_list *this = *cell;
*cell = this->tail;
objc_free(this);
}
else
cell = &(*cell)->tail;
}
objc_mutex_unlock(__objc_runtime_mutex);
} /* objc_init_statics */
/* This function is called by constructor functions generated for each
module compiled. (_GLOBAL_$I$...) The purpose of this function is to
gather the module pointers so that they may be processed by the
initialization routines as soon as possible */
void
__objc_exec_class (Module_t module)
{
/* Have we processed any constructors previously? This flag is used to
indicate that some global data structures need to be built. */
static BOOL previous_constructors = 0;
static struct objc_list* unclaimed_categories = 0;
/* The symbol table (defined in objc-api.h) generated by gcc */
Symtab_t symtab = module->symtab;
/* The statics in this module */
struct objc_static_instances **statics
= symtab->defs[symtab->cls_def_cnt + symtab->cat_def_cnt];
/* 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)
{
/* Initialize thread-safe system */
__objc_init_thread_system();
__objc_runtime_threads_alive = 1;
__objc_runtime_mutex = objc_mutex_allocate();
__objc_init_selector_tables();
__objc_init_class_tables();
__objc_init_dispatch_tables();
__objc_class_tree_list = list_cons (NULL, __objc_class_tree_list);
__objc_load_methods
= hash_new (128, (hash_func_type)hash_ptr, compare_ptrs);
previous_constructors = 1;
}
/* Save the module pointer for later processing. (not currently used) */
objc_mutex_lock(__objc_runtime_mutex);
__objc_module_list = list_cons(module, __objc_module_list);
/* Replace referenced selectors from names to SEL's. */
if (selectors)
{
for (i = 0; selectors[i].sel_id; ++i)
{
const char *name, *type;
name = (char*)selectors[i].sel_id;
type = (char*)selectors[i].sel_types;
/* Constructors are constant static data so we can safely store
pointers to them in the runtime structures. is_const == YES */
__sel_register_typed_name (name, type,
(struct objc_selector*)&(selectors[i]),
YES);
}
}
/* 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];
const char* superclass = (char*)class->super_class;
/* 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);
/* Initialize the subclass list to be NULL.
In some cases it isn't and this crashes the program. */
class->subclass_list = NULL;
/* 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);
/* Register the instance methods as class methods, this is
only done for root classes. */
__objc_register_instance_methods_to_class(class);
if (class->protocols)
__objc_init_protocols (class->protocols);
/* Check to see if the superclass is known in this point. If it's not
add the class to the unresolved_classes list. */
if (superclass && !objc_lookup_class (superclass))
unresolved_classes = list_cons (class, unresolved_classes);
}
/* 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);
}
/* Register the instance methods as class methods, this is
only done for root classes. */
__objc_register_instance_methods_to_class(class);
}
else
{
/* The object to which the category methods belong can't be found.
Save the information. */
unclaimed_categories = list_cons(category, unclaimed_categories);
}
}
if (statics)
uninitialized_statics = list_cons (statics, uninitialized_statics);
if (uninitialized_statics)
objc_init_statics ();
/* Scan the unclaimed category hash. Attempt to attach any unclaimed
categories to objects. */
for (cell = &unclaimed_categories;
*cell;
({ if (*cell) cell = &(*cell)->tail; }))
{
Category_t category = (*cell)->head;
Class class = objc_lookup_class (category->class_name);
if (class)
{
DEBUG_PRINTF ("attaching stored categories to object: %s\n",
class->name);
list_remove_head (cell);
if (category->instance_methods)
class_add_method_list (class, category->instance_methods);
if (category->class_methods)
class_add_method_list ((Class) class->class_pointer,
category->class_methods);
if (category->protocols)
{
__objc_init_protocols (category->protocols);
__objc_class_add_protocols (class, category->protocols);
}
/* Register the instance methods as class methods, this is
only done for root classes. */
__objc_register_instance_methods_to_class(class);
}
}
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;
}
objc_send_load ();
objc_mutex_unlock(__objc_runtime_mutex);
}
static void objc_send_load (void)
{
if (!__objc_module_list)
return;
/* Try to find out if all the classes loaded so far also have their
superclasses known to the runtime. We suppose that the objects that are
allocated in the +load method are in general of a class declared in the
same module. */
if (unresolved_classes)
{
Class class = unresolved_classes->head;
while (objc_lookup_class ((char*)class->super_class))
{
list_remove_head (&unresolved_classes);
if (unresolved_classes)
class = unresolved_classes->head;
else
break;
}
/*
* If we still have classes for whom we don't have yet their super
* classes known to the runtime we don't send the +load messages.
*/
if (unresolved_classes)
return;
}
/* Special check to allow creating and sending messages to constant strings
in +load methods. If these classes are not yet known, even if all the
other classes are known, delay sending of +load. */
if (!objc_lookup_class ("NXConstantString") ||
!objc_lookup_class ("Object"))
return;
/* Iterate over all modules in the __objc_module_list and call on them the
__objc_create_classes_tree function. This function creates a tree of
classes that resembles the class hierarchy. */
list_mapcar (__objc_module_list, (void(*)(void*))__objc_create_classes_tree);
while (__objc_class_tree_list)
{
#ifdef DEBUG
objc_preorder_traverse (__objc_class_tree_list->head,
0, __objc_tree_print);
#endif
objc_preorder_traverse (__objc_class_tree_list->head,
0, __objc_send_load);
objc_postorder_traverse (__objc_class_tree_list->head,
0, __objc_destroy_class_tree_node);
list_remove_head (&__objc_class_tree_list);
}
list_mapcar (__objc_module_list, (void(*)(void*))__objc_call_callback);
list_free (__objc_module_list);
__objc_module_list = NULL;
}
static void
__objc_create_classes_tree (Module_t module)
{
/* The runtime mutex is locked in this point */
Symtab_t symtab = module->symtab;
int i;
/* Iterate thru classes defined in this module and insert them in the classes
tree hierarchy. */
for (i = 0; i < symtab->cls_def_cnt; i++)
{
Class class = (Class) symtab->defs[i];
objc_tree_insert_class (class);
}
}
static void
__objc_call_callback (Module_t module)
{
/* The runtime mutex is locked in this point */
Symtab_t symtab = module->symtab;
int i;
/* Iterate thru classes defined in this module and call the callback for
each one. */
for (i = 0; i < symtab->cls_def_cnt; i++)
{
Class class = (Class) symtab->defs[i];
/* Call the _objc_load_callback for this class. */
if (_objc_load_callback)
_objc_load_callback(class, 0);
}
/* Call the _objc_load_callback for categories. Don't register the instance
methods as class methods for categories to root classes since they were
already added in the class. */
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 (_objc_load_callback)
_objc_load_callback(class, category);
}
}
/* 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)))
{
int code;
if(module->version > OBJC_VERSION)
code = OBJC_ERR_OBJC_VERSION;
else if (module->version < OBJC_VERSION)
code = OBJC_ERR_GCC_VERSION;
else
code = OBJC_ERR_MODULE_SIZE;
objc_error(nil, code, "Module %s version %d doesn't match runtime %d\n",
module->name, (int)module->version, OBJC_VERSION);
}
}
static void
__objc_init_protocols (struct objc_protocol_list* protos)
{
int i;
static Class proto_class = 0;
if (! protos)
return;
objc_mutex_lock(__objc_runtime_mutex);
if (!proto_class)
proto_class = objc_lookup_class("Protocol");
if (!proto_class)
{
unclaimed_proto_list = list_cons (protos, unclaimed_proto_list);
objc_mutex_unlock(__objc_runtime_mutex);
return;
}
#if 0
assert (protos->next == 0); /* only single ones allowed */
#endif
for(i = 0; i < protos->count; i++)
{
struct objc_protocol* aProto = protos->list[i];
if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION)
{
/* assign class pointer */
aProto->class_pointer = proto_class;
/* init super protocols */
__objc_init_protocols (aProto->protocol_list);
}
else if (protos->list[i]->class_pointer != proto_class)
{
objc_error(nil, OBJC_ERR_PROTOCOL_VERSION,
"Version %d doesn't match runtime protocol version %d\n",
(int)((char*)protos->list[i]->class_pointer-(char*)0),
PROTOCOL_VERSION);
}
}
objc_mutex_unlock(__objc_runtime_mutex);
}
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;
}

161
libobjc/libobjc.def Normal file
View File

@ -0,0 +1,161 @@
; GNU Objective C Runtime DLL Export Definitions
; Copyright (C) 1997 Free Software Foundation, Inc.
; Contributed by Scott Christley <scottc@net-community.com>
;
; This file is part of GNU CC.
;
; GNU CC is free software; you can redistribute it and/or modify it under the
; terms of the GNU General Public License as published by the Free Software
; Foundation; either version 2, or (at your option) any later version.
;
; GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
; details.
;
; You should have received a copy of the GNU General Public License along with
; GNU CC; see the file COPYING. If not, write to the Free Software
; Foundation, 59 Temple Place - Suite 330,
; Boston, MA 02111-1307, USA.
LIBRARY libobjc
EXPORTS
search_for_method_in_list
objc_get_uninstalled_dtable
hash_is_key_in_hash
objc_verror
_objc_load_callback
objc_malloc
objc_atomic_malloc
objc_valloc
objc_realloc
objc_calloc
objc_free
__objc_init_thread_system
objc_mutex_allocate
objc_mutex_deallocate
objc_mutex_lock
objc_mutex_trylock
objc_mutex_unlock
objc_thread_detach
objc_thread_exit
objc_thread_get_data
objc_thread_get_priority
objc_thread_id
objc_thread_set_data
objc_thread_set_priority
objc_thread_yield
__objc_class_name_Object
__objc_class_name_Protocol
__objc_class_name_NXConstantString
objc_error
__objc_object_alloc
__objc_object_copy
__objc_object_dispose
class_create_instance
object_copy
object_dispose
__objc_init_selector_tables
__objc_register_selectors_from_class
__sel_register_typed_name
sel_get_any_typed_uid
sel_get_any_uid
sel_get_name
sel_get_type
sel_get_typed_uid
sel_get_uid
sel_is_mapped
sel_register_name
sel_register_typed_name
sel_types_match
method_get_first_argument
method_get_next_argument
method_get_nth_argument
method_get_number_of_arguments
method_get_sizeof_arguments
objc_aligned_size
objc_alignof_type
objc_get_type_qualifiers
objc_promoted_size
objc_sizeof_type
objc_skip_argspec
objc_skip_offset
objc_skip_type_qualifiers
objc_skip_typespec
__objc_read_nbyte_uint
__objc_read_nbyte_ulong
__objc_write_class
__objc_write_object
__objc_write_selector
objc_close_typed_stream
objc_end_of_typed_stream
objc_flush_typed_stream
objc_get_stream_class_version
objc_open_typed_stream
objc_open_typed_stream_for_file
objc_read_array
objc_read_char
objc_read_int
objc_read_long
objc_read_object
objc_read_selector
objc_read_short
objc_read_string
objc_read_type
objc_read_types
objc_read_unsigned_char
objc_read_unsigned_int
objc_read_unsigned_long
objc_read_unsigned_short
objc_write_array
objc_write_char
objc_write_int
objc_write_long
objc_write_object
objc_write_object_reference
objc_write_root_object
objc_write_selector
objc_write_short
objc_write_string
objc_write_string_atomic
objc_write_type
objc_write_types
objc_write_unsigned_char
objc_write_unsigned_int
objc_write_unsigned_long
objc_write_unsigned_short
__objc_exec_class
__objc_init_dispatch_tables
__objc_install_premature_dtable
__objc_print_dtable_stats
__objc_responds_to
__objc_update_dispatch_table_for_class
class_add_method_list
class_get_class_method
class_get_instance_method
get_imp
nil_method
objc_msg_lookup
objc_msg_lookup_super
objc_msg_sendv
__objc_add_class_to_hash
__objc_init_class_tables
__objc_resolve_class_links
class_pose_as
objc_get_class
objc_get_meta_class
objc_lookup_class
objc_next_class
sarray_at_put
sarray_at_put_safe
sarray_free
sarray_lazy_copy
sarray_new
sarray_realloc
sarray_remove_garbage
hash_add
hash_delete
hash_new
hash_next
hash_remove
hash_value_for_key

55
libobjc/libobjc_entry.c Normal file
View File

@ -0,0 +1,55 @@
/* GNU Objective C Runtime DLL Entry
Copyright (C) 1997 Free Software Foundation, Inc.
Contributed by Scott Christley <scottc@net-community.com>
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <windows.h>
/*
DLL entry function for Objective-C Runtime library
This function gets called everytime a process/thread attaches to DLL
*/
WINBOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call,
LPVOID lpReserved)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
/*
This section terminates the list of imports under GCC. If you do not
include this then you will have problems when linking with DLLs.
*/
asm (".section .idata$3\n" ".long 0,0,0,0,0,0,0,0");

40
libobjc/linking.m Normal file
View File

@ -0,0 +1,40 @@
/* Force linking of classes required by Objective C runtime.
Copyright (C) 1997 Free Software Foundation, Inc.
Contributed by Ovidiu Predescu (ovidiu@net-community.com).
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <objc/Object.h>
#include <objc/NXConstStr.h>
/* Generate references to Object and NXConstanstString classes since they are
needed by the runtime system to run correctly. */
void __objc_linking (void)
{
[Object name];
[NXConstantString name];
}

56
libobjc/makefile.dos Normal file
View File

@ -0,0 +1,56 @@
# GNU Objective C Runtime Makefile for compiling with djgpp
# Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc.
#
# This file is part of GNU CC.
#
# GNU CC is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2, or (at your option) any later version.
#
# GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# GNU CC; see the file COPYING. If not, write to the Free Software
# Foundation, 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
# This Makefile is configured for GnuMAKE
GCC_FOR_TARGET=gcc
.SUFFIXES: .o .m
OPTIMIZE = -O2
# Always search these dirs when compiling.
SUBDIR_INCLUDES = -I. -I.. -I../config
.c.o:
$(GCC_FOR_TARGET) $(OPTIMIZE) \
-c $(GCC_CFLAGS) $(SUBDIR_INCLUDES) $<
.m.o:
$(GCC_FOR_TARGET) $(OPTIMIZE) -fgnu-runtime \
-c $(GCC_CFLAGS) $(SUBDIR_INCLUDES) $<
OBJC_O = hash.o sarray.o class.o sendmsg.o init.o archive.o \
selector.o objects.o misc.o object.o protocol.o encoding.o thread.o
libobjc.a: $(OBJC_O)
-rm -f libobjc.a
ar rc libobjc.a $(OBJC_O)
ranlib libobjc.a
OBJC_H = hash.h objc-list.h sarray.h objc.h \
objc-api.h \
object.h protocol.h mutex.h \
typedstream.h thread.h
mostlyclean:
-rm -f *.o libobjc.a xforward fflags
clean: mostlyclean
distclean: mostlyclean
extraclean: mostlyclean

180
libobjc/misc.c Normal file
View File

@ -0,0 +1,180 @@
/* GNU Objective C Runtime Miscellaneous
Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#define __USE_FIXED_PROTOTYPES__
#include <stdlib.h>
#include "runtime.h"
/*
** Error handler function
** NULL so that default is to just print to stderr
*/
static objc_error_handler _objc_error_handler = NULL;
/* Trigger an objc error */
void
objc_error(id object, int code, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
objc_verror(object, code, fmt, ap);
va_end(ap);
}
/* Trigger an objc error */
void
objc_verror(id object, int code, const char* fmt, va_list ap)
{
BOOL result = NO;
/* Call the error handler if its there
Otherwise print to stderr */
if (_objc_error_handler)
result = (*_objc_error_handler)(object, code, fmt, ap);
else
vfprintf (stderr, fmt, ap);
/* Continue if the error handler says its ok
Otherwise abort the program */
if (result)
return;
else
abort();
}
/* Set the error handler */
objc_error_handler
objc_set_error_handler(objc_error_handler func)
{
objc_error_handler temp = _objc_error_handler;
_objc_error_handler = func;
return temp;
}
/*
** Standard functions for memory allocation and disposal.
** Users should use these functions in their ObjC programs so
** that they work properly with garbage collectors as well as
** can take advantage of the exception/error handling available.
*/
void *
objc_malloc(size_t size)
{
void* res = (void*) (*_objc_malloc)(size);
if(!res)
objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
return res;
}
void *
objc_atomic_malloc(size_t size)
{
void* res = (void*) (*_objc_atomic_malloc)(size);
if(!res)
objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
return res;
}
void *
objc_valloc(size_t size)
{
void* res = (void*) (*_objc_valloc)(size);
if(!res)
objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
return res;
}
void *
objc_realloc(void *mem, size_t size)
{
void* res = (void*) (*_objc_realloc)(mem, size);
if(!res)
objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
return res;
}
void *
objc_calloc(size_t nelem, size_t size)
{
void* res = (void*) (*_objc_calloc)(nelem, size);
if(!res)
objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
return res;
}
void
objc_free(void *mem)
{
(*_objc_free)(mem);
}
/*
** Hook functions for memory allocation and disposal.
** This makes it easy to substitute garbage collection systems
** such as Boehm's GC by assigning these function pointers
** to the GC's allocation routines. By default these point
** to the ANSI standard malloc, realloc, free, etc.
**
** Users should call the normal objc routines above for
** memory allocation and disposal within their programs.
*/
#if OBJC_WITH_GC
#include <gc.h>
static void *GC_calloc (size_t nelem, size_t size)
{
void* p = GC_malloc (nelem * size);
if (!p)
objc_error (nil, OBJC_ERR_MEMORY, "Virtual memory exhausted!\n");
memset (p, 0, nelem * size);
return p;
}
static void noFree (void* p) {}
void *(*_objc_malloc)(size_t) = GC_malloc;
void *(*_objc_atomic_malloc)(size_t) = GC_malloc_atomic;
void *(*_objc_valloc)(size_t) = GC_malloc;
void *(*_objc_realloc)(void *, size_t) = GC_realloc;
void *(*_objc_calloc)(size_t, size_t) = GC_calloc;
void (*_objc_free)(void *) = noFree;
#else
void *(*_objc_malloc)(size_t) = malloc;
void *(*_objc_atomic_malloc)(size_t) = malloc;
void *(*_objc_valloc)(size_t) = malloc;
void *(*_objc_realloc)(void *, size_t) = realloc;
void *(*_objc_calloc)(size_t, size_t) = calloc;
void (*_objc_free)(void *) = free;
#endif

40
libobjc/nil_method.c Normal file
View File

@ -0,0 +1,40 @@
/* GNU Objective C Runtime nil receiver function
Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
/* This is the nil method, the function that is called when the receiver
of a method is nil */
#include "runtime.h"
id
nil_method(id receiver, SEL op, ...)
{
return receiver;
}

597
libobjc/objc-api.h Normal file
View File

@ -0,0 +1,597 @@
/* GNU Objective-C Runtime API.
Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled
with GCC to produce an executable, this does not cause the resulting
executable to be covered by the GNU General Public License. This
exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public License. */
#ifndef __objc_api_INCLUDE_GNU
#define __objc_api_INCLUDE_GNU
#include "objc/objc.h"
#include "objc/hash.h"
#include "objc/thr.h"
#include <stdio.h>
#include <stdarg.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_LNG_LNG 'q'
#define _C_ULNG_LNG 'Q'
#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 '}'
/*
** Error handling
**
** Call objc_error() or objc_verror() to record an error; this error
** routine will generally exit the program but not necessarily if the
** user has installed his own error handler.
**
** Call objc_set_error_handler to assign your own function for
** handling errors. The function should return YES if it is ok
** to continue execution, or return NO or just abort if the
** program should be stopped. The default error handler is just to
** print a message on stderr.
**
** The error handler function should be of type objc_error_handler
** The first parameter is an object instance of relevance.
** The second parameter is an error code.
** The third parameter is a format string in the printf style.
** The fourth parameter is a variable list of arguments.
*/
extern void objc_error(id object, int code, const char* fmt, ...);
extern void objc_verror(id object, int code, const char* fmt, va_list ap);
typedef BOOL (*objc_error_handler)(id, int code, const char *fmt, va_list ap);
objc_error_handler objc_set_error_handler(objc_error_handler func);
/*
** Error codes
** These are used by the runtime library, and your
** error handling may use them to determine if the error is
** hard or soft thus whether execution can continue or abort.
*/
#define OBJC_ERR_UNKNOWN 0 /* Generic error */
#define OBJC_ERR_OBJC_VERSION 1 /* Incorrect runtime version */
#define OBJC_ERR_GCC_VERSION 2 /* Incorrect compiler version */
#define OBJC_ERR_MODULE_SIZE 3 /* Bad module size */
#define OBJC_ERR_PROTOCOL_VERSION 4 /* Incorrect protocol version */
#define OBJC_ERR_MEMORY 10 /* Out of memory */
#define OBJC_ERR_RECURSE_ROOT 20 /* Attempt to archive the root
object more than once. */
#define OBJC_ERR_BAD_DATA 21 /* Didn't read expected data */
#define OBJC_ERR_BAD_KEY 22 /* Bad key for object */
#define OBJC_ERR_BAD_CLASS 23 /* Unknown class */
#define OBJC_ERR_BAD_TYPE 24 /* Bad type specification */
#define OBJC_ERR_NO_READ 25 /* Cannot read stream */
#define OBJC_ERR_NO_WRITE 26 /* Cannot write stream */
#define OBJC_ERR_STREAM_VERSION 27 /* Incorrect stream version */
#define OBJC_ERR_BAD_OPCODE 28 /* Bad opcode */
#define OBJC_ERR_UNIMPLEMENTED 30 /* Method is not implemented */
#define OBJC_ERR_BAD_STATE 40 /* Bad thread state */
/*
** Set this variable nonzero to print a line describing each
** message that is sent. (this is currently disabled)
*/
extern BOOL objc_trace;
/* For every class which happens to have statically allocated instances in
this module, one OBJC_STATIC_INSTANCES is allocated by the compiler.
INSTANCES is NULL terminated and points to all statically allocated
instances of this class. */
struct objc_static_instances
{
char *class_name;
id instances[0];
};
/*
** 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, followed
by a NULL terminated array
of objc_static_instances. */
} 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 its meta class object
*/
#define CLS_GETNUMBER(cls) (__CLS_INFO(cls) >> (HOST_BITS_PER_LONG/2))
#define CLS_SETNUMBER(cls, num) \
({ (cls)->info <<= (HOST_BITS_PER_LONG/2); \
(cls)->info >>= (HOST_BITS_PER_LONG/2); \
__CLS_SETINFO(cls, (((unsigned long)num) << (HOST_BITS_PER_LONG/2))); })
/*
** The compiler generates one of these structures for each category. A class
** may have many categories and contain both instance and factory methods.
*/
typedef struct objc_category {
const char* category_name; /* Name of the category. Name
contained in the () of the
category definition. */
const char* class_name; /* Name of the class to which
the category belongs. */
MethodList_t instance_methods; /* Linked list of instance
methods defined in the
category. NULL indicates no
instance methods defined. */
MethodList_t class_methods; /* Linked list of factory
methods defined in the
category. NULL indicates no
class methods defined. */
struct objc_protocol_list *protocols; /* List of Protocols
conformed to */
} Category, *Category_t;
/*
** Structure used when a message is send to a class's super class. The
** compiler generates one of these structures and passes it to
** objc_msg_super.
*/
typedef struct objc_super {
id self; /* Id of the object sending
the message. */
Class class; /* Object's super class. */
} Super, *Super_t;
IMP objc_msg_lookup_super(Super_t super, SEL sel);
retval_t objc_msg_sendv(id, SEL, arglist_t);
/*
** This is a hook which is called by objc_lookup_class and
** objc_get_class if the runtime is not able to find the class.
** This may e.g. try to load in the class using dynamic loading.
** The function is guaranteed to be passed a non-NULL name string.
*/
extern Class (*_objc_lookup_class)(const char *name);
/*
** This is a hook which is called by __objc_exec_class every time a class
** or a category is loaded into the runtime. This may e.g. help a
** dynamic loader determine the classes that have been loaded when
** an object file is dynamically linked in.
*/
extern void (*_objc_load_callback)(Class class, Category* category);
/*
** Hook functions for allocating, copying and disposing of instances
*/
extern id (*_objc_object_alloc)(Class class);
extern id (*_objc_object_copy)(id object);
extern id (*_objc_object_dispose)(id object);
/*
** Standard functions for memory allocation and disposal.
** Users should use these functions in their ObjC programs so
** that they work properly with garbage collectors as well as
** can take advantage of the exception/error handling available.
*/
void *
objc_malloc(size_t size);
void *
objc_atomic_malloc(size_t size);
void *
objc_valloc(size_t size);
void *
objc_realloc(void *mem, size_t size);
void *
objc_calloc(size_t nelem, size_t size);
void
objc_free(void *mem);
/*
** Hook functions for memory allocation and disposal.
** This makes it easy to substitute garbage collection systems
** such as Boehm's GC by assigning these function pointers
** to the GC's allocation routines. By default these point
** to the ANSI standard malloc, realloc, free, etc.
**
** Users should call the normal objc routines above for
** memory allocation and disposal within their programs.
*/
extern void *(*_objc_malloc)(size_t);
extern void *(*_objc_atomic_malloc)(size_t);
extern void *(*_objc_valloc)(size_t);
extern void *(*_objc_realloc)(void *, size_t);
extern void *(*_objc_calloc)(size_t, size_t);
extern void (*_objc_free)(void *);
Method_t class_get_class_method(MetaClass class, SEL aSel);
Method_t class_get_instance_method(Class class, SEL aSel);
Class class_pose_as(Class impostor, Class superclass);
Class objc_get_class(const char *name);
Class objc_lookup_class(const char *name);
Class objc_next_class(void **enum_state);
const char *sel_get_name(SEL selector);
const char *sel_get_type(SEL selector);
SEL sel_get_uid(const char *name);
SEL sel_get_any_uid(const char *name);
SEL sel_get_any_typed_uid(const char *name);
SEL sel_get_typed_uid(const char *name, const char*);
SEL sel_register_name(const char *name);
SEL sel_register_typed_name(const char *name, const char*type);
BOOL sel_is_mapped (SEL aSel);
extern id class_create_instance(Class class);
static inline const char *
class_get_class_name(Class class)
{
return CLS_ISCLASS(class)?class->name:((class==Nil)?"Nil":0);
}
static inline long
class_get_instance_size(Class class)
{
return CLS_ISCLASS(class)?class->instance_size:0;
}
static inline MetaClass
class_get_meta_class(Class class)
{
return CLS_ISCLASS(class)?class->class_pointer:Nil;
}
static inline Class
class_get_super_class(Class class)
{
return CLS_ISCLASS(class)?class->super_class:Nil;
}
static inline int
class_get_version(Class class)
{
return CLS_ISCLASS(class)?class->version:-1;
}
static inline BOOL
class_is_class(Class class)
{
return CLS_ISCLASS(class);
}
static inline BOOL
class_is_meta_class(Class class)
{
return CLS_ISMETA(class);
}
static inline void
class_set_version(Class class, long version)
{
if (CLS_ISCLASS(class))
class->version = version;
}
static inline void *
class_get_gc_object_type (Class class)
{
return CLS_ISCLASS(class) ? class->gc_object_type : NULL;
}
/* Mark the instance variable as innaccessible to the garbage collector */
extern void class_ivar_set_gcinvisible (Class class,
const char* ivarname,
BOOL gcInvisible);
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);
/* Redefine on NeXTSTEP so as not to conflict with system function */
#ifdef __NeXT__
#define object_copy gnu_object_copy
#define object_dispose gnu_object_dispose
#endif
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);
}
struct sarray*
objc_get_uninstalled_dtable(void);
#endif /* not __objc_api_INCLUDE_GNU */

147
libobjc/objc-list.h Normal file
View File

@ -0,0 +1,147 @@
/* Generic single linked list to keep various information
Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#ifndef __GNU_OBJC_LIST_H
#define __GNU_OBJC_LIST_H
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_malloc(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 */
objc_free(tail); /* free next */
}
else /* only one element in list */
{
objc_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);
objc_free(list);
}
}
#endif __GNU_OBJC_LIST_H

158
libobjc/objc.h Normal file
View File

@ -0,0 +1,158 @@
/* Basic data types for Objective C.
Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#ifndef __objc_INCLUDE_GNU
#define __objc_INCLUDE_GNU
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
/*
** Definition of the boolean type.
*/
#ifdef __vxworks
typedef int BOOL;
#else
typedef unsigned char BOOL;
#endif
#define YES (BOOL)1
#define NO (BOOL)0
/*
** Definition of a selector. Selectors themselves are not unique, but
** the sel_id is a unique identifier.
*/
typedef const struct objc_selector
{
void *sel_id;
const char *sel_types;
} *SEL;
inline static BOOL
sel_eq (SEL s1, SEL s2)
{
if (s1 == 0 || s2 == 0)
return s1 == s2;
else
return s1->sel_id == s2->sel_id;
}
/*
** ObjC uses this typedef for untyped instances.
*/
typedef struct objc_object {
struct objc_class* class_pointer;
} *id;
/*
** Definition of method type. When retrieving the implementation of a
** method, this is type of the pointer returned
*/
typedef id (*IMP)(id, SEL, ...);
/*
** More simple types...
*/
#define nil (id)0 /* id of Nil instance */
#define Nil (Class)0 /* id of Nil class */
typedef char *STR; /* String alias */
/*
** The compiler generates one of these structures for each class.
**
** This structure is the definition for classes.
**
** This structure is generated by the compiler in the executable and used by
** the run-time during normal messaging operations. Therefore some members
** change type. The compiler generates "char* const" and places a string in
** the following member variables: super_class.
*/
typedef struct objc_class *MetaClass;
typedef struct objc_class *Class;
struct objc_class {
MetaClass class_pointer; /* Pointer to the class's
meta class. */
struct objc_class* super_class; /* Pointer to the super
class. NULL for class
Object. */
const char* name; /* Name of the class. */
long version; /* Unknown. */
unsigned long info; /* Bit mask. See class masks
defined above. */
long instance_size; /* Size in bytes of the class.
The sum of the class
definition and all super
class definitions. */
struct objc_ivar_list* ivars; /* Pointer to a structure that
describes the instance
variables in the class
definition. NULL indicates
no instance variables. Does
not include super class
variables. */
struct objc_method_list* methods; /* Linked list of instance
methods defined for the
class. */
struct sarray * dtable; /* Pointer to instance
method dispatch table. */
struct objc_class* subclass_list; /* Subclasses */
struct objc_class* sibling_class;
struct objc_protocol_list *protocols; /* Protocols conformed to */
void* gc_object_type;
};
#ifndef __OBJC__
typedef struct objc_protocol {
struct objc_class* class_pointer;
char *protocol_name;
struct objc_protocol_list *protocol_list;
struct objc_method_description_list *instance_methods, *class_methods;
} Protocol;
#else /* __OBJC__ */
@class Protocol;
#endif
typedef void* retval_t; /* return value */
typedef void(*apply_t)(void); /* function pointer */
typedef union {
char *arg_ptr;
char arg_regs[sizeof (char*)];
} *arglist_t; /* argument frame */
IMP objc_msg_lookup(id receiver, SEL op);
#ifdef __cplusplus
}
#endif
#endif /* not __objc_INCLUDE_GNU */

105
libobjc/objects.c Normal file
View File

@ -0,0 +1,105 @@
/* GNU Objective C Runtime class related functions
Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include "../tconfig.h" /* include defs of bzero for target */
#include "objc.h"
#include "runtime.h" /* the kitchen sink */
#if OBJC_WITH_GC
# include <gc.h>
#endif
id __objc_object_alloc(Class);
id __objc_object_dispose(id);
id __objc_object_copy(id);
id (*_objc_object_alloc)(Class) = __objc_object_alloc; /* !T:SINGLE */
id (*_objc_object_dispose)(id) = __objc_object_dispose; /* !T:SINGLE */
id (*_objc_object_copy)(id) = __objc_object_copy; /* !T:SINGLE */
id
class_create_instance(Class class)
{
id new = nil;
#if OBJC_WITH_GC
if (CLS_ISCLASS(class))
new = (id)GC_malloc_explicitly_typed (class->instance_size,
class->gc_object_type);
#else
if (CLS_ISCLASS(class))
new = (*_objc_object_alloc)(class);
#endif
if (new!=nil)
{
memset (new, 0, class->instance_size);
new->class_pointer = class;
}
return new;
}
id
object_copy(id object)
{
if ((object!=nil)&&CLS_ISCLASS(object->class_pointer))
return (*_objc_object_copy)(object);
else
return nil;
}
id
object_dispose(id object)
{
if ((object!=nil)&&CLS_ISCLASS(object->class_pointer))
{
if (_objc_object_dispose)
(*_objc_object_dispose)(object);
else
objc_free(object);
}
return nil;
}
id __objc_object_alloc(Class class)
{
return (id)objc_malloc(class->instance_size);
}
id __objc_object_dispose(id object)
{
objc_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;
}

88
libobjc/runtime.h Normal file
View File

@ -0,0 +1,88 @@
/* GNU Objective C Runtime internal declarations
Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#ifndef __objc_runtime_INCLUDE_GNU
#define __objc_runtime_INCLUDE_GNU
#include <stdarg.h> /* for varargs and va_list's */
#include <stdio.h>
#include <ctype.h>
#include <stddef.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/thr.h" /* thread and mutex support */
#include "objc/hash.h" /* hash structures */
#include "objc/objc-list.h" /* linear lists */
extern void __objc_add_class_to_hash(Class); /* (objc-class.c) */
extern void __objc_init_selector_tables(void); /* (objc-sel.c) */
extern void __objc_init_class_tables(void); /* (objc-class.c) */
extern void __objc_init_dispatch_tables(void); /* (objc-dispatch.c) */
extern void __objc_install_premature_dtable(Class); /* (objc-dispatch.c) */
extern void __objc_resolve_class_links(void); /* (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 int __objc_init_thread_system(void); /* thread.c */
extern int __objc_fini_thread_system(void); /* thread.c */
extern void __objc_print_dtable_stats(void); /* sendmsg.c */
extern void class_add_method_list(Class, MethodList_t);
/* Registering instance methods as class methods for root classes */
extern void __objc_register_instance_methods_to_class(Class);
extern Method_t search_for_method_in_list(MethodList_t list, SEL op);
/* 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;
/* Mutex locking __objc_selector_max_index and its arrays. */
extern objc_mutex_t __objc_runtime_mutex;
/* Number of threads which are alive. */
extern int __objc_runtime_threads_alive;
#ifdef DEBUG
#define DEBUG_PRINTF(format, args...) printf (format, ## args)
#else
#define DEBUG_PRINTF(format, args...)
#endif
BOOL __objc_responds_to (id object, SEL sel); /* for internal use only! */
SEL __sel_register_typed_name (const char*, const char*,
struct objc_selector*, BOOL is_const);
#endif /* not __objc_runtime_INCLUDE_GNU */

522
libobjc/sarray.c Normal file
View File

@ -0,0 +1,522 @@
/* Sparse Arrays for Objective C dispatch tables
Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#include "objc/sarray.h"
#include "objc/runtime.h"
#include <stdio.h>
#include "assert.h"
int nbuckets = 0; /* !T:MUTEX */
int nindices = 0; /* !T:MUTEX */
int narrays = 0; /* !T:MUTEX */
int idxsize = 0; /* !T:MUTEX */
static void * first_free_data = NULL; /* !T:MUTEX */
#ifdef OBJC_SPARSE2
const char* __objc_sparse2_id = "2 level sparse indices";
#endif
#ifdef OBJC_SPARSE3
const char* __objc_sparse3_id = "3 level sparse indices";
#endif
#ifdef __alpha__
const void *memcpy (void*, const void*, size_t);
#endif
/* This function removes any structures left over from free operations
that were not safe in a multi-threaded environment. */
void
sarray_remove_garbage(void)
{
void **vp;
void *np;
objc_mutex_lock(__objc_runtime_mutex);
vp = first_free_data;
first_free_data = NULL;
while (vp) {
np = *vp;
objc_free(vp);
vp = np;
}
objc_mutex_unlock(__objc_runtime_mutex);
}
/* Free a block of dynamically allocated memory. If we are in multi-threaded
mode, it is ok to free it. If not, we add it to the garbage heap to be
freed later. */
static void
sarray_free_garbage(void *vp)
{
objc_mutex_lock(__objc_runtime_mutex);
if (__objc_runtime_threads_alive == 1) {
objc_free(vp);
if (first_free_data)
sarray_remove_garbage();
}
else {
*(void **)vp = first_free_data;
first_free_data = vp;
}
objc_mutex_unlock(__objc_runtime_mutex);
}
/* sarray_at_put : copies data in such a way as to be thread reader safe. */
void
sarray_at_put(struct sarray* array, sidx index, void* element)
{
#ifdef OBJC_SPARSE3
struct sindex** the_index;
struct sindex* new_index;
#endif
struct sbucket** the_bucket;
struct sbucket* new_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 */
new_index = (struct sindex*)objc_malloc(sizeof(struct sindex));
memcpy(new_index, array->empty_index, sizeof(struct sindex));
new_index->version.version = array->version.version;
*the_index = new_index; /* Prepared for install. */
the_bucket = &((*the_index)->buckets[boffset]);
nindices += 1;
} else if ((*the_index)->version.version != array->version.version) {
/* This index must be lazy copied */
struct sindex* old_index = *the_index;
new_index = (struct sindex*)objc_malloc(sizeof(struct sindex));
memcpy( new_index, old_index, sizeof(struct sindex));
new_index->version.version = array->version.version;
*the_index = new_index; /* Prepared for install. */
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 */
new_bucket = (struct sbucket*)objc_malloc(sizeof(struct sbucket));
memcpy((void *) new_bucket, (const void*)array->empty_bucket,
sizeof(struct sbucket));
new_bucket->version.version = array->version.version;
*the_bucket = new_bucket; /* Prepared for install. */
nbuckets += 1;
} else if ((*the_bucket)->version.version != array->version.version) {
/* Perform lazy copy. */
struct sbucket* old_bucket = *the_bucket;
new_bucket = (struct sbucket*)objc_malloc(sizeof(struct sbucket));
memcpy( new_bucket, old_bucket, sizeof(struct sbucket));
new_bucket->version.version = array->version.version;
*the_bucket = new_bucket; /* Prepared for install. */
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)
{
struct sarray* arr;
#ifdef OBJC_SPARSE3
size_t num_indices = ((size-1)/(INDEX_CAPACITY))+1;
struct sindex ** new_indices;
#else /* OBJC_SPARSE2 */
size_t num_indices = ((size-1)/BUCKET_SIZE)+1;
struct sbucket ** new_buckets;
#endif
int counter;
assert(size > 0);
/* Allocate core array */
arr = (struct sarray*) objc_malloc(sizeof(struct sarray));
arr->version.version = 0;
/* Initialize members */
#ifdef OBJC_SPARSE3
arr->capacity = num_indices*INDEX_CAPACITY;
new_indices = (struct sindex**)
objc_malloc(sizeof(struct sindex*)*num_indices);
arr->empty_index = (struct sindex*) objc_malloc(sizeof(struct sindex));
arr->empty_index->version.version = 0;
narrays += 1;
idxsize += num_indices;
nindices += 1;
#else /* OBJC_SPARSE2 */
arr->capacity = num_indices*BUCKET_SIZE;
new_buckets = (struct sbucket**)
objc_malloc(sizeof(struct sbucket*)*num_indices);
narrays += 1;
idxsize += num_indices;
#endif
arr->empty_bucket = (struct sbucket*) objc_malloc(sizeof(struct sbucket));
arr->empty_bucket->version.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++)
new_indices[counter] = arr->empty_index;
#else /* OBJC_SPARSE2 */
for (counter=0; counter<num_indices; counter++)
new_buckets[counter] = arr->empty_bucket;
#endif
#ifdef OBJC_SPARSE3
arr->indices = new_indices;
#else /* OBJC_SPARSE2 */
arr->buckets = new_buckets;
#endif
return arr;
}
/* Reallocate the sparse array to hold `newsize' entries
Note: We really allocate and then free. We have to do this to ensure that
any concurrent readers notice the update. */
void
sarray_realloc(struct sarray* array, int newsize)
{
#ifdef OBJC_SPARSE3
size_t old_max_index = (array->capacity-1)/INDEX_CAPACITY;
size_t new_max_index = ((newsize-1)/INDEX_CAPACITY);
size_t rounded_size = (new_max_index+1)*INDEX_CAPACITY;
struct sindex ** new_indices;
struct sindex ** old_indices;
#else /* OBJC_SPARSE2 */
size_t old_max_index = (array->capacity-1)/BUCKET_SIZE;
size_t new_max_index = ((newsize-1)/BUCKET_SIZE);
size_t rounded_size = (new_max_index+1)*BUCKET_SIZE;
struct sbucket ** new_buckets;
struct sbucket ** old_buckets;
#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... */
/* We are asked to extend the array -- allocate new bucket table, */
/* and insert empty_bucket in newly allocated places. */
if(rounded_size > array->capacity)
{
#ifdef OBJC_SPARSE3
new_max_index += 4;
rounded_size = (new_max_index+1)*INDEX_CAPACITY;
#else /* OBJC_SPARSE2 */
new_max_index += 4;
rounded_size = (new_max_index+1)*BUCKET_SIZE;
#endif
/* update capacity */
array->capacity = rounded_size;
#ifdef OBJC_SPARSE3
/* alloc to force re-read by any concurrent readers. */
old_indices = array->indices;
new_indices = (struct sindex**)
objc_malloc((new_max_index+1)*sizeof(struct sindex*));
#else /* OBJC_SPARSE2 */
old_buckets = array->buckets;
new_buckets = (struct sbucket**)
objc_malloc((new_max_index+1)*sizeof(struct sbucket*));
#endif
/* copy buckets below old_max_index (they are still valid) */
for(counter = 0; counter <= old_max_index; counter++ ) {
#ifdef OBJC_SPARSE3
new_indices[counter] = old_indices[counter];
#else /* OBJC_SPARSE2 */
new_buckets[counter] = old_buckets[counter];
#endif
}
#ifdef OBJC_SPARSE3
/* reset entries above old_max_index to empty_bucket */
for(counter = old_max_index+1; counter <= new_max_index; counter++)
new_indices[counter] = array->empty_index;
#else /* OBJC_SPARSE2 */
/* reset entries above old_max_index to empty_bucket */
for(counter = old_max_index+1; counter <= new_max_index; counter++)
new_buckets[counter] = array->empty_bucket;
#endif
#ifdef OBJC_SPARSE3
/* install the new indices */
array->indices = new_indices;
#else /* OBJC_SPARSE2 */
array->buckets = new_buckets;
#endif
#ifdef OBJC_SPARSE3
/* free the old indices */
sarray_free_garbage(old_indices);
#else /* OBJC_SPARSE2 */
sarray_free_garbage(old_buckets);
#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;
struct sindex ** old_indices;
#else
size_t old_max_index = (array->capacity-1)/BUCKET_SIZE;
struct sbucket ** old_buckets;
#endif
int counter = 0;
assert(array->ref_count != 0); /* Freed multiple times!!! */
if(--(array->ref_count) != 0) /* There exists copies of me */
return;
#ifdef OBJC_SPARSE3
old_indices = array->indices;
#else
old_buckets = array->buckets;
#endif
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 = old_indices[counter];
if((idx != array->empty_index) &&
(idx->version.version == array->version.version)) {
int c2;
for(c2=0; c2<INDEX_SIZE; c2++) {
struct sbucket* bkt = idx->buckets[c2];
if((bkt != array->empty_bucket) &&
(bkt->version.version == array->version.version))
{
sarray_free_garbage(bkt);
nbuckets -= 1;
}
}
sarray_free_garbage(idx);
nindices -= 1;
}
#else /* OBJC_SPARSE2 */
struct sbucket* bkt = array->buckets[counter];
if ((bkt != array->empty_bucket) &&
(bkt->version.version == array->version.version))
{
sarray_free_garbage(bkt);
nbuckets -= 1;
}
#endif
}
#ifdef OBJC_SPARSE3
/* free empty_index */
if(array->empty_index->version.version == array->version.version) {
sarray_free_garbage(array->empty_index);
nindices -= 1;
}
#endif
/* free empty_bucket */
if(array->empty_bucket->version.version == array->version.version) {
sarray_free_garbage(array->empty_bucket);
nbuckets -= 1;
}
idxsize -= (old_max_index+1);
narrays -= 1;
#ifdef OBJC_SPARSE3
/* free bucket table */
sarray_free_garbage(array->indices);
#else
/* free bucket table */
sarray_free_garbage(array->buckets);
#endif
/* free array */
sarray_free_garbage(array);
}
/* This is a lazy copy. Only the core of the structure is actually */
/* copied. */
struct sarray*
sarray_lazy_copy(struct sarray* oarr)
{
struct sarray* arr;
#ifdef OBJC_SPARSE3
size_t num_indices = ((oarr->capacity-1)/INDEX_CAPACITY)+1;
struct sindex ** new_indices;
#else /* OBJC_SPARSE2 */
size_t num_indices = ((oarr->capacity-1)/BUCKET_SIZE)+1;
struct sbucket ** new_buckets;
#endif
/* Allocate core array */
arr = (struct sarray*) objc_malloc(sizeof(struct sarray)); /* !!! */
arr->version.version = oarr->version.version + 1;
#ifdef OBJC_SPARSE3
arr->empty_index = oarr->empty_index;
#endif
arr->empty_bucket = oarr->empty_bucket;
arr->ref_count = 1;
oarr->ref_count += 1;
arr->is_copy_of = oarr;
arr->capacity = oarr->capacity;
#ifdef OBJC_SPARSE3
/* Copy bucket table */
new_indices = (struct sindex**)
objc_malloc(sizeof(struct sindex*)*num_indices);
memcpy( new_indices,oarr->indices,
sizeof(struct sindex*)*num_indices);
arr->indices = new_indices;
#else
/* Copy bucket table */
new_buckets = (struct sbucket**)
objc_malloc(sizeof(struct sbucket*)*num_indices);
memcpy( new_buckets,oarr->buckets,
sizeof(struct sbucket*)*num_indices);
arr->buckets = new_buckets;
#endif
idxsize += num_indices;
narrays += 1;
return arr;
}

237
libobjc/sarray.h Normal file
View File

@ -0,0 +1,237 @@
/* Sparse Arrays for Objective C dispatch tables
Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#ifndef __sarray_INCLUDE_GNU
#define __sarray_INCLUDE_GNU
#define OBJC_SPARSE2 /* 2-level sparse array */
/* #define OBJC_SPARSE3 */ /* 3-level sparse array */
#ifdef OBJC_SPARSE2
extern const char* __objc_sparse2_id;
#endif
#ifdef OBJC_SPARSE3
extern const char* __objc_sparse3_id;
#endif
#include <stddef.h>
#include "objc/thr.h"
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 */
union sversion {
int version;
void *next_free;
};
struct sbucket {
void* elems[BUCKET_SIZE]; /* elements stored in array */
union sversion version; /* used for copy-on-write */
};
#ifdef OBJC_SPARSE3
struct sindex {
struct sbucket* buckets[INDEX_SIZE];
union sversion version; /* used for copy-on-write */
};
#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;
union sversion version; /* used for copy-on-write */
short ref_count;
struct sarray* is_copy_of;
size_t capacity;
};
struct sarray* sarray_new(int, void* default_element);
void sarray_free(struct sarray*);
struct sarray* sarray_lazy_copy(struct sarray*);
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);
struct sarray* sarray_hard_copy(struct sarray*); /* ... like the name? */
void sarray_remove_garbage(void);
#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 */

458
libobjc/selector.c Normal file
View File

@ -0,0 +1,458 @@
/* GNU Objective C Runtime selector related functions
Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include "runtime.h"
#include "objc/sarray.h"
#include "encoding.h"
/* Initial selector hash table size. Value doesn't matter much */
#define SELECTOR_HASH_SIZE 128
/* Tables mapping selector names to uid and opposite */
static struct sarray* __objc_selector_array = 0; /* uid -> sel !T:MUTEX */
static struct sarray* __objc_selector_names = 0; /* uid -> name !T:MUTEX */
static cache_ptr __objc_selector_hash = 0; /* name -> uid !T:MUTEX */
static void register_selectors_from_list(MethodList_t);
/* Number of selectors stored in each of the above tables */
int __objc_selector_max_index = 0; /* !T:MUTEX */
void __objc_init_selector_tables()
{
__objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
__objc_selector_names = sarray_new (SELECTOR_HASH_SIZE, 0);
__objc_selector_hash
= hash_new (SELECTOR_HASH_SIZE,
(hash_func_type) hash_string,
(compare_func_type) compare_strings);
}
/* This routine is given a class and records all of the methods in its class
structure in the record table. */
void
__objc_register_selectors_from_class (Class class)
{
MethodList_t method_list;
method_list = class->methods;
while (method_list)
{
register_selectors_from_list (method_list);
method_list = method_list->method_next;
}
}
/* This routine is given a list of methods and records each of the methods in
the record table. This is the routine that does the actual recording
work.
This one is only called for Class objects. For categories,
class_add_method_list is called.
*/
static void
register_selectors_from_list (MethodList_t method_list)
{
int i = 0;
while (i < method_list->method_count)
{
Method_t method = &method_list->method_list[i];
method->method_name
= sel_register_typed_name ((const char*)method->method_name,
method->method_types);
i += 1;
}
}
/* Register instance methods as class methods for root classes */
void __objc_register_instance_methods_to_class(Class class)
{
MethodList_t method_list;
MethodList_t class_method_list;
int max_methods_no = 16;
MethodList_t new_list;
Method_t curr_method;
/* Only if a root class. */
if(class->super_class)
return;
/* Allocate a method list to hold the new class methods */
new_list = objc_calloc(sizeof(struct objc_method_list)
+ sizeof(struct objc_method[max_methods_no]), 1);
method_list = class->methods;
class_method_list = class->class_pointer->methods;
curr_method = &new_list->method_list[0];
/* Iterate through the method lists for the class */
while (method_list)
{
int i;
/* Iterate through the methods from this method list */
for (i = 0; i < method_list->method_count; i++)
{
Method_t mth = &method_list->method_list[i];
if (mth->method_name
&& !search_for_method_in_list (class_method_list,
mth->method_name))
{
/* This instance method isn't a class method.
Add it into the new_list. */
*curr_method = *mth;
/* Reallocate the method list if necessary */
if(++new_list->method_count == max_methods_no)
new_list =
objc_realloc(new_list, sizeof(struct objc_method_list)
+ sizeof(struct
objc_method[max_methods_no += 16]));
curr_method = &new_list->method_list[new_list->method_count];
}
}
method_list = method_list->method_next;
}
/* If we created any new class methods
then attach the method list to the class */
if (new_list->method_count)
{
new_list =
objc_realloc(new_list, sizeof(struct objc_method_list)
+ sizeof(struct objc_method[new_list->method_count]));
new_list->method_next = class->class_pointer->methods;
class->class_pointer->methods = new_list;
}
__objc_update_dispatch_table_for_class (class->class_pointer);
}
/* Returns YES iff t1 and t2 have same method types, but we ignore
the argframe layout */
BOOL
sel_types_match (const char* t1, const char* t2)
{
if (!t1 || !t2)
return NO;
while (*t1 && *t2)
{
if (*t1 == '+') t1++;
if (*t2 == '+') t2++;
while (isdigit(*t1)) t1++;
while (isdigit(*t2)) t2++;
/* xxx Remove these next two lines when qualifiers are put in
all selectors, not just Protocol selectors. */
t1 = objc_skip_type_qualifiers(t1);
t2 = objc_skip_type_qualifiers(t2);
if (!*t1 && !*t2)
return YES;
if (*t1 != *t2)
return NO;
t1++;
t2++;
}
return NO;
}
/* return selector representing name */
SEL
sel_get_typed_uid (const char *name, const char *types)
{
struct objc_list *l;
sidx i;
objc_mutex_lock(__objc_runtime_mutex);
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (i == 0)
{
objc_mutex_unlock(__objc_runtime_mutex);
return 0;
}
for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
l; l = l->tail)
{
SEL s = (SEL)l->head;
if (types == 0 || s->sel_types == 0)
{
if (s->sel_types == types)
{
objc_mutex_unlock(__objc_runtime_mutex);
return s;
}
}
else if (sel_types_match (s->sel_types, types))
{
objc_mutex_unlock(__objc_runtime_mutex);
return s;
}
}
objc_mutex_unlock(__objc_runtime_mutex);
return 0;
}
/* Return selector representing name; prefer a selector with non-NULL type */
SEL
sel_get_any_typed_uid (const char *name)
{
struct objc_list *l;
sidx i;
SEL s = NULL;
objc_mutex_lock(__objc_runtime_mutex);
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (i == 0)
{
objc_mutex_unlock(__objc_runtime_mutex);
return 0;
}
for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
l; l = l->tail)
{
s = (SEL) l->head;
if (s->sel_types)
{
objc_mutex_unlock(__objc_runtime_mutex);
return s;
}
}
objc_mutex_unlock(__objc_runtime_mutex);
return s;
}
/* return selector representing name */
SEL
sel_get_any_uid (const char *name)
{
struct objc_list *l;
sidx i;
objc_mutex_lock(__objc_runtime_mutex);
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (soffset_decode (i) == 0)
{
objc_mutex_unlock(__objc_runtime_mutex);
return 0;
}
l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
objc_mutex_unlock(__objc_runtime_mutex);
if (l == 0)
return 0;
return (SEL)l->head;
}
/* return selector representing name */
SEL
sel_get_uid (const char *name)
{
return sel_register_typed_name (name, 0);
}
/* Get name of selector. If selector is unknown, the empty string ""
is returned */
const char*
sel_get_name (SEL selector)
{
const char *ret;
objc_mutex_lock(__objc_runtime_mutex);
if ((soffset_decode((sidx)selector->sel_id) > 0)
&& (soffset_decode((sidx)selector->sel_id) <= __objc_selector_max_index))
ret = sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id);
else
ret = 0;
objc_mutex_unlock(__objc_runtime_mutex);
return ret;
}
BOOL
sel_is_mapped (SEL selector)
{
unsigned int idx = soffset_decode ((sidx)selector->sel_id);
return ((idx > 0) && (idx <= __objc_selector_max_index));
}
const char*
sel_get_type (SEL selector)
{
if (selector)
return selector->sel_types;
else
return 0;
}
/* The uninstalled dispatch table */
extern struct sarray* __objc_uninstalled_dtable;
/* Store the passed selector name in the selector record and return its
selector value (value returned by sel_get_uid).
Assumes that the calling function has locked down __objc_runtime_mutex. */
/* is_const parameter tells us if the name and types parameters
are really constant or not. If YES then they are constant and
we can just store the pointers. If NO then we need to copy
name and types because the pointers may disappear later on. */
SEL
__sel_register_typed_name (const char *name, const char *types,
struct objc_selector *orig, BOOL is_const)
{
struct objc_selector* j;
sidx i;
struct objc_list *l;
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (soffset_decode (i) != 0)
{
for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
l; l = l->tail)
{
SEL s = (SEL)l->head;
if (types == 0 || s->sel_types == 0)
{
if (s->sel_types == types)
{
if (orig)
{
orig->sel_id = (void*)i;
return orig;
}
else
return s;
}
}
else if (!strcmp (s->sel_types, types))
{
if (orig)
{
orig->sel_id = (void*)i;
return orig;
}
else
return s;
}
}
if (orig)
j = orig;
else
j = objc_malloc (sizeof (struct objc_selector));
j->sel_id = (void*)i;
/* Can we use the pointer or must copy types? Don't copy if NULL */
if ((is_const) || (types == 0))
j->sel_types = (const char*)types;
else {
j->sel_types = (char *) objc_malloc(strlen(types)+1);
strcpy((char *)j->sel_types, types);
}
l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
}
else
{
__objc_selector_max_index += 1;
i = soffset_encode(__objc_selector_max_index);
if (orig)
j = orig;
else
j = objc_malloc (sizeof (struct objc_selector));
j->sel_id = (void*)i;
/* Can we use the pointer or must copy types? Don't copy if NULL */
if ((is_const) || (types == 0))
j->sel_types = (const char*)types;
else {
j->sel_types = (char *) objc_malloc(strlen(types)+1);
strcpy((char *)j->sel_types, types);
}
l = 0;
}
DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types,
soffset_decode (i));
{
int is_new = (l == 0);
const char *new_name;
/* Can we use the pointer or must copy name? Don't copy if NULL */
if ((is_const) || (name == 0))
new_name = name;
else {
new_name = (char *) objc_malloc(strlen(name)+1);
strcpy((char *)new_name, name);
}
l = list_cons ((void*)j, l);
sarray_at_put_safe (__objc_selector_names, i, (void *) new_name);
sarray_at_put_safe (__objc_selector_array, i, (void *) l);
if (is_new)
hash_add (&__objc_selector_hash, (void *) new_name, (void *) i);
}
sarray_realloc(__objc_uninstalled_dtable, __objc_selector_max_index+1);
return (SEL) j;
}
SEL
sel_register_name (const char *name)
{
SEL ret;
objc_mutex_lock(__objc_runtime_mutex);
/* Assume that name is not constant static memory and needs to be
copied before put into a runtime structure. is_const == NO */
ret = __sel_register_typed_name (name, 0, 0, NO);
objc_mutex_unlock(__objc_runtime_mutex);
return ret;
}
SEL
sel_register_typed_name (const char *name, const char *type)
{
SEL ret;
objc_mutex_lock(__objc_runtime_mutex);
/* Assume that name and type are not constant static memory and need to
be copied before put into a runtime structure. is_const == NO */
ret = __sel_register_typed_name (name, type, 0, NO);
objc_mutex_unlock(__objc_runtime_mutex);
return ret;
}

648
libobjc/sendmsg.c Normal file
View File

@ -0,0 +1,648 @@
/* GNU Objective C Runtime message lookup
Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include "../tconfig.h"
#include "runtime.h"
#include "sarray.h"
#include "encoding.h"
#include "runtime-info.h"
/* this is how we hack STRUCT_VALUE to be 1 or 0 */
#define gen_rtx(args...) 1
#define gen_rtx_MEM(args...) 1
#define rtx int
#if !defined(STRUCT_VALUE) || STRUCT_VALUE == 0
#define INVISIBLE_STRUCT_RETURN 1
#else
#define INVISIBLE_STRUCT_RETURN 0
#endif
/* The uninstalled dispatch table */
struct sarray* __objc_uninstalled_dtable = 0; /* !T:MUTEX */
/* 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);
/* Various forwarding functions that are used based upon the
return type for the selector.
__objc_block_forward for structures.
__objc_double_forward for floats/doubles.
__objc_word_forward for pointers or types that fit in registers.
*/
static double __objc_double_forward(id, SEL, ...);
static id __objc_word_forward(id, SEL, ...);
typedef struct { id many[8]; } __big;
#if INVISIBLE_STRUCT_RETURN
static __big
#else
static id
#endif
__objc_block_forward(id, SEL, ...);
static Method_t search_for_method_in_hierarchy (Class class, SEL sel);
Method_t search_for_method_in_list(MethodList_t list, SEL op);
id nil_method(id, SEL, ...);
/* Given a selector, return the proper forwarding implementation. */
__inline__
IMP
__objc_get_forward_imp (SEL sel)
{
const char *t = sel->sel_types;
if (t && (*t == '[' || *t == '(' || *t == '{')
#ifdef OBJC_MAX_STRUCT_BY_VALUE
&& objc_sizeof_type(t) > OBJC_MAX_STRUCT_BY_VALUE
#endif
)
return (IMP)__objc_block_forward;
else if (t && (*t == 'f' || *t == 'd'))
return (IMP)__objc_double_forward;
else
return (IMP)__objc_word_forward;
}
/* Given a class and selector, return the selector's implementation. */
__inline__
IMP
get_imp (Class class, SEL sel)
{
void* res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
if (res == 0)
{
/* Not a valid method */
if(class->dtable == __objc_uninstalled_dtable)
{
/* The dispatch table needs to be installed. */
objc_mutex_lock(__objc_runtime_mutex);
__objc_install_dispatch_table_for_class (class);
objc_mutex_unlock(__objc_runtime_mutex);
/* Call ourselves with the installed dispatch table
and get the real method */
res = get_imp(class, sel);
}
else
{
/* The dispatch table has been installed so the
method just doesn't exist for the class.
Return the forwarding implementation. */
res = __objc_get_forward_imp(sel);
}
}
return res;
}
/* Query if an object can respond to a selector, returns YES if the
object implements the selector otherwise NO. Does not check if the
method can be forwarded. */
__inline__
BOOL
__objc_responds_to (id object, SEL sel)
{
void* res;
/* Install dispatch table if need be */
if (object->class_pointer->dtable == __objc_uninstalled_dtable)
{
objc_mutex_lock(__objc_runtime_mutex);
__objc_install_dispatch_table_for_class (object->class_pointer);
objc_mutex_unlock(__objc_runtime_mutex);
}
/* Get the method from the dispatch table */
res = sarray_get_safe (object->class_pointer->dtable, (size_t) sel->sel_id);
return (res != 0);
}
/* This is the lookup function. All entries in the table are either a
valid method *or* zero. If zero then either the dispatch table
needs to be installed or it doesn't exist and forwarding is attempted. */
__inline__
IMP
objc_msg_lookup(id receiver, SEL op)
{
IMP result;
if(receiver)
{
result = sarray_get_safe (receiver->class_pointer->dtable,
(sidx)op->sel_id);
if (result == 0)
{
/* Not a valid method */
if(receiver->class_pointer->dtable == __objc_uninstalled_dtable)
{
/* The dispatch table needs to be installed.
This happens on the very first method call to the class. */
__objc_init_install_dtable(receiver, op);
/* Get real method for this in newly installed dtable */
result = get_imp(receiver->class_pointer, op);
}
else
{
/* The dispatch table has been installed so the
method just doesn't exist for the class.
Attempt to forward the method. */
result = __objc_get_forward_imp(op);
}
}
return result;
}
else
return nil_method;
}
IMP
objc_msg_lookup_super (Super_t super, SEL sel)
{
if (super->self)
return get_imp (super->class, sel);
else
return nil_method;
}
int method_get_sizeof_arguments (Method*);
retval_t
objc_msg_sendv(id object, SEL op, arglist_t arg_frame)
{
Method* m = class_get_instance_method(object->class_pointer, op);
const char *type;
*((id*)method_get_first_argument (m, arg_frame, &type)) = object;
*((SEL*)method_get_next_argument (arg_frame, &type)) = op;
return __builtin_apply((apply_t)m->method_imp,
arg_frame,
method_get_sizeof_arguments (m));
}
void
__objc_init_dispatch_tables()
{
__objc_uninstalled_dtable
= sarray_new(200, 0);
}
/* This function is called by objc_msg_lookup when the
dispatch table needs to be installed; thus it is called once
for each class, namely when the very first message is sent to it. */
static void
__objc_init_install_dtable(id receiver, SEL op)
{
/* 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)
return;
objc_mutex_lock(__objc_runtime_mutex);
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);
__objc_send_initialize((Class)receiver);
}
objc_mutex_unlock(__objc_runtime_mutex);
}
/* Install dummy table for class which causes the first message to
that class (or instances hereof) to be initialized properly */
void
__objc_install_premature_dtable(Class class)
{
assert(__objc_uninstalled_dtable);
class->dtable = __objc_uninstalled_dtable;
}
/* Send +initialize to class if not already done */
static void
__objc_send_initialize(Class class)
{
/* This *must* be a class object */
assert(CLS_ISCLASS(class));
assert(!CLS_ISMETA(class));
if (!CLS_ISINITIALIZED(class))
{
CLS_SETINITIALIZED(class);
CLS_SETINITIALIZED(class->class_pointer);
/* Create the garbage collector type memory description */
__objc_generate_gc_type_description (class);
if(class->super_class)
__objc_send_initialize(class->super_class);
{
SEL op = sel_register_name ("initialize");
IMP imp = 0;
MethodList_t method_list = class->class_pointer->methods;
while (method_list) {
int i;
Method_t method;
for (i = 0; i< method_list->method_count; i++) {
method = &(method_list->method_list[i]);
if (method->method_name
&& method->method_name->sel_id == op->sel_id) {
imp = method->method_imp;
break;
}
}
if (imp)
break;
method_list = method_list->method_next;
}
if (imp)
(*imp)((id)class, op);
}
}
}
/* Walk on the methods list of class and install the methods in the reverse
order of the lists. Since methods added by categories are before the methods
of class in the methods list, this allows categories to substitute methods
declared in class. However if more than one category replaces the same
method nothing is guaranteed about what method will be used.
Assumes that __objc_runtime_mutex is locked down. */
static void
__objc_install_methods_in_dtable (Class class, MethodList_t method_list)
{
int i;
if (!method_list)
return;
if (method_list->method_next)
__objc_install_methods_in_dtable (class, method_list->method_next);
for (i = 0; i < method_list->method_count; i++)
{
Method_t method = &(method_list->method_list[i]);
sarray_at_put_safe (class->dtable,
(sidx) method->method_name->sel_id,
method->method_imp);
}
}
/* Assumes that __objc_runtime_mutex is locked down. */
static void
__objc_install_dispatch_table_for_class (Class class)
{
Class super;
/* If the class has not yet had its class links resolved, we must
re-compute all class links */
if(!CLS_ISRESOLV(class))
__objc_resolve_class_links();
super = class->super_class;
if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
__objc_install_dispatch_table_for_class (super);
/* Allocate dtable if necessary */
if (super == 0)
{
objc_mutex_lock(__objc_runtime_mutex);
class->dtable = sarray_new (__objc_selector_max_index, 0);
objc_mutex_unlock(__objc_runtime_mutex);
}
else
class->dtable = sarray_lazy_copy (super->dtable);
__objc_install_methods_in_dtable (class, class->methods);
}
void
__objc_update_dispatch_table_for_class (Class class)
{
Class next;
struct sarray *arr;
/* not yet installed -- skip it */
if (class->dtable == __objc_uninstalled_dtable)
return;
objc_mutex_lock(__objc_runtime_mutex);
arr = class->dtable;
__objc_install_premature_dtable (class); /* someone might require it... */
sarray_free (arr); /* release memory */
/* could have been lazy... */
__objc_install_dispatch_table_for_class (class);
if (class->subclass_list) /* Traverse subclasses */
for (next = class->subclass_list; next; next = next->sibling_class)
__objc_update_dispatch_table_for_class (next);
objc_mutex_unlock(__objc_runtime_mutex);
}
/* 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 issues.
This one is only called for categories. Class objects have their
methods installed right away, and their selectors are made into
SEL's by the function __objc_register_selectors_from_class. */
void
class_add_method_list (Class class, MethodList_t list)
{
int i;
/* Passing of a linked list is not allowed. Do multiple calls. */
assert (!list->method_next);
/* Check for duplicates. */
for (i = 0; i < list->method_count; ++i)
{
Method_t method = &list->method_list[i];
if (method->method_name) /* Sometimes these are NULL */
{
/* This is where selector names are transmogrified to SEL's */
method->method_name =
sel_register_typed_name ((const char*)method->method_name,
method->method_types);
}
}
/* Add the methods to the class's method list. */
list->method_next = class->methods;
class->methods = list;
/* Update the dispatch table of class */
__objc_update_dispatch_table_for_class (class);
}
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. */
Method_t
search_for_method_in_list (MethodList_t list, SEL op)
{
MethodList_t method_list = list;
if (! sel_is_mapped (op))
return NULL;
/* If not found then we'll search the list. */
while (method_list)
{
int i;
/* Search the method list. */
for (i = 0; i < method_list->method_count; ++i)
{
Method_t method = &method_list->method_list[i];
if (method->method_name)
if (method->method_name->sel_id == op->sel_id)
return method;
}
/* The method wasn't found. Follow the link to the next list of
methods. */
method_list = method_list->method_next;
}
return NULL;
}
static retval_t __objc_forward (id object, SEL sel, arglist_t args);
/* Forwarding pointers/integers through the normal registers */
static id
__objc_word_forward (id rcv, SEL op, ...)
{
void *args, *res;
args = __builtin_apply_args ();
res = __objc_forward (rcv, op, args);
if (res)
__builtin_return (res);
else
return res;
}
/* Specific routine for forwarding floats/double because of
architectural differences on some processors. i386s for
example which uses a floating point stack versus general
registers for floating point numbers. This forward routine
makes sure that GCC restores the proper return values */
static double
__objc_double_forward (id rcv, SEL op, ...)
{
void *args, *res;
args = __builtin_apply_args ();
res = __objc_forward (rcv, op, args);
__builtin_return (res);
}
#if INVISIBLE_STRUCT_RETURN
static __big
#else
static id
#endif
__objc_block_forward (id rcv, SEL op, ...)
{
void *args, *res;
args = __builtin_apply_args ();
res = __objc_forward (rcv, op, args);
if (res)
__builtin_return (res);
else
#if INVISIBLE_STRUCT_RETURN
return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
#else
return nil;
#endif
}
/* This function is installed in the dispatch table for all methods which are
not implemented. Thus, it is called when a selector is not recognized. */
static retval_t
__objc_forward (id object, SEL sel, arglist_t args)
{
IMP imp;
static SEL frwd_sel = 0; /* !T:SAFE2 */
SEL err_sel;
/* first try if the object understands forward:: */
if (!frwd_sel)
frwd_sel = sel_get_any_uid("forward::");
if (__objc_responds_to (object, frwd_sel))
{
imp = get_imp(object->class_pointer, frwd_sel);
return (*imp)(object, frwd_sel, sel, args);
}
/* If the object recognizes the doesNotRecognize: method then we're going
to send it. */
err_sel = sel_get_any_uid ("doesNotRecognize:");
if (__objc_responds_to (object, err_sel))
{
imp = get_imp (object->class_pointer, err_sel);
return (*imp) (object, err_sel, sel);
}
/* The object doesn't recognize the method. Check for responding to
error:. If it does then sent it. */
{
size_t strlen (const char*);
char msg[256 + strlen ((const char*)sel_get_name (sel))
+ strlen ((const char*)object->class_pointer->name)];
sprintf (msg, "(%s) %s does not recognize %s",
(CLS_ISMETA(object->class_pointer)
? "class"
: "instance" ),
object->class_pointer->name, sel_get_name (sel));
err_sel = sel_get_any_uid ("error:");
if (__objc_responds_to (object, err_sel))
{
imp = get_imp (object->class_pointer, err_sel);
return (*imp) (object, sel_get_any_uid ("error:"), msg);
}
/* The object doesn't respond to doesNotRecognize: or error:; Therefore,
a default action is taken. */
objc_error (object, OBJC_ERR_UNIMPLEMENTED, "%s\n", msg);
return 0;
}
}
void
__objc_print_dtable_stats()
{
int total = 0;
objc_mutex_lock(__objc_runtime_mutex);
printf("memory usage: (%s)\n",
#ifdef OBJC_SPARSE2
"2-level sparse arrays"
#else
"3-level sparse arrays"
#endif
);
printf("arrays: %d = %ld bytes\n", narrays,
(long)narrays*sizeof(struct sarray));
total += narrays*sizeof(struct sarray);
printf("buckets: %d = %ld bytes\n", nbuckets,
(long)nbuckets*sizeof(struct sbucket));
total += nbuckets*sizeof(struct sbucket);
printf("idxtables: %d = %ld bytes\n", idxsize, (long)idxsize*sizeof(void*));
total += idxsize*sizeof(void*);
printf("-----------------------------------\n");
printf("total: %d bytes\n", total);
printf("===================================\n");
objc_mutex_unlock(__objc_runtime_mutex);
}
/* Returns the uninstalled dispatch table indicator.
If a class' dispatch table points to __objc_uninstalled_dtable
then that means it needs its dispatch table to be installed. */
__inline__
struct sarray*
objc_get_uninstalled_dtable()
{
return __objc_uninstalled_dtable;
}

281
libobjc/thr-dce.c Normal file
View File

@ -0,0 +1,281 @@
/* GNU Objective C Runtime Thread Interface
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <pthread.h>
#include <objc/thr.h>
#include "runtime.h"
/* Key structure for maintaining thread specific storage */
static pthread_key_t _objc_thread_storage;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system(void)
{
/* Initialize the thread storage key */
return pthread_keycreate(&_objc_thread_storage, NULL);
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
/* Destroy the thread storage key */
/* Not implemented yet */
/* return pthread_key_delete(&_objc_thread_storage); */
return 0;
}
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
__objc_thread_detach(void (*func)(void *arg), void *arg)
{
objc_thread_t thread_id;
pthread_t new_thread_handle;
if (pthread_create(&new_thread_handle, pthread_attr_default,
(void *)func, arg) == 0)
{
/* ??? May not work! (64bit) */
thread_id = *(objc_thread_t *)&new_thread_handle;
pthread_detach(&new_thread_handle); /* Fully detach thread. */
}
else
thread_id = NULL;
return thread_id;
}
/* Set the current thread's priority. */
int
__objc_thread_set_priority(int priority)
{
int sys_priority = 0;
switch (priority)
{
case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_priority = (PRI_FG_MIN_NP + PRI_FG_MAX_NP) / 2;
break;
default:
case OBJC_THREAD_BACKGROUND_PRIORITY:
sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
break;
case OBJC_THREAD_LOW_PRIORITY:
sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
break;
}
/* Change the priority. */
if (pthread_setprio(pthread_self(), sys_priority) >= 0)
return 0;
else
/* Failed */
return -1;
}
/* Return the current thread's priority. */
int
__objc_thread_get_priority(void)
{
int sys_priority;
if ((sys_priority = pthread_getprio(pthread_self())) >= 0) {
if (sys_priority >= PRI_FG_MIN_NP && sys_priority <= PRI_FG_MAX_NP)
return OBJC_THREAD_INTERACTIVE_PRIORITY;
if (sys_priority >= PRI_BG_MIN_NP && sys_priority <= PRI_BG_MAX_NP)
return OBJC_THREAD_BACKGROUND_PRIORITY;
return OBJC_THREAD_LOW_PRIORITY;
}
/* Failed */
return -1;
}
/* Yield our process time to another thread. */
void
__objc_thread_yield(void)
{
pthread_yield();
}
/* Terminate the current thread. */
int
__objc_thread_exit(void)
{
/* exit the thread */
pthread_exit(&__objc_thread_exit_status);
/* Failed if we reached here */
return -1;
}
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
__objc_thread_id(void)
{
pthread_t self = pthread_self();
return (objc_thread_t) pthread_getunique_np (&self);
}
/* Sets the thread's local storage pointer. */
int
__objc_thread_set_data(void *value)
{
return pthread_setspecific(_objc_thread_storage, value);
}
/* Returns the thread's local storage pointer. */
void *
__objc_thread_get_data(void)
{
void *value = NULL;
if ( !(pthread_getspecific(_objc_thread_storage, &value)) )
return value;
return NULL;
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
if (pthread_mutex_init((pthread_mutex_t *)(&(mutex->backend)),
pthread_mutexattr_default))
return -1;
else
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
if (pthread_mutex_destroy((pthread_mutex_t *)(&(mutex->backend))))
return -1;
else
return 0;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
return pthread_mutex_lock((pthread_mutex_t *)(&(mutex->backend)));
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock(objc_mutex_t mutex)
{
if (pthread_mutex_trylock((pthread_mutex_t *)(&(mutex->backend))) != 1)
return -1;
else
return 0;
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
return pthread_mutex_unlock((pthread_mutex_t *)(&(mutex->backend)));
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
/*
if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL))
return -1;
else
return 0;
*/
}
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
/*
return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend)));
*/
}
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
/* Unimplemented. */
return -1;
/*
return pthread_cond_wait((pthread_cond_t *)(&(condition->backend)),
(pthread_mutex_t *)(&(mutex->backend)));
*/
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
/*
return pthread_cond_broadcast((pthread_cond_t *)(&(condition->backend)));
*/
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
/*
return pthread_cond_signal((pthread_cond_t *)(&(condition->backend)));
*/
}
/* End of File */

281
libobjc/thr-decosf1.c Normal file
View File

@ -0,0 +1,281 @@
/* GNU Objective C Runtime Thread Interface
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <pthread.h>
#include <objc/thr.h>
#include "runtime.h"
/* Key structure for maintaining thread specific storage */
static pthread_key_t _objc_thread_storage;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system(void)
{
/* Initialize the thread storage key */
return pthread_keycreate(&_objc_thread_storage, NULL);
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
/* Destroy the thread storage key */
/* Not implemented yet */
/* return pthread_key_delete(&_objc_thread_storage); */
return 0;
}
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
__objc_thread_detach(void (*func)(void *arg), void *arg)
{
objc_thread_t thread_id;
pthread_t new_thread_handle;
if (pthread_create(&new_thread_handle, pthread_attr_default,
(void *)func, arg) == 0)
{
/* ??? May not work! (64bit) */
thread_id = *(objc_thread_t *)&new_thread_handle;
pthread_detach(&new_thread_handle); /* Fully detach thread. */
}
else
thread_id = NULL;
return thread_id;
}
/* Set the current thread's priority. */
int
__objc_thread_set_priority(int priority)
{
int sys_priority = 0;
switch (priority)
{
case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_priority = (PRI_FG_MIN_NP + PRI_FG_MAX_NP) / 2;
break;
default:
case OBJC_THREAD_BACKGROUND_PRIORITY:
sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
break;
case OBJC_THREAD_LOW_PRIORITY:
sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
break;
}
/* Change the priority. */
if (pthread_setprio(pthread_self(), sys_priority) >= 0)
return 0;
else
/* Failed */
return -1;
}
/* Return the current thread's priority. */
int
__objc_thread_get_priority(void)
{
int sys_priority;
if ((sys_priority = pthread_getprio(pthread_self())) >= 0) {
if (sys_priority >= PRI_FG_MIN_NP && sys_priority <= PRI_FG_MAX_NP)
return OBJC_THREAD_INTERACTIVE_PRIORITY;
if (sys_priority >= PRI_BG_MIN_NP && sys_priority <= PRI_BG_MAX_NP)
return OBJC_THREAD_BACKGROUND_PRIORITY;
return OBJC_THREAD_LOW_PRIORITY;
}
/* Failed */
return -1;
}
/* Yield our process time to another thread. */
void
__objc_thread_yield(void)
{
pthread_yield();
}
/* Terminate the current thread. */
int
__objc_thread_exit(void)
{
/* exit the thread */
pthread_exit(&__objc_thread_exit_status);
/* Failed if we reached here */
return -1;
}
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
__objc_thread_id(void)
{
pthread_t self = pthread_self();
return (objc_thread_t) pthread_getunique_np (&self);
}
/* Sets the thread's local storage pointer. */
int
__objc_thread_set_data(void *value)
{
return pthread_setspecific(_objc_thread_storage, value);
}
/* Returns the thread's local storage pointer. */
void *
__objc_thread_get_data(void)
{
void *value = NULL;
if ( !(pthread_getspecific(_objc_thread_storage, &value)) )
return value;
return NULL;
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
if (pthread_mutex_init((pthread_mutex_t *)(&(mutex->backend)),
pthread_mutexattr_default))
return -1;
else
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
if (pthread_mutex_destroy((pthread_mutex_t *)(&(mutex->backend))))
return -1;
else
return 0;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
return pthread_mutex_lock((pthread_mutex_t *)(&(mutex->backend)));
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock(objc_mutex_t mutex)
{
if (pthread_mutex_trylock((pthread_mutex_t *)(&(mutex->backend))) != 1)
return -1;
else
return 0;
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
return pthread_mutex_unlock((pthread_mutex_t *)(&(mutex->backend)));
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
/*
if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL))
return -1;
else
return 0;
*/
}
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
/*
return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend)));
*/
}
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
/* Unimplemented. */
return -1;
/*
return pthread_cond_wait((pthread_cond_t *)(&(condition->backend)),
(pthread_mutex_t *)(&(mutex->backend)));
*/
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
/*
return pthread_cond_broadcast((pthread_cond_t *)(&(condition->backend)));
*/
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
/*
return pthread_cond_signal((pthread_cond_t *)(&(condition->backend)));
*/
}
/* End of File */

235
libobjc/thr-irix.c Normal file
View File

@ -0,0 +1,235 @@
/* GNU Objective C Runtime Thread Interface - SGI IRIX Implementation
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <stdlib.h>
#include <sys/types.h>
#include <sys/sysmp.h>
#include <sys/prctl.h>
#include <ulocks.h>
#include <objc/thr.h>
#include "runtime.h"
/* Key structure for maintaining thread specific storage */
static void * __objc_shared_arena_handle = NULL;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system(void)
{
/* Name of IRIX arena. */
char arena_name[64];
DEBUG_PRINTF("__objc_init_thread_system\n");
/* Construct a temporary name for arena. */
sprintf(arena_name, "/usr/tmp/objc_%05u", (unsigned)getpid());
/* Up to 256 threads. Arena only for threads. */
usconfig(CONF_INITUSERS, 256);
usconfig(CONF_ARENATYPE, US_SHAREDONLY);
/* Initialize the arena */
if (!(__objc_shared_arena_handle = usinit(arena_name)))
/* Failed */
return -1;
return 0;
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
return 0;
}
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
__objc_thread_detach(void (*func)(void *arg), void *arg)
{
objc_thread_t thread_id;
int sys_id;
if ((sys_id = sproc((void *)func, PR_SALL, arg)) >= 0)
thread_id = (objc_thread_t)sys_id;
else
thread_id = NULL;
return thread_id;
}
/* Set the current thread's priority. */
int
__objc_thread_set_priority(int priority)
{
/* Not implemented yet */
return -1;
}
/* Return the current thread's priority. */
int
__objc_thread_get_priority(void)
{
/* Not implemented yet */
return OBJC_THREAD_INTERACTIVE_PRIORITY;
}
/* Yield our process time to another thread. */
void
__objc_thread_yield(void)
{
sginap(0);
}
/* Terminate the current thread. */
int
__objc_thread_exit(void)
{
/* IRIX only has exit. */
exit(__objc_thread_exit_status);
/* Failed if we reached here */
return -1;
}
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
__objc_thread_id(void)
{
/* Threads are processes. */
return (objc_thread_t)get_pid();
}
/* Sets the thread's local storage pointer. */
int
__objc_thread_set_data(void *value)
{
*((void **)&PRDA->usr_prda) = value;
return 0;
}
/* Returns the thread's local storage pointer. */
void *
__objc_thread_get_data(void)
{
return *((void **)&PRDA->usr_prda);
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
if (!( (ulock_t)(mutex->backend) = usnewlock(__objc_shared_arena_handle) ))
return -1;
else
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
usfreelock((ulock_t)(mutex->backend), __objc_shared_arena_handle);
return 0;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
if (ussetlock((ulock_t)(mutex->backend)) == 0)
return -1;
else
return 0;
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock(objc_mutex_t mutex)
{
if (ustestlock((ulock_t)(mutex->backend)) == 0)
return -1;
else
return 0;
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
usunsetlock((ulock_t)(mutex->backend));
return 0;
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
/* Unimplemented. */
return -1;
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* End of File */

312
libobjc/thr-mach.c Normal file
View File

@ -0,0 +1,312 @@
/* GNU Objective C Runtime Thread Implementation
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
Modified for Mach threads by Bill Bumgarner <bbum@friday.com>
Condition functions added by Mircea Oancea <mircea@first.elcom.pub.ro>
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <mach/mach.h>
#include <mach/cthreads.h>
#include <objc/thr.h>
#include "runtime.h"
/*
Obtain the maximum thread priority that can set for t. Under the
mach threading model, it is possible for the developer to adjust the
maximum priority downward only-- cannot be raised without superuser
privileges. Once lowered, it cannot be raised.
*/
static int __mach_get_max_thread_priority(cthread_t t, int *base)
{
thread_t threadP;
kern_return_t error;
struct thread_sched_info info;
unsigned int info_count=THREAD_SCHED_INFO_COUNT;
if (t == NULL)
return -1;
threadP = cthread_thread(t); /* get thread underlying */
error=thread_info(threadP, THREAD_SCHED_INFO,
(thread_info_t)&info, &info_count);
if (error != KERN_SUCCESS)
return -1;
if (base != NULL)
*base = info.base_priority;
return info.max_priority;
}
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system(void)
{
return 0;
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
return 0;
}
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
__objc_thread_detach(void (*func)(void *arg), void *arg)
{
objc_thread_t thread_id;
cthread_t new_thread_handle;
/* create thread */
new_thread_handle = cthread_fork((cthread_fn_t)func, arg);
if(new_thread_handle)
{
/* this is not terribly portable */
thread_id = *(objc_thread_t *)&new_thread_handle;
cthread_detach(new_thread_handle);
}
else
thread_id = NULL;
return thread_id;
}
/* Set the current thread's priority. */
int
__objc_thread_set_priority(int priority)
{
objc_thread_t *t = objc_thread_id();
cthread_t cT = (cthread_t) t;
int maxPriority = __mach_get_max_thread_priority(cT, NULL);
int sys_priority = 0;
if (maxPriority == -1)
return -1;
switch (priority)
{
case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_priority = maxPriority;
break;
case OBJC_THREAD_BACKGROUND_PRIORITY:
sys_priority = (maxPriority * 2) / 3;
break;
case OBJC_THREAD_LOW_PRIORITY:
sys_priority = maxPriority / 3;
break;
default:
return -1;
}
if (sys_priority == 0)
return -1;
/* Change the priority */
if (cthread_priority(cT, sys_priority, 0) == KERN_SUCCESS)
return 0;
else
return -1;
}
/* Return the current thread's priority. */
int
__objc_thread_get_priority(void)
{
objc_thread_t *t = objc_thread_id();
cthread_t cT = (cthread_t) t; /* see objc_thread_id() */
int basePriority;
int maxPriority;
int sys_priority = 0;
int interactiveT, backgroundT, lowT; /* thresholds */
maxPriority = __mach_get_max_thread_priority(cT, &basePriority);
if(maxPriority == -1)
return -1;
if (basePriority > ( (maxPriority * 2) / 3))
return OBJC_THREAD_INTERACTIVE_PRIORITY;
if (basePriority > ( maxPriority / 3))
return OBJC_THREAD_BACKGROUND_PRIORITY;
return OBJC_THREAD_LOW_PRIORITY;
}
/* Yield our process time to another thread. */
void
__objc_thread_yield(void)
{
cthread_yield();
}
/* Terminate the current thread. */
int
__objc_thread_exit(void)
{
/* exit the thread */
cthread_exit(&__objc_thread_exit_status);
/* Failed if we reached here */
return -1;
}
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
__objc_thread_id(void)
{
cthread_t self = cthread_self();
return *(objc_thread_t *)&self;
}
/* Sets the thread's local storage pointer. */
int
__objc_thread_set_data(void *value)
{
cthread_set_data(cthread_self(), (any_t) value);
return 0;
}
/* Returns the thread's local storage pointer. */
void *
__objc_thread_get_data(void)
{
return (void *) cthread_data(cthread_self());
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
int err = 0;
mutex->backend = objc_malloc(sizeof(struct mutex));
err = mutex_init((mutex_t)(mutex->backend));
if (err != 0)
{
objc_free(mutex->backend);
return -1;
}
else
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
mutex_clear((mutex_t)(mutex->backend));
objc_free(mutex->backend);
mutex->backend = NULL;
return 0;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
mutex_lock((mutex_t)(mutex->backend));
return 0;
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock(objc_mutex_t mutex)
{
if (mutex_try_lock((mutex_t)(mutex->backend)) == 0)
return -1;
else
return 0;
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
mutex_unlock((mutex_t)(mutex->backend));
return 0;
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
condition->backend = objc_malloc(sizeof(struct condition));
condition_init((condition_t)(condition->backend));
return 0;
}
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
condition_clear((condition_t)(condition->backend));
objc_free(condition->backend);
condition->backend = NULL;
return 0;
}
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
condition_wait((condition_t)(condition->backend),
(mutex_t)(mutex->backend));
return 0;
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
condition_broadcast((condition_t)(condition->backend));
return 0;
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
condition_signal((condition_t)(condition->backend));
return 0;
}
/* End of File */

267
libobjc/thr-os2.c Normal file
View File

@ -0,0 +1,267 @@
/* GNU Objective C Runtime Thread Interface - OS/2 emx Implementation
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Thomas Baier (baier@ci.tuwien.ac.at)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <objc/thr.h>
#include "runtime.h"
#define INCL_DOSSEMAPHORES
#define INCL_DOSPROCESS
/*
* conflicts with objc.h: SEL, BOOL, id
* solution: prefixing those with _OS2_ before including <os2.h>
*/
#define SEL _OS2_SEL
#define BOOL _OS2_BOOL
#define id _OS2_id
#include <os2.h>
#undef id
#undef SEL
#undef BOOL
#include <stdlib.h>
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system(void)
{
return 0;
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
return 0;
}
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
__objc_thread_detach(void (*func)(void *arg), void *arg)
{
int thread_id = 0;
if ((thread_id = _beginthread (func,NULL,32768,arg)) < 0)
thread_id = 0;
return (objc_thread_t)thread_id;
}
/* Set the current thread's priority. */
int
__objc_thread_set_priority(int priority)
{
ULONG sys_class = 0;
ULONG sys_priority = 0;
/* OBJC_THREAD_INTERACTIVE_PRIORITY -> PRTYC_FOREGROUNDSERVER
* OBJC_THREAD_BACKGROUND_PRIORITY -> PRTYC_REGULAR
* OBJC_THREAD_LOW_PRIORITY -> PRTYC_IDLETIME */
switch (priority) {
case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_class = PRTYC_REGULAR;
sys_priority = 10;
break;
default:
case OBJC_THREAD_BACKGROUND_PRIORITY:
sys_class = PRTYC_IDLETIME;
sys_priority = 25;
break;
case OBJC_THREAD_LOW_PRIORITY:
sys_class = PRTYC_IDLETIME;
sys_priority = 0;
break;
}
/* Change priority */
if (!DosSetPriority (PRTYS_THREAD,sys_class,sys_priority,*_threadid))
return 0;
else
return -1;
}
/* Return the current thread's priority. */
int
__objc_thread_get_priority(void)
{
PTIB ptib;
PPIB ppib;
/* get information about current thread */
DosGetInfoBlocks (&ptib,&ppib);
switch (ptib->tib_ptib2->tib2_ulpri)
{
case PRTYC_IDLETIME:
case PRTYC_REGULAR:
case PRTYC_TIMECRITICAL:
case PRTYC_FOREGROUNDSERVER:
default:
return OBJC_THREAD_INTERACTIVE_PRIORITY;
}
return -1;
}
/* Yield our process time to another thread. */
void
__objc_thread_yield(void)
{
DosSleep (0);
}
/* Terminate the current thread. */
int
__objc_thread_exit(void)
{
/* terminate the thread, NEVER use DosExit () */
_endthread ();
/* Failed if we reached here */
return -1;
}
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
__objc_thread_id(void)
{
return (objc_thread_t) *_threadid;
}
/* Sets the thread's local storage pointer. */
int
__objc_thread_set_data(void *value)
{
*_threadstore () = value;
return 0;
}
/* Returns the thread's local storage pointer. */
void *
__objc_thread_get_data(void)
{
return *_threadstore ();
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
if (DosCreateMutexSem (NULL, (HMTX)(&(mutex->backend)),0L,0) > 0)
return -1;
else
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
DosCloseMutexSem ((HMTX)(mutex->backend));
return 0;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
if (DosRequestMutexSem ((HMTX)(mutex->backend),-1L) != 0)
return -1;
else
return 0;
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock(objc_mutex_t mutex)
{
if (DosRequestMutexSem ((HMTX)(mutex->backend),0L) != 0)
return -1;
else
return 0;
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
if (DosReleaseMutexSem((HMTX)(mutex->backend)) != 0)
return -1;
else
return 0;
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
/* Unimplemented. */
return -1;
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* End of File */

229
libobjc/thr-posix.c Normal file
View File

@ -0,0 +1,229 @@
/* GNU Objective C Runtime Thread Interface for POSIX compliant threads
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
Modified for Linux/Pthreads by Kai-Uwe Sattler (kus@iti.cs.uni-magdeburg.de)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <objc/thr.h>
#include "runtime.h"
#include <pthread.h>
/* Key structure for maintaining thread specific storage */
static pthread_key_t _objc_thread_storage;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system(void)
{
/* Initialize the thread storage key */
return pthread_key_create(&_objc_thread_storage, NULL);
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
return 0;
}
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
__objc_thread_detach(void (*func)(void *arg), void *arg)
{
objc_thread_t thread_id;
pthread_t new_thread_handle;
if ( !(pthread_create(&new_thread_handle, NULL, (void *)func, arg)) )
thread_id = *(objc_thread_t *)&new_thread_handle;
else
thread_id = NULL;
return thread_id;
}
/* Set the current thread's priority. */
int
__objc_thread_set_priority(int priority)
{
/* Not implemented yet */
return -1;
}
/* Return the current thread's priority. */
int
__objc_thread_get_priority(void)
{
/* Not implemented yet */
return -1;
}
/* Yield our process time to another thread. */
void
__objc_thread_yield(void)
{
sched_yield();
}
/* Terminate the current thread. */
int
__objc_thread_exit(void)
{
/* exit the thread */
pthread_exit(&__objc_thread_exit_status);
/* Failed if we reached here */
return -1;
}
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
__objc_thread_id(void)
{
pthread_t self = pthread_self();
return *(objc_thread_t *)&self;
}
/* Sets the thread's local storage pointer. */
int
__objc_thread_set_data(void *value)
{
return pthread_setspecific(_objc_thread_storage, value);
}
/* Returns the thread's local storage pointer. */
void *
__objc_thread_get_data(void)
{
return pthread_getspecific(_objc_thread_storage);
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
mutex->backend = objc_malloc(sizeof(pthread_mutex_t));
if (pthread_mutex_init((pthread_mutex_t *)mutex->backend, NULL))
{
objc_free(mutex->backend);
mutex->backend = NULL;
return -1;
}
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
if (pthread_mutex_destroy((pthread_mutex_t *)mutex->backend))
return -1;
objc_free(mutex->backend);
mutex->backend = NULL;
return 0;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
return pthread_mutex_lock((pthread_mutex_t *)mutex->backend);
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock(objc_mutex_t mutex)
{
return pthread_mutex_trylock((pthread_mutex_t *)mutex->backend);
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
return pthread_mutex_unlock((pthread_mutex_t *)mutex->backend);
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
condition->backend = objc_malloc(sizeof(pthread_cond_t));
if (pthread_cond_init((pthread_cond_t *)condition->backend, NULL))
{
objc_free(condition->backend);
condition->backend = NULL;
return -1;
}
return 0;
}
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
if (pthread_cond_destroy((pthread_cond_t *)condition->backend))
return -1;
objc_free(condition->backend);
condition->backend = NULL;
return 0;
}
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
return pthread_cond_wait((pthread_cond_t *)condition->backend,
(pthread_mutex_t *)mutex->backend);
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
return pthread_cond_broadcast((pthread_cond_t *)condition->backend);
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
return pthread_cond_signal((pthread_cond_t *)condition->backend);
}
/* End of File */

218
libobjc/thr-pthreads.c Normal file
View File

@ -0,0 +1,218 @@
/* GNU Objective C Runtime Thread Implementation for PCThreads under GNU/Linux.
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Scott Christley <scottc@net-community.com>
Condition functions added by: Mircea Oancea <mircea@first.elcom.pub.ro>
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <pcthread.h>
#include <objc/thr.h>
#include "runtime.h"
/* Key structure for maintaining thread specific storage */
static pthread_key_t _objc_thread_storage;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system(void)
{
/* Initialize the thread storage key */
return pthread_key_create(&_objc_thread_storage, NULL);
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
/* Destroy the thread storage key */
/* Not implemented yet */
/* return pthread_key_delete(&_objc_thread_storage); */
return 0;
}
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
__objc_thread_detach(void (*func)(void *arg), void *arg)
{
objc_thread_t thread_id;
pthread_t new_thread_handle;
if ( !(pthread_create(&new_thread_handle, NULL, (void *)func, arg)) )
thread_id = *(objc_thread_t *)&new_thread_handle;
else
thread_id = NULL;
return thread_id;
}
/* Set the current thread's priority. */
int
__objc_thread_set_priority(int priority)
{
/* Not implemented yet */
return -1;
}
/* Return the current thread's priority. */
int
__objc_thread_get_priority(void)
{
/* Not implemented yet */
return OBJC_THREAD_INTERACTIVE_PRIORITY;
}
/* Yield our process time to another thread. */
void
__objc_thread_yield(void)
{
pthread_yield(NULL);
}
/* Terminate the current thread. */
int
__objc_thread_exit(void)
{
/* exit the thread */
pthread_exit(&__objc_thread_exit_status);
/* Failed if we reached here */
return -1;
}
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
__objc_thread_id(void)
{
pthread_t self = pthread_self();
return *(objc_thread_t *)&self;
}
/* Sets the thread's local storage pointer. */
int
__objc_thread_set_data(void *value)
{
return pthread_setspecific(_objc_thread_storage, value);
}
/* Returns the thread's local storage pointer. */
void *
__objc_thread_get_data(void)
{
void *value = NULL;
if ( !(pthread_getspecific(_objc_thread_storage, &value)) )
return value;
return NULL;
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
if (pthread_mutex_init((pthread_mutex_t *)(&(mutex->backend)), NULL))
return -1;
else
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
if (pthread_mutex_destroy((pthread_mutex_t *)(&(mutex->backend))))
return -1;
else
return 0;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
return pthread_mutex_lock((pthread_mutex_t *)(&(mutex->backend)));
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock(objc_mutex_t mutex)
{
return pthread_mutex_trylock((pthread_mutex_t *)(&(mutex->backend)));
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
return pthread_mutex_unlock((pthread_mutex_t *)(&(mutex->backend)));
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL))
return -1;
else
return 0;
}
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend)));
}
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
return pthread_cond_wait((pthread_cond_t *)(&(condition->backend)),
(pthread_mutex_t *)(&(mutex->backend)));
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
return pthread_cond_broadcast((pthread_cond_t *)(&(condition->backend)));
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
return pthread_cond_signal((pthread_cond_t *)(&(condition->backend)));
}
/* End of File */

192
libobjc/thr-single.c Normal file
View File

@ -0,0 +1,192 @@
/* GNU Objective C Runtime Thread Implementation
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <objc/thr.h>
#include "runtime.h"
/* Thread local storage for a single thread */
static void *thread_local_storage = NULL;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system(void)
{
/* No thread support available */
return -1;
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
/* No thread support available */
return -1;
}
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
__objc_thread_detach(void (*func)(void *arg), void *arg)
{
/* No thread support available */
return NULL;
}
/* Set the current thread's priority. */
int
__objc_thread_set_priority(int priority)
{
/* No thread support available */
return -1;
}
/* Return the current thread's priority. */
int
__objc_thread_get_priority(void)
{
return OBJC_THREAD_INTERACTIVE_PRIORITY;
}
/* Yield our process time to another thread. */
void
__objc_thread_yield(void)
{
return;
}
/* Terminate the current thread. */
int
__objc_thread_exit(void)
{
/* No thread support available */
/* Should we really exit the program */
/* exit(&__objc_thread_exit_status); */
return -1;
}
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
__objc_thread_id(void)
{
/* No thread support, use 1. */
return (objc_thread_t)1;
}
/* Sets the thread's local storage pointer. */
int
__objc_thread_set_data(void *value)
{
thread_local_storage = value;
return 0;
}
/* Returns the thread's local storage pointer. */
void *
__objc_thread_get_data(void)
{
return thread_local_storage;
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
return 0;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
/* There can only be one thread, so we always get the lock */
return 0;
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock(objc_mutex_t mutex)
{
/* There can only be one thread, so we always get the lock */
return 0;
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
return 0;
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
return 0;
}
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
return 0;
}
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
return 0;
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
return 0;
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
return 0;
}
/* End of File */

259
libobjc/thr-solaris.c Normal file
View File

@ -0,0 +1,259 @@
/* GNU Objective C Runtime Thread Interface
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
Conditions added by Mircea Oancea (mircea@first.elcom.pub.ro)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <objc/thr.h>
#include "runtime.h"
#include <thread.h>
#include <synch.h>
#include <errno.h>
/* Key structure for maintaining thread specific storage */
static thread_key_t __objc_thread_data_key;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system(void)
{
/* Initialize the thread storage key */
if (thr_keycreate(&__objc_thread_data_key, NULL) == 0)
return 0;
else
return -1;
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
return 0;
}
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
__objc_thread_detach(void (*func)(void *arg), void *arg)
{
objc_thread_t thread_id;
thread_t new_thread_id = 0;
if (thr_create(NULL, 0, (void *)func, arg,
THR_DETACHED | THR_NEW_LWP,
&new_thread_id) == 0)
thread_id = *(objc_thread_t *)&new_thread_id;
else
thread_id = NULL;
return thread_id;
}
/* Set the current thread's priority. */
int
__objc_thread_set_priority(int priority)
{
int sys_priority = 0;
switch (priority)
{
case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_priority = 300;
break;
default:
case OBJC_THREAD_BACKGROUND_PRIORITY:
sys_priority = 200;
break;
case OBJC_THREAD_LOW_PRIORITY:
sys_priority = 1000;
break;
}
/* Change priority */
if (thr_setprio(thr_self(), sys_priority) == 0)
return 0;
else
return -1;
}
/* Return the current thread's priority. */
int
__objc_thread_get_priority(void)
{
int sys_priority;
if (thr_getprio(thr_self(), &sys_priority) == 0)
{
if (sys_priority >= 250)
return OBJC_THREAD_INTERACTIVE_PRIORITY;
else if (sys_priority >= 150)
return OBJC_THREAD_BACKGROUND_PRIORITY;
return OBJC_THREAD_LOW_PRIORITY;
}
/* Couldn't get priority. */
return -1;
}
/* Yield our process time to another thread. */
void
__objc_thread_yield(void)
{
thr_yield();
}
/* Terminate the current thread. */
int
__objc_thread_exit(void)
{
/* exit the thread */
thr_exit(&__objc_thread_exit_status);
/* Failed if we reached here */
return -1;
}
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
__objc_thread_id(void)
{
return (objc_thread_t)thr_self();
}
/* Sets the thread's local storage pointer. */
int
__objc_thread_set_data(void *value)
{
if (thr_setspecific(__objc_thread_data_key, value) == 0)
return 0;
else
return -1;
}
/* Returns the thread's local storage pointer. */
void *
__objc_thread_get_data(void)
{
void *value = NULL;
if (thr_getspecific(__objc_thread_data_key, &value) == 0)
return value;
return NULL;
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
if (mutex_init( (mutex_t *)(&(mutex->backend)), USYNC_THREAD, 0))
return -1;
else
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
mutex_destroy((mutex_t *)(&(mutex->backend)));
return 0;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
if (mutex_lock((mutex_t *)(&(mutex->backend))) != 0)
return -1;
else
return 0;
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock(objc_mutex_t mutex)
{
if (mutex_trylock((mutex_t *)(&(mutex->backend))) != 0)
return -1;
else
return 0;
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
if (mutex_unlock((mutex_t *)(&(mutex->backend))) != 0)
return -1;
else
return 0;
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
return cond_init((cond_t *)(&(condition->backend)), USYNC_THREAD, NULL);
}
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
return cond_destroy((cond_t *)(&(condition->backend)));
}
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
return cond_wait((cond_t *)(&(condition->backend)),
(mutex_t *)(&(mutex->backend)));
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
return cond_broadcast((cond_t *)(&(condition->backend)));
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
return cond_signal((cond_t *)(&(condition->backend)));
}
/* End of File */

192
libobjc/thr-vxworks.c Normal file
View File

@ -0,0 +1,192 @@
/* GNU Objective C Runtime Thread Implementation
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <objc/thr.h>
#include "runtime.h"
/* Thread local storage for a single thread */
static void *thread_local_storage = NULL;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system(void)
{
/* No thread support available */
return -1;
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
/* No thread support available */
return -1;
}
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
__objc_thread_detach(void (*func)(void *arg), void *arg)
{
/* No thread support available */
return NULL;
}
/* Set the current thread's priority. */
int
__objc_thread_set_priority(int priority)
{
/* No thread support available */
return -1;
}
/* Return the current thread's priority. */
int
__objc_thread_get_priority(void)
{
return OBJC_THREAD_INTERACTIVE_PRIORITY;
}
/* Yield our process time to another thread. */
void
__objc_thread_yield(void)
{
return;
}
/* Terminate the current thread. */
int
__objc_thread_exit(void)
{
/* No thread support available */
/* Should we really exit the program */
/* exit(&__objc_thread_exit_status); */
return -1;
}
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
__objc_thread_id(void)
{
/* No thread support, use 1. */
return (objc_thread_t)1;
}
/* Sets the thread's local storage pointer. */
int
__objc_thread_set_data(void *value)
{
thread_local_storage = value;
return 0;
}
/* Returns the thread's local storage pointer. */
void *
__objc_thread_get_data(void)
{
return thread_local_storage;
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
return 0;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
/* There can only be one thread, so we always get the lock */
return 0;
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock(objc_mutex_t mutex)
{
/* There can only be one thread, so we always get the lock */
return 0;
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
return 0;
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
return 0;
}
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
return 0;
}
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
return 0;
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
return 0;
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
return 0;
}
/* End of File */

272
libobjc/thr-win32.c Normal file
View File

@ -0,0 +1,272 @@
/* GNU Objective C Runtime Thread Interface - Win32 Implementation
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <objc/thr.h>
#include "runtime.h"
#ifndef __OBJC__
#define __OBJC__
#endif
#include <windows.h>
/* Key structure for maintaining thread specific storage */
static DWORD __objc_data_tls = (DWORD)-1;
/* Backend initialization functions */
/* Initialize the threads subsystem. */
int
__objc_init_thread_system(void)
{
/* Initialize the thread storage key */
if ((__objc_data_tls = TlsAlloc()) != (DWORD)-1)
return 0;
else
return -1;
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
if (__objc_data_tls != (DWORD)-1)
TlsFree(__objc_data_tls);
return 0;
}
/* Backend thread functions */
/* Create a new thread of execution. */
objc_thread_t
__objc_thread_detach(void (*func)(void *arg), void *arg)
{
DWORD thread_id = 0;
HANDLE win32_handle;
if (!(win32_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func,
arg, 0, &thread_id)))
thread_id = 0;
return (objc_thread_t)thread_id;
}
/* Set the current thread's priority. */
int
__objc_thread_set_priority(int priority)
{
int sys_priority = 0;
switch (priority)
{
case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_priority = THREAD_PRIORITY_NORMAL;
break;
default:
case OBJC_THREAD_BACKGROUND_PRIORITY:
sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
break;
case OBJC_THREAD_LOW_PRIORITY:
sys_priority = THREAD_PRIORITY_LOWEST;
break;
}
/* Change priority */
if (SetThreadPriority(GetCurrentThread(), sys_priority))
return 0;
else
return -1;
}
/* Return the current thread's priority. */
int
__objc_thread_get_priority(void)
{
int sys_priority;
sys_priority = GetThreadPriority(GetCurrentThread());
switch (sys_priority)
{
case THREAD_PRIORITY_HIGHEST:
case THREAD_PRIORITY_TIME_CRITICAL:
case THREAD_PRIORITY_ABOVE_NORMAL:
case THREAD_PRIORITY_NORMAL:
return OBJC_THREAD_INTERACTIVE_PRIORITY;
default:
case THREAD_PRIORITY_BELOW_NORMAL:
return OBJC_THREAD_BACKGROUND_PRIORITY;
case THREAD_PRIORITY_IDLE:
case THREAD_PRIORITY_LOWEST:
return OBJC_THREAD_LOW_PRIORITY;
}
/* Couldn't get priority. */
return -1;
}
/* Yield our process time to another thread. */
void
__objc_thread_yield(void)
{
Sleep(0);
}
/* Terminate the current thread. */
int
__objc_thread_exit(void)
{
/* exit the thread */
ExitThread(__objc_thread_exit_status);
/* Failed if we reached here */
return -1;
}
/* Returns an integer value which uniquely describes a thread. */
objc_thread_t
__objc_thread_id(void)
{
return (objc_thread_t)GetCurrentThreadId();
}
/* Sets the thread's local storage pointer. */
int
__objc_thread_set_data(void *value)
{
if (TlsSetValue(__objc_data_tls, value))
return 0;
else
return -1;
}
/* Returns the thread's local storage pointer. */
void *
__objc_thread_get_data(void)
{
return TlsGetValue(__objc_data_tls); /* Return thread data. */
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
if ((mutex->backend = (void *)CreateMutex(NULL, 0, NULL)) == NULL)
return -1;
else
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
CloseHandle((HANDLE)(mutex->backend));
return 0;
}
/* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
int status;
status = WaitForSingleObject((HANDLE)(mutex->backend), INFINITE);
if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
return -1;
else
return 0;
}
/* Try to grab a lock on a mutex. */
int
__objc_mutex_trylock(objc_mutex_t mutex)
{
int status;
status = WaitForSingleObject((HANDLE)(mutex->backend), 0);
if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
return -1;
else
return 0;
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
if (ReleaseMutex((HANDLE)(mutex->backend)) == 0)
return -1;
else
return 0;
}
/* Backend condition mutex functions */
/* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
/* Unimplemented. */
return -1;
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* End of File */

534
libobjc/thr.c Normal file
View File

@ -0,0 +1,534 @@
/* GNU Objective C Runtime Thread Interface
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
#include <stdlib.h>
#include "runtime.h"
/* Global exit status. */
int __objc_thread_exit_status = 0;
/* Flag which lets us know if we ever became multi threaded */
int __objc_is_multi_threaded = 0;
/* The hook function called when the runtime becomes multi threaded */
objc_thread_callback _objc_became_multi_threaded = NULL;
/*
Use this to set the hook function that will be called when the
runtime initially becomes multi threaded.
The hook function is only called once, meaning only when the
2nd thread is spawned, not for each and every thread.
It returns the previous hook function or NULL if there is none.
A program outside of the runtime could set this to some function so
it can be informed; for example, the GNUstep Base Library sets it
so it can implement the NSBecomingMultiThreaded notification.
*/
objc_thread_callback objc_set_thread_callback(objc_thread_callback func)
{
objc_thread_callback temp = _objc_became_multi_threaded;
_objc_became_multi_threaded = func;
return temp;
}
/*
Private functions
These functions are utilized by the frontend, but they are not
considered part of the public interface.
*/
/*
First function called in a thread, starts everything else.
This function is passed to the backend by objc_thread_detach
as the starting function for a new thread.
*/
struct __objc_thread_start_state
{
SEL selector;
id object;
id argument;
};
static volatile void
__objc_thread_detach_function(struct __objc_thread_start_state *istate)
{
/* Valid state? */
if (istate) {
id (*imp)(id,SEL,id);
SEL selector = istate->selector;
id object = istate->object;
id argument = istate->argument;
/* Don't need anymore so free it */
objc_free(istate);
/* Clear out the thread local storage */
objc_thread_set_data(NULL);
/* Check to see if we just became multi threaded */
if (!__objc_is_multi_threaded)
{
__objc_is_multi_threaded = 1;
/* Call the hook function */
if (_objc_became_multi_threaded != NULL)
(*_objc_became_multi_threaded)();
}
/* Call the method */
if ((imp = (id(*)(id, SEL, id))objc_msg_lookup(object, selector)))
(*imp)(object, selector, argument);
else
objc_error(object, OBJC_ERR_UNIMPLEMENTED,
"objc_thread_detach called with bad selector.\n");
}
else
objc_error(nil, OBJC_ERR_BAD_STATE,
"objc_thread_detach called with NULL state.\n");
/* Exit the thread */
objc_thread_exit();
}
/*
Frontend functions
These functions constitute the public interface to the Objective-C thread
and mutex functionality.
*/
/* Frontend thread functions */
/*
Detach a new thread of execution and return its id. Returns NULL if fails.
Thread is started by sending message with selector to object. Message
takes a single argument.
*/
objc_thread_t
objc_thread_detach(SEL selector, id object, id argument)
{
struct __objc_thread_start_state *istate;
objc_thread_t thread_id = NULL;
/* Allocate the state structure */
if (!(istate = (struct __objc_thread_start_state *)
objc_malloc(sizeof(*istate))))
return NULL;
/* Initialize the state structure */
istate->selector = selector;
istate->object = object;
istate->argument = argument;
/* lock access */
objc_mutex_lock(__objc_runtime_mutex);
/* Call the backend to spawn the thread */
if ((thread_id = __objc_thread_detach((void *)__objc_thread_detach_function,
istate)) == NULL)
{
/* failed! */
objc_mutex_unlock(__objc_runtime_mutex);
objc_free(istate);
return NULL;
}
/* Increment our thread counter */
__objc_runtime_threads_alive++;
objc_mutex_unlock(__objc_runtime_mutex);
return thread_id;
}
/* Set the current thread's priority. */
int
objc_thread_set_priority(int priority)
{
/* Call the backend */
return __objc_thread_set_priority(priority);
}
/* Return the current thread's priority. */
int
objc_thread_get_priority(void)
{
/* Call the backend */
return __objc_thread_get_priority();
}
/*
Yield our process time to another thread. Any BUSY waiting that is done
by a thread should use this function to make sure that other threads can
make progress even on a lazy uniprocessor system.
*/
void
objc_thread_yield(void)
{
/* Call the backend */
__objc_thread_yield();
}
/*
Terminate the current tread. Doesn't return.
Actually, if it failed returns -1.
*/
int
objc_thread_exit(void)
{
/* Decrement our counter of the number of threads alive */
objc_mutex_lock(__objc_runtime_mutex);
__objc_runtime_threads_alive--;
objc_mutex_unlock(__objc_runtime_mutex);
/* Call the backend to terminate the thread */
return __objc_thread_exit();
}
/*
Returns an integer value which uniquely describes a thread. Must not be
NULL which is reserved as a marker for "no thread".
*/
objc_thread_t
objc_thread_id(void)
{
/* Call the backend */
return __objc_thread_id();
}
/*
Sets the thread's local storage pointer.
Returns 0 if successful or -1 if failed.
*/
int
objc_thread_set_data(void *value)
{
/* Call the backend */
return __objc_thread_set_data(value);
}
/*
Returns the thread's local storage pointer. Returns NULL on failure.
*/
void *
objc_thread_get_data(void)
{
/* Call the backend */
return __objc_thread_get_data();
}
/* Frontend mutex functions */
/*
Allocate a mutex. Return the mutex pointer if successful or NULL if the
allocation failed for any reason.
*/
objc_mutex_t
objc_mutex_allocate(void)
{
objc_mutex_t mutex;
/* Allocate the mutex structure */
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex))))
return NULL;
/* Call backend to create the mutex */
if (__objc_mutex_allocate(mutex))
{
/* failed! */
objc_free(mutex);
return NULL;
}
/* Initialize mutex */
mutex->owner = NULL;
mutex->depth = 0;
return mutex;
}
/*
Deallocate a mutex. Note that this includes an implicit mutex_lock to
insure that no one else is using the lock. It is legal to deallocate
a lock if we have a lock on it, but illegal to deallocate a lock held
by anyone else.
Returns the number of locks on the thread. (1 for deallocate).
*/
int
objc_mutex_deallocate(objc_mutex_t mutex)
{
int depth;
/* Valid mutex? */
if (!mutex)
return -1;
/* Acquire lock on mutex */
depth = objc_mutex_lock(mutex);
/* Call backend to destroy mutex */
if (__objc_mutex_deallocate(mutex))
return -1;
/* Free the mutex structure */
objc_free(mutex);
/* Return last depth */
return depth;
}
/*
Grab a lock on a mutex. If this thread already has a lock on this mutex
then we increment the lock count. If another thread has a lock on the
mutex we block and wait for the thread to release the lock.
Returns the lock count on the mutex held by this thread.
*/
int
objc_mutex_lock(objc_mutex_t mutex)
{
objc_thread_t thread_id;
int status;
/* Valid mutex? */
if (!mutex)
return -1;
/* If we already own the lock then increment depth */
thread_id = objc_thread_id();
if (mutex->owner == thread_id)
return ++mutex->depth;
/* Call the backend to lock the mutex */
status = __objc_mutex_lock(mutex);
/* Failed? */
if (status)
return status;
/* Successfully locked the thread */
mutex->owner = thread_id;
return mutex->depth = 1;
}
/*
Try to grab a lock on a mutex. If this thread already has a lock on
this mutex then we increment the lock count and return it. If another
thread has a lock on the mutex returns -1.
*/
int
objc_mutex_trylock(objc_mutex_t mutex)
{
objc_thread_t thread_id;
int status;
/* Valid mutex? */
if (!mutex)
return -1;
/* If we already own the lock then increment depth */
thread_id = objc_thread_id();
if (mutex->owner == thread_id)
return ++mutex->depth;
/* Call the backend to try to lock the mutex */
status = __objc_mutex_trylock(mutex);
/* Failed? */
if (status)
return status;
/* Successfully locked the thread */
mutex->owner = thread_id;
return mutex->depth = 1;
}
/*
Unlocks the mutex by one level.
Decrements the lock count on this mutex by one.
If the lock count reaches zero, release the lock on the mutex.
Returns the lock count on the mutex.
It is an error to attempt to unlock a mutex which this thread
doesn't hold in which case return -1 and the mutex is unaffected.
*/
int
objc_mutex_unlock(objc_mutex_t mutex)
{
objc_thread_t thread_id;
int status;
/* Valid mutex? */
if (!mutex)
return -1;
/* If another thread owns the lock then abort */
thread_id = objc_thread_id();
if (mutex->owner != thread_id)
return -1;
/* Decrement depth and return */
if (mutex->depth > 1)
return --mutex->depth;
/* Depth down to zero so we are no longer the owner */
mutex->depth = 0;
mutex->owner = NULL;
/* Have the backend unlock the mutex */
status = __objc_mutex_unlock(mutex);
/* Failed? */
if (status)
return status;
return 0;
}
/* Frontend condition mutex functions */
/*
Allocate a condition. Return the condition pointer if successful or NULL
if the allocation failed for any reason.
*/
objc_condition_t
objc_condition_allocate(void)
{
objc_condition_t condition;
/* Allocate the condition mutex structure */
if (!(condition =
(objc_condition_t)objc_malloc(sizeof(struct objc_condition))))
return NULL;
/* Call the backend to create the condition mutex */
if (__objc_condition_allocate(condition))
{
/* failed! */
objc_free(condition);
return NULL;
}
/* Success! */
return condition;
}
/*
Deallocate a condition. Note that this includes an implicit
condition_broadcast to insure that waiting threads have the opportunity
to wake. It is legal to dealloc a condition only if no other
thread is/will be using it. Here we do NOT check for other threads
waiting but just wake them up.
*/
int
objc_condition_deallocate(objc_condition_t condition)
{
/* Broadcast the condition */
if (objc_condition_broadcast(condition))
return -1;
/* Call the backend to destroy */
if (__objc_condition_deallocate(condition))
return -1;
/* Free the condition mutex structure */
objc_free(condition);
return 0;
}
/*
Wait on the condition unlocking the mutex until objc_condition_signal()
or objc_condition_broadcast() are called for the same condition. The
given mutex *must* have the depth set to 1 so that it can be unlocked
here, so that someone else can lock it and signal/broadcast the condition.
The mutex is used to lock access to the shared data that make up the
"condition" predicate.
*/
int
objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
objc_thread_t thread_id;
/* Valid arguments? */
if (!mutex || !condition)
return -1;
/* Make sure we are owner of mutex */
thread_id = objc_thread_id();
if (mutex->owner != thread_id)
return -1;
/* Cannot be locked more than once */
if (mutex->depth > 1)
return -1;
/* Virtually unlock the mutex */
mutex->depth = 0;
mutex->owner = (objc_thread_t)NULL;
/* Call the backend to wait */
__objc_condition_wait(condition, mutex);
/* Make ourselves owner of the mutex */
mutex->owner = thread_id;
mutex->depth = 1;
return 0;
}
/*
Wake up all threads waiting on this condition. It is recommended that
the called would lock the same mutex as the threads in objc_condition_wait
before changing the "condition predicate" and make this call and unlock it
right away after this call.
*/
int
objc_condition_broadcast(objc_condition_t condition)
{
/* Valid condition mutex? */
if (!condition)
return -1;
return __objc_condition_broadcast(condition);
}
/*
Wake up one thread waiting on this condition. It is recommended that
the called would lock the same mutex as the threads in objc_condition_wait
before changing the "condition predicate" and make this call and unlock it
right away after this call.
*/
int
objc_condition_signal(objc_condition_t condition)
{
/* Valid condition mutex? */
if (!condition)
return -1;
return __objc_condition_signal(condition);
}
/* End of File */

143
libobjc/thr.h Normal file
View File

@ -0,0 +1,143 @@
/* Thread and mutex controls for Objective C.
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
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.
GNU CC is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
GNU CC; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files
compiled with GCC to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
#ifndef __thread_INCLUDE_GNU
#define __thread_INCLUDE_GNU
#include "objc/objc.h"
/*************************************************************************
* Universal static variables:
*/
extern int __objc_thread_exit_status; /* Global exit status. */
/********
* Thread safe implementation types and functions.
*/
/* Thread priorities */
#define OBJC_THREAD_INTERACTIVE_PRIORITY 2
#define OBJC_THREAD_BACKGROUND_PRIORITY 1
#define OBJC_THREAD_LOW_PRIORITY 0
/* A thread */
typedef void * objc_thread_t;
/* This structure represents a single mutual exclusion lock. */
struct objc_mutex
{
volatile objc_thread_t owner; /* Id of thread that owns. */
volatile int depth; /* # of acquires. */
void * backend; /* Specific to backend */
};
typedef struct objc_mutex *objc_mutex_t;
/* This structure represents a single condition mutex */
struct objc_condition
{
void * backend; /* Specific to backend */
};
typedef struct objc_condition *objc_condition_t;
/* Frontend mutex functions */
objc_mutex_t objc_mutex_allocate(void);
int objc_mutex_deallocate(objc_mutex_t mutex);
int objc_mutex_lock(objc_mutex_t mutex);
int objc_mutex_unlock(objc_mutex_t mutex);
int objc_mutex_trylock(objc_mutex_t mutex);
/* Frontend condition mutex functions */
objc_condition_t objc_condition_allocate(void);
int objc_condition_deallocate(objc_condition_t condition);
int objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex);
int objc_condition_signal(objc_condition_t condition);
int objc_condition_broadcast(objc_condition_t condition);
/* Frontend thread functions */
objc_thread_t objc_thread_detach(SEL selector, id object, id argument);
void objc_thread_yield(void);
int objc_thread_exit(void);
int objc_thread_set_priority(int priority);
int objc_thread_get_priority(void);
void * objc_thread_get_data(void);
int objc_thread_set_data(void *value);
objc_thread_t objc_thread_id(void);
/*
Use this to set the hook function that will be called when the
runtime initially becomes multi threaded.
The hook function is only called once, meaning only when the
2nd thread is spawned, not for each and every thread.
It returns the previous hook function or NULL if there is none.
A program outside of the runtime could set this to some function so
it can be informed; for example, the GNUstep Base Library sets it
so it can implement the NSBecomingMultiThreaded notification.
*/
typedef void (*objc_thread_callback)();
objc_thread_callback objc_set_thread_callback(objc_thread_callback func);
/* Backend initialization functions */
int __objc_init_thread_system(void);
int __objc_fini_thread_system(void);
/* Backend mutex functions */
int __objc_mutex_allocate(objc_mutex_t mutex);
int __objc_mutex_deallocate(objc_mutex_t mutex);
int __objc_mutex_lock(objc_mutex_t mutex);
int __objc_mutex_trylock(objc_mutex_t mutex);
int __objc_mutex_unlock(objc_mutex_t mutex);
/* Backend condition mutex functions */
int __objc_condition_allocate(objc_condition_t condition);
int __objc_condition_deallocate(objc_condition_t condition);
int __objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex);
int __objc_condition_broadcast(objc_condition_t condition);
int __objc_condition_signal(objc_condition_t condition);
/* Backend thread functions */
objc_thread_t __objc_thread_detach(void (*func)(void *arg), void *arg);
int __objc_thread_set_priority(int priority);
int __objc_thread_get_priority(void);
void __objc_thread_yield(void);
int __objc_thread_exit(void);
objc_thread_t __objc_thread_id(void);
int __objc_thread_set_data(void *value);
void * __objc_thread_get_data(void);
#endif /* not __thread_INCLUDE_GNU */

132
libobjc/typedstream.h Normal file
View File

@ -0,0 +1,132 @@
/* GNU Objective-C Typed Streams interface.
Copyright (C) 1993, 1995 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with files compiled
with GCC to produce an executable, this does not cause the resulting
executable to be covered by the GNU General Public License. This
exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public License. */
#ifndef __typedstream_INCLUDE_GNU
#define __typedstream_INCLUDE_GNU
#include "objc/objc.h"
#include "objc/hash.h"
#include <stdio.h>
typedef int (*objc_typed_read_func)(void*, char*, int);
typedef int (*objc_typed_write_func)(void*, const char*, int);
typedef int (*objc_typed_flush_func)(void*);
typedef int (*objc_typed_eof_func)(void*);
#define OBJC_READONLY 0x01
#define OBJC_WRITEONLY 0x02
#define OBJC_MANAGED_STREAM 0x01
#define OBJC_FILE_STREAM 0x02
#define OBJC_MEMORY_STREAM 0x04
#define OBJC_TYPED_STREAM_VERSION 0x01
typedef struct objc_typed_stream {
void* physical;
cache_ptr object_table; /* read/written objects */
cache_ptr stream_table; /* other read/written but shared things.. */
cache_ptr class_table; /* class version mapping */
cache_ptr object_refs; /* forward references */
int mode; /* OBJC_READONLY or OBJC_WRITEONLY */
int type; /* MANAGED, FILE, MEMORY etc bit string */
int version; /* version used when writing */
int writing_root_p;
objc_typed_read_func read;
objc_typed_write_func write;
objc_typed_eof_func eof;
objc_typed_flush_func flush;
} TypedStream;
/* opcode masks */
#define _B_VALUE 0x1fU
#define _B_CODE 0xe0U
#define _B_SIGN 0x10U
#define _B_NUMBER 0x0fU
/* standard opcodes */
#define _B_INVALID 0x00U
#define _B_SINT 0x20U
#define _B_NINT 0x40U
#define _B_SSTR 0x60U
#define _B_NSTR 0x80U
#define _B_RCOMM 0xa0U
#define _B_UCOMM 0xc0U
#define _B_EXT 0xe0U
/* eXtension opcodes */
#define _BX_OBJECT 0x00U
#define _BX_CLASS 0x01U
#define _BX_SEL 0x02U
#define _BX_OBJREF 0x03U
#define _BX_OBJROOT 0x04U
#define _BX_EXT 0x1fU
/*
** Read and write objects as specified by TYPE. All the `last'
** arguments are pointers to the objects to read/write.
*/
int objc_write_type (TypedStream* stream, const char* type, const void* data);
int objc_read_type (TypedStream* stream, const char* type, void* data);
int objc_write_types (TypedStream* stream, const char* type, ...);
int objc_read_types (TypedStream* stream, const char* type, ...);
int objc_write_object_reference (TypedStream* stream, id object);
int objc_write_root_object (TypedStream* stream, id object);
long objc_get_stream_class_version (TypedStream* stream, Class class);
/*
** Convenience functions
*/
int objc_write_array (TypedStream* stream, const char* type,
int count, const void* data);
int objc_read_array (TypedStream* stream, const char* type,
int count, void* data);
int objc_write_object (TypedStream* stream, id object);
int objc_read_object (TypedStream* stream, id* object);
/*
** Open a typed stream for reading or writing. MODE may be either of
** OBJC_READONLY or OBJC_WRITEONLY.
*/
TypedStream* objc_open_typed_stream (FILE* physical, int mode);
TypedStream* objc_open_typed_stream_for_file (const char* file_name, int mode);
void objc_close_typed_stream (TypedStream* stream);
BOOL objc_end_of_typed_stream (TypedStream* stream);
void objc_flush_typed_stream (TypedStream* stream);
#endif /* not __typedstream_INCLUDE_GNU */