([Invocation -initWithReturnType:]): Use new ivar names. Use calloc

instead of malloc.
([Invocation -encodeWithCoder:]): New method.
([Invocation -initWithCoder:]): New method.
([Invocation -classForConnectedCoder:]): New method.
([Invocation -returnType]): Use new ivar name.
([Invocation -setReturnValue:]): New method.
([Invocation -objectReturnValue]): Method implemented.
([Invocation -intReturnValue]): Method implemented.
([Invocation -returnValueIsTrue]): Method implementation finished.
([Invocation -dealloc]): Use new ivar name.  Release return type if
necessary.
([ArgframeInvocation -_retainArguments]): New method.
([ArgframeInvocation -_initArgframeFrom:withType:retainArgs:]): Method
overhauled.
([ArgframeInvocation -initWithArgframe:type:]): Use new method.
([ArgframeInvocation -encodeWithCoder:]): New method.
([ArgframeInvocation -initWithCoder:]): New method.
([ArgframeInvocation -argumentTypeAtIndex:]): Use new ivar name.
([ArgframeInvocation -retainArguments]): New method.
([ArgframeInvocation -argumentsRetained]): New method.
([ArgframeInvocation -_deallocArgframe]): New method.
([ArgframeInvocation -dealloc]): Use new method.  Release args if
necessary.
([MethodInvocation -_initTargetAndSelPointers]): New method.
([MethodInvocation -initWithArgframe:selector:]): Use new method.
([MethodInvocation -initWithCoder:]): New method.
([MethodInvocation -initWithTarget:selector:...]): Retain args if
necessary.
([MethodInvocation -invoke]): Use new ivars.
([MethodInvocation -invokeWithTarget:]): Use -setTarget:.
([MethodInvocation -selector]): Use new ivar.
([MethodInvocation -setSelector:]): Likewise.
([MethodInvocation -target]): Likewise.
([MethodInvocation -setTarget:]): Likewise.
([ObjectMethodInvocation -_initArgObjectPointer]): New method.
([ObjectMethodInvocation -initWithArgframe:selector:]): Use new method.
([ObjectMethodInvocation -initWithCoder:]): New method.
([ObjectMethodInvocation -invokeWithObject:]): New method.
(VoidFunctionInvocation): New class implementation.
(ObjectFunctionInvocation): New class implementation.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@998 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Andrew McCallum 1996-02-24 17:03:04 +00:00
parent 49f9e1b864
commit 645c3c3c96

View file

