This patch makes selectors in the Objective-C language be pointers to a struct { void *sel_id...
This patch makes selectors in the Objective-C language be pointers to a struct { void *sel_id, char *sel_types }, where the sel_types element is the type encoding of the method arguments. From-SVN: r7622
This commit is contained in:
parent
7a1dd32325
commit
a39d31bc0c
|
@ -1,5 +1,5 @@
|
|||
/* Interface for the Object class for Objective-C.
|
||||
Copyright (C) 1993 Free Software Foundation, Inc.
|
||||
Copyright (C) 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
||||
|
@ -93,8 +93,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
- perform:(SEL)aSel with:anObject1 with:anObject2;
|
||||
|
||||
/* Forwarding */
|
||||
- forward:(SEL)aSel :(arglist_t)argFrame;
|
||||
- performv:(SEL)aSel :(arglist_t)argFrame;
|
||||
- (retval_t)forward:(SEL)aSel :(arglist_t)argFrame;
|
||||
- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame;
|
||||
|
||||
/* Posing */
|
||||
+ poseAs:(Class*)aClassObject;
|
||||
|
@ -112,14 +112,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
/* Archiving */
|
||||
+ (int)version;
|
||||
+ setVersion:(int)aVersion;
|
||||
|
||||
#ifndef __alpha__ /* TypedStream not supported on alpha yet. */
|
||||
+ (int)streamVersion: (TypedStream*)aStream;
|
||||
|
||||
- read: (TypedStream*)aStream;
|
||||
- write: (TypedStream*)aStream;
|
||||
#endif
|
||||
|
||||
- awake;
|
||||
|
||||
@end
|
||||
|
|
|
@ -24,14 +24,18 @@ You should have received a copy of the GNU General Public License along with
|
|||
however invalidate any other reasons why the executable file might be
|
||||
covered by the GNU General Public License. */
|
||||
|
||||
/*
|
||||
** Note: This version assumes that int and longs are both 32bit.
|
||||
*/
|
||||
|
||||
#ifndef __alpha__
|
||||
|
||||
#include "runtime.h"
|
||||
#include "typedstream.h"
|
||||
#include "encoding.h"
|
||||
|
||||
extern int fflush(FILE*);
|
||||
|
||||
#define ROUND(V, A) \
|
||||
({ typeof(V) __v=(V); typeof(A) __a=(A); \
|
||||
__a*((__v+__a-1)/__a); })
|
||||
|
||||
#define PTR2LONG(P) (((char*)(P))-(char*)0)
|
||||
#define LONG2PTR(L) (((char*)0)+(L))
|
||||
|
||||
#define __objc_fatal(format, args...) \
|
||||
{ fprintf(stderr, "archiving: "); \
|
||||
|
@ -43,22 +47,20 @@ You should have received a copy of the GNU General Public License along with
|
|||
static int
|
||||
objc_read_class (struct objc_typed_stream* stream, Class** class);
|
||||
|
||||
static int
|
||||
objc_sizeof_type(const char* type);
|
||||
int objc_sizeof_type(const char* type);
|
||||
|
||||
static int
|
||||
objc_write_use_common (struct objc_typed_stream* stream, unsigned int key);
|
||||
objc_write_use_common (struct objc_typed_stream* stream, unsigned long key);
|
||||
|
||||
static int
|
||||
objc_write_register_common (struct objc_typed_stream* stream,
|
||||
unsigned int key);
|
||||
unsigned long key);
|
||||
|
||||
static int
|
||||
objc_write_class (struct objc_typed_stream* stream,
|
||||
struct objc_class* class);
|
||||
|
||||
static const char*
|
||||
__objc_skip_type (const char* type);
|
||||
const char* objc_skip_type (const char* type);
|
||||
|
||||
static void __objc_finish_write_root_object(struct objc_typed_stream*);
|
||||
static void __objc_finish_read_root_object(struct objc_typed_stream*);
|
||||
|
@ -112,15 +114,29 @@ objc_write_char (struct objc_typed_stream* stream, char value)
|
|||
static __inline__ int
|
||||
__objc_code_unsigned_short (unsigned char* buf, unsigned short val)
|
||||
{
|
||||
if (val <= 0xffU)
|
||||
return __objc_code_unsigned_char (buf, val);
|
||||
|
||||
if ((val&_B_VALUE) == val)
|
||||
{
|
||||
buf[0] = val|_B_SINT;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[0] = _B_NINT|0x02;
|
||||
buf[1] = val/0x100;
|
||||
buf[2] = val%0x100;
|
||||
return 3;
|
||||
int c, b;
|
||||
|
||||
buf[0] = _B_NINT;
|
||||
|
||||
for (c= sizeof(short); c != 0; c -= 1)
|
||||
if (((val>>(8*(c-1)))%0x100) != 0)
|
||||
break;
|
||||
|
||||
buf[0] |= c;
|
||||
|
||||
for (b = 1; c != 0; c--, b++)
|
||||
{
|
||||
buf[b] = (val >> (8*(c-1)))%0x100;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,18 +151,11 @@ objc_write_unsigned_short (struct objc_typed_stream* stream, unsigned short valu
|
|||
static __inline__ int
|
||||
__objc_code_short (unsigned char* buf, short val)
|
||||
{
|
||||
if (val > 0)
|
||||
return __objc_code_unsigned_short (buf, val);
|
||||
|
||||
if (val > -0x7f) /* val > -128 */
|
||||
return __objc_code_char (buf, val);
|
||||
|
||||
else
|
||||
{
|
||||
int len = __objc_code_unsigned_short (buf, -val);
|
||||
buf[0] |= _B_SIGN;
|
||||
return len;
|
||||
}
|
||||
int sign = (val < 0);
|
||||
int size = __objc_code_unsigned_short (buf, sign ? -val : val);
|
||||
if (sign)
|
||||
buf[0] |= _B_SIGN;
|
||||
return size;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -161,26 +170,29 @@ objc_write_short (struct objc_typed_stream* stream, short value)
|
|||
static __inline__ int
|
||||
__objc_code_unsigned_int (unsigned char* buf, unsigned int val)
|
||||
{
|
||||
if (val < 0x10000)
|
||||
return __objc_code_unsigned_short (buf, val%0x10000);
|
||||
|
||||
else if (val < 0x1000000)
|
||||
if ((val&_B_VALUE) == val)
|
||||
{
|
||||
buf[0] = _B_NINT|3;
|
||||
buf[1] = val/0x10000;
|
||||
buf[2] = (val%0x10000)/0x100;
|
||||
buf[3] = val%0x100;
|
||||
return 4;
|
||||
buf[0] = val|_B_SINT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
buf[0] = _B_NINT|4;
|
||||
buf[1] = val/0x1000000;
|
||||
buf[2] = (val%0x1000000)/0x10000;
|
||||
buf[3] = (val%0x10000)/0x100;
|
||||
buf[4] = val%0x100;
|
||||
return 5;
|
||||
int c, b;
|
||||
|
||||
buf[0] = _B_NINT;
|
||||
|
||||
for (c= sizeof(int); c != 0; c -= 1)
|
||||
if (((val>>(8*(c-1)))%0x100) != 0)
|
||||
break;
|
||||
|
||||
buf[0] |= c;
|
||||
|
||||
for (b = 1; c != 0; c--, b++)
|
||||
{
|
||||
buf[b] = (val >> (8*(c-1)))%0x100;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,18 +207,11 @@ objc_write_unsigned_int (struct objc_typed_stream* stream, unsigned int value)
|
|||
static __inline__ int
|
||||
__objc_code_int (unsigned char* buf, int val)
|
||||
{
|
||||
if (val >= 0)
|
||||
return __objc_code_unsigned_int (buf, val);
|
||||
|
||||
if (val > -0x7f)
|
||||
return __objc_code_char (buf, val);
|
||||
|
||||
else
|
||||
{
|
||||
int len = __objc_code_unsigned_int (buf, -val);
|
||||
buf[0] |= _B_SIGN;
|
||||
return len;
|
||||
}
|
||||
int sign = (val < 0);
|
||||
int size = __objc_code_unsigned_int (buf, sign ? -val : val);
|
||||
if (sign)
|
||||
buf[0] |= _B_SIGN;
|
||||
return size;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -217,6 +222,62 @@ objc_write_int (struct objc_typed_stream* stream, int value)
|
|||
return (*stream->write)(stream->physical, buf, len);
|
||||
}
|
||||
|
||||
static __inline__ int
|
||||
__objc_code_unsigned_long (unsigned char* buf, unsigned long val)
|
||||
{
|
||||
if ((val&_B_VALUE) == val)
|
||||
{
|
||||
buf[0] = val|_B_SINT;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int c, b;
|
||||
|
||||
buf[0] = _B_NINT;
|
||||
|
||||
for (c= sizeof(long); c != 0; c -= 1)
|
||||
if (((val>>(8*(c-1)))%0x100) != 0)
|
||||
break;
|
||||
|
||||
buf[0] |= c;
|
||||
|
||||
for (b = 1; c != 0; c--, b++)
|
||||
{
|
||||
buf[b] = (val >> (8*(c-1)))%0x100;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
objc_write_unsigned_long (struct objc_typed_stream* stream, unsigned long value)
|
||||
{
|
||||
unsigned char buf[sizeof(unsigned long)+1];
|
||||
int len = __objc_code_unsigned_long (buf, value);
|
||||
return (*stream->write)(stream->physical, buf, len);
|
||||
}
|
||||
|
||||
static __inline__ int
|
||||
__objc_code_long (unsigned char* buf, long val)
|
||||
{
|
||||
int sign = (val < 0);
|
||||
int size = __objc_code_unsigned_long (buf, sign ? -val : val);
|
||||
if (sign)
|
||||
buf[0] |= _B_SIGN;
|
||||
return size;
|
||||
}
|
||||
|
||||
int
|
||||
objc_write_long (struct objc_typed_stream* stream, long value)
|
||||
{
|
||||
unsigned char buf[sizeof(long)+1];
|
||||
int len = __objc_code_long (buf, value);
|
||||
return (*stream->write)(stream->physical, buf, len);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
objc_write_string (struct objc_typed_stream* stream,
|
||||
const unsigned char* string, unsigned int nbytes)
|
||||
|
@ -240,13 +301,13 @@ int
|
|||
objc_write_string_atomic (struct objc_typed_stream* stream,
|
||||
unsigned char* string, unsigned int nbytes)
|
||||
{
|
||||
unsigned int key;
|
||||
if ((key = (unsigned int)hash_value_for_key (stream->stream_table, string)))
|
||||
unsigned long key;
|
||||
if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, string))))
|
||||
return objc_write_use_common (stream, key);
|
||||
else
|
||||
{
|
||||
int length;
|
||||
hash_add (&stream->stream_table, (void*)key=(unsigned int)string, string);
|
||||
hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(string)), string);
|
||||
if ((length = objc_write_register_common (stream, key)))
|
||||
return objc_write_string (stream, string, nbytes);
|
||||
return length;
|
||||
|
@ -254,10 +315,10 @@ objc_write_string_atomic (struct objc_typed_stream* stream,
|
|||
}
|
||||
|
||||
static int
|
||||
objc_write_register_common (struct objc_typed_stream* stream, unsigned int key)
|
||||
objc_write_register_common (struct objc_typed_stream* stream, unsigned long key)
|
||||
{
|
||||
unsigned char buf[sizeof (unsigned int)+2];
|
||||
int len = __objc_code_unsigned_int (buf+1, key);
|
||||
unsigned char buf[sizeof (unsigned long)+2];
|
||||
int len = __objc_code_unsigned_long (buf+1, key);
|
||||
if (len == 1)
|
||||
{
|
||||
buf[0] = _B_RCOMM|0x01;
|
||||
|
@ -272,10 +333,10 @@ objc_write_register_common (struct objc_typed_stream* stream, unsigned int key)
|
|||
}
|
||||
|
||||
static int
|
||||
objc_write_use_common (struct objc_typed_stream* stream, unsigned int key)
|
||||
objc_write_use_common (struct objc_typed_stream* stream, unsigned long key)
|
||||
{
|
||||
unsigned char buf[sizeof (unsigned int)+2];
|
||||
int len = __objc_code_unsigned_int (buf+1, key);
|
||||
unsigned char buf[sizeof (unsigned long)+2];
|
||||
int len = __objc_code_unsigned_long (buf+1, key);
|
||||
if (len == 1)
|
||||
{
|
||||
buf[0] = _B_UCOMM|0x01;
|
||||
|
@ -305,7 +366,7 @@ __inline__ int
|
|||
__objc_write_object (struct objc_typed_stream* stream, id object)
|
||||
{
|
||||
unsigned char buf = '\0';
|
||||
SEL write_sel = sel_get_uid ("write:");
|
||||
SEL write_sel = sel_get_any_uid ("write:");
|
||||
if (object)
|
||||
{
|
||||
__objc_write_extension (stream, _BX_OBJECT);
|
||||
|
@ -320,12 +381,12 @@ __objc_write_object (struct objc_typed_stream* stream, id object)
|
|||
int
|
||||
objc_write_object_reference (struct objc_typed_stream* stream, id object)
|
||||
{
|
||||
unsigned int key;
|
||||
if ((key = (unsigned int)hash_value_for_key (stream->object_table, object)))
|
||||
unsigned long key;
|
||||
if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object))))
|
||||
return objc_write_use_common (stream, key);
|
||||
|
||||
__objc_write_extension (stream, _BX_OBJREF);
|
||||
return objc_write_unsigned_int (stream, (unsigned int)object);
|
||||
return objc_write_unsigned_long (stream, PTR2LONG (object));
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -348,8 +409,8 @@ objc_write_root_object (struct objc_typed_stream* stream, id object)
|
|||
int
|
||||
objc_write_object (struct objc_typed_stream* stream, id object)
|
||||
{
|
||||
unsigned int key;
|
||||
if ((key = (unsigned int)hash_value_for_key (stream->object_table, object)))
|
||||
unsigned long key;
|
||||
if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object))))
|
||||
return objc_write_use_common (stream, key);
|
||||
|
||||
else if (object == nil)
|
||||
|
@ -358,20 +419,26 @@ objc_write_object (struct objc_typed_stream* stream, id object)
|
|||
else
|
||||
{
|
||||
int length;
|
||||
hash_add (&stream->object_table, (void*)key=(unsigned int)object, object);
|
||||
hash_add (&stream->object_table, LONG2PTR(key=PTR2LONG(object)), object);
|
||||
if ((length = objc_write_register_common (stream, key)))
|
||||
return __objc_write_object (stream, object);
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __alpha__
|
||||
extern int atoi (const char*);
|
||||
extern size_t strlen(const char*);
|
||||
extern size_t strcpy(char*, const char*);
|
||||
#endif
|
||||
|
||||
__inline__ int
|
||||
__objc_write_class (struct objc_typed_stream* stream, struct objc_class* class)
|
||||
{
|
||||
__objc_write_extension (stream, _BX_CLASS);
|
||||
objc_write_string_atomic(stream, (char*)class->name,
|
||||
strlen((char*)class->name));
|
||||
return objc_write_unsigned_int (stream, CLS_GETNUMBER(class));
|
||||
return objc_write_unsigned_long (stream, CLS_GETNUMBER(class));
|
||||
}
|
||||
|
||||
|
||||
|
@ -379,13 +446,13 @@ static int
|
|||
objc_write_class (struct objc_typed_stream* stream,
|
||||
struct objc_class* class)
|
||||
{
|
||||
unsigned int key;
|
||||
if ((key = (unsigned int)hash_value_for_key (stream->stream_table, class)))
|
||||
unsigned long key;
|
||||
if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, class))))
|
||||
return objc_write_use_common (stream, key);
|
||||
else
|
||||
{
|
||||
int length;
|
||||
hash_add (&stream->stream_table, (void*)key=(unsigned int)class, class);
|
||||
hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(class)), class);
|
||||
if ((length = objc_write_register_common (stream, key)))
|
||||
return __objc_write_class (stream, class);
|
||||
return length;
|
||||
|
@ -405,13 +472,13 @@ int
|
|||
objc_write_selector (struct objc_typed_stream* stream, SEL selector)
|
||||
{
|
||||
const char* sel_name = sel_get_name (selector);
|
||||
unsigned int key;
|
||||
if ((key = (unsigned int)hash_value_for_key (stream->stream_table, sel_name)))
|
||||
unsigned long key;
|
||||
if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, sel_name))))
|
||||
return objc_write_use_common (stream, key);
|
||||
else
|
||||
{
|
||||
int length;
|
||||
hash_add (&stream->stream_table, (void*)key=(unsigned int)sel_name, (char*)sel_name);
|
||||
hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(sel_name)), (char*)sel_name);
|
||||
if ((length = objc_write_register_common (stream, key)))
|
||||
return __objc_write_selector (stream, selector);
|
||||
return length;
|
||||
|
@ -551,6 +618,33 @@ objc_read_int (struct objc_typed_stream* stream, int* value)
|
|||
return len;
|
||||
}
|
||||
|
||||
__inline__ int
|
||||
objc_read_long (struct objc_typed_stream* stream, long* value)
|
||||
{
|
||||
unsigned char buf[sizeof(long)+1];
|
||||
int len;
|
||||
if ((len = (*stream->read)(stream->physical, buf, 1)))
|
||||
{
|
||||
if ((buf[0] & _B_CODE) == _B_SINT)
|
||||
(*value) = (buf[0] & _B_VALUE);
|
||||
|
||||
else
|
||||
{
|
||||
int pos = 1;
|
||||
int nbytes = buf[0] & _B_NUMBER;
|
||||
if (nbytes > sizeof (long))
|
||||
__objc_fatal("expected long, got bigger");
|
||||
len = (*stream->read)(stream->physical, buf+1, nbytes);
|
||||
(*value) = 0;
|
||||
while (pos <= nbytes)
|
||||
(*value) = ((*value)*0x100) + buf[pos++];
|
||||
if (buf[0] & _B_SIGN)
|
||||
(*value) = -(*value);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
__inline__ int
|
||||
__objc_read_nbyte_uint (struct objc_typed_stream* stream,
|
||||
unsigned int nbytes, unsigned int* val)
|
||||
|
@ -587,6 +681,42 @@ objc_read_unsigned_int (struct objc_typed_stream* stream,
|
|||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
__objc_read_nbyte_ulong (struct objc_typed_stream* stream,
|
||||
unsigned int nbytes, unsigned long* val)
|
||||
{
|
||||
int len, pos = 0;
|
||||
unsigned char buf[sizeof(unsigned long)+1];
|
||||
|
||||
if (nbytes > sizeof (long))
|
||||
__objc_fatal("expected long, got bigger");
|
||||
|
||||
len = (*stream->read)(stream->physical, buf, nbytes);
|
||||
(*val) = 0;
|
||||
while (pos < nbytes)
|
||||
(*val) = ((*val)*0x100) + buf[pos++];
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
__inline__ int
|
||||
objc_read_unsigned_long (struct objc_typed_stream* stream,
|
||||
unsigned long* value)
|
||||
{
|
||||
unsigned char buf[sizeof(unsigned long)+1];
|
||||
int len;
|
||||
if ((len = (*stream->read)(stream->physical, buf, 1)))
|
||||
{
|
||||
if ((buf[0] & _B_CODE) == _B_SINT)
|
||||
(*value) = (buf[0] & _B_VALUE);
|
||||
|
||||
else
|
||||
len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value);
|
||||
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
__inline__ int
|
||||
objc_read_string (struct objc_typed_stream* stream,
|
||||
char** string)
|
||||
|
@ -595,11 +725,11 @@ objc_read_string (struct objc_typed_stream* stream,
|
|||
int len;
|
||||
if ((len = (*stream->read)(stream->physical, buf, 1)))
|
||||
{
|
||||
unsigned int key = 0;
|
||||
unsigned long key = 0;
|
||||
|
||||
if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
|
||||
{
|
||||
len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
|
||||
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
|
||||
len = (*stream->read)(stream->physical, buf, 1);
|
||||
}
|
||||
|
||||
|
@ -609,7 +739,7 @@ objc_read_string (struct objc_typed_stream* stream,
|
|||
int length = buf[0]&_B_VALUE;
|
||||
(*string) = (char*)__objc_xmalloc(length+1);
|
||||
if (key)
|
||||
hash_add (&stream->stream_table, (void*)key, *string);
|
||||
hash_add (&stream->stream_table, LONG2PTR(key), *string);
|
||||
len = (*stream->read)(stream->physical, *string, length);
|
||||
(*string)[length] = '\0';
|
||||
}
|
||||
|
@ -618,9 +748,9 @@ objc_read_string (struct objc_typed_stream* stream,
|
|||
case _B_UCOMM:
|
||||
{
|
||||
char *tmp;
|
||||
len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), &key);
|
||||
tmp = hash_value_for_key (stream->stream_table, (void*)key);
|
||||
*string = __objc_xmalloc (strlen (tmp) + 1);
|
||||
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
|
||||
tmp = hash_value_for_key (stream->stream_table, LONG2PTR (key));
|
||||
*string = __objc_xmalloc (strlen(tmp) + 1);
|
||||
strcpy (*string, tmp);
|
||||
}
|
||||
break;
|
||||
|
@ -632,7 +762,7 @@ objc_read_string (struct objc_typed_stream* stream,
|
|||
if (len) {
|
||||
(*string) = (char*)__objc_xmalloc(nbytes+1);
|
||||
if (key)
|
||||
hash_add (&stream->stream_table, (void*)key, *string);
|
||||
hash_add (&stream->stream_table, LONG2PTR(key), *string);
|
||||
len = (*stream->read)(stream->physical, *string, nbytes);
|
||||
(*string)[nbytes] = '\0';
|
||||
}
|
||||
|
@ -655,12 +785,12 @@ objc_read_object (struct objc_typed_stream* stream, id* object)
|
|||
int len;
|
||||
if ((len = (*stream->read)(stream->physical, buf, 1)))
|
||||
{
|
||||
SEL read_sel = sel_get_uid ("read:");
|
||||
unsigned int key = 0;
|
||||
SEL read_sel = sel_get_any_uid ("read:");
|
||||
unsigned long key = 0;
|
||||
|
||||
if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */
|
||||
{
|
||||
len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
|
||||
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
|
||||
len = (*stream->read)(stream->physical, buf, 1);
|
||||
}
|
||||
|
||||
|
@ -676,7 +806,7 @@ objc_read_object (struct objc_typed_stream* stream, id* object)
|
|||
|
||||
/* register? */
|
||||
if (key)
|
||||
hash_add (&stream->object_table, (void*)key, *object);
|
||||
hash_add (&stream->object_table, LONG2PTR(key), *object);
|
||||
|
||||
/* send -read: */
|
||||
if (__objc_responds_to (*object, read_sel))
|
||||
|
@ -692,16 +822,16 @@ objc_read_object (struct objc_typed_stream* stream, id* object)
|
|||
{
|
||||
if (key)
|
||||
__objc_fatal("cannot register use upcode...");
|
||||
len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
|
||||
(*object) = hash_value_for_key (stream->object_table, (void*)key);
|
||||
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
|
||||
(*object) = hash_value_for_key (stream->object_table, LONG2PTR(key));
|
||||
}
|
||||
|
||||
else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */
|
||||
{
|
||||
struct objc_list* other;
|
||||
len = objc_read_unsigned_int (stream, &key);
|
||||
other = (struct objc_list*)hash_value_for_key (stream->object_refs, (void*)key);
|
||||
hash_add (&stream->object_refs, (void*)key, (void*)list_cons(object, other));
|
||||
len = objc_read_unsigned_long (stream, &key);
|
||||
other = (struct objc_list*)hash_value_for_key (stream->object_refs, LONG2PTR(key));
|
||||
hash_add (&stream->object_refs, LONG2PTR(key), (void*)list_cons(object, other));
|
||||
}
|
||||
|
||||
else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */
|
||||
|
@ -725,18 +855,18 @@ objc_read_class (struct objc_typed_stream* stream, Class** class)
|
|||
int len;
|
||||
if ((len = (*stream->read)(stream->physical, buf, 1)))
|
||||
{
|
||||
unsigned int key = 0;
|
||||
unsigned long key = 0;
|
||||
|
||||
if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
|
||||
{
|
||||
len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
|
||||
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
|
||||
len = (*stream->read)(stream->physical, buf, 1);
|
||||
}
|
||||
|
||||
if (buf[0] == (_B_EXT | _BX_CLASS))
|
||||
{
|
||||
char* class_name;
|
||||
int version;
|
||||
unsigned long version;
|
||||
|
||||
/* get class */
|
||||
len = objc_read_string (stream, &class_name);
|
||||
|
@ -745,9 +875,9 @@ objc_read_class (struct objc_typed_stream* stream, Class** class)
|
|||
|
||||
/* register */
|
||||
if (key)
|
||||
hash_add (&stream->stream_table, (void*)key, *class);
|
||||
hash_add (&stream->stream_table, LONG2PTR(key), *class);
|
||||
|
||||
objc_read_unsigned_int(stream, &version);
|
||||
objc_read_unsigned_long(stream, &version);
|
||||
hash_add (&stream->class_table, (*class)->name, (void*)version);
|
||||
}
|
||||
|
||||
|
@ -755,10 +885,10 @@ objc_read_class (struct objc_typed_stream* stream, Class** class)
|
|||
{
|
||||
if (key)
|
||||
__objc_fatal("cannot register use upcode...");
|
||||
len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
|
||||
(*class) = hash_value_for_key (stream->stream_table, (void*)key);
|
||||
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
|
||||
(*class) = hash_value_for_key (stream->stream_table, LONG2PTR(key));
|
||||
if (!*class)
|
||||
__objc_fatal("cannot find class for key %x", key);
|
||||
__objc_fatal("cannot find class for key %lu", key);
|
||||
}
|
||||
|
||||
else
|
||||
|
@ -774,11 +904,11 @@ objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
|
|||
int len;
|
||||
if ((len = (*stream->read)(stream->physical, buf, 1)))
|
||||
{
|
||||
unsigned int key = 0;
|
||||
unsigned long key = 0;
|
||||
|
||||
if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
|
||||
{
|
||||
len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
|
||||
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
|
||||
len = (*stream->read)(stream->physical, buf, 1);
|
||||
}
|
||||
|
||||
|
@ -788,20 +918,20 @@ objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
|
|||
|
||||
/* get selector */
|
||||
len = objc_read_string (stream, &selector_name);
|
||||
(*selector) = sel_get_uid(selector_name);
|
||||
(*selector) = sel_get_any_uid(selector_name);
|
||||
free (selector_name);
|
||||
|
||||
/* register */
|
||||
if (key)
|
||||
hash_add (&stream->stream_table, (void*)key, *selector);
|
||||
hash_add (&stream->stream_table, LONG2PTR(key), (void*)*selector);
|
||||
}
|
||||
|
||||
else if ((buf[0]&_B_CODE) == _B_UCOMM)
|
||||
{
|
||||
if (key)
|
||||
__objc_fatal("cannot register use upcode...");
|
||||
len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
|
||||
(*selector) = hash_value_for_key (stream->stream_table, (void*)key);
|
||||
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
|
||||
(*selector) = hash_value_for_key (stream->stream_table, LONG2PTR(key));
|
||||
}
|
||||
|
||||
else
|
||||
|
@ -810,96 +940,6 @@ objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
|
|||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
objc_sizeof_type(const char* type)
|
||||
{
|
||||
switch(*type) {
|
||||
case _C_ID: return sizeof(id);
|
||||
break;
|
||||
|
||||
case _C_CLASS:
|
||||
return sizeof(Class*);
|
||||
break;
|
||||
|
||||
case _C_SEL:
|
||||
return sizeof(SEL);
|
||||
break;
|
||||
|
||||
case _C_CHR:
|
||||
return sizeof(char);
|
||||
break;
|
||||
|
||||
case _C_UCHR:
|
||||
return sizeof(unsigned char);
|
||||
break;
|
||||
|
||||
case _C_SHT:
|
||||
return sizeof(short);
|
||||
break;
|
||||
|
||||
case _C_USHT:
|
||||
return sizeof(unsigned short);
|
||||
break;
|
||||
|
||||
case _C_INT:
|
||||
case _C_LNG:
|
||||
return sizeof(int);
|
||||
break;
|
||||
|
||||
case _C_UINT:
|
||||
case _C_ULNG:
|
||||
return sizeof(unsigned int);
|
||||
break;
|
||||
|
||||
case _C_ATOM:
|
||||
case _C_CHARPTR:
|
||||
return sizeof(char*);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "objc_sizeof_type: cannot parse typespec: %s\n", type);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char*
|
||||
__objc_skip_type (const char* type)
|
||||
{
|
||||
switch (*type) {
|
||||
case _C_ID:
|
||||
case _C_CLASS:
|
||||
case _C_SEL:
|
||||
case _C_CHR:
|
||||
case _C_UCHR:
|
||||
case _C_CHARPTR:
|
||||
case _C_ATOM:
|
||||
case _C_SHT:
|
||||
case _C_USHT:
|
||||
case _C_INT:
|
||||
case _C_UINT:
|
||||
case _C_LNG:
|
||||
case _C_ULNG:
|
||||
case _C_FLT:
|
||||
case _C_DBL:
|
||||
return ++type;
|
||||
break;
|
||||
|
||||
case _C_ARY_B:
|
||||
while(isdigit(*++type));
|
||||
type = __objc_skip_type(type);
|
||||
if (*type == _C_ARY_E)
|
||||
return ++type;
|
||||
else
|
||||
__objc_fatal("cannot parse typespec: %s", type);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "__objc_skip_type: cannot parse typespec: %s\n", type);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** USER LEVEL FUNCTIONS
|
||||
*/
|
||||
|
@ -942,15 +982,21 @@ objc_write_type(TypedStream* stream, const char* type, const void* data)
|
|||
break;
|
||||
|
||||
case _C_INT:
|
||||
case _C_LNG:
|
||||
return objc_write_int(stream, *(int*)data);
|
||||
break;
|
||||
|
||||
case _C_UINT:
|
||||
case _C_ULNG:
|
||||
return objc_write_unsigned_int(stream, *(unsigned int*)data);
|
||||
break;
|
||||
|
||||
case _C_LNG:
|
||||
return objc_write_long(stream, *(long*)data);
|
||||
break;
|
||||
|
||||
case _C_ULNG:
|
||||
return objc_write_unsigned_long(stream, *(unsigned long*)data);
|
||||
break;
|
||||
|
||||
case _C_CHARPTR:
|
||||
return objc_write_string (stream, *(char**)data, strlen(*(char**)data));
|
||||
break;
|
||||
|
@ -967,6 +1013,22 @@ objc_write_type(TypedStream* stream, const char* type, const void* data)
|
|||
}
|
||||
break;
|
||||
|
||||
case _C_STRUCT_B:
|
||||
{
|
||||
int acc_size = 0;
|
||||
int align;
|
||||
while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
|
||||
while (*type != _C_STRUCT_E);
|
||||
{
|
||||
align = objc_alignof_type (type); /* padd to alignment */
|
||||
acc_size += ROUND (acc_size, align);
|
||||
objc_write_type (stream, type, ((char*)data)+acc_size);
|
||||
acc_size += objc_sizeof_type (type); /* add component size */
|
||||
type = objc_skip_typespec (type); /* skip component */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
default:
|
||||
fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
|
||||
abort();
|
||||
|
@ -1014,15 +1076,21 @@ objc_read_type(TypedStream* stream, const char* type, void* data)
|
|||
break;
|
||||
|
||||
case _C_INT:
|
||||
case _C_LNG:
|
||||
return objc_read_int (stream, (int*)data);
|
||||
break;
|
||||
|
||||
case _C_UINT:
|
||||
case _C_ULNG:
|
||||
return objc_read_unsigned_int (stream, (unsigned int*)data);
|
||||
break;
|
||||
|
||||
case _C_LNG:
|
||||
return objc_read_long (stream, (long*)data);
|
||||
break;
|
||||
|
||||
case _C_ULNG:
|
||||
return objc_read_unsigned_long (stream, (unsigned long*)data);
|
||||
break;
|
||||
|
||||
case _C_CHARPTR:
|
||||
case _C_ATOM:
|
||||
return objc_read_string (stream, (char**)data);
|
||||
|
@ -1036,6 +1104,22 @@ objc_read_type(TypedStream* stream, const char* type, void* data)
|
|||
}
|
||||
break;
|
||||
|
||||
case _C_STRUCT_B:
|
||||
{
|
||||
int acc_size = 0;
|
||||
int align;
|
||||
while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
|
||||
while (*type != _C_STRUCT_E);
|
||||
{
|
||||
align = objc_alignof_type (type); /* padd to alignment */
|
||||
acc_size += ROUND (acc_size, align);
|
||||
objc_read_type (stream, type, ((char*)data)+acc_size);
|
||||
acc_size += objc_sizeof_type (type); /* add component size */
|
||||
type = objc_skip_typespec (type); /* skip component */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
default:
|
||||
fprintf(stderr, "objc_read_type: cannot parse typespec: %s\n", type);
|
||||
abort();
|
||||
|
@ -1061,7 +1145,7 @@ objc_write_types (TypedStream* stream, const char* type, ...)
|
|||
|
||||
va_start(args, type);
|
||||
|
||||
for (c = type; *c; c = __objc_skip_type (c))
|
||||
for (c = type; *c; c = objc_skip_typespec (c))
|
||||
{
|
||||
switch(*c) {
|
||||
case _C_ID:
|
||||
|
@ -1095,15 +1179,21 @@ objc_write_types (TypedStream* stream, const char* type, ...)
|
|||
break;
|
||||
|
||||
case _C_INT:
|
||||
case _C_LNG:
|
||||
res = objc_write_int(stream, *va_arg(args, int*));
|
||||
break;
|
||||
|
||||
case _C_UINT:
|
||||
case _C_ULNG:
|
||||
res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*));
|
||||
break;
|
||||
|
||||
case _C_LNG:
|
||||
res = objc_write_long(stream, *va_arg(args, long*));
|
||||
break;
|
||||
|
||||
case _C_ULNG:
|
||||
res = objc_write_unsigned_long(stream, *va_arg(args, unsigned long*));
|
||||
break;
|
||||
|
||||
case _C_CHARPTR:
|
||||
{
|
||||
char** str = va_arg(args, char**);
|
||||
|
@ -1124,7 +1214,7 @@ objc_write_types (TypedStream* stream, const char* type, ...)
|
|||
const char* t = c;
|
||||
while (isdigit(*++t));
|
||||
res = objc_write_array (stream, t, len, va_arg(args, void*));
|
||||
t = __objc_skip_type (t);
|
||||
t = objc_skip_typespec (t);
|
||||
if (*t != _C_ARY_E)
|
||||
__objc_fatal("expected `]', got: %s", t);
|
||||
}
|
||||
|
@ -1154,7 +1244,7 @@ objc_read_types(TypedStream* stream, const char* type, ...)
|
|||
|
||||
va_start(args, type);
|
||||
|
||||
for (c = type; *c; c = __objc_skip_type(c))
|
||||
for (c = type; *c; c = objc_skip_typespec(c))
|
||||
{
|
||||
switch(*c) {
|
||||
case _C_ID:
|
||||
|
@ -1186,15 +1276,21 @@ objc_read_types(TypedStream* stream, const char* type, ...)
|
|||
break;
|
||||
|
||||
case _C_INT:
|
||||
case _C_LNG:
|
||||
res = objc_read_int(stream, va_arg(args, int*));
|
||||
break;
|
||||
|
||||
case _C_UINT:
|
||||
case _C_ULNG:
|
||||
res = objc_read_unsigned_int(stream, va_arg(args, unsigned int*));
|
||||
break;
|
||||
|
||||
case _C_LNG:
|
||||
res = objc_read_long(stream, va_arg(args, long*));
|
||||
break;
|
||||
|
||||
case _C_ULNG:
|
||||
res = objc_read_unsigned_long(stream, va_arg(args, unsigned long*));
|
||||
break;
|
||||
|
||||
case _C_CHARPTR:
|
||||
case _C_ATOM:
|
||||
{
|
||||
|
@ -1209,7 +1305,7 @@ objc_read_types(TypedStream* stream, const char* type, ...)
|
|||
const char* t = c;
|
||||
while (isdigit(*++t));
|
||||
res = objc_read_array (stream, t, len, va_arg(args, void*));
|
||||
t = __objc_skip_type (t);
|
||||
t = objc_skip_typespec (t);
|
||||
if (*t != _C_ARY_E)
|
||||
__objc_fatal("expected `]', got: %s", t);
|
||||
}
|
||||
|
@ -1331,7 +1427,7 @@ static void __objc_finish_write_root_object(struct objc_typed_stream* stream)
|
|||
static void __objc_finish_read_root_object(struct objc_typed_stream* stream)
|
||||
{
|
||||
node_ptr node;
|
||||
SEL awake_sel = sel_get_uid ("awake");
|
||||
SEL awake_sel = sel_get_any_uid ("awake");
|
||||
|
||||
/* resolve object forward references */
|
||||
for (node = hash_next (stream->object_refs, NULL); node;
|
||||
|
@ -1379,8 +1475,6 @@ static void __objc_finish_read_root_object(struct objc_typed_stream* stream)
|
|||
TypedStream*
|
||||
objc_open_typed_stream (FILE* physical, int mode)
|
||||
{
|
||||
int fflush(FILE*);
|
||||
|
||||
TypedStream* s = (TypedStream*)__objc_xmalloc(sizeof(TypedStream));
|
||||
|
||||
s->mode = mode;
|
||||
|
@ -1483,13 +1577,12 @@ objc_flush_typed_stream (TypedStream* stream)
|
|||
(*stream->flush)(stream->physical);
|
||||
}
|
||||
|
||||
int
|
||||
long
|
||||
objc_get_stream_class_version (TypedStream* stream, Class* class)
|
||||
{
|
||||
if (stream->class_table)
|
||||
return (int) hash_value_for_key (stream->class_table, class->name);
|
||||
return PTR2LONG(hash_value_for_key (stream->class_table, class->name));
|
||||
else
|
||||
return class_get_version (class);
|
||||
}
|
||||
|
||||
#endif /* __alpha__ */
|
||||
|
|
116
gcc/objc/class.c
116
gcc/objc/class.c
|
@ -132,6 +132,27 @@ objc_get_class (const char *name)
|
|||
abort();
|
||||
}
|
||||
|
||||
/* This function provides a way to enumerate all the classes in the
|
||||
executable. Pass *ENUM_STATE == NULL to start the enumeration. The
|
||||
function will return 0 when there are no more classes.
|
||||
For example:
|
||||
id class;
|
||||
void *es = NULL;
|
||||
while ((class = objc_next_class(&es)))
|
||||
... do something with class;
|
||||
*/
|
||||
Class*
|
||||
objc_next_class(void **enum_state)
|
||||
{
|
||||
/* make sure the table is there */
|
||||
assert(__objc_class_hash);
|
||||
|
||||
*(node_ptr*)enum_state =
|
||||
hash_next(__objc_class_hash, *(node_ptr*)enum_state);
|
||||
if (*(node_ptr*)enum_state)
|
||||
return (*(node_ptr*)enum_state)->value;
|
||||
return (Class*)0;
|
||||
}
|
||||
|
||||
/* Resolve super/subclass links for all classes. The only thing we
|
||||
can be sure of is that the class_pointer for class objects point
|
||||
|
@ -217,6 +238,9 @@ void __objc_resolve_class_links()
|
|||
Class*
|
||||
class_pose_as (Class* impostor, Class* super_class)
|
||||
{
|
||||
node_ptr node;
|
||||
Class* class1;
|
||||
|
||||
if (!CLS_ISRESOLV (impostor))
|
||||
__objc_resolve_class_links ();
|
||||
|
||||
|
@ -230,19 +254,13 @@ class_pose_as (Class* impostor, Class* super_class)
|
|||
|
||||
{
|
||||
Class **subclass = &(super_class->subclass_list);
|
||||
BOOL super_is_base_class = NO;
|
||||
|
||||
/* move subclasses of super_class to impostor */
|
||||
while (*subclass)
|
||||
{
|
||||
Class *nextSub = (*subclass)->sibling_class;
|
||||
|
||||
/* this happens when super_class is a base class */
|
||||
if (*subclass == CLASSOF (super_class))
|
||||
{
|
||||
super_is_base_class = YES;
|
||||
}
|
||||
else if (*subclass != impostor)
|
||||
if (*subclass != impostor)
|
||||
{
|
||||
Class *sub = *subclass;
|
||||
|
||||
|
@ -250,11 +268,18 @@ class_pose_as (Class* impostor, Class* super_class)
|
|||
sub->sibling_class = impostor->subclass_list;
|
||||
sub->super_class = impostor;
|
||||
impostor->subclass_list = sub;
|
||||
|
||||
/* meta classes */
|
||||
CLASSOF (sub)->sibling_class = CLASSOF (impostor)->subclass_list;
|
||||
CLASSOF (sub)->super_class = CLASSOF (impostor);
|
||||
CLASSOF (impostor)->subclass_list = CLASSOF (sub);
|
||||
|
||||
/* It will happen that SUB is not a class object if it is
|
||||
the top of the meta class hierachy chain. (root
|
||||
meta-class objects inherit theit class object) If that is
|
||||
the case... dont 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;
|
||||
|
@ -267,66 +292,31 @@ class_pose_as (Class* impostor, Class* super_class)
|
|||
/* set impostor to have no sibling classes */
|
||||
impostor->sibling_class = 0;
|
||||
CLASSOF (impostor)->sibling_class = 0;
|
||||
|
||||
/* impostor has a sibling... */
|
||||
if (super_is_base_class)
|
||||
{
|
||||
CLASSOF (super_class)->sibling_class = 0;
|
||||
impostor->sibling_class = CLASSOF (super_class);
|
||||
}
|
||||
}
|
||||
|
||||
/* check relationship of impostor and super_class */
|
||||
/* check relationship of impostor and super_class is kept. */
|
||||
assert (impostor->super_class == super_class);
|
||||
assert (CLASSOF (impostor)->super_class == CLASSOF (super_class));
|
||||
|
||||
/* by now, the re-organization of the class hierachy
|
||||
is done. We only need to update various tables. */
|
||||
/* This is how to update the lookup table. Regardless of
|
||||
what the keys of the hashtable is, change all values that are
|
||||
suprecalss into impostor. */
|
||||
|
||||
/* First, we change the names in the hash table.
|
||||
This will change the behavior of objc_get_class () */
|
||||
{
|
||||
char* buffer = (char*) __objc_xmalloc(strlen (super_class->name) + 2);
|
||||
|
||||
strcpy (buffer+1, super_class->name);
|
||||
buffer[0] = '*';
|
||||
|
||||
/* keep on prepending '*' until the name is unique */
|
||||
while (hash_value_for_key (__objc_class_hash, buffer))
|
||||
{
|
||||
char *bbuffer = (char*) __objc_xmalloc (strlen (buffer)+2);
|
||||
|
||||
strcpy (bbuffer+1, buffer);
|
||||
bbuffer[0] = '*';
|
||||
free (buffer);
|
||||
buffer = bbuffer;
|
||||
}
|
||||
|
||||
hash_remove (__objc_class_hash, super_class->name);
|
||||
hash_add (&__objc_class_hash, buffer, super_class);
|
||||
hash_add (&__objc_class_hash, super_class->name, impostor);
|
||||
|
||||
/* Note that -name and +name will still respond with
|
||||
the same strings as before. This way any
|
||||
-isKindOfGivenName: will always work. */
|
||||
}
|
||||
for (node = hash_next (__objc_class_hash, NULL); node;
|
||||
node = hash_next (__objc_class_hash, node))
|
||||
{
|
||||
class1 = (Class*)node->value;
|
||||
if (class1 == super_class)
|
||||
{
|
||||
node->value = impostor; /* change hash table value */
|
||||
}
|
||||
}
|
||||
|
||||
/* next, we update the dispatch tables... */
|
||||
{
|
||||
Class *subclass;
|
||||
|
||||
for (subclass = impostor->subclass_list;
|
||||
subclass; subclass = subclass->sibling_class)
|
||||
{
|
||||
/* we use the opportunity to check what we did */
|
||||
assert (subclass->super_class == impostor);
|
||||
assert (CLASSOF (subclass)->super_class == CLASSOF (impostor));
|
||||
|
||||
__objc_update_dispatch_table_for_class (CLASSOF (subclass));
|
||||
__objc_update_dispatch_table_for_class (subclass);
|
||||
}
|
||||
}
|
||||
__objc_update_dispatch_table_for_class (CLASSOF (impostor));
|
||||
__objc_update_dispatch_table_for_class (impostor);
|
||||
|
||||
return impostor;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -35,6 +35,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
({ typeof(X) __x = (X), __y = (Y); \
|
||||
(__x < __y ? __x : __y); })
|
||||
|
||||
#define ROUND(V, A) \
|
||||
({ typeof(V) __v=(V); typeof(A) __a=(A); \
|
||||
__a*((__v+__a-1)/__a); })
|
||||
|
||||
|
||||
static inline int
|
||||
atoi (const char* str)
|
||||
|
@ -121,8 +125,7 @@ objc_sizeof_type(const char* type)
|
|||
while (*type != _C_STRUCT_E);
|
||||
{
|
||||
align = objc_alignof_type (type); /* padd to alignment */
|
||||
if ((acc_size % align) != 0)
|
||||
acc_size += align - (acc_size % align);
|
||||
acc_size += ROUND (acc_size, align);
|
||||
acc_size += objc_sizeof_type (type); /* add component size */
|
||||
type = objc_skip_typespec (type); /* skip component */
|
||||
}
|
||||
|
@ -244,11 +247,7 @@ objc_aligned_size (const char* type)
|
|||
{
|
||||
int size = objc_sizeof_type (type);
|
||||
int align = objc_alignof_type (type);
|
||||
|
||||
if ((size % align) != 0)
|
||||
return size + align - (size % align);
|
||||
else
|
||||
return size;
|
||||
return ROUND (size, align);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -262,10 +261,7 @@ objc_promoted_size (const char* type)
|
|||
int size = objc_sizeof_type (type);
|
||||
int wordsize = sizeof (void*);
|
||||
|
||||
if ((size % wordsize) != 0)
|
||||
return size + wordsize - (size % wordsize);
|
||||
else
|
||||
return size;
|
||||
return ROUND (size, wordsize);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -39,6 +39,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
#define EXPANSION(cache) \
|
||||
((cache)->size * 2)
|
||||
|
||||
void *__objc_xcalloc (size_t, size_t);
|
||||
|
||||
cache_ptr
|
||||
hash_new (unsigned int size, hash_func_type hash_func,
|
||||
compare_func_type compare_func)
|
||||
|
|
|
@ -28,7 +28,7 @@ You should have received a copy of the GNU General Public License along with
|
|||
|
||||
/* The version number of this runtime. This must match the number
|
||||
defined in gcc (objc-act.c) */
|
||||
#define OBJC_VERSION 5
|
||||
#define OBJC_VERSION 6
|
||||
#define PROTOCOL_VERSION 2
|
||||
|
||||
/* This list contains all modules currently loaded into the runtime */
|
||||
|
@ -49,6 +49,11 @@ static void __objc_class_add_protocols (Class*, struct objc_protocol_list*);
|
|||
/* Is all categories/classes resolved? */
|
||||
BOOL __objc_dangling_categories = NO;
|
||||
|
||||
extern SEL
|
||||
__sel_register_typed_name (const char *name, const char *types,
|
||||
struct objc_selector *orig);
|
||||
|
||||
|
||||
/* 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
|
||||
|
@ -70,7 +75,7 @@ __objc_exec_class (Module_t module)
|
|||
struct objc_list** cell;
|
||||
|
||||
/* The table of selector references for this module */
|
||||
SEL *selectors = symtab->refs;
|
||||
SEL selectors = symtab->refs;
|
||||
|
||||
/* dummy counter */
|
||||
int i;
|
||||
|
@ -91,6 +96,19 @@ __objc_exec_class (Module_t module)
|
|||
/* Save the module pointer for later processing. (not currently used) */
|
||||
__objc_module_list = list_cons(module, __objc_module_list);
|
||||
|
||||
/* Replace referenced selectors from names to SEL's. */
|
||||
if (selectors)
|
||||
{
|
||||
for (i = 0; selectors[i].sel_id; ++i)
|
||||
{
|
||||
const char *name, *type;
|
||||
name = (char*)selectors[i].sel_id;
|
||||
type = (char*)selectors[i].sel_types;
|
||||
__sel_register_typed_name (name, type,
|
||||
(struct objc_selector*)&(selectors[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the classes in the load module and gather selector information. */
|
||||
DEBUG_PRINTF ("gathering selectors from module: %s\n", module->name);
|
||||
for (i = 0; i < symtab->cls_def_cnt; ++i)
|
||||
|
@ -117,13 +135,6 @@ __objc_exec_class (Module_t module)
|
|||
__objc_init_protocols (class->protocols);
|
||||
}
|
||||
|
||||
/* Replace referenced selectors from names to SEL's. */
|
||||
if (selectors)
|
||||
{
|
||||
for (i = 0; selectors[i]; ++i)
|
||||
selectors[i] = sel_register_name ((const char *) selectors[i]);
|
||||
}
|
||||
|
||||
/* Process category information from the module. */
|
||||
for (i = 0; i < symtab->cat_def_cnt; ++i)
|
||||
{
|
||||
|
@ -166,7 +177,7 @@ __objc_exec_class (Module_t module)
|
|||
categories to objects. */
|
||||
for (cell = &unclaimed_categories;
|
||||
*cell;
|
||||
*cell && ((cell = &(*cell)->tail)))
|
||||
({ if (*cell) cell = &(*cell)->tail; }))
|
||||
{
|
||||
Category_t category = (*cell)->head;
|
||||
Class* class = objc_lookup_class (category->class_name);
|
||||
|
@ -209,7 +220,7 @@ static void init_check_module_version(Module_t module)
|
|||
if ((module->version != OBJC_VERSION) || (module->size != sizeof (Module)))
|
||||
{
|
||||
fprintf (stderr, "Module %s version %d doesn't match runtime %d\n",
|
||||
module->name, module->version, OBJC_VERSION);
|
||||
module->name, (int)module->version, OBJC_VERSION);
|
||||
if(module->version > OBJC_VERSION)
|
||||
fprintf (stderr, "Runtime (libobjc.a) is out of date\n");
|
||||
else if (module->version < OBJC_VERSION)
|
||||
|
@ -255,7 +266,7 @@ __objc_init_protocols (struct objc_protocol_list* protos)
|
|||
{
|
||||
fprintf (stderr,
|
||||
"Version %d doesn't match runtime protocol version %d\n",
|
||||
((size_t)protos->list[i]->class_pointer),
|
||||
(int)((char*)protos->list[i]->class_pointer-(char*)0),
|
||||
PROTOCOL_VERSION);
|
||||
abort ();
|
||||
}
|
||||
|
|
|
@ -30,6 +30,12 @@ void objc_error(id object, const char* fmt, va_list);
|
|||
|
||||
void (*_objc_error)(id, const char*, va_list) = objc_error;
|
||||
|
||||
#ifdef __alpha__
|
||||
#include <stdlib.h>
|
||||
extern int write (int, const char*, int);
|
||||
extern size_t strlen (const char*);
|
||||
#endif
|
||||
|
||||
void
|
||||
objc_error(id object, const char* fmt, va_list ap)
|
||||
{
|
||||
|
@ -40,7 +46,7 @@ objc_error(id object, const char* fmt, va_list ap)
|
|||
volatile void
|
||||
objc_fatal(const char* msg)
|
||||
{
|
||||
write(2, msg, (size_t)strlen((char*)msg));
|
||||
write(2, msg, (int)strlen((const char*)msg));
|
||||
abort();
|
||||
}
|
||||
|
||||
|
@ -65,8 +71,12 @@ __objc_xrealloc(void* mem, size_t size)
|
|||
void*
|
||||
__objc_xcalloc(size_t nelem, size_t size)
|
||||
{
|
||||
void* res = (void*)calloc(nelem, size);
|
||||
#ifdef __alpha__
|
||||
extern bzero (void *, size_t);
|
||||
#endif
|
||||
void* res = (void*)malloc(nelem * size);
|
||||
if(!res)
|
||||
objc_fatal("Virtual memory exhausted\n");
|
||||
bzero (res, nelem * size);
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -44,8 +44,6 @@ struct objc_method_description
|
|||
char *types; /* type encoding */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Filer types used to describe Ivars and Methods. */
|
||||
#define _C_ID '@'
|
||||
#define _C_CLASS '#'
|
||||
|
@ -92,7 +90,7 @@ extern BOOL objc_trace;
|
|||
*/
|
||||
typedef struct objc_symtab {
|
||||
unsigned long sel_ref_cnt; /* Unknown. */
|
||||
SEL *refs; /* 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
|
||||
|
@ -146,7 +144,7 @@ typedef struct objc_ivar_list {
|
|||
const char* ivar_type; /* Description of the Ivar's
|
||||
type. Useful for
|
||||
debuggers. */
|
||||
int ivar_offset; /* Byte offset from the base
|
||||
int ivar_offset; /* Byte offset from the base
|
||||
address of the instance
|
||||
structure to the variable. */
|
||||
|
||||
|
@ -169,7 +167,7 @@ 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
|
||||
int method_count; /* Number of methods defined in
|
||||
this structure. */
|
||||
struct objc_method {
|
||||
SEL method_name; /* This variable is the method's
|
||||
|
@ -303,12 +301,23 @@ 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_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);
|
||||
|
|
|
@ -40,12 +40,24 @@ typedef char BOOL;
|
|||
#define NO (BOOL)0
|
||||
|
||||
/*
|
||||
** Definition of a selector. Selectors are really of type unsigned int.
|
||||
** The runtime does this mapping from SEL's to names internally in the
|
||||
** sel_... operations. You should never use the fact that it is actually
|
||||
** an integer, since other Objective-C implementations use other conventions.
|
||||
** Definition of a selector. Selectors themselves are not unique, but
|
||||
** the sel_id is a unique identifier.
|
||||
*/
|
||||
typedef void* SEL;
|
||||
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.
|
||||
|
@ -131,36 +143,8 @@ typedef union {
|
|||
} *arglist_t; /* argument frame */
|
||||
|
||||
|
||||
#if defined(__OBJC__)
|
||||
#include "objc/sarray.h"
|
||||
|
||||
/*
|
||||
This is the function called when messages are send to nil. You may
|
||||
set a breakpoint in your debugger at this function to catch messages
|
||||
too nil.
|
||||
*/
|
||||
extern id nil_method(id rcv, SEL op, ...);
|
||||
|
||||
/*
|
||||
The messager is inlined, thus it is defined here directly. The
|
||||
inlining is quite time-consuming when optimizing. This will be
|
||||
taken care of later by hand-coding the messager in the compiler.
|
||||
*/
|
||||
extern __inline__ IMP
|
||||
objc_msg_lookup(id receiver, SEL op)
|
||||
{
|
||||
if(receiver)
|
||||
return sarray_get(receiver->class_pointer->dtable, (size_t)(op));
|
||||
else
|
||||
return nil_method;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
IMP objc_msg_lookup(id receiver, SEL op);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,7 @@ class_create_instance(Class* class)
|
|||
new = (*_objc_object_alloc)(class);
|
||||
if (new!=nil)
|
||||
{
|
||||
bzero (new, class->instance_size);
|
||||
memchr (new, 0, class->instance_size);
|
||||
new->class_pointer = class;
|
||||
}
|
||||
return new;
|
||||
|
|
|
@ -61,12 +61,14 @@ extern BOOL __objc_class_links_resolved;
|
|||
extern int __objc_selector_max_index;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_PRINTF printf
|
||||
#define DEBUG_PRINTF(format, args...) printf (format, ## args)
|
||||
#else
|
||||
#define DEBUG_PRINTF
|
||||
#define DEBUG_PRINTF(format, args...)
|
||||
#endif
|
||||
|
||||
BOOL __objc_responds_to (id object, SEL sel); /* for internal use only! */
|
||||
SEL __sel_register_typed_name (const char*, const char*,
|
||||
struct objc_selector*);
|
||||
|
||||
#endif /* not __objc_runtime_INCLUDE_GNU */
|
||||
|
||||
|
|
|
@ -40,6 +40,11 @@ const char* __objc_sparse2_id = "2 level sparse indices";
|
|||
const char* __objc_sparse3_id = "3 level sparse indices";
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
const void *memcpy (void*, const void*, size_t);
|
||||
void free (const void*);
|
||||
#endif
|
||||
|
||||
void
|
||||
sarray_at_put(struct sarray* array, sidx index, void* element)
|
||||
{
|
||||
|
@ -117,7 +122,7 @@ sarray_at_put(struct sarray* array, sidx index, void* element)
|
|||
/* The bucket was previously empty (or something like that), */
|
||||
/* allocate a new. This is the effect of `lazy' allocation */
|
||||
*the_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket));
|
||||
memcpy( *the_bucket,array->empty_bucket, sizeof(struct sbucket));
|
||||
memcpy((void *) *the_bucket, (const void*)array->empty_bucket, sizeof(struct sbucket));
|
||||
(*the_bucket)->version = array->version;
|
||||
nbuckets += 1;
|
||||
|
||||
|
|
|
@ -31,7 +31,8 @@ You should have received a copy of the GNU General Public License along with
|
|||
#define SELECTOR_HASH_SIZE 128
|
||||
|
||||
/* Tables mapping selector names to uid and opposite */
|
||||
static struct sarray* __objc_selector_array = 0; /* uid -> name */
|
||||
static struct sarray* __objc_selector_array = 0; /* uid -> sel */
|
||||
static struct sarray* __objc_selector_names = 0; /* uid -> name */
|
||||
static cache_ptr __objc_selector_hash = 0; /* name -> uid */
|
||||
|
||||
static void register_selectors_from_list(MethodList_t);
|
||||
|
@ -42,6 +43,7 @@ int __objc_selector_max_index = 0;
|
|||
void __objc_init_selector_tables()
|
||||
{
|
||||
__objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
|
||||
__objc_selector_names = sarray_new (SELECTOR_HASH_SIZE, 0);
|
||||
__objc_selector_hash
|
||||
= hash_new (SELECTOR_HASH_SIZE,
|
||||
(hash_func_type) hash_string,
|
||||
|
@ -78,16 +80,67 @@ register_selectors_from_list (MethodList_t method_list)
|
|||
while (i < method_list->method_count)
|
||||
{
|
||||
Method_t method = &method_list->method_list[i];
|
||||
method->method_name = sel_register_name ((char*)method->method_name);
|
||||
method->method_name
|
||||
= sel_register_typed_name ((const char*)method->method_name,
|
||||
method->method_types);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* return selector representing name */
|
||||
SEL
|
||||
sel_get_typed_uid (const char *name, const char *types)
|
||||
{
|
||||
struct objc_list *l;
|
||||
sidx i;
|
||||
|
||||
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
|
||||
if (i == 0)
|
||||
return 0;
|
||||
|
||||
for (l = (struct objc_list*)sarray_get (__objc_selector_array, i);
|
||||
l; l = l->tail)
|
||||
{
|
||||
SEL s = (SEL)l->head;
|
||||
if (types == 0 || s->sel_types == 0)
|
||||
{
|
||||
if (s->sel_types == types)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
}
|
||||
else if (! strcmp (s->sel_types, types))
|
||||
{
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return selector representing name */
|
||||
SEL
|
||||
sel_get_any_uid (const char *name)
|
||||
{
|
||||
struct objc_list *l;
|
||||
sidx i;
|
||||
|
||||
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
|
||||
if (soffset_decode (i) == 0)
|
||||
return 0;
|
||||
|
||||
l = (struct objc_list*)sarray_get (__objc_selector_array, i);
|
||||
if (l == 0)
|
||||
return 0;
|
||||
|
||||
return (SEL)l->head;
|
||||
}
|
||||
|
||||
/* return selector representing name */
|
||||
SEL
|
||||
sel_get_uid (const char *name)
|
||||
{
|
||||
return (SEL) hash_value_for_key (__objc_selector_hash, name);
|
||||
return sel_register_typed_name (name, 0);
|
||||
}
|
||||
|
||||
/* Get name of selector. If selector is unknown, the empty string ""
|
||||
|
@ -95,45 +148,123 @@ sel_get_uid (const char *name)
|
|||
const char*
|
||||
sel_get_name (SEL selector)
|
||||
{
|
||||
if ((soffset_decode((sidx)selector) > 0)
|
||||
&& (soffset_decode((sidx)selector) <= __objc_selector_max_index))
|
||||
return sarray_get (__objc_selector_array, (sidx) selector);
|
||||
if ((soffset_decode((sidx)selector->sel_id) > 0)
|
||||
&& (soffset_decode((sidx)selector->sel_id) <= __objc_selector_max_index))
|
||||
return sarray_get (__objc_selector_array, (sidx) selector->sel_id);
|
||||
else
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL
|
||||
sel_is_mapped (SEL selector)
|
||||
{
|
||||
unsigned int idx = soffset_decode ((sidx)selector);
|
||||
unsigned int idx = soffset_decode ((sidx)selector->sel_id);
|
||||
return ((idx > 0) && (idx <= __objc_selector_max_index));
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
sel_get_type (SEL selector)
|
||||
{
|
||||
if (selector)
|
||||
return selector->sel_types;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The uninstalled dispatch table */
|
||||
extern struct sarray* __objc_uninstalled_dtable;
|
||||
|
||||
/* Store the passed selector name in the selector record and return its
|
||||
selector value (value returned by sel_get_uid). */
|
||||
SEL
|
||||
sel_register_name (const char *sel)
|
||||
__sel_register_typed_name (const char *name, const char *types,
|
||||
struct objc_selector *orig)
|
||||
{
|
||||
SEL j;
|
||||
struct objc_selector* j;
|
||||
sidx i;
|
||||
struct objc_list *l;
|
||||
|
||||
if ((j = sel_get_uid ((const char *) sel)))
|
||||
return j;
|
||||
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
|
||||
if (soffset_decode (i) != 0)
|
||||
{
|
||||
for (l = (struct objc_list*)sarray_get (__objc_selector_array, i);
|
||||
l; l = l->tail)
|
||||
{
|
||||
SEL s = (SEL)l->head;
|
||||
if (types == 0 || s->sel_types == 0)
|
||||
{
|
||||
if (s->sel_types == types)
|
||||
{
|
||||
if (orig)
|
||||
{
|
||||
orig->sel_id = (void*)i;
|
||||
return orig;
|
||||
}
|
||||
else
|
||||
return s;
|
||||
}
|
||||
}
|
||||
else if (strcmp (s->sel_types, types))
|
||||
{
|
||||
if (orig)
|
||||
{
|
||||
orig->sel_id = (void*)i;
|
||||
return orig;
|
||||
}
|
||||
else
|
||||
return s;
|
||||
}
|
||||
}
|
||||
if (orig)
|
||||
j = orig;
|
||||
else
|
||||
j = __objc_xmalloc (sizeof (struct objc_selector));
|
||||
|
||||
/* Save the selector name. */
|
||||
__objc_selector_max_index += 1;
|
||||
i = soffset_encode(__objc_selector_max_index);
|
||||
j->sel_id = (void*)i;
|
||||
j->sel_types = (const char*)types;
|
||||
l = (struct objc_list*)sarray_get (__objc_selector_array, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
__objc_selector_max_index += 1;
|
||||
i = soffset_encode(__objc_selector_max_index);
|
||||
if (orig)
|
||||
j = orig;
|
||||
else
|
||||
j = __objc_xmalloc (sizeof (struct objc_selector));
|
||||
|
||||
j->sel_id = (void*)i;
|
||||
j->sel_types = (const char*)types;
|
||||
l = 0;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF ("Record selector %s as: %#x\n", sel, i);
|
||||
|
||||
sarray_at_put_safe (__objc_selector_array, i, (void *) sel);
|
||||
hash_add (&__objc_selector_hash, (void *) sel, (void *) i);
|
||||
DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types,
|
||||
soffset_decode (i));
|
||||
|
||||
{
|
||||
int is_new = (l == 0);
|
||||
l = list_cons ((void*)j, l);
|
||||
sarray_at_put_safe (__objc_selector_names, i, (void *) name);
|
||||
sarray_at_put_safe (__objc_selector_array, i, (void *) l);
|
||||
if (is_new)
|
||||
hash_add (&__objc_selector_hash, (void *) name, (void *) i);
|
||||
}
|
||||
|
||||
sarray_realloc(__objc_uninstalled_dtable, __objc_selector_max_index+1);
|
||||
|
||||
return (SEL) i;
|
||||
return (SEL) j;
|
||||
}
|
||||
|
||||
SEL
|
||||
sel_register_name (const char *name)
|
||||
{
|
||||
return __sel_register_typed_name (name, 0, 0);
|
||||
}
|
||||
|
||||
SEL
|
||||
sel_register_typed_name (const char *name, const char *type)
|
||||
{
|
||||
return __sel_register_typed_name (name, type, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,10 +24,21 @@ You should have received a copy of the GNU General Public License along with
|
|||
however invalidate any other reasons why the executable file might be
|
||||
covered by the GNU General Public License. */
|
||||
|
||||
#include "../tconfig.h"
|
||||
#include "runtime.h"
|
||||
#include "sarray.h"
|
||||
#include "encoding.h"
|
||||
|
||||
/* this is how we hack STRUCT_VALUE to be 1 or 0 */
|
||||
#define gen_rtx(args...) 1
|
||||
#define rtx int
|
||||
|
||||
#if STRUCT_VALUE == 0
|
||||
#define INVISIBLE_STRUCT_RETURN 1
|
||||
#else
|
||||
#define INVISIBLE_STRUCT_RETURN 0
|
||||
#endif
|
||||
|
||||
/* The uninstalled dispatch table */
|
||||
struct sarray* __objc_uninstalled_dtable = 0;
|
||||
|
||||
|
@ -38,7 +49,14 @@ static void __objc_install_dispatch_table_for_class (Class*);
|
|||
|
||||
/* Forward declare some functions */
|
||||
static void __objc_init_install_dtable(id, SEL);
|
||||
static id __objc_missing_method(id, SEL, ...);
|
||||
static id __objc_word_forward(id, SEL, ...);
|
||||
typedef struct { id many[8]; } __big;
|
||||
#if INVISIBLE_STRUCT_RETURN
|
||||
static __big
|
||||
#else
|
||||
static id
|
||||
#endif
|
||||
__objc_block_forward(id, SEL, ...);
|
||||
static Method_t search_for_method_in_hierarchy (Class* class, SEL sel);
|
||||
static Method_t search_for_method_in_list(MethodList_t list, SEL op);
|
||||
id nil_method(id, SEL, ...);
|
||||
|
@ -53,16 +71,34 @@ nil_method(id receiver, SEL op, ...)
|
|||
__inline__ IMP
|
||||
get_imp (Class* class, SEL sel)
|
||||
{
|
||||
void* res = sarray_get (class->dtable, (size_t) sel);
|
||||
IMP impl;
|
||||
void* res = sarray_get (class->dtable, (size_t) sel->sel_id);
|
||||
if(res == __objc_init_install_dtable)
|
||||
__objc_install_dispatch_table_for_class (class);
|
||||
return sarray_get (class->dtable, (size_t) sel);
|
||||
{
|
||||
__objc_install_dispatch_table_for_class (class);
|
||||
res = sarray_get (class->dtable, (size_t) sel->sel_id);
|
||||
}
|
||||
if (res == 0)
|
||||
{
|
||||
const char *t = sel->sel_types;
|
||||
if (t && (*t == '[' || *t == '(' || *t == '{'))
|
||||
res = (IMP)__objc_block_forward;
|
||||
else
|
||||
res = (IMP)__objc_word_forward;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
__inline__ BOOL
|
||||
__objc_responds_to (id object, SEL sel)
|
||||
{
|
||||
return get_imp (object->class_pointer, sel) != __objc_missing_method;
|
||||
void* res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id);
|
||||
if(res == __objc_init_install_dtable)
|
||||
{
|
||||
__objc_install_dispatch_table_for_class (object->class_pointer);
|
||||
res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id);
|
||||
}
|
||||
return (res != 0);
|
||||
}
|
||||
|
||||
/* This is the lookup function. All entries in the table are either a
|
||||
|
@ -72,8 +108,20 @@ __objc_responds_to (id object, SEL sel)
|
|||
__inline__ IMP
|
||||
objc_msg_lookup(id receiver, SEL op)
|
||||
{
|
||||
IMP result;
|
||||
if(receiver)
|
||||
return sarray_get(receiver->class_pointer->dtable, (sidx)op);
|
||||
{
|
||||
result = sarray_get(receiver->class_pointer->dtable, (sidx)op->sel_id);
|
||||
if (result == 0)
|
||||
{
|
||||
const char *t = op->sel_types;
|
||||
if (t && (*t == '[' || *t == '(' || *t == '{'))
|
||||
result = (IMP)__objc_block_forward;
|
||||
else
|
||||
result = (IMP)__objc_word_forward;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return nil_method;
|
||||
}
|
||||
|
@ -87,6 +135,8 @@ objc_msg_lookup_super (Super_t super, SEL sel)
|
|||
return nil_method;
|
||||
}
|
||||
|
||||
int method_get_sizeof_arguments (Method*);
|
||||
|
||||
retval_t
|
||||
objc_msg_sendv(id object, SEL op, arglist_t arg_frame)
|
||||
{
|
||||
|
@ -141,8 +191,8 @@ static void __objc_init_install_dtable(id receiver, SEL op)
|
|||
|
||||
/* Install real dtable for factory methods */
|
||||
__objc_install_dispatch_table_for_class (receiver->class_pointer);
|
||||
|
||||
if(op != sel_get_uid ("initialize"))
|
||||
|
||||
if (strcmp (sel_get_name (op), "initialize"))
|
||||
__objc_send_initialize((Class*)receiver);
|
||||
else
|
||||
CLS_SETINITIALIZED((Class*)receiver);
|
||||
|
@ -155,7 +205,10 @@ allready_initialized:
|
|||
|
||||
args = __builtin_apply_args();
|
||||
result = __builtin_apply((apply_t)imp, args, 96);
|
||||
__builtin_return (result);
|
||||
if (result)
|
||||
__builtin_return (result);
|
||||
else
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
@ -170,8 +223,6 @@ void __objc_install_premature_dtable(Class* class)
|
|||
/* Send +initialize to class if not already done */
|
||||
static void __objc_send_initialize(Class* class)
|
||||
{
|
||||
Method_t m;
|
||||
|
||||
/* This *must* be a class object */
|
||||
assert(CLS_ISCLASS(class));
|
||||
assert(!CLS_ISMETA(class));
|
||||
|
@ -199,7 +250,7 @@ static void __objc_send_initialize(Class* class)
|
|||
Method_t method = &method_list->method_list[i];
|
||||
|
||||
|
||||
if (method->method_name == op)
|
||||
if (method->method_name->sel_id == op->sel_id)
|
||||
(*method->method_imp)((id) class, op);
|
||||
}
|
||||
|
||||
|
@ -231,8 +282,7 @@ __objc_install_dispatch_table_for_class (Class* class)
|
|||
/* Allocate dtable if nessecary */
|
||||
if (super == 0)
|
||||
{
|
||||
class->dtable = sarray_new (__objc_selector_max_index,
|
||||
__objc_missing_method);
|
||||
class->dtable = sarray_new (__objc_selector_max_index, 0);
|
||||
}
|
||||
else
|
||||
class->dtable = sarray_lazy_copy (super->dtable);
|
||||
|
@ -244,7 +294,7 @@ __objc_install_dispatch_table_for_class (Class* class)
|
|||
{
|
||||
Method_t method = &(mlist->method_list[counter]);
|
||||
sarray_at_put_safe (class->dtable,
|
||||
(sidx) method->method_name,
|
||||
(sidx) method->method_name->sel_id,
|
||||
method->method_imp);
|
||||
counter -= 1;
|
||||
}
|
||||
|
@ -254,7 +304,6 @@ __objc_install_dispatch_table_for_class (Class* class)
|
|||
void __objc_update_dispatch_table_for_class (Class* class)
|
||||
{
|
||||
Class* next;
|
||||
struct sarray* save;
|
||||
|
||||
/* not yet installed -- skip it */
|
||||
if (class->dtable == __objc_uninstalled_dtable)
|
||||
|
@ -297,10 +346,12 @@ class_add_method_list (Class* class, MethodList_t list)
|
|||
if (method->method_name) /* Sometimes these are NULL */
|
||||
{
|
||||
/* This is where selector names are transmogriffed to SEL's */
|
||||
method->method_name = sel_register_name ((char*)method->method_name);
|
||||
method->method_name =
|
||||
sel_register_typed_name ((const char*)method->method_name,
|
||||
method->method_types);
|
||||
|
||||
if (search_for_method_in_list (class->methods, method->method_name)
|
||||
&& method->method_name != initialize_sel)
|
||||
&& method->method_name->sel_id != initialize_sel->sel_id)
|
||||
{
|
||||
/* Duplication. Print a error message an change the method name
|
||||
to NULL. */
|
||||
|
@ -375,7 +426,7 @@ search_for_method_in_list (MethodList_t list, SEL op)
|
|||
Method_t method = &method_list->method_list[i];
|
||||
|
||||
if (method->method_name)
|
||||
if (method->method_name == op)
|
||||
if (method->method_name->sel_id == op->sel_id)
|
||||
return method;
|
||||
}
|
||||
|
||||
|
@ -387,40 +438,71 @@ search_for_method_in_list (MethodList_t list, SEL op)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static retval_t __objc_forward (id object, SEL sel, arglist_t args);
|
||||
|
||||
static id
|
||||
__objc_word_forward (id rcv, SEL op, ...)
|
||||
{
|
||||
void *args, *res;
|
||||
|
||||
args = __builtin_apply_args ();
|
||||
res = __objc_forward (rcv, op, args);
|
||||
if (res)
|
||||
__builtin_return (res);
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
#if INVISIBLE_STRUCT_RETURN
|
||||
static __big
|
||||
#else
|
||||
static id
|
||||
#endif
|
||||
__objc_block_forward (id rcv, SEL op, ...)
|
||||
{
|
||||
void *args, *res;
|
||||
|
||||
args = __builtin_apply_args ();
|
||||
res = __objc_forward (rcv, op, args);
|
||||
if (res)
|
||||
__builtin_return (res);
|
||||
}
|
||||
|
||||
|
||||
/* This fuction is installed in the dispatch table for all methods which are
|
||||
not implemented. Thus, it is called when a selector is not recognized. */
|
||||
static id
|
||||
__objc_missing_method (id object, SEL sel, ...)
|
||||
static retval_t
|
||||
__objc_forward (id object, SEL sel, arglist_t args)
|
||||
{
|
||||
IMP imp;
|
||||
SEL frwd_sel;
|
||||
static SEL frwd_sel = 0;
|
||||
SEL err_sel;
|
||||
|
||||
/* first try if the object understands forward:: */
|
||||
frwd_sel = sel_get_uid("forward::");
|
||||
imp = get_imp(object->class_pointer, frwd_sel);
|
||||
if(imp != __objc_missing_method)
|
||||
if (!frwd_sel)
|
||||
frwd_sel = sel_get_any_uid("forward::");
|
||||
|
||||
if (__objc_responds_to (object, frwd_sel))
|
||||
{
|
||||
void *result, *args = __builtin_apply_args();
|
||||
result = (*imp)(object, frwd_sel, sel, args);
|
||||
__builtin_return(result);
|
||||
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_uid ("doesNotRecognize:");
|
||||
imp = get_imp (object->class_pointer, err_sel);
|
||||
if (imp != __objc_missing_method)
|
||||
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. */
|
||||
{
|
||||
char msg[256 + strlen ((char*)sel_get_name (sel))
|
||||
+ strlen ((char*)object->class_pointer->name)];
|
||||
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)
|
||||
|
@ -428,10 +510,12 @@ __objc_missing_method (id object, SEL sel, ...)
|
|||
: "instance" ),
|
||||
object->class_pointer->name, sel_get_name (sel));
|
||||
|
||||
err_sel = sel_get_uid ("error:");
|
||||
imp = get_imp (object->class_pointer, err_sel);
|
||||
if (imp != __objc_missing_method)
|
||||
return (*imp) (object, sel_get_uid ("error:"), msg);
|
||||
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. */
|
||||
|
@ -451,12 +535,12 @@ void __objc_print_dtable_stats()
|
|||
#endif
|
||||
);
|
||||
|
||||
printf("arrays: %d = %d bytes\n", narrays, narrays*sizeof(struct sarray));
|
||||
printf("arrays: %d = %ld bytes\n", narrays, (int)narrays*sizeof(struct sarray));
|
||||
total += narrays*sizeof(struct sarray);
|
||||
printf("buckets: %d = %d bytes\n", nbuckets, nbuckets*sizeof(struct sbucket));
|
||||
printf("buckets: %d = %ld bytes\n", nbuckets, (int)nbuckets*sizeof(struct sbucket));
|
||||
total += nbuckets*sizeof(struct sbucket);
|
||||
|
||||
printf("idxtables: %d = %d bytes\n", idxsize, idxsize*sizeof(void*));
|
||||
printf("idxtables: %d = %ld bytes\n", idxsize, (int)idxsize*sizeof(void*));
|
||||
total += idxsize*sizeof(void*);
|
||||
printf("-----------------------------------\n");
|
||||
printf("total: %d bytes\n", total);
|
||||
|
|
|
@ -30,8 +30,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
#include "objc/hash.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef __alpha__ /* alpha is currently not supported */
|
||||
|
||||
typedef int (*objc_typed_read_func)(void*, char*, int);
|
||||
typedef int (*objc_typed_write_func)(void*, const char*, int);
|
||||
typedef int (*objc_typed_flush_func)(void*);
|
||||
|
@ -100,7 +98,7 @@ int objc_read_types (TypedStream* stream, const char* type, ...);
|
|||
int objc_write_object_reference (TypedStream* stream, id object);
|
||||
int objc_write_root_object (TypedStream* stream, id object);
|
||||
|
||||
int objc_get_stream_class_version (TypedStream* stream, Class* class);
|
||||
long objc_get_stream_class_version (TypedStream* stream, Class* class);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -130,6 +128,4 @@ void objc_close_typed_stream (TypedStream* stream);
|
|||
BOOL objc_end_of_typed_stream (TypedStream* stream);
|
||||
void objc_flush_typed_stream (TypedStream* stream);
|
||||
|
||||
#endif /* __alpha__ */
|
||||
|
||||
#endif /* not __typedstream_INCLUDE_GNU */
|
||||
|
|
Loading…
Reference in New Issue