3 #include <objc/objc-runtime.h>
5 @interface Super { id isa; }
9 @interface Sub : Super @end
13 #if defined(__ppc__) || defined(__ppc64__)
14 // On ppc and ppc64, methods must be called with r12==IMP (i.e. indirect function call convention)
15 #define CHECK_R12(cls) \
18 __asm__ volatile ("mr %[val], r12\n" : [val] "=r" (val)); \
19 testassert(val == method_getImplementation(class_getClassMethod([cls class], _cmd))); \
22 #define CHECK_R12(cls) do {/* empty */} while (0)
26 #define CHECK_ARGS(cls, sel) \
28 testassert(self == [cls class]); \
29 testassert(_cmd == sel_registerName(#sel "::::::::::::::::::::::::::::"));\
30 testassert(i1 == 1); \
31 testassert(i2 == 2); \
32 testassert(i3 == 3); \
33 testassert(i4 == 4); \
34 testassert(i5 == 5); \
35 testassert(i6 == 6); \
36 testassert(i7 == 7); \
37 testassert(i8 == 8); \
38 testassert(i9 == 9); \
39 testassert(i10 == 10); \
40 testassert(i11 == 11); \
41 testassert(i12 == 12); \
42 testassert(i13 == 13); \
43 testassert(f1 == 1.0); \
44 testassert(f2 == 2.0); \
45 testassert(f3 == 3.0); \
46 testassert(f4 == 4.0); \
47 testassert(f5 == 5.0); \
48 testassert(f6 == 6.0); \
49 testassert(f7 == 7.0); \
50 testassert(f8 == 8.0); \
51 testassert(f9 == 9.0); \
52 testassert(f10 == 10.0); \
53 testassert(f11 == 11.0); \
54 testassert(f12 == 12.0); \
55 testassert(f13 == 13.0); \
56 testassert(f14 == 14.0); \
57 testassert(f15 == 15.0); \
66 int pad[32]; // force stack return on ppc64
69 BOOL stret_equal(struct stret a, struct stret b)
78 id ID_RESULT = (id)0x12345678;
79 long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
80 struct stret STRET_RESULT = {1, 2, 3, 4, 5, {0}};
81 double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
82 long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
86 +class { return self; }
90 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
93 if (state == 10) CHECK_ARGS(Sub, idret);
94 else CHECK_ARGS(Super, idret);
100 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
103 if (state == 10) CHECK_ARGS(Sub, llret);
104 else CHECK_ARGS(Super, llret);
109 +(struct stret)stret:
110 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
113 if (state == 10) CHECK_ARGS(Sub, stret);
114 else CHECK_ARGS(Super, stret);
120 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
123 if (state == 10) CHECK_ARGS(Sub, fpret);
124 else CHECK_ARGS(Super, fpret);
129 +(long double)lfpret:
130 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
133 if (state == 10) CHECK_ARGS(Sub, lfpret);
134 else CHECK_ARGS(Super, lfpret);
141 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
143 fail("-idret called instead of +idret");
144 CHECK_ARGS(Super, idret);
148 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
150 fail("-llret called instead of +llret");
151 CHECK_ARGS(Super, llret);
154 -(struct stret)stret:
155 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
157 fail("-stret called instead of +stret");
158 CHECK_ARGS(Super, stret);
162 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
164 fail("-fpret called instead of +fpret");
165 CHECK_ARGS(Super, fpret);
168 -(long double)lfpret:
169 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
171 fail("-lfpret called instead of +lfpret");
172 CHECK_ARGS(Super, lfpret);
181 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
185 CHECK_ARGS(Sub, idret);
187 result = [super idret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
188 testassert(state == 1);
189 testassert(result == ID_RESULT);
195 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
199 CHECK_ARGS(Sub, llret);
201 result = [super llret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
202 testassert(state == 2);
203 testassert(result == LL_RESULT);
208 +(struct stret)stret:
209 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
213 CHECK_ARGS(Sub, stret);
215 result = [super stret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
216 testassert(state == 3);
217 testassert(stret_equal(result, STRET_RESULT));
223 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
227 CHECK_ARGS(Sub, fpret);
229 result = [super fpret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
230 testassert(state == 4);
231 testassert(result == FP_RESULT);
236 +(long double)lfpret:
237 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
241 CHECK_ARGS(Sub, lfpret);
243 result = [super lfpret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
244 testassert(state == 5);
245 testassert(result == LFP_RESULT);
252 // performance-test code (do nothing for better comparability)
259 +(long long)llret_perf
264 +(struct stret)stret_perf
274 +(long double)lfpret_perf
287 struct stret stretval;
301 id (*idfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
302 long long (*llfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
303 struct stret (*stretfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
304 double (*fpfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
305 long double (*lfpfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
307 struct stret zero = {0, 0, 0, 0, 0, {0}};
309 // get +initialize out of the way
312 idmethod = class_getClassMethod([Super class], @selector(idret::::::::::::::::::::::::::::));
313 testassert(idmethod);
314 llmethod = class_getClassMethod([Super class], @selector(llret::::::::::::::::::::::::::::));
315 testassert(llmethod);
316 stretmethod = class_getClassMethod([Super class], @selector(stret::::::::::::::::::::::::::::));
317 testassert(stretmethod);
318 fpmethod = class_getClassMethod([Super class], @selector(fpret::::::::::::::::::::::::::::));
319 testassert(fpmethod);
320 lfpmethod = class_getClassMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::));
321 testassert(lfpmethod);
323 idfn = (id (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
324 llfn = (long long (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
325 stretfn = (struct stret (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke_stret;
326 fpfn = (double (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
327 lfpfn = (long double (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
330 // message uncached long long
331 // message uncached stret
332 // message uncached fpret
333 // message uncached fpret long double
335 // message cached long long
336 // message cached stret
337 // message cached fpret
338 // message cached fpret long double
339 // fixme verify that uncached lookup didn't happen the 2nd time?
340 for (i = 0; i < 5; i++) {
343 idval = [Sub idret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
344 testassert(state == 11);
345 testassert(idval == ID_RESULT);
348 llval = [Sub llret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
349 testassert(state == 12);
350 testassert(llval == LL_RESULT);
353 stretval = [Sub stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
354 testassert(state == 13);
355 testassert(stret_equal(stretval, STRET_RESULT));
358 fpval = [Sub fpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
359 testassert(state == 14);
360 testassert(fpval == FP_RESULT);
363 lfpval = [Sub lfpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
364 testassert(state == 15);
365 testassert(lfpval == LFP_RESULT);
368 // cached message performance
369 // catches failure to cache or (abi=2) failure to fixup (#5584187)
370 // fixme unless they all fail
371 // `.align 4` matches loop alignment to make -O0 work
372 #define COUNT 1000000
374 startTime = mach_absolute_time();
376 for (i = 0; i < COUNT; i++) {
379 totalTime = mach_absolute_time() - startTime;
380 testprintf("idret %llu\n", totalTime);
381 targetTime = totalTime;
384 startTime = mach_absolute_time();
386 for (i = 0; i < COUNT; i++) {
389 totalTime = mach_absolute_time() - startTime;
390 testprintf("llret %llu\n", totalTime);
391 timeassert(totalTime > targetTime * 0.8 && totalTime < targetTime * 2.0);
394 startTime = mach_absolute_time();
396 for (i = 0; i < COUNT; i++) {
399 totalTime = mach_absolute_time() - startTime;
400 testprintf("stret %llu\n", totalTime);
401 timeassert(totalTime > targetTime * 0.8 && totalTime < targetTime * 5.0);
404 startTime = mach_absolute_time();
406 for (i = 0; i < COUNT; i++) {
409 totalTime = mach_absolute_time() - startTime;
410 testprintf("fpret %llu\n", totalTime);
411 timeassert(totalTime > targetTime * 0.8 && totalTime < targetTime * 2.0);
414 startTime = mach_absolute_time();
416 for (i = 0; i < COUNT; i++) {
419 totalTime = mach_absolute_time() - startTime;
420 testprintf("lfpret %llu\n", totalTime);
421 timeassert(totalTime > targetTime * 0.8 && totalTime < targetTime * 2.0);
425 // method_invoke long long
426 // method_invoke_stret stret
427 // method_invoke_stret fpret
428 // method_invoke fpret long double
432 idval = (*idfn)([Super class], idmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
433 testassert(state == 1);
434 testassert(idval == ID_RESULT);
437 llval = (*llfn)([Super class], llmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
438 testassert(state == 2);
439 testassert(llval == LL_RESULT);
442 stretval = (*stretfn)([Super class], stretmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
443 testassert(state == 3);
444 testassert(stret_equal(stretval, STRET_RESULT));
447 fpval = (*fpfn)([Super class], fpmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
448 testassert(state == 4);
449 testassert(fpval == FP_RESULT);
452 lfpval = (*lfpfn)([Super class], lfpmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
453 testassert(state == 5);
454 testassert(lfpval == LFP_RESULT);
458 // message to nil long long
459 // message to nil stret
460 // message to nil fpret
461 // message to nil fpret long double
464 idval = [(id)nil idret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
465 testassert(state == 0);
466 testassert(idval == nil);
470 llval = [(id)nil llret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
471 testassert(state == 0);
472 testassert(llval == 0LL);
476 stretval = [(id)nil stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
477 testassert(state == 0);
478 // no stret result guarantee
482 fpval = [(id)nil fpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
483 testassert(state == 0);
484 testassert(fpval == 0.0);
488 lfpval = [(id)nil lfpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
489 testassert(state == 0);
490 testassert(lfpval == 0.0);
494 // message forwarded long long
495 // message forwarded stret
496 // message forwarded fpret
497 // message forwarded fpret long double