#import @interface InvokedObject : NSObject - (void) noarg; - (void) chararg:(char) arg; - (void) shortarg:(short) arg; - (void) intarg:(int) arg; - (void) doublearg:(double) arg; - (void) idarg:(id) arg; - (void) idarg:(id) arg idarg:(id) arg2; - (void) indirect; @end @implementation InvokedObject - (void) noarg; { NSLog(@"noarg"); } - (void) intarg:(int) arg; { NSLog(@"intarg:%d", arg); } - (void) chararg:(char) arg; { NSLog(@"chararg:%d", arg); } - (void) shortarg:(short) arg; { NSLog(@"shortarg:%d", arg); } - (void) doublearg:(double) arg; { NSLog(@"doublearg:%lf", arg); } - (void) idarg:(id) arg; { NSLog(@"idarg:%@", arg); } - (void) idarg:(id) arg idarg:(id) arg2; { int i; NSLog(@"&self=%p", &self); NSLog(@"&_cmd=%p", &_cmd); NSLog(@"&arg=%p", &arg); NSLog(@"&arg2=%p", &arg2); for(i=-24; i<48; i++) { NSString *note=@""; void **addr=((void **)&arg); // array of pointers to something if(addr[i] == self) note=(@"self"); if(addr[i] == _cmd) note=(@"_cmd"); if(addr[i] == arg) note=(@"arg"); if(addr[i] == arg2) note=(@"arg2"); NSLog(@"stack[%2d]:%08x %08x %@", i, &(addr[i]), addr[i], note); } NSLog(@"idarg:%@ :%@", arg, arg2); } - (void) idarg:(id) arg idarg:(id) arg2 idarg:(id) arg3; { NSLog(@"&idarg1:%p", &arg); NSLog(@"idarg1:%@", arg); NSLog(@"idarg2:%@", arg2); NSLog(@"&idarg3:%p", &arg3); NSLog(@"idarg3:%p", arg3); NSLog(@"idarg3:%@", arg3); } - (oneway void) sameSignature:(int) pid name:(bycopy NSString *) name // name path:(bycopy NSString *) path // full path NSApp:(byref NSString *) app; // creates NSDistantObject to remotely access { NSLog(@"dummy to provide method signature"); } - (NSMethodSignature *) methodSignatureForSelector:(SEL)aSelector { NSLog(@"methodSignatureForSelector %@", NSStringFromSelector(aSelector)); // NSLog(@"methodSignatureForSelector %s", sel_getName(aSelector)); #if __mySTEP__ if(strcmp(sel_get_name(aSelector), "forward:name:path:NSApp:") == 0) #else if(strcmp(sel_getName(aSelector), "forward:name:path:NSApp:") == 0) #endif { NSMethodSignature *sig; NSLog(@"found forward:name:path:NSApp:"); sig=[super methodSignatureForSelector:@selector(sameSignature:name:path:NSApp:)]; NSLog(@" replaced by %@ returning %s", sig, [sig methodReturnType]); return sig; } return [super methodSignatureForSelector:aSelector]; } - (void) forwardInvocation:(NSInvocation *)anInvocation { unsigned n; NSMethodSignature *ms; NSLog(@"forwardInvocation: %p", anInvocation); ms=[anInvocation methodSignature]; NSLog(@"target=%@", [anInvocation target]); NSLog(@"selector=%@", NSStringFromSelector([anInvocation selector])); NSLog(@"isOneway=%u", [ms isOneway]); NSLog(@"frameLength=%u", [ms frameLength]); NSLog(@"methodReturnLength=%u", [ms methodReturnLength]); NSLog(@"numberOfArguments=%u", [ms numberOfArguments]); NSLog(@"methodReturnType=%s", [ms methodReturnType]); for(n=0; n<[ms numberOfArguments]; n++) NSLog(@"type[%u]=%s", n, [ms getArgumentTypeAtIndex:n]); [anInvocation setSelector:@selector(registerApplication:name:path:NSApp:)]; // redirect NSLog(@"redirected=%@", NSStringFromSelector([anInvocation selector])); [anInvocation invoke]; // and call } - (oneway void) registerApplication:(int) pid name:(bycopy NSString *) name // name path:(bycopy NSString *) path // full path NSApp:(byref NSString *) app; // creates NSDistantObject to remotely access { int i; long *frame=(long *)__builtin_apply_args(); NSLog(@"*** registerApplication (%p) has been called ***", self); NSLog(@"__builtin_apply_args returns frame=%p", frame); for(i=0; i<24; i++) { NSLog(@"frame[%2d]:%p %08x%@", i, &frame[i], frame[i], &frame[i] == ((void **)&pid)-8 ? @" <-- SP":@""); } for(i=-8; i<48; i++) { NSString *note=@""; void **addr=((void **)&pid)-8; // array of pointers to something if(addr[i] == self) note=(@"self"); if(addr[i] == _cmd) note=(@"_cmd"); if(addr[i] == (void *) pid) note=(@"pid"); if(addr[i] == name) note=(@"name"); if(addr[i] == path) note=(@"path"); if(addr[i] == app) note=(@"app"); NSLog(@"stack[%2d]:%08x %08x %@", i, &(addr[i]), addr[i], note); } // addresses on stack NSLog(@"&self=%p", &self); NSLog(@"&_cmd=%p", &_cmd); NSLog(@"&pid=%p", &pid); NSLog(@"&name=%p", &name); NSLog(@"&path=%p", &path); NSLog(@"&app=%p", &app); // values NSLog(@"self=%p", self); NSLog(@"_cmd=%p", _cmd); NSLog(@"pid=%d (should be 13, 14, 15, 16)", pid); NSLog(@"name=%p", name); NSLog(@"path=%p", path); NSLog(@"app=%p", app); // objects (typed values) NSLog(@"self=%@", self); NSLog(@"_cmd=%@", NSStringFromSelector(_cmd)); NSLog(@"pid=%d", pid); NSLog(@"name=%@", name); NSLog(@"path=%@", path); NSLog(@"app=%@", app); NSLog(@"*** registerApplication has been done ***"); } - (void) indirect { // direct(); void *args[50]; void *frame[6]; // build our own stack frame manually NSLog(@"indirect preparing frame=%p args=%p", frame, args); frame[0]=args; frame[1]=self; // self frame[2]=@"frame[2]"; // this one is ignored! frame[3]=@selector(registerApplication:name:path:NSApp:); frame[4]=(void *) 16; // pid frame[5]=@"directname"; args[0]=@"directpath"; // this are the args that are NOT passed in registers args[1]=@"directapp"; NSLog(@"indirect apply"); __builtin_apply((void *) [self methodForSelector:(SEL) frame[3]], (void *) frame, 2*sizeof(args[0])); NSLog(@"indirect done"); } @end InvokedObject *target; NSInvocation *invocation(SEL sel) { // create invocation NSLog(@"*** construct invocation ***"); { NSMethodSignature *ms=[target methodSignatureForSelector:sel]; NSInvocation *i=ms?[NSInvocation invocationWithMethodSignature:ms]:(NSInvocation *) nil; unsigned n; NSLog(@"selector=%@", NSStringFromSelector(sel)); NSLog(@"isOneway=%u", [ms isOneway]); NSLog(@"frameLength=%u", [ms frameLength]); NSLog(@"methodReturnLength=%u", [ms methodReturnLength]); NSLog(@"numberOfArguments=%u", [ms numberOfArguments]); NSLog(@"methodReturnType=%s", [ms methodReturnType]); for(n=0; n<[ms numberOfArguments]; n++) NSLog(@"type[%u]=%s", n, [ms getArgumentTypeAtIndex:n]); NSLog(@"*** inserting target and selector ***"); [i setTarget:target]; [i setSelector:sel]; return i; } } void function(int arg1, int arg2, int arg3) { NSLog(@"arg1=%d", arg1); NSLog(@"arg2=%d", arg2); NSLog(@"arg3=%d", arg3); } // this also works!!! void other() { typedef struct args { void *a[16]; } args; int iargs[]={ target, @selector(idarg:idarg:idarg:), @"String 1", @"String 2", @"String 3" }; void (*fnp)(args arg)=[target methodForSelector:(SEL)iargs[1]]; (*fnp)(*(args *) iargs); // this should copy the struct onto the stack like directly supplied arguments // abort(); } void direct() { void *args[50]; void *frame[6]; // build our own stack frame manually NSLog(@"preparing frame=%p args=%p", frame, args); frame[0]=args; frame[1]=target; // self frame[2]=@"frame[2]"; // this one is ignored! frame[3]=@selector(registerApplication:name:path:NSApp:); frame[4]=(void *) 15; // pid frame[5]=@"directname"; args[0]=@"directpath"; // this are the args that are NOT passed in registers args[1]=@"directapp"; NSLog(@"apply"); __builtin_apply((void *) [target methodForSelector:(SEL) frame[3]], (void *) frame, 2*sizeof(args[0])); NSLog(@"done"); } int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSInvocation *i; char cval='@'; short sval=1234; int ival=4321; double dval=3.1415; id oval=@"constant string"; id oval2=@"second constant string"; target=[InvokedObject new]; // global... #if 0 direct(); other(); i=invocation(@selector(noarg)); [i invoke]; i=invocation(@selector(intarg:)); [i setArgument:&ival atIndex:2]; [i invoke]; i=invocation(@selector(chararg:)); [i setArgument:&cval atIndex:2]; [i invoke]; i=invocation(@selector(shortarg:)); [i setArgument:&sval atIndex:2]; [i invoke]; i=invocation(@selector(doublearg:)); [i setArgument:&dval atIndex:2]; [i invoke]; i=invocation(@selector(idarg:)); [i setArgument:&oval atIndex:2]; [i invoke]; i=invocation(@selector(idarg:idarg:)); [i setArgument:&oval atIndex:2]; [i setArgument:&oval2 atIndex:3]; [i invoke]; i=invocation(@selector(idarg:idarg:idarg:)); oval=@"arg1"; [i setArgument:&oval atIndex:2]; oval=@"arg2"; [i setArgument:&oval atIndex:3]; oval=@"arg3"; [i setArgument:&oval atIndex:4]; [i invoke]; #endif // [(id)target registerApplication:123 name:@"name" path:@"/usr/path" NSApp:@"NSApp"]; // call directly NSLog(@"*** call through forwardInvocation called ***"); [(id)target forward:13 name:@"name" path:@"/usr/path" NSApp:@"NSApp"]; // should issue a forwardInvocation NSLog(@"*** call by constructed NSInvocation ***"); // direct(); i=invocation(@selector(registerApplication:name:path:NSApp:)); NSLog(@"*** set arguments manually ***"); ival=14; [i setArgument:&ival atIndex:2]; oval=@"name"; [i setArgument:&oval atIndex:3]; oval=@"/usr/bin/path"; [i setArgument:&oval atIndex:4]; oval=@"NSApp"; [i setArgument:&oval atIndex:5]; // direct(); // [target indirect]; NSLog(@"*** invoke ***"); [i invoke]; NSLog(@"*** done ***"); [pool release]; return 0; }