diff --git a/Headers/gnustep/base/Invocation.h b/Headers/gnustep/base/Invocation.h new file mode 100644 index 000000000..708e9f583 --- /dev/null +++ b/Headers/gnustep/base/Invocation.h @@ -0,0 +1,82 @@ +#ifndef __Invocation_h_OBJECTS_INCLUDE +#define __Invocation_h_OBJECTS_INCLUDE + +/* + Use these for notifications! + Don't forget to make these archivable / transportable. + WARNING: All the (char*) type arguments and return values may + extraneous stuff after the first type. +*/ + +#include +#include + +@interface Invocation : NSObject +{ + char *encoding; + unsigned return_size; + void *return_value; +} +- initWithReturnType: (const char *)encoding; +- (void) invoke; +- (void) invokeWithObject: anObj; +- (void) invokeWithElement: (elt)anElt; +- (const char *) returnType; +- (unsigned) returnSize; +- (void) getReturnValue: (void *)addr; +@end + +@interface ArgframeInvocation : Invocation +{ + arglist_t argframe; + /* char *function_encoding; Using return_encoding */ +} +- initWithArgframe: (arglist_t)frame type: (const char *)e; +- initWithType: (const char *)e; +- (const char *) argumentTypeAtIndex: (unsigned)i; +- (unsigned) argumentSizeAtIndex: (unsigned)i; +- (void) getArgument: (void*)addr atIndex: (unsigned)i; +- (void) setArgumentAtIndex: (unsigned)i + toValueAt: (const void*)addr; +@end + +@interface MethodInvocation : ArgframeInvocation +- initWithArgframe: (arglist_t)frame selector: (SEL)s; +- initWithSelector: (SEL)s; +- (void) invokeWithTarget: t; +- (SEL) selector; +- (void) setSelector: (SEL)s; +- target; +- (void) setTarget: t; +@end + +@interface FunctionInvocation : ArgframeInvocation +{ + void (*function)(); +} +- initWithFunction: (void(*)())f + argframe: (arglist_t)frame type: (const char *)e; +- initWithFunction: (void(*)())f; +@end + +#if 0 +// NO, instead do above; +@interface EltFunctionInvocation +{ + void (*func)(elt); +} +- initWithEltFunction: (void(*)(elt))func; +@end + +@interface TclInvocation +- initWithTcl: (Tcl*)t command: (const char*)c; +@end + +@interface Collection (Invokes) +- makeObjectsInvoke: (MethodInvocation*)i; +- withObjectsInvoke: (Invocation*)i; +- withElementsInvoke: (EltInvocation*)i; +@end +#endif + +#endif /* __Invocation_h_OBJECTS_INCLUDE */ diff --git a/Source/Invocation.m b/Source/Invocation.m new file mode 100644 index 000000000..1c8f87a41 --- /dev/null +++ b/Source/Invocation.m @@ -0,0 +1,285 @@ + +#include + +/* Deal with strrchr: */ +#if STDC_HEADERS || HAVE_STRING_H +#include +/* An ANSI string.h and pre-ANSI memory.h might conflict. */ +#if !STDC_HEADERS && HAVE_MEMORY_H +#include +#endif /* not STDC_HEADERS and HAVE_MEMORY_H */ +#define rindex strrchr +#define bcopy(s, d, n) memcpy ((d), (s), (n)) +#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) +#define bzero(s, n) memset ((s), 0, (n)) +#else /* not STDC_HEADERS and not HAVE_STRING_H */ +#include +/* memory.h and strings.h conflict on some systems. */ +#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); + memcpy(encoding, enc, l); + return_size = objc_sizeof_type(encoding); + return_value = NULL; + return self; +} +- (void) invoke +{ + [self subclassResponsibility:_cmd]; +} + +- (void) invokeWithObject: anObj +{ + [self invoke]; +} + +- (void) invokeWithElement: (elt)anElt +{ + [self invoke]; +} + +- (const char *) returnType +{ + return encoding; +} + +- (unsigned) returnSize +{ + return return_size; +} + +- (void) getReturnValue: (void *)addr +{ + memcpy(addr, return_value, return_size); +} + +- (void) dealloc +{ + OBJC_FREE(encoding); + [super dealloc]; +} + +@end + + +static int +types_get_size_of_stack_arguments(const char *types) +{ + const char* type = objc_skip_typespec (types); + return atoi(type); +} + +static int +types_get_size_of_register_arguments(const char *types) +{ + const char* type = strrchr(types, '+'); + if (type) + return atoi(++type) + sizeof(void*); + else + return 0; +} + +/* To fix temporary bug in method_get_next_argument() on m68k */ +static char* +my_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 + /* xxx What's going on here? This -8 needed on my 68k NeXT box. */ +#if m68k + return argframe->arg_ptr + (atoi(t) - 8); +#else + return argframe->arg_ptr + atoi(t); +#endif +} + +@implementation ArgframeInvocation + +/* This is the designated initializer. */ +- initWithArgframe: (arglist_t)frame type: (const char *)type +{ + int stack_argsize, reg_argsize; + + /* xxx we could just use the return part. Does this matter? */ + [super initWithReturnType:type]; + + /* allocate the argframe */ + stack_argsize = types_get_size_of_stack_arguments(type); + reg_argsize = types_get_size_of_register_arguments(type); + argframe = (arglist_t) (*objc_malloc)(sizeof(char*) + reg_argsize); + if (stack_argsize) + argframe->arg_ptr = (*objc_malloc)(stack_argsize); + else + argframe->arg_ptr = 0; + + /* copy the frame into the argframe */ + if (frame) + { + memcpy((char*)argframe + sizeof(char*), + (char*)frame + sizeof(char*), + reg_argsize); + memcpy(argframe->arg_ptr, frame->arg_ptr, stack_argsize); + } + + return self; +} + +- initWithType: (const char *)e +{ + [self initWithArgframe:NULL type:e]; + return self; +} + +- (const char *) argumentTypeAtIndex: (unsigned)i +{ + const char *tmptype = encoding; + + do + { + tmptype = objc_skip_argspec(objc_skip_typespec(tmptype)); + } + while (i--); + return tmptype; +} + +- (unsigned) argumentSizeAtIndex: (unsigned)i +{ + return objc_sizeof_type([self argumentTypeAtIndex:i]); +} + +- (void) getArgument: (void*)addr atIndex: (unsigned)i +{ + const char *tmptype = encoding; + void *datum; + + do + datum = my_method_get_next_argument(argframe, &tmptype); + while (i--); + memcpy(addr, datum, objc_sizeof_type(tmptype)); +} + +- (void) setArgumentAtIndex: (unsigned)i + toValueAt: (const void*)addr +{ + const char *tmptype = encoding; + void *datum; + + do + datum = my_method_get_next_argument(argframe, &tmptype); + while (i--); + memcpy(datum, addr, objc_sizeof_type(tmptype)); +} + +@end + + +@implementation MethodInvocation + +- initWithArgframe: (arglist_t)frame selector: (SEL)sel +{ + [self initWithArgframe:frame type:sel_get_type(sel)]; + return self; +} + +- initWithSelector: (SEL)s +{ + [self initWithArgframe:NULL selector:s]; + return self; +} + +- (void) invoke +{ + void *ret; + IMP imp; + + imp = get_imp([self target], [self selector]); + assert(imp); + ret = __builtin_apply((void(*)(void))imp, + argframe, + type_get_size_of_stack_arguments(encoding)); + if (*encoding == 'd') + memcpy(return_value, (char*)ret + 2*sizeof(void*), return_size); + else + memcpy(return_value, ret, return_size); +} + +- (void) invokeWithTarget: t +{ + [self setArgumentAtIndex:0 toValueAt:&t]; + [self invoke]; +} + +- (SEL) selector +{ + SEL s; + [self getArgument:&s atIndex:1]; + return s; +} + +- (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]; + else + { + [self notImplemented:_cmd]; + /* We will need to reallocate the argframe */ + } +} + +- target +{ + id t; + [self getArgument:&t atIndex:1]; + return t; +} + +- (void) setTarget: t +{ + [self setArgumentAtIndex:0 toValueAt:&t]; +} + +@end + + +/* Many other kinds of Invocations are possible: + SchemeInvocation, TclInvocation */ + +#if 0 +What is this nonsense? +@interface StreamInvocation +@interface LogInvocation +@interface PrintingInvocation +{ + Stream *stream; + char *format_string; +} +@end +#endif diff --git a/Source/objects/Invocation.h b/Source/objects/Invocation.h new file mode 100644 index 000000000..708e9f583 --- /dev/null +++ b/Source/objects/Invocation.h @@ -0,0 +1,82 @@ +#ifndef __Invocation_h_OBJECTS_INCLUDE +#define __Invocation_h_OBJECTS_INCLUDE + +/* + Use these for notifications! + Don't forget to make these archivable / transportable. + WARNING: All the (char*) type arguments and return values may + extraneous stuff after the first type. +*/ + +#include +#include + +@interface Invocation : NSObject +{ + char *encoding; + unsigned return_size; + void *return_value; +} +- initWithReturnType: (const char *)encoding; +- (void) invoke; +- (void) invokeWithObject: anObj; +- (void) invokeWithElement: (elt)anElt; +- (const char *) returnType; +- (unsigned) returnSize; +- (void) getReturnValue: (void *)addr; +@end + +@interface ArgframeInvocation : Invocation +{ + arglist_t argframe; + /* char *function_encoding; Using return_encoding */ +} +- initWithArgframe: (arglist_t)frame type: (const char *)e; +- initWithType: (const char *)e; +- (const char *) argumentTypeAtIndex: (unsigned)i; +- (unsigned) argumentSizeAtIndex: (unsigned)i; +- (void) getArgument: (void*)addr atIndex: (unsigned)i; +- (void) setArgumentAtIndex: (unsigned)i + toValueAt: (const void*)addr; +@end + +@interface MethodInvocation : ArgframeInvocation +- initWithArgframe: (arglist_t)frame selector: (SEL)s; +- initWithSelector: (SEL)s; +- (void) invokeWithTarget: t; +- (SEL) selector; +- (void) setSelector: (SEL)s; +- target; +- (void) setTarget: t; +@end + +@interface FunctionInvocation : ArgframeInvocation +{ + void (*function)(); +} +- initWithFunction: (void(*)())f + argframe: (arglist_t)frame type: (const char *)e; +- initWithFunction: (void(*)())f; +@end + +#if 0 +// NO, instead do above; +@interface EltFunctionInvocation +{ + void (*func)(elt); +} +- initWithEltFunction: (void(*)(elt))func; +@end + +@interface TclInvocation +- initWithTcl: (Tcl*)t command: (const char*)c; +@end + +@interface Collection (Invokes) +- makeObjectsInvoke: (MethodInvocation*)i; +- withObjectsInvoke: (Invocation*)i; +- withElementsInvoke: (EltInvocation*)i; +@end +#endif + +#endif /* __Invocation_h_OBJECTS_INCLUDE */