You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
6.2 KiB
Objective-C
266 lines
6.2 KiB
Objective-C
// Needed with glibc to expose vasprintf
|
|
#define _GNU_SOURCE
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include "../objc/runtime.h"
|
|
#include "../objc/hooks.h"
|
|
|
|
//#define assert(x) if (!(x)) { printf("Failed %d\n", __LINE__); }
|
|
|
|
typedef void (*fwdManyFunc)(id, SEL, int, int, int, int, int, int, int, int, int, int, int, float, float, float, float, float, float, float, float, float, float, float);
|
|
|
|
typedef struct { int a,b,c,d,e; } s;
|
|
@interface Fake
|
|
- (int)izero;
|
|
- (float)fzero;
|
|
- (double)dzero;
|
|
- (long double)ldzero;
|
|
@end
|
|
|
|
Class TestCls;
|
|
#ifdef __has_attribute
|
|
#if __has_attribute(objc_root_class)
|
|
__attribute__((objc_root_class))
|
|
#endif
|
|
#endif
|
|
@interface MsgTest { id isa; } @end
|
|
@interface MsgTest (Dynamic)
|
|
+ (void)manyArgs: (int)a0
|
|
: (int) a1
|
|
: (int) a2
|
|
: (int) a3
|
|
: (int) a4
|
|
: (int) a5
|
|
: (int) a6
|
|
: (int) a7
|
|
: (int) a8
|
|
: (int) a9
|
|
: (int) a10
|
|
: (float) f0
|
|
: (float) f1
|
|
: (float) f2
|
|
: (float) f3
|
|
: (float) f4
|
|
: (float) f5
|
|
: (float) f6
|
|
: (float) f7
|
|
: (float) f8
|
|
: (float) f9
|
|
: (float) f10;
|
|
@end
|
|
@implementation MsgTest
|
|
- foo
|
|
{
|
|
assert((id)1 == self);
|
|
assert(strcmp("foo", sel_getName(_cmd)) == 0);
|
|
return (id)0x42;
|
|
}
|
|
+ foo
|
|
{
|
|
assert(TestCls == self);
|
|
assert(strcmp("foo", sel_getName(_cmd)) == 0);
|
|
return (id)0x42;
|
|
}
|
|
+ (s)sret
|
|
{
|
|
assert(TestCls == self);
|
|
assert(strcmp("sret", sel_getName(_cmd)) == 0);
|
|
s st = {1,2,3,4,5};
|
|
return st;
|
|
}
|
|
- (s)sret
|
|
{
|
|
assert((id)3 == self);
|
|
assert(strcmp("sret", sel_getName(_cmd)) == 0);
|
|
s st = {1,2,3,4,5};
|
|
return st;
|
|
}
|
|
+ (void)printf: (const char*)str, ...
|
|
{
|
|
va_list ap;
|
|
char s[100];
|
|
|
|
va_start(ap, str);
|
|
|
|
vsnprintf(s, 100, str, ap);
|
|
va_end(ap);
|
|
assert(strcmp(s, "Format string 42 42.000000\n") ==0);
|
|
}
|
|
+ (void)initialize
|
|
{
|
|
[self printf: "Format %s %d %f%c", "string", 42, 42.0, '\n'];
|
|
@throw self;
|
|
}
|
|
+ nothing { return 0; }
|
|
@end
|
|
|
|
int forwardcalls;
|
|
void fwdMany(id self,
|
|
SEL _cmd,
|
|
int a0,
|
|
int a1,
|
|
int a2,
|
|
int a3,
|
|
int a4,
|
|
int a5,
|
|
int a6,
|
|
int a7,
|
|
int a8,
|
|
int a9,
|
|
int a10,
|
|
float f0,
|
|
float f1,
|
|
float f2,
|
|
float f3,
|
|
float f4,
|
|
float f5,
|
|
float f6,
|
|
float f7,
|
|
float f8,
|
|
float f9,
|
|
float f10)
|
|
{
|
|
forwardcalls++;
|
|
assert(self == objc_getClass("MsgTest"));
|
|
if (sel_isEqual(_cmd, sel_registerName("manyArgs:::::::::::::::::::::")))
|
|
assert(a0 == 0);
|
|
assert(a1 == 1);
|
|
assert(a2 == 2);
|
|
assert(a3 == 3);
|
|
assert(a4 == 4);
|
|
assert(a5 == 5);
|
|
assert(a6 == 6);
|
|
assert(a7 == 7);
|
|
assert(a8 == 8);
|
|
assert(a9 == 9);
|
|
assert(a10 == 10);
|
|
assert(f0 == 0);
|
|
assert(f1 == 1);
|
|
assert(f2 == 2);
|
|
assert(f3 == 3);
|
|
assert(f4 == 4);
|
|
assert(f5 == 5);
|
|
assert(f6 == 6);
|
|
assert(f7 == 7);
|
|
assert(f8 == 8);
|
|
assert(f9 == 9);
|
|
assert(f10 == 10);
|
|
}
|
|
|
|
void fwd(void)
|
|
{
|
|
forwardcalls++;
|
|
}
|
|
|
|
IMP forward(id o, SEL s)
|
|
{
|
|
assert(o == objc_getClass("MsgTest"));
|
|
if (sel_isEqual(s, sel_registerName("missing")))
|
|
{
|
|
return (IMP)fwd;
|
|
}
|
|
return (IMP)fwdMany;
|
|
}
|
|
|
|
static struct objc_slot slot;
|
|
struct objc_slot *forward_slot(id o, SEL s)
|
|
{
|
|
slot.method = (IMP)fwd;
|
|
return &slot;
|
|
}
|
|
|
|
|
|
|
|
int main(void)
|
|
{
|
|
#ifdef __GNUSTEP_MSGSEND__
|
|
__objc_msg_forward2 = forward;
|
|
__objc_msg_forward3 = forward_slot;
|
|
TestCls = objc_getClass("MsgTest");
|
|
int exceptionThrown = 0;
|
|
@try {
|
|
objc_msgSend(TestCls, @selector(foo));
|
|
} @catch (id e)
|
|
{
|
|
assert((TestCls == e) && "Exceptions propagate out of +initialize");
|
|
exceptionThrown = 1;
|
|
}
|
|
assert(exceptionThrown && "An exception was thrown");
|
|
assert((id)0x42 == objc_msgSend(TestCls, @selector(foo)));
|
|
objc_msgSend(TestCls, @selector(nothing));
|
|
objc_msgSend(TestCls, @selector(missing));
|
|
assert(forwardcalls == 1);
|
|
assert(0 == objc_msgSend(0, @selector(nothing)));
|
|
id a = objc_msgSend(objc_getClass("MsgTest"), @selector(foo));
|
|
assert((id)0x42 == a);
|
|
a = objc_msgSend(TestCls, @selector(foo));
|
|
assert((id)0x42 == a);
|
|
assert(objc_registerSmallObjectClass_np(objc_getClass("MsgTest"), 1));
|
|
a = objc_msgSend((id)01, @selector(foo));
|
|
assert((id)0x42 == a);
|
|
s ret = ((s(*)(id, SEL))objc_msgSend_stret)(TestCls, @selector(sret));
|
|
assert(ret.a == 1);
|
|
assert(ret.b == 2);
|
|
assert(ret.c == 3);
|
|
assert(ret.d == 4);
|
|
assert(ret.e == 5);
|
|
if (sizeof(id) == 8)
|
|
{
|
|
assert(objc_registerSmallObjectClass_np(objc_getClass("MsgTest"), 3));
|
|
ret = ((s(*)(id, SEL))objc_msgSend_stret)((id)3, @selector(sret));
|
|
assert(ret.a == 1);
|
|
assert(ret.b == 2);
|
|
assert(ret.c == 3);
|
|
assert(ret.d == 4);
|
|
assert(ret.e == 5);
|
|
}
|
|
Fake *f = nil;
|
|
assert(0 == [f izero]);
|
|
assert(0 == [f dzero]);
|
|
assert(0 == [f ldzero]);
|
|
assert(0 == [f fzero]);
|
|
// Call manyArgs with objc_msgSend explicitly to test the slow lookup path
|
|
SEL manyArgsSel = sel_registerName("manyArgs::::::::::::::::::::::");
|
|
((fwdManyFunc)objc_msgSend)(TestCls, manyArgsSel, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
|
assert(forwardcalls == 2);
|
|
[TestCls manyArgs: 0 : 1 : 2 : 3: 4: 5: 6: 7: 8: 9: 10 : 0 : 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10];
|
|
assert(forwardcalls == 3);
|
|
#ifdef BENCHMARK
|
|
const int iterations = 1000000000;
|
|
double times[3];
|
|
clock_t c1, c2;
|
|
c1 = clock();
|
|
for (int i=0 ; i<iterations ; i++)
|
|
{
|
|
[TestCls nothing];
|
|
}
|
|
c2 = clock();
|
|
times[0] = ((double)c2 - (double)c1) / (double)CLOCKS_PER_SEC;
|
|
fprintf(stderr, "Traditional message send took %f seconds. \n", times[0]);
|
|
c1 = clock();
|
|
for (int i=0 ; i<iterations ; i++)
|
|
{
|
|
objc_msgSend(TestCls, @selector(nothing));
|
|
}
|
|
c2 = clock();
|
|
times[1] = ((double)c2 - (double)c1) / (double)CLOCKS_PER_SEC;
|
|
fprintf(stderr, "objc_msgSend() message send took %f seconds. \n", times[1]);
|
|
IMP nothing = objc_msg_lookup(TestCls, @selector(nothing));
|
|
c1 = clock();
|
|
for (int i=0 ; i<iterations ; i++)
|
|
{
|
|
nothing(TestCls, @selector(nothing));
|
|
}
|
|
c2 = clock();
|
|
times[2] = ((double)c2 - (double)c1) / (double)CLOCKS_PER_SEC;
|
|
fprintf(stderr, "Direct IMP call took %f seconds. \n", times[2]);
|
|
printf("%f\t%f\t%f\n", times[0], times[1], times[2]);
|
|
#endif // BENCHMARK
|
|
return 0;
|
|
#endif // __GNUSTEP_MSGSEND__
|
|
return 77; // Skip test
|
|
}
|