@ -1,5 +1,5 @@
/* Implementation for Objective-C Invocation object
Copyright (C) 1993,1994, 1995, 1996 Free Software Foundation, Inc.
Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: May 1993
@ -23,6 +23,10 @@
#include <objects/stdobjects.h>
#include <objects/Invocation.h>
#include <Foundation/NSValue.h>
#include <objects/NSString.h>
#include <objects/Connection.h>
#include <objects/ConnectedCoder.h>
/* Deal with strrchr: */
#if STDC_HEADERS || HAVE_STRING_H
@ -41,30 +45,20 @@
#endif /* not STDC_HEADERS and not HAVE_STRING_H */
/*
Put something like this in Collecting:
- withObjectsAtArgumentIndex: (unsigned)index
invoke: (Invocation*)invocation;
- putObjectsAtArgumentIndex: (unsigned)index
andInvoke: (Invocation*)invocation;
- invoke: (Invocation*)invocation
withObjectsAtArgumentIndex: (unsigned)index
*/
@implementation Invocation
- initWithReturnType: (const char *)enc
{
int l = strlen(enc);
OBJC_MALLOC(encoding, char, l + 1);
memcpy(encoding, enc, l);
encoding[l] = '\0';
enc = objc_skip_type_qualifiers (encoding);
OBJC_MALLOC(return_type, char, l + 1);
memcpy(return_type, enc, l);
return_type[l] = '\0';
enc = objc_skip_type_qualifiers (return_type);
if (*enc != 'v')
{
/* Work around bug in objc_sizeof_type; it doesn't handle void type */
return_size = objc_sizeof_type (enc);
return_value = (*objc_malloc) (return_size);
return_value = (*objc_calloc) (1, return_size);
}
else
{
@ -73,6 +67,50 @@
}
return self;
}
- (void) encodeWithCoder: (id <Encoding>)coder
{
[super encodeWithCoder: coder];
[coder encodeValueOfCType: @encode(char*)
at: &return_type
withName: @"Invocation return type"];
[coder encodeValueOfCType: @encode(unsigned)
at: &return_size
withName: @"Invocation return size"];
if (return_size)
[coder encodeValueOfObjCType: return_type
at: return_value
withName: @"Invocation return value"];
}
- initWithCoder: (id <Decoding>)coder
{
self = [super initWithCoder: coder];
[coder decodeValueOfCType: @encode(char*)
at: &return_type
withName: NULL];
[coder decodeValueOfCType: @encode(unsigned)
at: &return_size
withName: NULL];
if (return_size)
{
return_value = (*objc_malloc) (return_size);
[coder decodeValueOfObjCType: return_type
at: return_value
withName: NULL];
}
else
return_value = 0;
return self;
}
- (Class) classForConnectedCoder: coder
{
/* Make sure that Connection's always send us bycopy,
i.e. as our own class, not a Proxy class. */
return [self class];
}
- (void) invoke
{
[self subclassResponsibility:_cmd];
@ -85,7 +123,7 @@
- (const char *) returnType
{
return encoding;
return return_type;
}
- (unsigned) returnSize
@ -101,15 +139,71 @@
a return value yet. */
}
- (void) setReturnValue: (void*)addr
{
if (return_value)
memcpy (return_value, addr, return_size);
/* xxx retain, if necessary. */
}
- objectReturnValue
{
switch (*return_type)
{
#define CASE_RETURN(C,T,S) \
case C: return [NSNumber numberWith ## S: *(T*)return_value]
CASE_RETURN (_C_LNG, long, Long);
CASE_RETURN (_C_ULNG, unsigned long, UnsignedLong);
CASE_RETURN (_C_INT, int, Int);
CASE_RETURN (_C_UINT, unsigned int, UnsignedInt);
CASE_RETURN (_C_SHT, short, Short);
CASE_RETURN (_C_USHT, unsigned short, UnsignedShort);
CASE_RETURN (_C_CHR, char, Char);
CASE_RETURN (_C_UCHR, unsigned char, UnsignedChar);
CASE_RETURN (_C_FLT, float, Float);
CASE_RETURN (_C_DBL, double, Double);
#undef CASE_RETURN
case _C_PTR:
return [NSNumber numberWithUnsignedLong: (long) *(void**)return_value];
case _C_CHARPTR:
return [NSString stringWithCString: *(char**)return_value];
case _C_ID:
return *(id*)return_value;
case 'v':
return nil;
default:
[self notImplemented: _cmd];
}
return 0;
[self notImplemented: _cmd];
return nil;
}
- (int) intReturnValue
{
[self notImplemented: _cmd];
switch (*return_type)
{
#define CASE_RETURN(_C,_T) case _C: return (int) *(_T*)return_value
CASE_RETURN (_C_LNG, long);
CASE_RETURN (_C_ULNG, unsigned long);
CASE_RETURN (_C_INT, int);
CASE_RETURN (_C_UINT, unsigned int);
CASE_RETURN (_C_SHT, short);
CASE_RETURN (_C_USHT, unsigned short);
CASE_RETURN (_C_CHR, char);
CASE_RETURN (_C_UCHR, unsigned char);
CASE_RETURN (_C_CHARPTR, char*);
CASE_RETURN (_C_FLT, float);
CASE_RETURN (_C_DBL, double);
CASE_RETURN (_C_PTR, void*);
#undef CASE_RETURN
case _C_ID:
return [*(id*)return_value intValue];
case 'v':
return 0;
default:
[self notImplemented: _cmd];
}
return 0;
}
@ -121,27 +215,29 @@
return (*(char*)return_value != 0);
case sizeof(short):
return (*(short*)return_value != 0);
case sizeof(long):
return (*(long*)return_value != 0);
case sizeof(int):
return (*(int*)return_value != 0);
}
[self notImplemented: _cmd];
{
int i;
for (i = 0; i < return_size; i++)
if (*((char*)return_value + i) != 0)
return YES;
return NO;
}
}
- (void) dealloc
{
OBJC_FREE(encoding);
if (*return_type == _C_ID)
[*(id*)return_value release];
OBJC_FREE(return_type);
[super dealloc];
}
@end
#if 0
@implementation CurriedInvocation
@end
#endif
static int
types_get_size_of_stack_arguments(const char *types)
{
@ -185,20 +281,32 @@ my_method_get_next_argument (arglist_t argframe,
@implementation ArgframeInvocation
/* This is the designated initializer. */
- initWithArgframe: (arglist_t)frame type: (const char *)type
- (void) _retainArguments
{
const char *tmptype;
tmptype = return_type;
while ((datum = my_method_get_next_argument (argframe, &tmptype)))
{
tmptype = objc_skip_type_qualifiers (tmptype);
if (*tmptype == _C_ID)
[*(id*)datum retain];
}
}
- (void) _initArgframeFrom: (arglist_t)frame
withType: (const char*)type
retainArgs: (BOOL)f
{
int stack_argsize, reg_argsize;
/* xxx we could just use the return part. Does this matter? */
[super initWithReturnType:type];
void *datum;
/* allocate the argframe */
stack_argsize = types_get_size_of_stack_arguments(type);
stack_argsize = types_get_size_of_stack_arguments (type);
reg_argsize = types_get_size_of_register_arguments(type);
argframe = (arglist_t) (*objc_calloc)(1 ,sizeof(char*) + reg_argsize);
argframe = (arglist_t) (*objc_calloc) (1 ,sizeof(char*) + reg_argsize);
if (stack_argsize)
argframe->arg_ptr = (*objc_calloc)(1, stack_argsize);
argframe->arg_ptr = (*objc_calloc) (1, stack_argsize);
else
argframe->arg_ptr = 0;
@ -209,8 +317,50 @@ my_method_get_next_argument (arglist_t argframe,
(char*)frame + sizeof(char*),
reg_argsize);
memcpy(argframe->arg_ptr, frame->arg_ptr, stack_argsize);
if (f)
[self _retainArguments];
}
}
/* This is the designated initializer. */
- initWithArgframe: (arglist_t)frame type: (const char *)type
{
/* xxx we are just using the return part. Does this matter? */
[super initWithReturnType: type];
[self _initArgframeFrom: frame withType: type retainArgs: NO];
return self;
}
- (void) encodeWithCoder: (id <Encoding>)coder
{
const char *tmptype;
void *datum;
[super encodeWithCoder: coder];
tmptype = return_type;
while ((datum = my_method_get_next_argument(argframe, &tmptype)))
{
[coder encodeValueOfObjCType: tmptype
at: datum
withName: @"Invocation Argframe argument"];
}
}
- initWithCoder: (id <Decoding>)coder
{
const char *tmptype;
void *datum;
self = [super initWithCoder: coder];
[self _initArgframeFrom: NULL withType: return_type retainArgs: NO];
tmptype = return_type;
while ((datum = my_method_get_next_argument(argframe, &tmptype)))
{
[coder decodeValueOfObjCType: tmptype
at: datum
withName: NULL];
}
return self;
}
@ -220,13 +370,28 @@ my_method_get_next_argument (arglist_t argframe,
return self;
}
- (void) retainArguments
{
if (!args_retained)
{
if (argframe)
[self _retainArguments];
args_retained = YES;
}
}
- (BOOL) argumentsRetained
{
return args_retained;
}
- (const char *) argumentTypeAtIndex: (unsigned)i
{
const char *tmptype = encoding;
const char *tmptype = return_type;
do
{
tmptype = objc_skip_argspec(objc_skip_typespec(tmptype));
tmptype = objc_skip_argspec (tmptype);
}
while (i--);
return tmptype;
@ -239,19 +404,20 @@ my_method_get_next_argument (arglist_t argframe,
- (void) getArgument: (void*)addr atIndex: (unsigned)i
{
const char *tmptype = encoding;
const char *tmptype = return_type;
void *datum;
do
datum = my_method_get_next_argument(argframe, &tmptype);
while (i--);
while (i-- && datum);
/* xxx Give error msg for null datum */
memcpy (addr, datum, objc_sizeof_type(tmptype));
}
- (void) setArgumentAtIndex: (unsigned)i
toValueAt: (const void*)addr
{
const char *tmptype = encoding;
const char *tmptype = return_type;
void *datum;
do
@ -260,23 +426,72 @@ my_method_get_next_argument (arglist_t argframe,
memcpy (datum, addr, objc_sizeof_type(tmptype));
}
- (void) _deallocArgframe
{
if (argframe)
{
if (argframe->arg_ptr)
(*objc_free) (argframe->arg_ptr);
(*objc_free) (argframe);
}
}
- (void) dealloc
{
void *datum;
const char *tmptype = return_type;
while ((datum = my_method_get_next_argument(argframe, &tmptype)))
{
tmptype = objc_skip_type_qualifiers (tmptype);
if (*tmptype == _C_ID)
[*(id*)datum release];
}
[self _deallocArgframe];
[super dealloc];
}
#if 0
- resetArgframeWithReturnType: (const char*)encoding
{
[self _deallocArgframe];
[self _allocArgframe];
}
#endif
@end
@implementation MethodInvocation
- (void) _initTargetAndSelPointers
{
const char *tmptype = return_type;
target_pointer = (id*) my_method_get_next_argument (argframe, &tmptype);
sel_pointer = (SEL*) my_method_get_next_argument (argframe, &tmptype);
}
/* This is the designated initializer */
- initWithArgframe: (arglist_t)frame selector: (SEL)sel
{
const char *sel_type;
if (! (sel_type = sel_get_type (sel)) )
sel_type = sel_get_type ( sel_get_any_typed_uid (sel_get_name (sel)));
[self initWithArgframe: frame type: sel_type];
[self _initTargetAndSelPointers];
return self;
}
- initWithCoder: (id <Decoding>)coder
{
self = [super initWithCoder: coder];
[self _initTargetAndSelPointers];
return self;
}
- initWithSelector: (SEL)s
{
[self initWithArgframe: NULL selector: s];
[self setArgumentAtIndex: 1 toValueAt: &s];
*sel_pointer = s;
return self;
}
@ -287,9 +502,11 @@ my_method_get_next_argument (arglist_t argframe,
void *arg_datum;
va_list ap;
[self initWithSelector:s];
tmptype = encoding;
[self initWithArgframe: NULL selector: s];
tmptype = return_type;
datum = my_method_get_next_argument(argframe, &tmptype);
if (args_retained)
[target retain];
*((id*)datum) = target;
datum = my_method_get_next_argument(argframe, &tmptype);
*((SEL*)datum) = s;
@ -300,7 +517,13 @@ my_method_get_next_argument (arglist_t argframe,
#define CASE_TYPE(_C,_T) case _C: *(_T*)datum = va_arg (ap, _T); break
switch (*tmptype)
{
CASE_TYPE(_C_ID, id);
case _C_ID:
*(id*)datum = va_arg (ap, id);
if (args_retained)
[*(id*)datum retain];
break;
CASE_TYPE(_C_SEL, SEL);
CASE_TYPE(_C_LNG, long);
CASE_TYPE(_C_ULNG, unsigned long);
CASE_TYPE(_C_INT, int);
@ -309,7 +532,10 @@ my_method_get_next_argument (arglist_t argframe,
CASE_TYPE(_C_USHT, unsigned short);
CASE_TYPE(_C_CHR, char);
CASE_TYPE(_C_UCHR, unsigned char);
CASE_TYPE(_C_FLT, float);
CASE_TYPE(_C_DBL, double);
CASE_TYPE(_C_CHARPTR, char*);
CASE_TYPE(_C_PTR, void*);
default:
[self notImplemented: _cmd];
// memcpy (datum, va_arg (ap, void*), objc_sizeof_type(tmptype));
@ -327,35 +553,53 @@ my_method_get_next_argument (arglist_t argframe,
id target;
id cl;
SEL sel;
char *tmp_type = return_type;
/* xxx This could be more efficient by using my_method_get_next_argument
instead of -target and -selector. Or, even better, caching the
memory offsets of the target and selector in the argframe. */
target = [self target];
target = *target_pointer;
if (target == nil)
return;
cl = object_get_class (target);
sel = [self selector];
sel = *sel_pointer;
/* xxx Perhaps we could speed things up by making this an ivar,
and caching it. */
imp = get_imp (cl, sel);
assert(imp);
ret = __builtin_apply((void(*)(void))imp,
argframe,
types_get_size_of_stack_arguments(encoding));
if (return_value)
types_get_size_of_stack_arguments(return_type));
if (return_size)
{
if (*encoding == 'd')
if (*return_type == _C_DBL)
/* DBL's are stored in a different place relative to RET. */
memcpy(return_value, (char*)ret + 2*sizeof(void*), return_size);
else if (*return_type == _C_ID)
{
if (*(id*)return_value != *(id*)ret)
{
if (return_retained)
{
if (*(id*)return_value)
[*(id*)return_value release];
[*(id*)ret retain];
}
*(id*)return_value = *(id*)ret;
}
}
else
memcpy(return_value, ret, return_size);
{
memcpy(return_value, ret, return_size);
}
}
}
- (void) invokeWithTarget: t
{
/* xxx Could be more efficient. */
[self setArgumentAtIndex:0 toValueAt:&t];
[self setTarget: t];
[self invoke];
}
@ -366,35 +610,90 @@ my_method_get_next_argument (arglist_t argframe,
- (SEL) selector
{
SEL s;
[self getArgument:&s atIndex:1];
return s;
return *sel_pointer;
}
- (void) setSelector: (SEL)s
{
[self setArgumentAtIndex:1 toValueAt:&s];
if (sel_types_match(sel_get_type([self selector]), sel_get_type(s)))
[self setArgumentAtIndex:1 toValueAt:&s];
*sel_pointer = s;
else
{
/* We need to reallocate the argframe */
[self notImplemented:_cmd];
/* We will need to reallocate the argframe */
}
}
- target
{
id t;
[self getArgument:&t atIndex:0];
return t;
return *target_pointer;
}
- (void) setTarget: t
{
[self setArgumentAtIndex:0 toValueAt:&t];
if (*target_pointer != t)
{
if (args_retained)
{
[*target_pointer release];
[t retain];
}
*target_pointer = t;
}
}
@end
@implementation ObjectMethodInvocation
- (void) _initArgObjectPointer
{
const char *tmptype;
void *datum;
tmptype = return_type;
my_method_get_next_argument (argframe, &tmptype);
my_method_get_next_argument (argframe, &tmptype);
do
{
datum = my_method_get_next_argument (argframe, &tmptype);
tmptype = objc_skip_type_qualifiers (tmptype);
}
while (datum && tmptype && *tmptype != _C_ID);
if (*tmptype != _C_ID)
[self error: "This method does not have an object argument."];
arg_object_pointer = (id*) datum;
}
- initWithArgframe: (arglist_t)frame selector: (SEL)sel
{
[super initWithArgframe: frame selector: sel];
[self _initArgObjectPointer];
return self;
}
- initWithCoder: (id <Decoding>)coder
{
self = [super initWithCoder: coder];
[self _initArgObjectPointer];
return self;
}
- (void) invokeWithObject: anObject
{
if (*arg_object_pointer != anObject)
{
if (args_retained)
{
[*arg_object_pointer release];
[anObject retain];
}
*arg_object_pointer = anObject;
}
[self invoke];
}
@end
@implementation VoidFunctionInvocation
@ -409,19 +708,88 @@ my_method_get_next_argument (arglist_t argframe,
}
#endif
- initWithFunction: (void(*)())f
- initWithVoidFunction: (void(*)())f
{
[super initWithReturnType: "v"];
function = f;
return self;
}
/* Encode ourself as a proxies across Connection's; we can't encode
a function across the wire. */
- classForConnectedCoder: coder
{
return [[coder connection] proxyClass];
}
- (void) encodeWithCoder: (id <Encoding>)coder
{
[self shouldNotImplement: _cmd];
}
- (void) invoke
{
(*function) ();
}
- (void) invokeWithObject
{
[self shouldNotImplement: _cmd];
}
@end
@implementation ObjectFunctionInvocation
- initWithObjectFunction: (id(*)(id))f
{
[super initWithReturnType: "@"];
function = f;
return self;
}
/* Encode ourself as a proxies across Connection's; we can't encode
a function across the wire. */
- classForConnectedCoder: coder
{
return [[coder connection] proxyClass];
}
- (void) encodeWithCoder: (id <Encoding>)coder
{
[self shouldNotImplement: _cmd];
}
- (void) invoke
{
[self invokeWithObject: nil];
}
- (void) invokeWithObject: anObject
{
id r;
r = (*function) (anObject);
if (*(id*)return_value != r)
{
if (args_retained)
{
[*(id*)return_value release];
[r retain];
}
*(id*)return_value = r;
}
}
@end
/* Many other kinds of Invocations are possible:
SchemeInvocation, TclInvocation */
#if 0
@implementation CurriedInvocation
@end
What is this nonsense?
@interface StreamInvocation
@interface LogInvocation