1 // TEST_CFLAGS -Wno-unused-parameter -Wundeclared-selector
6 #if __cplusplus && !__clang__
10 // llvm-g++ is confused by @selector(foo::) and will never be fixed
16 #include <objc/objc.h>
17 #include <objc/runtime.h>
18 #include <objc/objc-internal.h>
19 #include <objc/objc-abi.h>
20 #include <simd/simd.h>
22 // rdar://21694990 simd.h should have a vector_equal(a, b) function
23 static bool vector_equal(vector_ulong2 lhs, vector_ulong2 rhs) {
24 return vector_all(lhs == rhs);
28 // no stret dispatchers
29 # define SUPPORT_STRET 0
30 # define objc_msgSend_stret objc_msgSend
31 # define objc_msgSendSuper2_stret objc_msgSendSuper2
32 # define objc_msgSend_stret_debug objc_msgSend_debug
33 # define objc_msgSendSuper2_stret_debug objc_msgSendSuper2_debug
34 # define method_invoke_stret method_invoke
36 # define SUPPORT_STRET 1
44 # define ALIGN_() asm(".align 4");
47 @interface Super : TestRoot @end
49 @interface Sub : Super @end
55 // for typeof() shorthand only
56 id (*idmsg0)(id, SEL) __attribute__((unused));
57 long long (*llmsg0)(id, SEL) __attribute__((unused));
58 // struct stret (*stretmsg0)(id, SEL) __attribute__((unused));
59 double (*fpmsg0)(id, SEL) __attribute__((unused));
60 long double (*lfpmsg0)(id, SEL) __attribute__((unused));
61 vector_ulong2 (*vecmsg0)(id, SEL) __attribute__((unused));
63 #define VEC1 ((vector_ulong2){1, 1})
64 #define VEC2 ((vector_ulong2){2, 2})
65 #define VEC3 ((vector_ulong2){3, 3})
66 #define VEC4 ((vector_ulong2){4, 4})
67 #define VEC5 ((vector_ulong2){5, 5})
68 #define VEC6 ((vector_ulong2){6, 6})
69 #define VEC7 ((vector_ulong2){7, 7})
70 #define VEC8 ((vector_ulong2){8, 8})
72 #define CHECK_ARGS(sel) \
74 testassert(self == SELF); \
75 testassert(_cmd == sel_registerName(#sel "::::::::::::::::::::::::::::::::::::"));\
76 testassert(vector_all(v1 == 1)); \
77 testassert(vector_all(v2 == 2)); \
78 testassert(vector_all(v3 == 3)); \
79 testassert(vector_all(v4 == 4)); \
80 testassert(vector_all(v5 == 5)); \
81 testassert(vector_all(v6 == 6)); \
82 testassert(vector_all(v7 == 7)); \
83 testassert(vector_all(v8 == 8)); \
84 testassert(i1 == 1); \
85 testassert(i2 == 2); \
86 testassert(i3 == 3); \
87 testassert(i4 == 4); \
88 testassert(i5 == 5); \
89 testassert(i6 == 6); \
90 testassert(i7 == 7); \
91 testassert(i8 == 8); \
92 testassert(i9 == 9); \
93 testassert(i10 == 10); \
94 testassert(i11 == 11); \
95 testassert(i12 == 12); \
96 testassert(i13 == 13); \
97 testassert(f1 == 1.0); \
98 testassert(f2 == 2.0); \
99 testassert(f3 == 3.0); \
100 testassert(f4 == 4.0); \
101 testassert(f5 == 5.0); \
102 testassert(f6 == 6.0); \
103 testassert(f7 == 7.0); \
104 testassert(f8 == 8.0); \
105 testassert(f9 == 9.0); \
106 testassert(f10 == 10.0); \
107 testassert(f11 == 11.0); \
108 testassert(f12 == 12.0); \
109 testassert(f13 == 13.0); \
110 testassert(f14 == 14.0); \
111 testassert(f15 == 15.0); \
114 #define CHECK_ARGS_NOARG(sel) \
116 testassert(self == SELF); \
117 testassert(_cmd == sel_registerName(#sel "_noarg"));\
122 long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
123 double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
124 long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
125 vector_ulong2 VEC_RESULT = { 0x1234567890abcdefULL, 0xfedcba0987654321ULL };
126 // STRET_RESULT in test.h
128 static struct stret zero;
255 @interface Super (Prototypes)
257 // Method prototypes to pacify -Wundeclared-selector.
260 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
263 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
265 -(struct stret)stret:
266 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
269 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
271 -(long double)lfpret:
272 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
274 -(vector_ulong2)vecret:
275 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
280 // Zero all volatile registers.
299 "\n xorps %xmm0, %xmm0"
300 "\n xorps %xmm1, %xmm1"
301 "\n xorps %xmm2, %xmm2"
302 "\n xorps %xmm3, %xmm3"
303 "\n xorps %xmm4, %xmm4"
304 "\n xorps %xmm5, %xmm5"
305 "\n xorps %xmm6, %xmm6"
306 "\n xorps %xmm7, %xmm7"
307 "\n xorps %xmm8, %xmm8"
308 "\n xorps %xmm9, %xmm9"
309 "\n xorps %xmm10, %xmm10"
310 "\n xorps %xmm11, %xmm11"
311 "\n xorps %xmm12, %xmm12"
312 "\n xorps %xmm13, %xmm13"
313 "\n xorps %xmm14, %xmm14"
314 "\n xorps %xmm15, %xmm15"
324 "\n xorps %xmm0, %xmm0"
325 "\n xorps %xmm1, %xmm1"
326 "\n xorps %xmm2, %xmm2"
327 "\n xorps %xmm3, %xmm3"
328 "\n xorps %xmm4, %xmm4"
329 "\n xorps %xmm5, %xmm5"
330 "\n xorps %xmm6, %xmm6"
331 "\n xorps %xmm7, %xmm7"
370 "\n .thumb_func _stomp"
388 "\n vmov.i32 q10, #0"
389 "\n vmov.i32 q11, #0"
390 "\n vmov.i32 q12, #0"
391 "\n vmov.i32 q13, #0"
392 "\n vmov.i32 q14, #0"
393 "\n vmov.i32 q15, #0"
398 # error unknown architecture
402 @implementation Super
403 -(struct stret)stret { return STRET_RESULT; }
405 // The IMPL_ methods are not called directly. Instead the non IMPL_ name is
406 // called. The resolver function installs the real method. This allows
407 // the resolver function to stomp on registers to help test register
408 // preservation in the uncached path.
410 +(BOOL) resolveInstanceMethod:(SEL)sel
412 const char *name = sel_getName(sel);
413 if (! strstr(name, "::::::::")) return false;
415 testprintf("resolving %s\n", name);
419 asprintf(&realName, "IMPL_%s", name);
420 SEL realSel = sel_registerName(realName);
423 IMP imp = class_getMethodImplementation(self, realSel);
424 if (imp == &_objc_msgForward) return false;
425 return class_addMethod(self, sel, imp, "");
429 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
436 -(long long)IMPL_llret:
437 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
444 -(struct stret)IMPL_stret:
445 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
453 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
460 -(long double)IMPL_lfpret:
461 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
468 -(vector_ulong2)IMPL_vecret:
469 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
479 CHECK_ARGS_NOARG(idret);
484 -(long long)llret_noarg
486 CHECK_ARGS_NOARG(llret);
491 -(struct stret)stret_noarg
493 CHECK_ARGS_NOARG(stret);
500 CHECK_ARGS_NOARG(fpret);
505 -(long double)lfpret_noarg
507 CHECK_ARGS_NOARG(lfpret);
512 -(vector_ulong2)vecret_noarg
514 CHECK_ARGS_NOARG(vecret);
535 -(long long)llret_nop
540 -(struct stret)stret_nop
550 -(long double)lfpret_nop
555 -(vector_ulong2)vecret_nop
560 #define STRET_IMP(n) \
561 +(struct stret_##n)stret_##n##_zero \
563 struct stret_##n ret; \
564 bzero(&ret, sizeof(ret)); \
567 +(struct stret_##n)stret_##n##_nonzero \
569 struct stret_##n ret; \
570 memset(&ret, 0xff, sizeof(ret)); \
596 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
598 fail("+idret called instead of -idret");
603 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
605 fail("+llret called instead of -llret");
609 +(struct stret)stret:
610 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
612 fail("+stret called instead of -stret");
617 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
619 fail("+fpret called instead of -fpret");
623 +(long double)lfpret:
624 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
626 fail("+lfpret called instead of -lfpret");
632 fail("+idret_noarg called instead of -idret_noarg");
633 CHECK_ARGS_NOARG(idret);
636 +(long long)llret_noarg
638 fail("+llret_noarg called instead of -llret_noarg");
639 CHECK_ARGS_NOARG(llret);
642 +(struct stret)stret_noarg
644 fail("+stret_noarg called instead of -stret_noarg");
645 CHECK_ARGS_NOARG(stret);
650 fail("+fpret_noarg called instead of -fpret_noarg");
651 CHECK_ARGS_NOARG(fpret);
654 +(long double)lfpret_noarg
656 fail("+lfpret_noarg called instead of -lfpret_noarg");
657 CHECK_ARGS_NOARG(lfpret);
660 +(vector_ulong2)vecret_noarg
662 fail("+vecret_noarg called instead of -vecret_noarg");
663 CHECK_ARGS_NOARG(vecret);
672 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
677 result = [super idret:v1:v2:v3:v4:v5:v6:v7:v8: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];
678 testassert(state == 1);
679 testassert(result == ID_RESULT);
684 -(long long)IMPL_llret:
685 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
690 result = [super llret:v1:v2:v3:v4:v5:v6:v7:v8: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];
691 testassert(state == 2);
692 testassert(result == LL_RESULT);
697 -(struct stret)IMPL_stret:
698 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
703 result = [super stret:v1:v2:v3:v4:v5:v6:v7:v8: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];
704 testassert(state == 3);
705 testassert(stret_equal(result, STRET_RESULT));
711 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
716 result = [super fpret:v1:v2:v3:v4:v5:v6:v7:v8: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];
717 testassert(state == 4);
718 testassert(result == FP_RESULT);
723 -(long double)IMPL_lfpret:
724 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
729 result = [super lfpret:v1:v2:v3:v4:v5:v6:v7:v8: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];
730 testassert(state == 5);
731 testassert(result == LFP_RESULT);
736 -(vector_ulong2)IMPL_vecret:
737 (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
739 vector_ulong2 result;
742 result = [super vecret:v1:v2:v3:v4:v5:v6:v7:v8: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];
743 testassert(state == 6);
744 testassert(vector_equal(result, VEC_RESULT));
753 CHECK_ARGS_NOARG(idret);
755 result = [super idret_noarg];
756 testassert(state == 11);
757 testassert(result == ID_RESULT);
762 -(long long)llret_noarg
765 CHECK_ARGS_NOARG(llret);
767 result = [super llret_noarg];
768 testassert(state == 12);
769 testassert(result == LL_RESULT);
774 -(struct stret)stret_noarg
777 CHECK_ARGS_NOARG(stret);
779 result = [super stret_noarg];
780 testassert(state == 13);
781 testassert(stret_equal(result, STRET_RESULT));
789 CHECK_ARGS_NOARG(fpret);
791 result = [super fpret_noarg];
792 testassert(state == 14);
793 testassert(result == FP_RESULT);
798 -(long double)lfpret_noarg
801 CHECK_ARGS_NOARG(lfpret);
803 result = [super lfpret_noarg];
804 testassert(state == 15);
805 testassert(result == LFP_RESULT);
810 -(vector_ulong2)vecret_noarg
812 vector_ulong2 result;
813 CHECK_ARGS_NOARG(vecret);
815 result = [super vecret_noarg];
816 testassert(state == 16);
817 testassert(vector_equal(result, VEC_RESULT));
825 #if OBJC_HAVE_TAGGED_POINTERS
827 @interface TaggedSub : Sub @end
829 @implementation TaggedSub : Sub
833 _objc_registerTaggedPointerClass(OBJC_TAG_7, self);
841 // DWARF checking machinery
844 // unimplemented on this platform
846 // 32-bit Mac doesn't use DWARF unwind
847 #elif TARGET_OS_IPHONE && __arm__
848 // 32-bit iOS device doesn't use DWARF unwind
849 #elif __has_feature(objc_arc)
850 // ARC's extra RR calls hit the traps at the wrong times
855 // Classes with no implementations and no cache contents from elsewhere.
856 @interface SuperDW : TestRoot @end
857 @implementation SuperDW @end
859 @interface Sub0DW : SuperDW @end
860 @implementation Sub0DW @end
862 @interface SubDW : Sub0DW @end
863 @implementation SubDW @end
867 #include <sys/mman.h>
868 #include <libunwind.h>
870 #define UNW_STEP_SUCCESS 1
871 #define UNW_STEP_END 0
877 extern void callit(void *obj, void *sel, void *fn);
878 extern struct stret callit_stret(void *obj, void *sel, void *fn);
883 #define OTOOL "/usr/bin/xcrun otool -arch x86_64 "
885 typedef uint8_t insn_t;
886 #define BREAK_INSN ((insn_t)0xcc) // int3
897 void handle_exception(x86_thread_state64_t *state)
904 err = unw_init_local(&curs, (unw_context_t *)state);
907 step = unw_step(&curs);
908 testassert(step == UNW_STEP_SUCCESS);
910 err = unw_get_reg(&curs, UNW_X86_64_R12, ®);
912 testassert(reg == r12);
914 err = unw_get_reg(&curs, UNW_X86_64_R13, ®);
916 testassert(reg == r13);
918 err = unw_get_reg(&curs, UNW_X86_64_R14, ®);
920 testassert(reg == r14);
922 err = unw_get_reg(&curs, UNW_X86_64_R15, ®);
924 testassert(reg == r15);
926 err = unw_get_reg(&curs, UNW_X86_64_RBX, ®);
928 testassert(reg == rbx);
930 err = unw_get_reg(&curs, UNW_X86_64_RBP, ®);
932 testassert(reg == rbp);
934 err = unw_get_reg(&curs, UNW_X86_64_RSP, ®);
936 testassert(reg == rsp);
938 err = unw_get_reg(&curs, UNW_REG_IP, ®);
940 testassert(reg == rip);
943 // set thread state to unwound state
957 void sigtrap(int sig, siginfo_t *info, void *cc)
959 ucontext_t *uc = (ucontext_t *)cc;
960 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
962 testprintf(" handled\n");
964 testassert(sig == SIGTRAP);
965 testassert((uintptr_t)info->si_addr-1 == clobbered);
967 handle_exception(&mc->__ss);
968 // handle_exception changed register state for continuation
975 // save sp and return address to variables
976 "\n movq (%rsp), %r10"
977 "\n movq %r10, _rip(%rip)"
978 "\n movq %rsp, _rsp(%rip)"
979 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
980 // save other non-volatile registers to variables
981 "\n movq %rbx, _rbx(%rip)"
982 "\n movq %rbp, _rbp(%rip)"
983 "\n movq %r12, _r12(%rip)"
984 "\n movq %r13, _r13(%rip)"
985 "\n movq %r14, _r14(%rip)"
986 "\n movq %r15, _r15(%rip)"
992 "\n .globl _callit_stret"
994 // save sp and return address to variables
995 "\n movq (%rsp), %r10"
996 "\n movq %r10, _rip(%rip)"
997 "\n movq %rsp, _rsp(%rip)"
998 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
999 // save other non-volatile registers to variables
1000 "\n movq %rbx, _rbx(%rip)"
1001 "\n movq %rbp, _rbp(%rip)"
1002 "\n movq %r12, _r12(%rip)"
1003 "\n movq %r13, _r13(%rip)"
1004 "\n movq %r14, _r14(%rip)"
1005 "\n movq %r15, _r15(%rip)"
1014 #define OTOOL "/usr/bin/xcrun otool -arch i386 "
1016 typedef uint8_t insn_t;
1017 #define BREAK_INSN ((insn_t)0xcc) // int3
1025 uintptr_t espfix = 0;
1027 void handle_exception(i386_thread_state_t *state)
1034 err = unw_init_local(&curs, (unw_context_t *)state);
1037 step = unw_step(&curs);
1038 testassert(step == UNW_STEP_SUCCESS);
1040 err = unw_get_reg(&curs, UNW_REG_IP, ®);
1042 testassert(reg == eip);
1044 err = unw_get_reg(&curs, UNW_X86_ESP, ®);
1046 testassert(reg == esp);
1048 err = unw_get_reg(&curs, UNW_X86_EBX, ®);
1050 testassert(reg == ebx);
1052 err = unw_get_reg(&curs, UNW_X86_EBP, ®);
1054 testassert(reg == ebp);
1056 err = unw_get_reg(&curs, UNW_X86_EDI, ®);
1058 testassert(reg == edi);
1060 err = unw_get_reg(&curs, UNW_X86_ESI, ®);
1062 testassert(reg == esi);
1065 // set thread state to unwound state
1067 state->__esp = esp + espfix;
1077 void sigtrap(int sig, siginfo_t *info, void *cc)
1079 ucontext_t *uc = (ucontext_t *)cc;
1080 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
1082 testprintf(" handled\n");
1084 testassert(sig == SIGTRAP);
1085 testassert((uintptr_t)info->si_addr-1 == clobbered);
1087 handle_exception(&mc->__ss);
1088 // handle_exception changed register state for continuation
1095 // save sp and return address to variables
1098 "\n movl (%esp), %eax"
1099 "\n movl %eax, _eip-1b(%edx)"
1100 "\n movl %esp, _esp-1b(%edx)"
1101 "\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
1102 "\n movl $0, _espfix-1b(%edx)"
1103 // save other non-volatile registers to variables
1104 "\n movl %ebx, _ebx-1b(%edx)"
1105 "\n movl %ebp, _ebp-1b(%edx)"
1106 "\n movl %edi, _edi-1b(%edx)"
1107 "\n movl %esi, _esi-1b(%edx)"
1113 "\n .globl _callit_stret"
1115 // save sp and return address to variables
1118 "\n movl (%esp), %eax"
1119 "\n movl %eax, _eip-1b(%edx)"
1120 "\n movl %esp, _esp-1b(%edx)"
1121 "\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
1122 "\n movl $4, _espfix-1b(%edx)"
1123 // save other non-volatile registers to variables
1124 "\n movl %ebx, _ebx-1b(%edx)"
1125 "\n movl %ebp, _ebp-1b(%edx)"
1126 "\n movl %edi, _edi-1b(%edx)"
1127 "\n movl %esi, _esi-1b(%edx)"
1135 #include <sys/ucontext.h>
1137 // runs on iOS device, no xcrun command present
1138 #define OTOOL "/usr/bin/otool -arch arm64 "
1140 typedef uint32_t insn_t;
1141 #define BREAK_INSN ((insn_t)0xd4200020) // brk #1
1157 void handle_exception(arm_thread_state64_t *state)
1164 err = unw_init_local(&curs, (unw_context_t *)state);
1167 step = unw_step(&curs);
1168 testassert(step == UNW_STEP_SUCCESS);
1170 err = unw_get_reg(&curs, UNW_ARM64_X19, ®);
1172 testassert(reg == x19);
1174 err = unw_get_reg(&curs, UNW_ARM64_X20, ®);
1176 testassert(reg == x20);
1178 err = unw_get_reg(&curs, UNW_ARM64_X21, ®);
1180 testassert(reg == x21);
1182 err = unw_get_reg(&curs, UNW_ARM64_X22, ®);
1184 testassert(reg == x22);
1186 err = unw_get_reg(&curs, UNW_ARM64_X23, ®);
1188 testassert(reg == x23);
1190 err = unw_get_reg(&curs, UNW_ARM64_X24, ®);
1192 testassert(reg == x24);
1194 err = unw_get_reg(&curs, UNW_ARM64_X25, ®);
1196 testassert(reg == x25);
1198 err = unw_get_reg(&curs, UNW_ARM64_X26, ®);
1200 testassert(reg == x26);
1202 err = unw_get_reg(&curs, UNW_ARM64_X27, ®);
1204 testassert(reg == x27);
1206 err = unw_get_reg(&curs, UNW_ARM64_X28, ®);
1208 testassert(reg == x28);
1210 err = unw_get_reg(&curs, UNW_ARM64_FP, ®);
1212 testassert(reg == fp);
1214 err = unw_get_reg(&curs, UNW_ARM64_SP, ®);
1216 testassert(reg == sp);
1218 err = unw_get_reg(&curs, UNW_REG_IP, ®);
1220 testassert(reg == pc);
1222 // libunwind restores PC into LR and doesn't track LR
1223 // err = unw_get_reg(&curs, UNW_ARM64_LR, ®);
1224 // testassert(!err);
1225 // testassert(reg == lr);
1227 // set thread state to unwound state
1228 state->__x[19] = x19;
1229 state->__x[20] = x20;
1230 state->__x[20] = x21;
1231 state->__x[22] = x22;
1232 state->__x[23] = x23;
1233 state->__x[24] = x24;
1234 state->__x[25] = x25;
1235 state->__x[26] = x26;
1236 state->__x[27] = x27;
1237 state->__x[28] = x28;
1239 state->__lr = pc; // libunwind restores PC into LR
1247 void sigtrap(int sig, siginfo_t *info, void *cc)
1249 ucontext_t *uc = (ucontext_t *)cc;
1250 struct __darwin_mcontext64 *mc = (struct __darwin_mcontext64 *)uc->uc_mcontext;
1252 testprintf(" handled\n");
1254 testassert(sig == SIGTRAP);
1255 testassert((uintptr_t)info->si_addr == clobbered);
1257 handle_exception(&mc->__ss);
1258 // handle_exception changed register state for continuation
1266 // save sp and return address to variables
1268 "\n adrp x17, _sp@PAGE"
1269 "\n str x16, [x17, _sp@PAGEOFF]"
1270 "\n adrp x17, _pc@PAGE"
1271 "\n str lr, [x17, _pc@PAGEOFF]"
1272 // save other non-volatile registers to variables
1273 "\n adrp x17, _x19@PAGE"
1274 "\n str x19, [x17, _x19@PAGEOFF]"
1275 "\n adrp x17, _x19@PAGE"
1276 "\n str x20, [x17, _x20@PAGEOFF]"
1277 "\n adrp x17, _x19@PAGE"
1278 "\n str x21, [x17, _x21@PAGEOFF]"
1279 "\n adrp x17, _x19@PAGE"
1280 "\n str x22, [x17, _x22@PAGEOFF]"
1281 "\n adrp x17, _x19@PAGE"
1282 "\n str x23, [x17, _x23@PAGEOFF]"
1283 "\n adrp x17, _x19@PAGE"
1284 "\n str x24, [x17, _x24@PAGEOFF]"
1285 "\n adrp x17, _x19@PAGE"
1286 "\n str x25, [x17, _x25@PAGEOFF]"
1287 "\n adrp x17, _x19@PAGE"
1288 "\n str x26, [x17, _x26@PAGEOFF]"
1289 "\n adrp x17, _x19@PAGE"
1290 "\n str x27, [x17, _x27@PAGEOFF]"
1291 "\n adrp x17, _x19@PAGE"
1292 "\n str x28, [x17, _x28@PAGEOFF]"
1293 "\n adrp x17, _x19@PAGE"
1294 "\n str fp, [x17, _fp@PAGEOFF]"
1302 #error unknown architecture
1307 insn_t set(uintptr_t dst, insn_t newvalue)
1309 uintptr_t start = dst & ~(PAGE_MAX_SIZE-1);
1310 mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_WRITE);
1311 insn_t oldvalue = *(insn_t *)dst;
1312 *(insn_t *)dst = newvalue;
1313 mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_EXEC);
1317 insn_t clobber(void *fn, uintptr_t offset)
1319 clobbered = (uintptr_t)fn + offset;
1320 return set((uintptr_t)fn + offset, BREAK_INSN);
1323 void unclobber(void *fn, uintptr_t offset, insn_t oldvalue)
1325 set((uintptr_t)fn + offset, oldvalue);
1329 uintptr_t *getOffsets(void *symbol, const char *symname, uintptr_t *outBase)
1331 uintptr_t *result = (uintptr_t *)malloc(1000 * sizeof(uintptr_t));
1332 uintptr_t *end = result + 1000;
1333 uintptr_t *p = result;
1337 dladdr(symbol, &dl);
1339 // call `otool` on library
1340 unsetenv("DYLD_LIBRARY_PATH");
1341 unsetenv("DYLD_ROOT_PATH");
1342 unsetenv("DYLD_INSERT_LIBRARIES");
1343 unsetenv("DYLD_SHARED_REGION");
1344 unsetenv("DYLD_SHARED_CACHE_DIR");
1345 unsetenv("DYLD_SHARED_CACHE_DONT_VALIDATE");
1347 asprintf(&cmd, OTOOL "-tv -p _%s %s",
1348 symname, dl.dli_fname);
1349 testprintf("%s\n", cmd);
1350 FILE *disa = popen(cmd, "r");
1354 // read past "_symname:" line
1357 while ((line = fgetln(disa, &len))) {
1358 if (0 == strncmp(1+line, symname, MIN(len-1, strlen(symname)))) break;
1361 // read instructions and save offsets
1365 while (2 == fscanf(disa, "%lx%s%*[^\n]\n", &addr, op)) {
1366 if (base == 0) base = addr;
1367 if (0 != strncmp(op, "nop", 3)) {
1368 testassert(p < end);
1371 // assume nops are unreached (e.g. alignment padding)
1377 // Also add breakpoints in _objc_msgSend_uncached_impcache
1378 // (which is the slow path and has a frame to unwind)
1379 if (0 != strcmp(symname, "_objc_msgSend_uncached_impcache")) {
1381 uintptr_t *more_offsets = getOffsets(symbol, "_objc_msgSend_uncached_impcache", &base2);
1382 uintptr_t *q = more_offsets;
1383 // Skip prologue because it's imprecisely modeled in compact unwind
1384 testassert(*q != ~0UL);
1386 testassert(*q != ~0UL);
1388 while (*q != ~0UL) *p++ = *q++ + base2 - base;
1389 // Skip return because it's imprecisely modeled in compact unwind
1395 testassert(p > result);
1396 testassert(p < end);
1399 // hack: skip last instruction because libunwind blows up if it's
1400 // one byte long and followed by the next function with no NOPs first
1403 if (outBase) *outBase = base;
1407 void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret) __attribute__((noinline));
1408 void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret)
1410 uintptr_t message_ref[2];
1413 // copy to a local buffer to keep sel_arg un-fixed-up
1414 memcpy(message_ref, sel_arg, sizeof(message_ref));
1415 sel_arg = message_ref;
1417 if (!stret) callit(o, sel_arg, f);
1419 else callit_stret(o, sel_arg, f);
1421 else fail("stret?");
1425 void test_dw_forward(void)
1430 struct stret test_dw_forward_stret(void)
1435 // sub = ordinary receiver object
1436 // tagged = tagged receiver object
1437 // SEL = selector to send
1438 // sub_arg = arg to pass in receiver register (may be objc_super struct)
1439 // tagged_arg = arg to pass in receiver register (may be objc_super struct)
1440 // sel_arg = arg to pass in sel register (may be message_ref)
1441 // uncaughtAllowed is the number of acceptable unreachable instructions
1442 // (for example, the ones that handle the corrupt-cache-error case)
1443 void test_dw(const char *name, id sub, id tagged, bool stret,
1444 int uncaughtAllowed)
1447 testprintf("DWARF FOR %s%s\n", name, stret ? " (stret)" : "");
1449 // We need 2 SELs of each alignment so we can generate hash collisions.
1450 // sel_registerName() never returns those alignments because they
1451 // differ from malloc's alignment. So we create lots of compiled-in
1452 // SELs here and hope something fits.
1453 #pragma clang diagnostic push
1454 #pragma clang diagnostic ignored "-Wundeclared-selector"
1455 SEL sel = @selector(a);
1456 SEL lotsOfSels[] = {
1457 @selector(a1), @selector(a2), @selector(a3), @selector(a4),
1458 @selector(a5), @selector(a6), @selector(a7), @selector(a8),
1459 @selector(aa), @selector(ab), @selector(ac), @selector(ad),
1460 @selector(ae), @selector(af), @selector(ag), @selector(ah),
1461 @selector(A1), @selector(A2), @selector(A3), @selector(A4),
1462 @selector(A5), @selector(A6), @selector(A7), @selector(A8),
1463 @selector(AA), @selector(Ab), @selector(Ac), @selector(Ad),
1464 @selector(Ae), @selector(Af), @selector(Ag), @selector(Ah),
1465 @selector(bb1), @selector(bb2), @selector(bb3), @selector(bb4),
1466 @selector(bb5), @selector(bb6), @selector(bb7), @selector(bb8),
1467 @selector(bba), @selector(bbb), @selector(bbc), @selector(bbd),
1468 @selector(bbe), @selector(bbf), @selector(bbg), @selector(bbh),
1469 @selector(BB1), @selector(BB2), @selector(BB3), @selector(BB4),
1470 @selector(BB5), @selector(BB6), @selector(BB7), @selector(BB8),
1471 @selector(BBa), @selector(BBb), @selector(BBc), @selector(BBd),
1472 @selector(BBe), @selector(BBf), @selector(BBg), @selector(BBh),
1473 @selector(ccc1), @selector(ccc2), @selector(ccc3), @selector(ccc4),
1474 @selector(ccc5), @selector(ccc6), @selector(ccc7), @selector(ccc8),
1475 @selector(ccca), @selector(cccb), @selector(cccc), @selector(cccd),
1476 @selector(ccce), @selector(cccf), @selector(cccg), @selector(ccch),
1477 @selector(CCC1), @selector(CCC2), @selector(CCC3), @selector(CCC4),
1478 @selector(CCC5), @selector(CCC6), @selector(CCC7), @selector(CCC8),
1479 @selector(CCCa), @selector(CCCb), @selector(CCCc), @selector(CCCd),
1480 @selector(CCCe), @selector(CCCf), @selector(CCCg), @selector(CCCh),
1482 #pragma clang diagnostic pop
1485 IMP imp = stret ? (IMP)test_dw_forward_stret : (IMP)test_dw_forward;
1486 Class cls = object_getClass(sub);
1487 Class tagcls = object_getClass(tagged);
1488 class_replaceMethod(cls, sel, imp, "");
1489 class_replaceMethod(tagcls, sel, imp, "");
1490 for (size_t i = 0; i < sizeof(lotsOfSels)/sizeof(lotsOfSels[0]); i++) {
1491 class_replaceMethod(cls, lotsOfSels[i], imp, "");
1492 class_replaceMethod(tagcls, lotsOfSels[i], imp, "");
1496 #define ALIGNCOUNT 16
1497 SEL sels[ALIGNCOUNT][2] = {{0}};
1498 for (int align = 0; align < ALIGNCOUNT; align++) {
1499 for (size_t i = 0; i < sizeof(lotsOfSels)/sizeof(lotsOfSels[0]); i++) {
1500 if ((uintptr_t)(void*)lotsOfSels[i] % ALIGNCOUNT == align) {
1501 if (sels[align][0]) {
1502 sels[align][1] = lotsOfSels[i];
1504 sels[align][0] = lotsOfSels[i];
1508 if (!sels[align][0]) fail("no SEL with alignment %d", align);
1509 if (!sels[align][1]) fail("only one SEL with alignment %d", align);
1512 void *fn = dlsym(RTLD_DEFAULT, name);
1515 // argument substitutions
1517 void *sub_arg = (void*)objc_unretainedPointer(sub);
1518 void *tagged_arg = (void*)objc_unretainedPointer(tagged);
1519 void *sel_arg = (void*)sel;
1521 struct objc_super sup_st = { sub, object_getClass(sub) };
1522 struct objc_super tagged_sup_st = { tagged, object_getClass(tagged) };
1523 struct { void *imp; SEL sel; } message_ref = { fn, sel };
1525 Class cache_cls = object_getClass(sub);
1527 if (strstr(name, "Super")) {
1528 // super version - replace receiver with objc_super
1529 // clear caches of superclass
1530 cache_cls = class_getSuperclass(cache_cls);
1532 tagged_arg = &tagged_sup_st;
1535 if (strstr(name, "_fixup")) {
1536 // fixup version - replace sel with message_ref
1537 sel_arg = &message_ref;
1541 uintptr_t *insnOffsets = getOffsets(fn, name, nil);
1543 int uncaughtCount = 0;
1544 for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
1545 offset = insnOffsets[oo];
1546 testprintf("OFFSET %lu\n", offset);
1548 insn_t saved_insn = clobber(fn, offset);
1552 if ((void*)objc_unretainedPointer(sub) == sub_arg) {
1554 testprintf(" nil\n");
1555 CALLIT(nil, sel_arg, sel, fn, stret);
1556 CALLIT(nil, sel_arg, sel, fn, stret);
1561 testprintf(" uncached\n");
1562 _objc_flush_caches(cache_cls);
1563 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1564 _objc_flush_caches(cache_cls);
1565 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1569 testprintf(" cached\n");
1570 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1571 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1575 testprintf(" uncached,tagged\n");
1576 _objc_flush_caches(cache_cls);
1577 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1578 _objc_flush_caches(cache_cls);
1579 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1583 testprintf(" cached,tagged\n");
1584 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1585 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1587 // multiple SEL alignments, collisions, wraps
1589 for (int a = 0; a < ALIGNCOUNT; a++) {
1590 testprintf(" cached, SEL alignment %d\n", a);
1592 // Count both up and down to be independent of
1593 // implementation's cache scan direction
1595 _objc_flush_caches(cache_cls);
1596 for (int x2 = 0; x2 < 8; x2++) {
1597 for (int s = 0; s < 4; s++) {
1598 int align = (a+s) % ALIGNCOUNT;
1599 CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
1600 CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
1604 _objc_flush_caches(cache_cls);
1605 for (int x2 = 0; x2 < 8; x2++) {
1606 for (int s = 0; s < 4; s++) {
1607 int align = abs(a-s) % ALIGNCOUNT;
1608 CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
1609 CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
1614 unclobber(fn, offset, saved_insn);
1616 // remember offsets that were caught by none of the above
1618 insnOffsets[oo] = 0;
1621 testprintf("offset %s+%lu not caught (%d/%d)\n",
1622 name, offset, uncaughtCount, uncaughtAllowed);
1626 // Complain if too many offsets went uncaught.
1627 // Acceptably-uncaught offsets include the corrupt-cache-error handler.
1628 if (uncaughtCount != uncaughtAllowed) {
1629 for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
1630 if (insnOffsets[oo]) {
1631 fprintf(stderr, "BAD: offset %s+%lu not caught\n",
1632 name, insnOffsets[oo]);
1635 fail("wrong instructions not reached for %s (missed %d, expected %d)",
1636 name, uncaughtCount, uncaughtAllowed);
1647 void test_basic(id receiver)
1651 struct stret stretval;
1654 vector_ulong2 vecval;
1657 // message uncached long long
1658 // message uncached stret
1659 // message uncached fpret
1660 // message uncached fpret long double
1661 // message uncached noarg (as above)
1663 // message cached long long
1664 // message cached stret
1665 // message cached fpret
1666 // message cached fpret long double
1667 // message cached noarg (as above)
1668 // fixme verify that uncached lookup didn't happen the 2nd time?
1670 for (int i = 0; i < 5; i++) {
1671 testprintf("idret\n");
1674 idval = [receiver idret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
1675 testassert(state == 101);
1676 testassert(idval == ID_RESULT);
1678 testprintf("llret\n");
1680 llval = [receiver llret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
1681 testassert(state == 102);
1682 testassert(llval == LL_RESULT);
1684 testprintf("stret\n");
1686 stretval = [receiver stret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
1687 testassert(state == 103);
1688 testassert(stret_equal(stretval, STRET_RESULT));
1690 testprintf("fpret\n");
1692 fpval = [receiver fpret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
1693 testassert(state == 104);
1694 testassert(fpval == FP_RESULT);
1696 testprintf("lfpret\n");
1698 lfpval = [receiver lfpret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
1699 testassert(state == 105);
1700 testassert(lfpval == LFP_RESULT);
1702 testprintf("vecret\n");
1704 vecval = [receiver vecret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
1705 testassert(state == 106);
1706 testassert(vector_equal(vecval, VEC_RESULT));
1709 // explicitly call noarg messenger, even if compiler doesn't emit it
1711 testprintf("idret noarg\n");
1713 idval = ((typeof(idmsg0))objc_msgSend_noarg)(receiver, @selector(idret_noarg));
1714 testassert(state == 111);
1715 testassert(idval == ID_RESULT);
1717 testprintf("llret noarg\n");
1719 llval = ((typeof(llmsg0))objc_msgSend_noarg)(receiver, @selector(llret_noarg));
1720 testassert(state == 112);
1721 testassert(llval == LL_RESULT);
1723 no objc_msgSend_stret_noarg
1725 stretval = ((typeof(stretmsg0))objc_msgSend_stret_noarg)(receiver, @selector(stret_noarg));
1726 stretval = [receiver stret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
1727 testassert(state == 113);
1728 testassert(stret_equal(stretval, STRET_RESULT));
1731 testprintf("fpret noarg\n");
1733 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(receiver, @selector(fpret_noarg));
1734 testassert(state == 114);
1735 testassert(fpval == FP_RESULT);
1737 testprintf("vecret noarg\n");
1739 vecval = ((typeof(vecmsg0))objc_msgSend_noarg)(receiver, @selector(vecret_noarg));
1740 testassert(state == 116);
1741 testassert(vector_equal(vecval, VEC_RESULT));
1743 # if !__i386__ && !__x86_64__
1744 testprintf("lfpret noarg\n");
1746 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(receiver, @selector(lfpret_noarg));
1747 testassert(state == 115);
1748 testassert(lfpval == LFP_RESULT);
1753 testprintf("basic done\n");
1763 struct stret stretval;
1766 vector_ulong2 vecval;
1769 struct stret *stretptr;
1774 uint64_t targetTime;
1783 id (*idfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
1784 long long (*llfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
1785 struct stret (*stretfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
1786 double (*fpfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
1787 long double (*lfpfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
1788 vector_ulong2 (*vecfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
1790 id (*idmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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) __attribute__((unused));
1791 id (*idmsgsuper)(struct objc_super *, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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) __attribute__((unused));
1792 long long (*llmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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) __attribute__((unused));
1793 struct stret (*stretmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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) __attribute__((unused));
1794 struct stret (*stretmsgsuper)(struct objc_super *, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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) __attribute__((unused));
1795 double (*fpmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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) __attribute__((unused));
1796 long double (*lfpmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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) __attribute__((unused));
1797 vector_ulong2 (*vecmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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) __attribute__((unused));
1799 // get +initialize out of the way
1801 #if OBJC_HAVE_TAGGED_POINTERS
1805 ID_RESULT = [Super new];
1807 Sub *sub = [Sub new];
1808 Super *sup = [Super new];
1809 #if OBJC_HAVE_TAGGED_POINTERS
1810 TaggedSub *tagged = objc_unretainedObject(_objc_makeTaggedPointer(OBJC_TAG_7, 999));
1813 // Basic cached and uncached dispatch.
1814 // Do this first before anything below caches stuff.
1815 testprintf("basic\n");
1817 #if OBJC_HAVE_TAGGED_POINTERS
1818 testprintf("basic tagged\n");
1822 idmethod = class_getInstanceMethod([Super class], @selector(idret::::::::::::::::::::::::::::::::::::));
1823 testassert(idmethod);
1824 llmethod = class_getInstanceMethod([Super class], @selector(llret::::::::::::::::::::::::::::::::::::));
1825 testassert(llmethod);
1826 stretmethod = class_getInstanceMethod([Super class], @selector(stret::::::::::::::::::::::::::::::::::::));
1827 testassert(stretmethod);
1828 fpmethod = class_getInstanceMethod([Super class], @selector(fpret::::::::::::::::::::::::::::::::::::));
1829 testassert(fpmethod);
1830 lfpmethod = class_getInstanceMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::::::::::));
1831 testassert(lfpmethod);
1832 vecmethod = class_getInstanceMethod([Super class], @selector(vecret::::::::::::::::::::::::::::::::::::));
1833 testassert(vecmethod);
1835 idfn = (id (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
1836 llfn = (long long (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
1837 stretfn = (struct stret (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
1838 fpfn = (double (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
1839 lfpfn = (long double (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
1840 vecfn = (vector_ulong2 (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
1842 // cached message performance
1843 // catches failure to cache or (abi=2) failure to fixup (#5584187)
1844 // fixme unless they all fail
1845 // `.align 4` matches loop alignment to make -O0 work
1847 testprintf("time checks\n");
1872 // Some of these times have high variance on some compilers.
1873 // The errors we're trying to catch should be catastrophically slow,
1874 // so the margins here are generous to avoid false failures.
1876 // Use voidret because id return is too slow for perf test with ARC.
1878 // Pick smallest of voidret_nop and voidret_nop2 time
1879 // in the hopes that one of them didn't collide in the method cache.
1881 #define COUNT 1000000
1883 startTime = mach_absolute_time();
1885 for (i = 0; i < COUNT; i++) {
1888 totalTime = mach_absolute_time() - startTime;
1889 testprintf("time: voidret %llu\n", totalTime);
1890 targetTime = totalTime;
1892 startTime = mach_absolute_time();
1894 for (i = 0; i < COUNT; i++) {
1897 totalTime = mach_absolute_time() - startTime;
1898 testprintf("time: voidret2 %llu\n", totalTime);
1899 if (totalTime < targetTime) targetTime = totalTime;
1901 startTime = mach_absolute_time();
1903 for (i = 0; i < COUNT; i++) {
1906 totalTime = mach_absolute_time() - startTime;
1907 timecheck("llret ", totalTime, targetTime * 0.7, targetTime * 2.0);
1909 startTime = mach_absolute_time();
1911 for (i = 0; i < COUNT; i++) {
1914 totalTime = mach_absolute_time() - startTime;
1915 timecheck("stret ", totalTime, targetTime * 0.7, targetTime * 5.0);
1917 startTime = mach_absolute_time();
1919 for (i = 0; i < COUNT; i++) {
1922 totalTime = mach_absolute_time() - startTime;
1923 timecheck("fpret ", totalTime, targetTime * 0.7, targetTime * 4.0);
1925 startTime = mach_absolute_time();
1927 for (i = 0; i < COUNT; i++) {
1930 totalTime = mach_absolute_time() - startTime;
1931 timecheck("lfpret", totalTime, targetTime * 0.7, targetTime * 4.0);
1933 startTime = mach_absolute_time();
1935 for (i = 0; i < COUNT; i++) {
1938 totalTime = mach_absolute_time() - startTime;
1939 timecheck("vecret", totalTime, targetTime * 0.7, targetTime * 4.0);
1942 // Removing this testwarn(), or changing voidret_nop to nop;ret,
1943 // changes the voidret_nop and stret_nop times above by a factor of 2.
1944 testwarn("rdar://13896922 nop;ret is faster than ret?");
1950 // method_invoke long long
1951 // method_invoke_stret stret
1952 // method_invoke_stret fpret
1953 // method_invoke fpret long double
1954 testprintf("method_invoke\n");
1960 idval = (*idfn)(sup, idmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
1961 testassert(state == 1);
1962 testassert(idval == ID_RESULT);
1965 llval = (*llfn)(sup, llmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
1966 testassert(state == 2);
1967 testassert(llval == LL_RESULT);
1970 stretval = (*stretfn)(sup, stretmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
1971 testassert(state == 3);
1972 testassert(stret_equal(stretval, STRET_RESULT));
1975 fpval = (*fpfn)(sup, fpmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
1976 testassert(state == 4);
1977 testassert(fpval == FP_RESULT);
1980 lfpval = (*lfpfn)(sup, lfpmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
1981 testassert(state == 5);
1982 testassert(lfpval == LFP_RESULT);
1985 vecval = (*vecfn)(sup, vecmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
1986 testassert(state == 6);
1987 testassert(vector_equal(vecval, VEC_RESULT));
1991 // message to nil long long
1992 // message to nil stret
1993 // message to nil fpret
1994 // message to nil fpret long double
1995 // Use NIL_RECEIVER to avoid compiler optimizations.
1996 testprintf("message to nil\n");
2000 idval = [(id)NIL_RECEIVER idret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
2001 testassert(state == 0);
2002 testassert(idval == nil);
2006 llval = [(id)NIL_RECEIVER llret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
2007 testassert(state == 0);
2008 testassert(llval == 0LL);
2012 stretval = [(id)NIL_RECEIVER stret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
2013 testassert(state == 0);
2015 testassert(0 == memcmp(&stretval, &zero, sizeof(stretval)));
2017 // no stret result guarantee
2021 // check stret return register
2024 stretptr = ((struct stret *(*)(struct stret *, id, SEL))objc_msgSend_stret)
2025 (&stretval, nil, @selector(stret_nop));
2026 testassert(stretptr == &stretval);
2027 testassert(state == 0);
2028 // no stret result guarantee for hand-written calls, even with clang
2032 // check struct-return address stack pop
2033 for (int i = 0; i < 10000000; i++) {
2035 ((struct stret (*)(id, SEL))objc_msgSend_stret)
2036 (nil, @selector(stret_nop));
2042 fpval = [(id)NIL_RECEIVER fpret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
2043 testassert(state == 0);
2044 testassert(fpval == 0.0);
2047 lfpval = LFP_RESULT;
2048 lfpval = [(id)NIL_RECEIVER lfpret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
2049 testassert(state == 0);
2050 testassert(lfpval == 0.0);
2053 vecval = VEC_RESULT;
2054 vecval = [(id)NIL_RECEIVER vecret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
2055 testassert(state == 0);
2056 testassert(vector_all(vecval == 0));
2058 // message to nil, different struct types
2059 // This verifies that ordinary objc_msgSend() erases enough registers
2060 // for structs that return in registers.
2061 #define TEST_NIL_STRUCT(i,n) \
2063 struct stret_##i##n z; \
2064 bzero(&z, sizeof(z)); \
2065 [Super stret_i##n##_nonzero]; \
2066 [Super stret_d##n##_nonzero]; \
2067 struct stret_##i##n val = [(id)NIL_RECEIVER stret_##i##n##_zero]; \
2068 testassert(0 == memcmp(&z, &val, sizeof(val))); \
2071 TEST_NIL_STRUCT(i,1);
2072 TEST_NIL_STRUCT(i,2);
2073 TEST_NIL_STRUCT(i,3);
2074 TEST_NIL_STRUCT(i,4);
2075 TEST_NIL_STRUCT(i,5);
2076 TEST_NIL_STRUCT(i,6);
2077 TEST_NIL_STRUCT(i,7);
2078 TEST_NIL_STRUCT(i,8);
2079 TEST_NIL_STRUCT(i,9);
2082 testwarn("rdar://16267205 i386 struct{float} and struct{double}");
2084 TEST_NIL_STRUCT(d,1);
2086 TEST_NIL_STRUCT(d,2);
2087 TEST_NIL_STRUCT(d,3);
2088 TEST_NIL_STRUCT(d,4);
2089 TEST_NIL_STRUCT(d,5);
2090 TEST_NIL_STRUCT(d,6);
2091 TEST_NIL_STRUCT(d,7);
2092 TEST_NIL_STRUCT(d,8);
2093 TEST_NIL_STRUCT(d,9);
2097 // message to nil noarg
2098 // explicitly call noarg messenger, even if compiler doesn't emit it
2101 idval = ((typeof(idmsg0))objc_msgSend_noarg)(nil, @selector(idret_noarg));
2102 testassert(state == 0);
2103 testassert(idval == nil);
2107 llval = ((typeof(llmsg0))objc_msgSend_noarg)(nil, @selector(llret_noarg));
2108 testassert(state == 0);
2109 testassert(llval == 0LL);
2111 // no stret_noarg messenger
2116 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(nil, @selector(fpret_noarg));
2117 testassert(state == 0);
2118 testassert(fpval == 0.0);
2121 vecval = VEC_RESULT;
2122 vecval = ((typeof(vecmsg0))objc_msgSend_noarg)(nil, @selector(vecret_noarg));
2123 testassert(state == 0);
2124 testassert(vector_all(vecval == 0));
2126 # if !__i386__ && !__x86_64__
2128 lfpval = LFP_RESULT;
2129 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(nil, @selector(lfpret_noarg));
2130 testassert(state == 0);
2131 testassert(lfpval == 0.0);
2137 // rdar://8271364 objc_msgSendSuper2 must not change objc_super
2138 testprintf("super struct\n");
2139 struct objc_super sup_st = {
2141 object_getClass(sub),
2148 idval = ((id(*)(struct objc_super *, SEL, vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2, 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))objc_msgSendSuper2) (&sup_st, @selector(idret::::::::::::::::::::::::::::::::::::), VEC1,VEC2,VEC3,VEC4,VEC5,VEC6,VEC7,VEC8, 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);
2149 testassert(state == 1);
2150 testassert(idval == ID_RESULT);
2151 testassert(sup_st.receiver == sub);
2152 testassert(sup_st.super_class == object_getClass(sub));
2156 stretval = ((struct stret(*)(struct objc_super *, SEL, vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2, 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))objc_msgSendSuper2_stret) (&sup_st, @selector(stret::::::::::::::::::::::::::::::::::::), VEC1,VEC2,VEC3,VEC4,VEC5,VEC6,VEC7,VEC8, 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);
2157 testassert(state == 3);
2158 testassert(stret_equal(stretval, STRET_RESULT));
2159 testassert(sup_st.receiver == sub);
2160 testassert(sup_st.super_class == object_getClass(sub));
2163 #if __OBJC2__ && !__arm64__
2164 // Debug messengers.
2165 testprintf("debug messengers\n");
2168 idmsg = (typeof(idmsg))objc_msgSend_debug;
2170 idval = (*idmsg)(sub, @selector(idret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
2171 testassert(state == 101);
2172 testassert(idval == ID_RESULT);
2175 llmsg = (typeof(llmsg))objc_msgSend_debug;
2177 llval = (*llmsg)(sub, @selector(llret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
2178 testassert(state == 102);
2179 testassert(llval == LL_RESULT);
2182 stretmsg = (typeof(stretmsg))objc_msgSend_stret_debug;
2184 stretval = (*stretmsg)(sub, @selector(stret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
2185 testassert(state == 103);
2186 testassert(stret_equal(stretval, STRET_RESULT));
2189 sup_st.receiver = sub;
2190 sup_st.super_class = object_getClass(sub);
2191 idmsgsuper = (typeof(idmsgsuper))objc_msgSendSuper2_debug;
2193 idval = (*idmsgsuper)(&sup_st, @selector(idret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
2194 testassert(state == 1);
2195 testassert(idval == ID_RESULT);
2198 sup_st.receiver = sub;
2199 sup_st.super_class = object_getClass(sub);
2200 stretmsgsuper = (typeof(stretmsgsuper))objc_msgSendSuper2_stret_debug;
2202 stretval = (*stretmsgsuper)(&sup_st, @selector(stret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
2203 testassert(state == 3);
2204 testassert(stret_equal(stretval, STRET_RESULT));
2208 fpmsg = (typeof(fpmsg))objc_msgSend_fpret_debug;
2210 fpval = (*fpmsg)(sub, @selector(fpret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
2211 testassert(state == 104);
2212 testassert(fpval == FP_RESULT);
2216 lfpmsg = (typeof(lfpmsg))objc_msgSend_fpret_debug;
2218 lfpval = (*lfpmsg)(sub, @selector(lfpret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
2219 testassert(state == 105);
2220 testassert(lfpval == LFP_RESULT);
2230 testwarn("no unwind tables in this configuration");
2232 // DWARF unwind tables
2233 testprintf("unwind tables\n");
2235 // install exception handler
2236 struct sigaction act;
2237 act.sa_sigaction = sigtrap;
2239 act.sa_flags = SA_SIGINFO;
2240 sigaction(SIGTRAP, &act, NULL);
2242 SubDW *dw = [[SubDW alloc] init];
2244 objc_setForwardHandler((void*)test_dw_forward, (void*)test_dw_forward_stret);
2247 test_dw("objc_msgSend", dw, tagged, false, 0);
2248 test_dw("objc_msgSend_stret", dw, tagged, true, 0);
2249 test_dw("objc_msgSend_fpret", dw, tagged, false, 0);
2250 test_dw("objc_msgSend_fp2ret", dw, tagged, false, 0);
2251 test_dw("objc_msgSendSuper", dw, tagged, false, 0);
2252 test_dw("objc_msgSendSuper2", dw, tagged, false, 0);
2253 test_dw("objc_msgSendSuper_stret", dw, tagged, true, 0);
2254 test_dw("objc_msgSendSuper2_stret", dw, tagged, true, 0);
2256 test_dw("objc_msgSend", dw, dw, false, 0);
2257 test_dw("objc_msgSend_stret", dw, dw, true, 0);
2258 test_dw("objc_msgSend_fpret", dw, dw, false, 0);
2259 test_dw("objc_msgSendSuper", dw, dw, false, 0);
2260 test_dw("objc_msgSendSuper2", dw, dw, false, 0);
2261 test_dw("objc_msgSendSuper_stret", dw, dw, true, 0);
2262 test_dw("objc_msgSendSuper2_stret", dw, dw, true, 0);
2264 test_dw("objc_msgSend", dw, tagged, false, 1);
2265 test_dw("objc_msgSendSuper", dw, tagged, false, 1);
2266 test_dw("objc_msgSendSuper2", dw, tagged, false, 1);
2268 # error unknown architecture
2271 // DWARF unwind tables