2 asm-placeholder.exe is used below to disassemble objc_msgSend
5 $C{COMPILE} -x assembler $DIR/asm-placeholder.s -o asm-placeholder.exe
6 $C{COMPILE} $DIR/msgSend.m -o msgSend.exe -Wno-unused-parameter -Wundeclared-selector -D__DARWIN_OPAQUE_ARM_THREAD_STATE64=1
14 #include <objc/objc.h>
15 #include <objc/runtime.h>
16 #include <objc/objc-internal.h>
17 #include <objc/objc-abi.h>
18 #include <simd/simd.h>
19 #include <mach-o/loader.h>
21 // rdar://21694990 simd.h should have a vector_equal(a, b) function
22 static bool vector_equal(vector_ulong2 lhs, vector_ulong2 rhs) {
23 return vector_all(lhs == rhs);
27 // no stret dispatchers
28 # define SUPPORT_STRET 0
29 # define objc_msgSend_stret objc_msgSend
30 # define objc_msgSendSuper2_stret objc_msgSendSuper2
31 # define objc_msgSend_stret_debug objc_msgSend_debug
32 # define objc_msgSendSuper2_stret_debug objc_msgSendSuper2_debug
33 # define objc_msgLookup_stret objc_msgLookup
34 # define objc_msgLookupSuper2_stret objc_msgLookupSuper2
35 # define method_invoke_stret method_invoke
37 # define SUPPORT_STRET 1
45 # define ALIGN_() asm(".align 4");
48 @interface Super : TestRoot @end
50 @interface Sub : Super @end
56 // for typeof() shorthand only
57 id (*idmsg0)(id, SEL) __attribute__((unused));
58 long long (*llmsg0)(id, SEL) __attribute__((unused));
59 // struct stret (*stretmsg0)(id, SEL) __attribute__((unused));
60 double (*fpmsg0)(id, SEL) __attribute__((unused));
61 long double (*lfpmsg0)(id, SEL) __attribute__((unused));
62 vector_ulong2 (*vecmsg0)(id, SEL) __attribute__((unused));
64 #define VEC1 ((vector_ulong2){1, 1})
65 #define VEC2 ((vector_ulong2){2, 2})
66 #define VEC3 ((vector_ulong2){3, 3})
67 #define VEC4 ((vector_ulong2){4, 4})
68 #define VEC5 ((vector_ulong2){5, 5})
69 #define VEC6 ((vector_ulong2){6, 6})
70 #define VEC7 ((vector_ulong2){7, 7})
71 #define VEC8 ((vector_ulong2){8, 8})
73 #define CHECK_ARGS(sel) \
75 testassert(self == SELF); \
76 testassert(_cmd == sel_registerName(#sel "::::::::::::::::::::::::::::::::::::"));\
77 testassert(i1 == 1); \
78 testassert(i2 == 2); \
79 testassert(i3 == 3); \
80 testassert(i4 == 4); \
81 testassert(i5 == 5); \
82 testassert(i6 == 6); \
83 testassert(i7 == 7); \
84 testassert(i8 == 8); \
85 testassert(i9 == 9); \
86 testassert(i10 == 10); \
87 testassert(i11 == 11); \
88 testassert(i12 == 12); \
89 testassert(i13 == 13); \
90 testassert(f1 == 1.0); \
91 testassert(f2 == 2.0); \
92 testassert(f3 == 3.0); \
93 testassert(f4 == 4.0); \
94 testassert(f5 == 5.0); \
95 testassert(f6 == 6.0); \
96 testassert(f7 == 7.0); \
97 testassert(f8 == 8.0); \
98 testassert(f9 == 9.0); \
99 testassert(f10 == 10.0); \
100 testassert(f11 == 11.0); \
101 testassert(f12 == 12.0); \
102 testassert(f13 == 13.0); \
103 testassert(f14 == 14.0); \
104 testassert(f15 == 15.0); \
105 testassert(vector_all(v1 == 1)); \
106 testassert(vector_all(v2 == 2)); \
107 testassert(vector_all(v3 == 3)); \
108 testassert(vector_all(v4 == 4)); \
109 testassert(vector_all(v5 == 5)); \
110 testassert(vector_all(v6 == 6)); \
111 testassert(vector_all(v7 == 7)); \
112 testassert(vector_all(v8 == 8)); \
115 #define CHECK_ARGS_NOARG(sel) \
117 testassert(self == SELF); \
118 testassert(_cmd == sel_registerName(#sel "_noarg"));\
123 long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
124 double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
125 long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
126 vector_ulong2 VEC_RESULT = { 0x1234567890abcdefULL, 0xfedcba0987654321ULL };
127 // STRET_RESULT in test.h
129 static struct stret zero;
256 @interface Super (Prototypes)
258 // Method prototypes to pacify -Wundeclared-selector.
261 (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;
264 (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;
266 -(struct stret)stret:
267 (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;
270 (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;
272 -(long double)lfpret:
273 (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;
275 -(vector_ulong2)vecret:
276 (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;
281 // Zero all volatile registers.
300 "\n xorps %xmm0, %xmm0"
301 "\n xorps %xmm1, %xmm1"
302 "\n xorps %xmm2, %xmm2"
303 "\n xorps %xmm3, %xmm3"
304 "\n xorps %xmm4, %xmm4"
305 "\n xorps %xmm5, %xmm5"
306 "\n xorps %xmm6, %xmm6"
307 "\n xorps %xmm7, %xmm7"
308 "\n xorps %xmm8, %xmm8"
309 "\n xorps %xmm9, %xmm9"
310 "\n xorps %xmm10, %xmm10"
311 "\n xorps %xmm11, %xmm11"
312 "\n xorps %xmm12, %xmm12"
313 "\n xorps %xmm13, %xmm13"
314 "\n xorps %xmm14, %xmm14"
315 "\n xorps %xmm15, %xmm15"
325 "\n xorps %xmm0, %xmm0"
326 "\n xorps %xmm1, %xmm1"
327 "\n xorps %xmm2, %xmm2"
328 "\n xorps %xmm3, %xmm3"
329 "\n xorps %xmm4, %xmm4"
330 "\n xorps %xmm5, %xmm5"
331 "\n xorps %xmm6, %xmm6"
332 "\n xorps %xmm7, %xmm7"
371 "\n .thumb_func _stomp"
385 "\n vmov.i32 q10, #0"
386 "\n vmov.i32 q11, #0"
387 "\n vmov.i32 q12, #0"
388 "\n vmov.i32 q13, #0"
389 "\n vmov.i32 q14, #0"
390 "\n vmov.i32 q15, #0"
395 # error unknown architecture
399 @implementation Super
400 -(struct stret)stret { return STRET_RESULT; }
402 // The IMPL_ methods are not called directly. Instead the non IMPL_ name is
403 // called. The resolver function installs the real method. This allows
404 // the resolver function to stomp on registers to help test register
405 // preservation in the uncached path.
407 +(BOOL) resolveInstanceMethod:(SEL)sel
409 const char *name = sel_getName(sel);
410 if (! strstr(name, "::::::::")) return false;
412 testprintf("resolving %s\n", name);
416 asprintf(&realName, "IMPL_%s", name);
417 SEL realSel = sel_registerName(realName);
420 IMP imp = class_getMethodImplementation(self, realSel);
421 if (imp == &_objc_msgForward) return false;
422 return class_addMethod(self, sel, imp, "");
426 (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
433 -(long long)IMPL_llret:
434 (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
441 -(struct stret)IMPL_stret:
442 (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
450 (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
457 -(long double)IMPL_lfpret:
458 (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
465 -(vector_ulong2)IMPL_vecret:
466 (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
476 CHECK_ARGS_NOARG(idret);
481 -(long long)llret_noarg
483 CHECK_ARGS_NOARG(llret);
488 -(struct stret)stret_noarg
490 CHECK_ARGS_NOARG(stret);
497 CHECK_ARGS_NOARG(fpret);
502 -(long double)lfpret_noarg
504 CHECK_ARGS_NOARG(lfpret);
509 -(vector_ulong2)vecret_noarg
511 CHECK_ARGS_NOARG(vecret);
517 -(struct stret)stret_nop
523 #define STRET_IMP(n) \
524 +(struct stret_##n)stret_##n##_zero \
526 struct stret_##n ret; \
527 bzero(&ret, sizeof(ret)); \
530 +(struct stret_##n)stret_##n##_nonzero \
532 struct stret_##n ret; \
533 memset(&ret, 0xff, sizeof(ret)); \
559 (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
561 fail("+idret called instead of -idret");
566 (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
568 fail("+llret called instead of -llret");
572 +(struct stret)stret:
573 (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
575 fail("+stret called instead of -stret");
580 (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
582 fail("+fpret called instead of -fpret");
586 +(long double)lfpret:
587 (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
589 fail("+lfpret called instead of -lfpret");
595 fail("+idret_noarg called instead of -idret_noarg");
596 CHECK_ARGS_NOARG(idret);
599 +(long long)llret_noarg
601 fail("+llret_noarg called instead of -llret_noarg");
602 CHECK_ARGS_NOARG(llret);
605 +(struct stret)stret_noarg
607 fail("+stret_noarg called instead of -stret_noarg");
608 CHECK_ARGS_NOARG(stret);
613 fail("+fpret_noarg called instead of -fpret_noarg");
614 CHECK_ARGS_NOARG(fpret);
617 +(long double)lfpret_noarg
619 fail("+lfpret_noarg called instead of -lfpret_noarg");
620 CHECK_ARGS_NOARG(lfpret);
623 +(vector_ulong2)vecret_noarg
625 fail("+vecret_noarg called instead of -vecret_noarg");
626 CHECK_ARGS_NOARG(vecret);
635 (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
640 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];
641 testassert(state == 1);
642 testassert(result == ID_RESULT);
647 -(long long)IMPL_llret:
648 (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
653 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];
654 testassert(state == 2);
655 testassert(result == LL_RESULT);
660 -(struct stret)IMPL_stret:
661 (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
666 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];
667 testassert(state == 3);
668 testassert(stret_equal(result, STRET_RESULT));
674 (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
679 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];
680 testassert(state == 4);
681 testassert(result == FP_RESULT);
686 -(long double)IMPL_lfpret:
687 (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
692 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];
693 testassert(state == 5);
694 testassert(result == LFP_RESULT);
699 -(vector_ulong2)IMPL_vecret:
700 (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
702 vector_ulong2 result;
705 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];
706 testassert(state == 6);
707 testassert(vector_equal(result, VEC_RESULT));
716 CHECK_ARGS_NOARG(idret);
718 result = [super idret_noarg];
719 testassert(state == 11);
720 testassert(result == ID_RESULT);
725 -(long long)llret_noarg
728 CHECK_ARGS_NOARG(llret);
730 result = [super llret_noarg];
731 testassert(state == 12);
732 testassert(result == LL_RESULT);
737 -(struct stret)stret_noarg
740 CHECK_ARGS_NOARG(stret);
742 result = [super stret_noarg];
743 testassert(state == 13);
744 testassert(stret_equal(result, STRET_RESULT));
752 CHECK_ARGS_NOARG(fpret);
754 result = [super fpret_noarg];
755 testassert(state == 14);
756 testassert(result == FP_RESULT);
761 -(long double)lfpret_noarg
764 CHECK_ARGS_NOARG(lfpret);
766 result = [super lfpret_noarg];
767 testassert(state == 15);
768 testassert(result == LFP_RESULT);
773 -(vector_ulong2)vecret_noarg
775 vector_ulong2 result;
776 CHECK_ARGS_NOARG(vecret);
778 result = [super vecret_noarg];
779 testassert(state == 16);
780 testassert(vector_equal(result, VEC_RESULT));
788 #if OBJC_HAVE_TAGGED_POINTERS
790 @interface TaggedSub : Sub @end
792 @implementation TaggedSub : Sub
796 _objc_registerTaggedPointerClass(OBJC_TAG_1, self);
801 @interface ExtTaggedSub : Sub @end
803 @implementation ExtTaggedSub : Sub
807 _objc_registerTaggedPointerClass(OBJC_TAG_First52BitPayload, self);
815 // DWARF checking machinery
818 // unimplemented on this platform
819 #define NO_DWARF_REASON "(windows)"
821 #elif TARGET_OS_WATCH
822 // fixme unimplemented - ucontext not passed to signal handlers
823 #define NO_DWARF_REASON "(watchOS)"
825 #elif __has_feature(objc_arc)
826 // ARC's extra RR calls hit the traps at the wrong times
827 #define NO_DWARF_REASON "(ARC)"
833 // Classes with no implementations and no cache contents from elsewhere.
834 @interface SuperDW : TestRoot @end
835 @implementation SuperDW @end
837 @interface Sub0DW : SuperDW @end
838 @implementation Sub0DW @end
840 @interface SubDW : Sub0DW @end
841 @implementation SubDW @end
845 #include <sys/mman.h>
846 #include <libunwind.h>
852 extern void callit(void *obj, void *sel, void *fn);
853 extern struct stret callit_stret(void *obj, void *sel, void *fn);
858 typedef uint8_t insn_t;
859 typedef insn_t clobbered_insn_t;
860 #define BREAK_INSN ((insn_t)0x06) // undefined
861 #define BREAK_SIGNAL SIGILL
872 void handle_exception(x86_thread_state64_t *state)
879 err = unw_init_local(&curs, (unw_context_t *)state);
882 step = unw_step(&curs);
883 testassert(step > 0);
885 err = unw_get_reg(&curs, UNW_X86_64_R12, ®);
887 testassert(reg == r12);
889 err = unw_get_reg(&curs, UNW_X86_64_R13, ®);
891 testassert(reg == r13);
893 err = unw_get_reg(&curs, UNW_X86_64_R14, ®);
895 testassert(reg == r14);
897 err = unw_get_reg(&curs, UNW_X86_64_R15, ®);
899 testassert(reg == r15);
901 err = unw_get_reg(&curs, UNW_X86_64_RBX, ®);
903 testassert(reg == rbx);
905 err = unw_get_reg(&curs, UNW_X86_64_RBP, ®);
907 testassert(reg == rbp);
909 err = unw_get_reg(&curs, UNW_X86_64_RSP, ®);
911 testassert(reg == rsp);
913 err = unw_get_reg(&curs, UNW_REG_IP, ®);
915 testassert(reg == rip);
918 // set thread state to unwound state
932 void break_handler(int sig, siginfo_t *info, void *cc)
934 ucontext_t *uc = (ucontext_t *)cc;
935 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
937 testprintf(" handled\n");
939 testassert(sig == BREAK_SIGNAL);
940 testassert((uintptr_t)info->si_addr == clobbered);
942 handle_exception(&mc->__ss);
943 // handle_exception changed register state for continuation
950 // save sp and return address to variables
951 "\n movq (%rsp), %r10"
952 "\n movq %r10, _rip(%rip)"
953 "\n movq %rsp, _rsp(%rip)"
954 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
955 // save other non-volatile registers to variables
956 "\n movq %rbx, _rbx(%rip)"
957 "\n movq %rbp, _rbp(%rip)"
958 "\n movq %r12, _r12(%rip)"
959 "\n movq %r13, _r13(%rip)"
960 "\n movq %r14, _r14(%rip)"
961 "\n movq %r15, _r15(%rip)"
967 "\n .globl _callit_stret"
969 // save sp and return address to variables
970 "\n movq (%rsp), %r10"
971 "\n movq %r10, _rip(%rip)"
972 "\n movq %rsp, _rsp(%rip)"
973 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
974 // save other non-volatile registers to variables
975 "\n movq %rbx, _rbx(%rip)"
976 "\n movq %rbp, _rbp(%rip)"
977 "\n movq %r12, _r12(%rip)"
978 "\n movq %r13, _r13(%rip)"
979 "\n movq %r14, _r14(%rip)"
980 "\n movq %r15, _r15(%rip)"
989 typedef uint8_t insn_t;
990 typedef insn_t clobbered_insn_t;
991 #define BREAK_INSN ((insn_t)0xcc) // int3
992 #define BREAK_SIGNAL SIGTRAP
1000 uintptr_t espfix = 0;
1002 void handle_exception(i386_thread_state_t *state)
1009 err = unw_init_local(&curs, (unw_context_t *)state);
1012 step = unw_step(&curs);
1013 testassert(step > 0);
1015 err = unw_get_reg(&curs, UNW_REG_IP, ®);
1017 testassert(reg == eip);
1019 err = unw_get_reg(&curs, UNW_X86_ESP, ®);
1021 testassert(reg == esp);
1023 err = unw_get_reg(&curs, UNW_X86_EBX, ®);
1025 testassert(reg == ebx);
1027 err = unw_get_reg(&curs, UNW_X86_EBP, ®);
1029 testassert(reg == ebp);
1031 err = unw_get_reg(&curs, UNW_X86_EDI, ®);
1033 testassert(reg == edi);
1035 err = unw_get_reg(&curs, UNW_X86_ESI, ®);
1037 testassert(reg == esi);
1040 // set thread state to unwound state
1042 state->__esp = esp + espfix;
1052 void break_handler(int sig, siginfo_t *info, void *cc)
1054 ucontext_t *uc = (ucontext_t *)cc;
1055 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
1057 testprintf(" handled\n");
1059 testassert(sig == BREAK_SIGNAL);
1060 testassert((uintptr_t)info->si_addr-1 == clobbered);
1062 handle_exception(&mc->__ss);
1063 // handle_exception changed register state for continuation
1070 // save sp and return address to variables
1073 "\n movl (%esp), %eax"
1074 "\n movl %eax, _eip-1b(%edx)"
1075 "\n movl %esp, _esp-1b(%edx)"
1076 "\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
1077 "\n movl $0, _espfix-1b(%edx)"
1078 // save other non-volatile registers to variables
1079 "\n movl %ebx, _ebx-1b(%edx)"
1080 "\n movl %ebp, _ebp-1b(%edx)"
1081 "\n movl %edi, _edi-1b(%edx)"
1082 "\n movl %esi, _esi-1b(%edx)"
1088 "\n .globl _callit_stret"
1090 // save sp and return address to variables
1093 "\n movl (%esp), %eax"
1094 "\n movl %eax, _eip-1b(%edx)"
1095 "\n movl %esp, _esp-1b(%edx)"
1096 "\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
1097 "\n movl $4, _espfix-1b(%edx)"
1098 // save other non-volatile registers to variables
1099 "\n movl %ebx, _ebx-1b(%edx)"
1100 "\n movl %ebp, _ebp-1b(%edx)"
1101 "\n movl %edi, _edi-1b(%edx)"
1102 "\n movl %esi, _esi-1b(%edx)"
1110 #include <sys/ucontext.h>
1112 typedef uint32_t insn_t;
1113 typedef insn_t clobbered_insn_t;
1114 #define BREAK_INSN ((insn_t)0xd4200020) // brk #1
1115 #define BREAK_SIGNAL SIGTRAP
1131 void handle_exception(arm_thread_state64_t *state)
1138 // libunwind layout differs from mcontext layout
1139 // GPRs are the same but vector registers are not
1140 unw_context_t unwstate;
1141 unw_getcontext(&unwstate);
1142 memcpy(&unwstate, state, sizeof(*state));
1144 // libunwind and xnu sign some pointers differently
1145 // xnu: not signed (fixme this may change?)
1146 // libunwind: PC and LR both signed with return address key and SP
1147 void **pcp = &((arm_thread_state64_t *)&unwstate)->__opaque_pc;
1148 *pcp = ptrauth_sign_unauthenticated((void*)__darwin_arm_thread_state64_get_pc(*state),
1149 ptrauth_key_return_address,
1150 (ptrauth_extra_data_t)__darwin_arm_thread_state64_get_sp(*state));
1151 void **lrp = &((arm_thread_state64_t *)&unwstate)->__opaque_lr;
1152 *lrp = ptrauth_sign_unauthenticated((void*)__darwin_arm_thread_state64_get_lr(*state),
1153 ptrauth_key_return_address,
1154 (ptrauth_extra_data_t)__darwin_arm_thread_state64_get_sp(*state));
1156 err = unw_init_local(&curs, &unwstate);
1159 step = unw_step(&curs);
1160 testassert(step > 0);
1162 err = unw_get_reg(&curs, UNW_ARM64_X19, ®);
1164 testassert(reg == x19);
1166 err = unw_get_reg(&curs, UNW_ARM64_X20, ®);
1168 testassert(reg == x20);
1170 err = unw_get_reg(&curs, UNW_ARM64_X21, ®);
1172 testassert(reg == x21);
1174 err = unw_get_reg(&curs, UNW_ARM64_X22, ®);
1176 testassert(reg == x22);
1178 err = unw_get_reg(&curs, UNW_ARM64_X23, ®);
1180 testassert(reg == x23);
1182 err = unw_get_reg(&curs, UNW_ARM64_X24, ®);
1184 testassert(reg == x24);
1186 err = unw_get_reg(&curs, UNW_ARM64_X25, ®);
1188 testassert(reg == x25);
1190 err = unw_get_reg(&curs, UNW_ARM64_X26, ®);
1192 testassert(reg == x26);
1194 err = unw_get_reg(&curs, UNW_ARM64_X27, ®);
1196 testassert(reg == x27);
1198 err = unw_get_reg(&curs, UNW_ARM64_X28, ®);
1200 testassert(reg == x28);
1202 err = unw_get_reg(&curs, UNW_ARM64_FP, ®);
1204 testassert(reg == fp);
1206 err = unw_get_reg(&curs, UNW_ARM64_SP, ®);
1208 testassert(reg == sp);
1210 err = unw_get_reg(&curs, UNW_REG_IP, ®);
1212 // libunwind's return is signed but our value is not
1213 reg = (uintptr_t)ptrauth_strip((void *)reg, ptrauth_key_return_address);
1214 testassert(reg == pc);
1216 // libunwind restores PC into LR and doesn't track LR
1217 // err = unw_get_reg(&curs, UNW_ARM64_LR, ®);
1218 // testassert(!err);
1219 // testassert(reg == lr);
1221 // set signal handler's thread state to unwound state
1222 state->__x[19] = x19;
1223 state->__x[20] = x20;
1224 state->__x[21] = x21;
1225 state->__x[22] = x22;
1226 state->__x[23] = x23;
1227 state->__x[24] = x24;
1228 state->__x[25] = x25;
1229 state->__x[26] = x26;
1230 state->__x[27] = x27;
1231 state->__x[28] = x28;
1232 state->__opaque_fp = (void *)fp;
1233 state->__opaque_lr = (void *)pc; // libunwind restores PC into LR
1234 state->__opaque_sp = (void *)sp;
1235 state->__opaque_pc = (void *)pc;
1241 void break_handler(int sig, siginfo_t *info, void *cc)
1243 ucontext_t *uc = (ucontext_t *)cc;
1244 struct __darwin_mcontext64 *mc = (struct __darwin_mcontext64 *)uc->uc_mcontext;
1246 testprintf(" handled\n");
1248 testassert(sig == BREAK_SIGNAL);
1249 testassert((uintptr_t)info->si_addr == clobbered);
1251 handle_exception(&mc->__ss);
1252 // handle_exception changed register state for continuation
1260 // save sp and return address to variables
1262 "\n adrp x17, _sp@PAGE"
1263 "\n str x16, [x17, _sp@PAGEOFF]"
1264 "\n adrp x17, _pc@PAGE"
1265 "\n str lr, [x17, _pc@PAGEOFF]"
1266 // save other non-volatile registers to variables
1267 "\n adrp x17, _x19@PAGE"
1268 "\n str x19, [x17, _x19@PAGEOFF]"
1269 "\n adrp x17, _x19@PAGE"
1270 "\n str x20, [x17, _x20@PAGEOFF]"
1271 "\n adrp x17, _x19@PAGE"
1272 "\n str x21, [x17, _x21@PAGEOFF]"
1273 "\n adrp x17, _x19@PAGE"
1274 "\n str x22, [x17, _x22@PAGEOFF]"
1275 "\n adrp x17, _x19@PAGE"
1276 "\n str x23, [x17, _x23@PAGEOFF]"
1277 "\n adrp x17, _x19@PAGE"
1278 "\n str x24, [x17, _x24@PAGEOFF]"
1279 "\n adrp x17, _x19@PAGE"
1280 "\n str x25, [x17, _x25@PAGEOFF]"
1281 "\n adrp x17, _x19@PAGE"
1282 "\n str x26, [x17, _x26@PAGEOFF]"
1283 "\n adrp x17, _x19@PAGE"
1284 "\n str x27, [x17, _x27@PAGEOFF]"
1285 "\n adrp x17, _x19@PAGE"
1286 "\n str x28, [x17, _x28@PAGEOFF]"
1287 "\n adrp x17, _x19@PAGE"
1288 "\n str fp, [x17, _fp@PAGEOFF]"
1296 #include <sys/ucontext.h>
1298 typedef uint16_t insn_t;
1304 #define BREAK_INSN ((insn_t)0xdefe) // trap
1305 #define BREAK_SIGNAL SIGILL
1306 #define BREAK_SIGNAL2 SIGTRAP
1318 void handle_exception(arm_thread_state_t *state)
1320 // No unwind tables on this architecture so no libunwind checks.
1321 // We run the test anyway to verify instruction-level coverage.
1323 // set thread state to unwound state
1329 state->__r[10] = r10;
1330 state->__r[11] = r11;
1333 // clear IT... bits so caller doesn't act on them
1334 state->__cpsr &= ~0x0600fc00;
1340 void break_handler(int sig, siginfo_t *info, void *cc)
1342 ucontext_t *uc = (ucontext_t *)cc;
1343 struct __darwin_mcontext32 *mc = (struct __darwin_mcontext32 *)uc->uc_mcontext;
1345 testprintf(" handled\n");
1347 testassert(sig == BREAK_SIGNAL || sig == BREAK_SIGNAL2);
1348 testassert((uintptr_t)info->si_addr == clobbered);
1350 handle_exception(&mc->__ss);
1351 // handle_exception changed register state for continuation
1357 "\n .syntax unified"
1363 // save sp and return address to variables
1364 "\n movw r12, :lower16:(_sp-1f-4)"
1365 "\n movt r12, :upper16:(_sp-1f-4)"
1368 "\n movw r12, :lower16:(_pc-1f-4)"
1369 "\n movt r12, :upper16:(_pc-1f-4)"
1372 // save other non-volatile registers to variables
1373 "\n movw r12, :lower16:(_r4-1f-4)"
1374 "\n movt r12, :upper16:(_r4-1f-4)"
1377 "\n movw r12, :lower16:(_r5-1f-4)"
1378 "\n movt r12, :upper16:(_r5-1f-4)"
1381 "\n movw r12, :lower16:(_r6-1f-4)"
1382 "\n movt r12, :upper16:(_r6-1f-4)"
1385 "\n movw r12, :lower16:(_r7-1f-4)"
1386 "\n movt r12, :upper16:(_r7-1f-4)"
1389 "\n movw r12, :lower16:(_r8-1f-4)"
1390 "\n movt r12, :upper16:(_r8-1f-4)"
1393 "\n movw r12, :lower16:(_r10-1f-4)"
1394 "\n movt r12, :upper16:(_r10-1f-4)"
1397 "\n movw r12, :lower16:(_r11-1f-4)"
1398 "\n movt r12, :upper16:(_r11-1f-4)"
1406 "\n .syntax unified"
1409 "\n .globl _callit_stret"
1412 // save sp and return address to variables
1413 "\n movw r12, :lower16:(_sp-1f-4)"
1414 "\n movt r12, :upper16:(_sp-1f-4)"
1417 "\n movw r12, :lower16:(_pc-1f-4)"
1418 "\n movt r12, :upper16:(_pc-1f-4)"
1421 // save other non-volatile registers to variables
1422 "\n movw r12, :lower16:(_r4-1f-4)"
1423 "\n movt r12, :upper16:(_r4-1f-4)"
1426 "\n movw r12, :lower16:(_r5-1f-4)"
1427 "\n movt r12, :upper16:(_r5-1f-4)"
1430 "\n movw r12, :lower16:(_r6-1f-4)"
1431 "\n movt r12, :upper16:(_r6-1f-4)"
1434 "\n movw r12, :lower16:(_r7-1f-4)"
1435 "\n movt r12, :upper16:(_r7-1f-4)"
1438 "\n movw r12, :lower16:(_r8-1f-4)"
1439 "\n movt r12, :upper16:(_r8-1f-4)"
1442 "\n movw r12, :lower16:(_r10-1f-4)"
1443 "\n movt r12, :upper16:(_r10-1f-4)"
1446 "\n movw r12, :lower16:(_r11-1f-4)"
1447 "\n movt r12, :upper16:(_r11-1f-4)"
1457 #error unknown architecture
1463 uintptr_t fnaddr(void *fn) { return (uintptr_t)fn & ~(uintptr_t)1; }
1465 uintptr_t fnaddr(void *fn) { return (uintptr_t)fn; }
1468 insn_t set(uintptr_t dst, insn_t newvalue)
1470 uintptr_t start = dst & ~(PAGE_MAX_SIZE-1);
1471 int err = mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_WRITE);
1472 if (err) fail("mprotect(%p, RW-) failed (%d)", start, errno);
1473 insn_t oldvalue = *(insn_t *)dst;
1474 *(insn_t *)dst = newvalue;
1475 err = mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_EXEC);
1476 if (err) fail("mprotect(%p, R-X) failed (%d)", start, errno);
1480 clobbered_insn_t clobber(void *fn, uintptr_t offset)
1482 clobbered = fnaddr(fn) + offset;
1483 insn_t oldInsn = set(fnaddr(fn) + offset, BREAK_INSN);
1485 // Need to clobber 32-bit Thumb instructions with another 32-bit instruction
1486 // to preserve the behavior of IT... blocks.
1487 clobbered_insn_t result = {oldInsn, 0, false};
1488 if (((oldInsn & 0xf000) == 0xf000) ||
1489 ((oldInsn & 0xf800) == 0xe800))
1491 testprintf("clobbering thumb-32 at offset %zu\n", offset);
1492 // Old insn was 32-bit. Clobber all of it.
1494 set(fnaddr(fn) + offset, oldInsn);
1495 // f7f0 a0f0 is a "permanently undefined" Thumb-2 instruction.
1496 // Clobber the first half last so `clobbered` gets the right value.
1497 result.second = set(fnaddr(fn) + offset + 2, 0xa0f0);
1498 result.first = set(fnaddr(fn) + offset, 0xf7f0);
1499 result.thirty_two = true;
1507 void unclobber(void *fn, uintptr_t offset, clobbered_insn_t oldvalue)
1510 if (oldvalue.thirty_two) {
1511 set(fnaddr(fn) + offset + 2, oldvalue.second);
1513 set(fnaddr(fn) + offset, oldvalue.first);
1515 set(fnaddr(fn) + offset, oldvalue);
1520 // terminator for the list of instruction offsets
1521 #define END_OFFSETS ~0UL
1523 // Disassemble instructions symbol..<symbolEnd.
1524 // Write the offset of each non-NOP instruction start to *offsets..<end.
1525 // Return the incremented offsets pointer.
1526 uintptr_t *disassemble(uintptr_t symbol, uintptr_t symbolEnd,
1527 uintptr_t *offsets, uintptr_t *end)
1530 // 1. Copy asm-placeholder.exe into a temporary file.
1531 // 2. Write the instructions into the temp file.
1532 // 3. Run llvm-objdump on the temp file.
1533 // 4. Parse the llvm-objdump output.
1535 // copy asm-placeholder.exe into a new temporary file and open it.
1536 int placeholder = open("asm-placeholder.exe", O_RDONLY);
1537 if (placeholder < 0) {
1538 fail("couldn't open asm-placeholder.exe (%d)", errno);
1541 size_t tempdirlen = confstr(_CS_DARWIN_USER_TEMP_DIR, nil, 0);
1542 char tempsuffix[] = "objc-test-msgSend-asm-XXXXXX";
1543 char *tempname = (char *)malloc(tempdirlen + strlen(tempsuffix));
1544 confstr(_CS_DARWIN_USER_TEMP_DIR, tempname, tempdirlen);
1545 strcat(tempname, tempsuffix);
1547 int fd = mkstemp(tempname);
1549 fail("couldn't create asm temp file %s (%d)", tempname, errno);
1552 if (fstat(placeholder, &st) < 0) {
1553 fail("couldn't stat asm-placeholder.exe (%d)", errno);
1555 char *buf = (char *)malloc(st.st_size);
1556 if (pread(placeholder, buf, st.st_size, 0) != st.st_size) {
1557 fail("couldn't read asm-placeholder.exe (%d)", errno);
1559 if (pwrite(fd, buf, st.st_size, 0) != st.st_size) {
1560 fail("couldn't write asm temp file %s (%d)", tempname, errno);
1565 // write code into asm-placeholder.exe
1566 // asm-placeholder.exe may have as little as 1024 bytes of space reserved
1567 testassert(symbolEnd - symbol < 1024);
1568 // text section should be 16KB into asm-placeholder.exe
1569 if (pwrite(fd, (void*)symbol, symbolEnd - symbol, 16384) < 0) {
1570 fail("couldn't write code into asm temp file %s (%d)", tempname, errno);
1574 // run `llvm-objdump -disassemble`
1575 const char *objdump;
1576 if (0 == access("/usr/local/bin/llvm-objdump", F_OK)) {
1577 objdump = "/usr/local/bin/llvm-objdump";
1578 } else if (0 == access("/usr/bin/llvm-objdump", F_OK)) {
1579 objdump = "/usr/bin/llvm-objdump";
1581 fail("couldn't find llvm-objdump");
1584 asprintf(&cmd, "%s -disassemble %s", objdump, tempname);
1585 FILE *disa = popen(cmd, "r");
1587 fail("couldn't popen %s", cmd);
1592 // read past "_main:" line
1595 while ((line = fgetln(disa, &len))) {
1596 testprintf("ASM: %.*s", (int)len, line);
1597 if (0 == strncmp(line, "_main:", strlen("_main:"))) break;
1600 // read instructions and save offsets
1604 uintptr_t *p = offsets;
1605 // disassembly format:
1606 // ADDR:\t ...instruction bytes... \tOPCODE ...etc...\n
1607 while (2 == fscanf(disa, "%lx:\t%*[a-fA-F0-9 ]\t%s%*[^\n]\n", &addr, op)) {
1608 if (base == 0) base = addr;
1609 testprintf("ASM: %lx (+%d) ... %s ...\n", addr, addr - base, op);
1610 // allow longer nops like Intel nopw and nopl
1611 if (0 != strncmp(op, "nop", 3)) {
1612 testassert(offsets < end);
1615 // assume nops are unreached (e.g. alignment padding)
1621 // hack: skip last instruction because libunwind blows up if it's
1622 // one byte long and followed by the next function with no NOPs first
1623 if (p > offsets) *p-- = END_OFFSETS;
1630 uintptr_t *getOffsets(const char *symname, uintptr_t *outBase)
1632 // Find the start of our function.
1633 uintptr_t symbol = (uintptr_t)dlsym(RTLD_NEXT, symname);
1634 if (!symbol) return nil;
1635 #if __has_feature(ptrauth_calls)
1636 symbol = (uintptr_t)
1637 ptrauth_strip((void*)symbol, ptrauth_key_function_pointer);
1640 if (outBase) *outBase = symbol;
1642 // Find the end of our function by finding the start
1643 // of the next symbol after our target symbol.
1645 const int insnIncrement =
1649 2; // in case of thumb or thumb-2
1650 #elif __i386__ || __x86_64__
1653 #error unknown architecture
1656 uintptr_t symbolEnd;
1659 for (symbolEnd = symbol + insnIncrement;
1660 ((ok = dladdr((void*)symbolEnd, &dli))) && dli.dli_saddr == (void*)symbol;
1661 symbolEnd += insnIncrement)
1664 testprintf("found %s at %p..<%p %d %p %s\n",
1665 symname, (void*)symbol, (void*)symbolEnd, ok, dli.dli_saddr, dli.dli_sname);
1667 // Record the offset to each non-NOP instruction.
1668 uintptr_t *result = (uintptr_t *)malloc(1000 * sizeof(uintptr_t));
1669 uintptr_t *end = result + 1000;
1670 uintptr_t *p = result;
1672 p = disassemble(symbol, symbolEnd, p, end);
1674 // Also record the offsets in _objc_msgSend_uncached when present
1675 // (which is the slow path and has a frame to unwind)
1676 if (!strstr(symname, "_uncached")) {
1677 const char *uncached_symname = strstr(symname, "stret")
1678 ? "_objc_msgSend_stret_uncached" : "_objc_msgSend_uncached";
1679 uintptr_t uncached_symbol;
1680 uintptr_t *uncached_offsets =
1681 getOffsets(uncached_symname, &uncached_symbol);
1682 if (uncached_offsets) {
1683 uintptr_t *q = uncached_offsets;
1684 // Skip prologue and epilogue of objc_msgSend_uncached
1685 // because it's imprecisely modeled in compact unwind
1686 int prologueInstructions, epilogueInstructions;
1688 prologueInstructions = 3;
1689 epilogueInstructions = 2;
1690 #elif __arm64__ || __x86_64__ || __i386__ || __arm__
1691 prologueInstructions = 2;
1692 epilogueInstructions = 1;
1694 #error unknown architecture
1696 // skip past prologue
1697 for (int i = 0; i < prologueInstructions; i++) {
1698 testassert(*q != END_OFFSETS);
1702 // copy instructions
1703 while (*q != END_OFFSETS) *p++ = *q++ + uncached_symbol - symbol;
1705 // rewind past epilogue
1706 for (int i = 0; i < epilogueInstructions; i++) {
1707 testassert(p > result);
1711 free(uncached_offsets);
1715 // Terminate the list of offsets and return.
1716 testassert(p > result);
1717 testassert(p < end);
1724 void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret) __attribute__((noinline));
1725 void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret)
1727 uintptr_t message_ref[2];
1730 // copy to a local buffer to keep sel_arg un-fixed-up
1731 memcpy(message_ref, sel_arg, sizeof(message_ref));
1732 sel_arg = message_ref;
1734 if (!stret) callit(o, sel_arg, f);
1736 else callit_stret(o, sel_arg, f);
1738 else fail("stret?");
1742 void test_dw_forward(void)
1747 struct stret test_dw_forward_stret(void)
1752 // sub = ordinary receiver object
1753 // tagged = tagged receiver object
1754 // SEL = selector to send
1755 // sub_arg = arg to pass in receiver register (may be objc_super struct)
1756 // tagged_arg = arg to pass in receiver register (may be objc_super struct)
1757 // sel_arg = arg to pass in sel register (may be message_ref)
1758 // uncaughtAllowed is the number of acceptable unreachable instructions
1759 // (for example, the ones that handle the corrupt-cache-error case)
1760 void test_dw(const char *name, id sub, id tagged, id exttagged, bool stret,
1761 int uncaughtAllowed)
1764 testprintf("DWARF FOR %s%s\n", name, stret ? " (stret)" : "");
1766 // We need 2 SELs of each alignment so we can generate hash collisions.
1767 // sel_registerName() never returns those alignments because they
1768 // differ from malloc's alignment. So we create lots of compiled-in
1769 // SELs here and hope something fits.
1770 #pragma clang diagnostic push
1771 #pragma clang diagnostic ignored "-Wundeclared-selector"
1772 SEL sel = @selector(a);
1773 SEL lotsOfSels[] = {
1774 @selector(a1), @selector(a2), @selector(a3), @selector(a4),
1775 @selector(a5), @selector(a6), @selector(a7), @selector(a8),
1776 @selector(aa), @selector(ab), @selector(ac), @selector(ad),
1777 @selector(ae), @selector(af), @selector(ag), @selector(ah),
1778 @selector(A1), @selector(A2), @selector(A3), @selector(A4),
1779 @selector(A5), @selector(A6), @selector(A7), @selector(A8),
1780 @selector(AA), @selector(Ab), @selector(Ac), @selector(Ad),
1781 @selector(Ae), @selector(Af), @selector(Ag), @selector(Ah),
1782 @selector(bb1), @selector(bb2), @selector(bb3), @selector(bb4),
1783 @selector(bb5), @selector(bb6), @selector(bb7), @selector(bb8),
1784 @selector(bba), @selector(bbb), @selector(bbc), @selector(bbd),
1785 @selector(bbe), @selector(bbf), @selector(bbg), @selector(bbh),
1786 @selector(BB1), @selector(BB2), @selector(BB3), @selector(BB4),
1787 @selector(BB5), @selector(BB6), @selector(BB7), @selector(BB8),
1788 @selector(BBa), @selector(BBb), @selector(BBc), @selector(BBd),
1789 @selector(BBe), @selector(BBf), @selector(BBg), @selector(BBh),
1790 @selector(ccc1), @selector(ccc2), @selector(ccc3), @selector(ccc4),
1791 @selector(ccc5), @selector(ccc6), @selector(ccc7), @selector(ccc8),
1792 @selector(ccca), @selector(cccb), @selector(cccc), @selector(cccd),
1793 @selector(ccce), @selector(cccf), @selector(cccg), @selector(ccch),
1794 @selector(CCC1), @selector(CCC2), @selector(CCC3), @selector(CCC4),
1795 @selector(CCC5), @selector(CCC6), @selector(CCC7), @selector(CCC8),
1796 @selector(CCCa), @selector(CCCb), @selector(CCCc), @selector(CCCd),
1797 @selector(CCCe), @selector(CCCf), @selector(CCCg), @selector(CCCh),
1799 #pragma clang diagnostic pop
1802 IMP imp = stret ? (IMP)test_dw_forward_stret : (IMP)test_dw_forward;
1803 Class cls = object_getClass(sub);
1804 Class tagcls = object_getClass(tagged);
1805 Class exttagcls = object_getClass(exttagged);
1806 class_replaceMethod(cls, sel, imp, "");
1807 class_replaceMethod(tagcls, sel, imp, "");
1808 class_replaceMethod(exttagcls, sel, imp, "");
1809 for (size_t i = 0; i < sizeof(lotsOfSels)/sizeof(lotsOfSels[0]); i++) {
1810 class_replaceMethod(cls, lotsOfSels[i], imp, "");
1811 class_replaceMethod(tagcls, lotsOfSels[i], imp, "");
1812 class_replaceMethod(exttagcls, lotsOfSels[i], imp, "");
1816 #define ALIGNCOUNT 16
1817 SEL sels[ALIGNCOUNT][2] = {{0}};
1818 for (int align = 0; align < ALIGNCOUNT; align++) {
1819 for (size_t i = 0; i < sizeof(lotsOfSels)/sizeof(lotsOfSels[0]); i++) {
1820 if ((uintptr_t)(void*)lotsOfSels[i] % ALIGNCOUNT == align) {
1821 if (sels[align][0]) {
1822 sels[align][1] = lotsOfSels[i];
1824 sels[align][0] = lotsOfSels[i];
1828 if (!sels[align][0]) fail("no SEL with alignment %d", align);
1829 if (!sels[align][1]) fail("only one SEL with alignment %d", align);
1832 void *fn = dlsym(RTLD_DEFAULT, name);
1833 #if __has_feature(ptrauth_calls)
1834 fn = ptrauth_strip(fn, ptrauth_key_function_pointer);
1838 // argument substitutions
1840 void *sub_arg = (__bridge void*)sub;
1841 void *tagged_arg = (__bridge void*)tagged;
1842 void *exttagged_arg = (__bridge void*)exttagged;
1843 void *sel_arg = (void*)sel;
1845 struct objc_super sup_st = { sub, object_getClass(sub) };
1846 struct objc_super tagged_sup_st = { tagged, object_getClass(tagged) };
1847 struct objc_super exttagged_sup_st = { exttagged, object_getClass(exttagged) };
1848 struct { void *imp; SEL sel; } message_ref = { fn, sel };
1850 Class cache_cls = object_getClass(sub);
1851 Class tagged_cache_cls = object_getClass(tagged);
1852 Class exttagged_cache_cls = object_getClass(exttagged);
1854 if (strstr(name, "Super")) {
1855 // super version - replace receiver with objc_super
1856 // clear caches of superclass
1857 cache_cls = class_getSuperclass(cache_cls);
1858 tagged_cache_cls = class_getSuperclass(tagged_cache_cls);
1859 exttagged_cache_cls = class_getSuperclass(exttagged_cache_cls);
1861 tagged_arg = &tagged_sup_st;
1862 exttagged_arg = &exttagged_sup_st;
1865 if (strstr(name, "_fixup")) {
1866 // fixup version - replace sel with message_ref
1867 sel_arg = &message_ref;
1871 uintptr_t *insnOffsets = getOffsets(name, nil);
1872 testassert(insnOffsets);
1874 int uncaughtCount = 0;
1875 for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
1876 offset = insnOffsets[oo];
1877 testprintf("OFFSET %lu\n", offset);
1879 clobbered_insn_t saved_insn = clobber(fn, offset);
1883 if ((__bridge void*)sub == sub_arg) {
1885 testprintf(" nil\n");
1886 CALLIT(nil, sel_arg, sel, fn, stret);
1887 CALLIT(nil, sel_arg, sel, fn, stret);
1892 testprintf(" uncached\n");
1893 _objc_flush_caches(cache_cls);
1894 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1895 _objc_flush_caches(cache_cls);
1896 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1900 testprintf(" cached\n");
1901 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1902 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1906 testprintf(" uncached,tagged\n");
1907 _objc_flush_caches(tagged_cache_cls);
1908 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1909 _objc_flush_caches(tagged_cache_cls);
1910 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1911 _objc_flush_caches(exttagged_cache_cls);
1912 CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
1913 _objc_flush_caches(exttagged_cache_cls);
1914 CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
1918 testprintf(" cached,tagged\n");
1919 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1920 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1921 CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
1922 CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
1924 // multiple SEL alignments, collisions, wraps
1926 for (int a = 0; a < ALIGNCOUNT; a++) {
1927 testprintf(" cached and uncached, SEL alignment %d\n", a);
1929 // Count both up and down to be independent of
1930 // implementation's cache scan direction
1932 _objc_flush_caches(cache_cls);
1933 for (int x2 = 0; x2 < 8; x2++) {
1934 for (int s = 0; s < 4; s++) {
1935 int align = (a+s) % ALIGNCOUNT;
1936 CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
1937 CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
1941 _objc_flush_caches(cache_cls);
1942 for (int x2 = 0; x2 < 8; x2++) {
1943 for (int s = 0; s < 4; s++) {
1944 int align = abs(a-s) % ALIGNCOUNT;
1945 CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
1946 CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
1951 unclobber(fn, offset, saved_insn);
1953 // remember offsets that were caught by none of the above
1955 insnOffsets[oo] = 0;
1958 testprintf("offset %s+%lu not caught (%d/%d)\n",
1959 name, offset, uncaughtCount, uncaughtAllowed);
1963 // Complain if too many offsets went uncaught.
1964 // Acceptably-uncaught offsets include the corrupt-cache-error handler.
1965 if (uncaughtCount != uncaughtAllowed) {
1966 for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
1967 if (insnOffsets[oo]) {
1968 fprintf(stderr, "BAD: offset %s+%lu not caught\n",
1969 name, insnOffsets[oo]);
1972 fail("wrong instructions not reached for %s (missed %d, expected %d)",
1973 name, uncaughtCount, uncaughtAllowed);
1984 void test_basic(id receiver)
1988 struct stret stretval;
1991 vector_ulong2 vecval;
1994 // message uncached long long
1995 // message uncached stret
1996 // message uncached fpret
1997 // message uncached fpret long double
1998 // message uncached noarg (as above)
2000 // message cached long long
2001 // message cached stret
2002 // message cached fpret
2003 // message cached fpret long double
2004 // message cached noarg (as above)
2005 // fixme verify that uncached lookup didn't happen the 2nd time?
2007 _objc_flush_caches(object_getClass(receiver));
2008 for (int i = 0; i < 5; i++) {
2009 testprintf("idret\n");
2012 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];
2013 testassert(state == 101);
2014 testassert(idval == ID_RESULT);
2016 testprintf("llret\n");
2018 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];
2019 testassert(state == 102);
2020 testassert(llval == LL_RESULT);
2022 testprintf("stret\n");
2024 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];
2025 testassert(state == 103);
2026 testassert(stret_equal(stretval, STRET_RESULT));
2028 testprintf("fpret\n");
2030 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];
2031 testassert(state == 104);
2032 testassert(fpval == FP_RESULT);
2034 testprintf("lfpret\n");
2036 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];
2037 testassert(state == 105);
2038 testassert(lfpval == LFP_RESULT);
2040 testprintf("vecret\n");
2042 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];
2043 testassert(state == 106);
2044 testassert(vector_equal(vecval, VEC_RESULT));
2046 // explicitly call noarg messenger, even if compiler doesn't emit it
2048 testprintf("idret noarg\n");
2050 idval = ((typeof(idmsg0))objc_msgSend_noarg)(receiver, @selector(idret_noarg));
2051 testassert(state == 111);
2052 testassert(idval == ID_RESULT);
2054 testprintf("llret noarg\n");
2056 llval = ((typeof(llmsg0))objc_msgSend_noarg)(receiver, @selector(llret_noarg));
2057 testassert(state == 112);
2058 testassert(llval == LL_RESULT);
2060 no objc_msgSend_stret_noarg
2062 stretval = ((typeof(stretmsg0))objc_msgSend_stret_noarg)(receiver, @selector(stret_noarg));
2063 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];
2064 testassert(state == 113);
2065 testassert(stret_equal(stretval, STRET_RESULT));
2068 testprintf("fpret noarg\n");
2070 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(receiver, @selector(fpret_noarg));
2071 testassert(state == 114);
2072 testassert(fpval == FP_RESULT);
2074 testprintf("vecret noarg\n");
2076 vecval = ((typeof(vecmsg0))objc_msgSend_noarg)(receiver, @selector(vecret_noarg));
2077 testassert(state == 116);
2078 testassert(vector_equal(vecval, VEC_RESULT));
2080 #if !__i386__ && !__x86_64__
2081 testprintf("lfpret noarg\n");
2083 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(receiver, @selector(lfpret_noarg));
2084 testassert(state == 115);
2085 testassert(lfpval == LFP_RESULT);
2089 testprintf("basic done\n");
2097 struct stret stretval;
2100 vector_ulong2 vecval;
2103 struct stret *stretptr;
2113 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);
2114 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);
2115 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);
2116 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);
2117 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);
2118 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);
2120 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));
2121 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));
2122 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));
2123 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));
2124 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));
2125 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));
2126 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));
2127 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));
2129 // get +initialize out of the way
2131 #if OBJC_HAVE_TAGGED_POINTERS
2133 [ExtTaggedSub class];
2136 ID_RESULT = [Super new];
2138 Sub *sub = [Sub new];
2139 Super *sup = [Super new];
2140 #if OBJC_HAVE_TAGGED_POINTERS
2141 TaggedSub *tagged = (__bridge id)_objc_makeTaggedPointer(OBJC_TAG_1, 999);
2142 ExtTaggedSub *exttagged = (__bridge id)_objc_makeTaggedPointer(OBJC_TAG_First52BitPayload, 999);
2145 // Basic cached and uncached dispatch.
2146 // Do this first before anything below caches stuff.
2147 testprintf("basic\n");
2149 #if OBJC_HAVE_TAGGED_POINTERS
2150 testprintf("basic tagged\n");
2152 testprintf("basic ext tagged\n");
2153 test_basic(exttagged);
2156 idmethod = class_getInstanceMethod([Super class], @selector(idret::::::::::::::::::::::::::::::::::::));
2157 testassert(idmethod);
2158 llmethod = class_getInstanceMethod([Super class], @selector(llret::::::::::::::::::::::::::::::::::::));
2159 testassert(llmethod);
2160 stretmethod = class_getInstanceMethod([Super class], @selector(stret::::::::::::::::::::::::::::::::::::));
2161 testassert(stretmethod);
2162 fpmethod = class_getInstanceMethod([Super class], @selector(fpret::::::::::::::::::::::::::::::::::::));
2163 testassert(fpmethod);
2164 lfpmethod = class_getInstanceMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::::::::::));
2165 testassert(lfpmethod);
2166 vecmethod = class_getInstanceMethod([Super class], @selector(vecret::::::::::::::::::::::::::::::::::::));
2167 testassert(vecmethod);
2169 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;
2170 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;
2171 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;
2172 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;
2173 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;
2174 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;
2177 // method_invoke long long
2178 // method_invoke_stret stret
2179 // method_invoke_stret fpret
2180 // method_invoke fpret long double
2181 testprintf("method_invoke\n");
2187 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);
2188 testassert(state == 1);
2189 testassert(idval == ID_RESULT);
2192 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);
2193 testassert(state == 2);
2194 testassert(llval == LL_RESULT);
2197 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);
2198 testassert(state == 3);
2199 testassert(stret_equal(stretval, STRET_RESULT));
2202 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);
2203 testassert(state == 4);
2204 testassert(fpval == FP_RESULT);
2207 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);
2208 testassert(state == 5);
2209 testassert(lfpval == LFP_RESULT);
2212 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);
2213 testassert(state == 6);
2214 testassert(vector_equal(vecval, VEC_RESULT));
2218 // message to nil long long
2219 // message to nil stret
2220 // message to nil fpret
2221 // message to nil fpret long double
2222 // Use NIL_RECEIVER to avoid compiler optimizations.
2223 testprintf("message to nil\n");
2227 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];
2228 testassert(state == 0);
2229 testassert(idval == nil);
2233 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];
2234 testassert(state == 0);
2235 testassert(llval == 0LL);
2239 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];
2240 testassert(state == 0);
2241 testassert(0 == memcmp(&stretval, &zero, sizeof(stretval)));
2244 // check stret return register
2247 stretptr = ((struct stret *(*)(struct stret *, id, SEL))objc_msgSend_stret)
2248 (&stretval, nil, @selector(stret_nop));
2249 testassert(stretptr == &stretval);
2250 testassert(state == 0);
2251 // no stret result guarantee for hand-written calls
2255 // check struct-return address stack pop
2256 for (int i = 0; i < 10000000; i++) {
2258 ((struct stret (*)(id, SEL))objc_msgSend_stret)
2259 (nil, @selector(stret_nop));
2265 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];
2266 testassert(state == 0);
2267 testassert(fpval == 0.0);
2270 lfpval = LFP_RESULT;
2271 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];
2272 testassert(state == 0);
2273 testassert(lfpval == 0.0);
2276 vecval = VEC_RESULT;
2277 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];
2278 testassert(state == 0);
2279 testassert(vector_all(vecval == 0));
2281 // message to nil, different struct types
2282 // This verifies that ordinary objc_msgSend() erases enough registers
2283 // for structs that return in registers.
2284 #define TEST_NIL_STRUCT(i,n) \
2286 struct stret_##i##n z; \
2287 bzero(&z, sizeof(z)); \
2288 [Super stret_i##n##_nonzero]; \
2289 [Super stret_d##n##_nonzero]; \
2290 struct stret_##i##n val = [(id)NIL_RECEIVER stret_##i##n##_zero]; \
2291 testassert(0 == memcmp(&z, &val, sizeof(val))); \
2294 TEST_NIL_STRUCT(i,1);
2295 TEST_NIL_STRUCT(i,2);
2296 TEST_NIL_STRUCT(i,3);
2297 TEST_NIL_STRUCT(i,4);
2298 TEST_NIL_STRUCT(i,5);
2299 TEST_NIL_STRUCT(i,6);
2300 TEST_NIL_STRUCT(i,7);
2301 TEST_NIL_STRUCT(i,8);
2302 TEST_NIL_STRUCT(i,9);
2305 testwarn("rdar://16267205 i386 struct{float} and struct{double}");
2307 TEST_NIL_STRUCT(d,1);
2309 TEST_NIL_STRUCT(d,2);
2310 TEST_NIL_STRUCT(d,3);
2311 TEST_NIL_STRUCT(d,4);
2312 TEST_NIL_STRUCT(d,5);
2313 TEST_NIL_STRUCT(d,6);
2314 TEST_NIL_STRUCT(d,7);
2315 TEST_NIL_STRUCT(d,8);
2316 TEST_NIL_STRUCT(d,9);
2319 // message to nil noarg
2320 // explicitly call noarg messenger, even if compiler doesn't emit it
2323 idval = ((typeof(idmsg0))objc_msgSend_noarg)(nil, @selector(idret_noarg));
2324 testassert(state == 0);
2325 testassert(idval == nil);
2329 llval = ((typeof(llmsg0))objc_msgSend_noarg)(nil, @selector(llret_noarg));
2330 testassert(state == 0);
2331 testassert(llval == 0LL);
2333 // no stret_noarg messenger
2338 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(nil, @selector(fpret_noarg));
2339 testassert(state == 0);
2340 testassert(fpval == 0.0);
2343 vecval = VEC_RESULT;
2344 vecval = ((typeof(vecmsg0))objc_msgSend_noarg)(nil, @selector(vecret_noarg));
2345 testassert(state == 0);
2346 testassert(vector_all(vecval == 0));
2348 #if !__i386__ && !__x86_64__
2350 lfpval = LFP_RESULT;
2351 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(nil, @selector(lfpret_noarg));
2352 testassert(state == 0);
2353 testassert(lfpval == 0.0);
2357 // rdar://8271364 objc_msgSendSuper2 must not change objc_super
2358 testprintf("super struct\n");
2359 struct objc_super sup_st = {
2361 object_getClass(sub),
2368 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);
2369 testassert(state == 1);
2370 testassert(idval == ID_RESULT);
2371 testassert(sup_st.receiver == sub);
2372 testassert(sup_st.super_class == object_getClass(sub));
2376 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);
2377 testassert(state == 3);
2378 testassert(stret_equal(stretval, STRET_RESULT));
2379 testassert(sup_st.receiver == sub);
2380 testassert(sup_st.super_class == object_getClass(sub));
2383 // Debug messengers.
2384 testprintf("debug messengers\n");
2387 idmsg = (typeof(idmsg))objc_msgSend_debug;
2389 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);
2390 testassert(state == 101);
2391 testassert(idval == ID_RESULT);
2394 llmsg = (typeof(llmsg))objc_msgSend_debug;
2396 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);
2397 testassert(state == 102);
2398 testassert(llval == LL_RESULT);
2401 stretmsg = (typeof(stretmsg))objc_msgSend_stret_debug;
2403 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);
2404 testassert(state == 103);
2405 testassert(stret_equal(stretval, STRET_RESULT));
2408 sup_st.receiver = sub;
2409 sup_st.super_class = object_getClass(sub);
2410 idmsgsuper = (typeof(idmsgsuper))objc_msgSendSuper2_debug;
2412 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);
2413 testassert(state == 1);
2414 testassert(idval == ID_RESULT);
2417 sup_st.receiver = sub;
2418 sup_st.super_class = object_getClass(sub);
2419 stretmsgsuper = (typeof(stretmsgsuper))objc_msgSendSuper2_stret_debug;
2421 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);
2422 testassert(state == 3);
2423 testassert(stret_equal(stretval, STRET_RESULT));
2427 fpmsg = (typeof(fpmsg))objc_msgSend_fpret_debug;
2429 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);
2430 testassert(state == 104);
2431 testassert(fpval == FP_RESULT);
2435 lfpmsg = (typeof(lfpmsg))objc_msgSend_fpret_debug;
2437 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);
2438 testassert(state == 105);
2439 testassert(lfpval == LFP_RESULT);
2451 // fixme objc_msgLookup test hack stopped working after a compiler update
2453 #elif __has_feature(objc_arc)
2454 // ARC interferes with objc_msgLookup test hacks
2456 #elif __i386__ && TARGET_OS_SIMULATOR
2457 testwarn("fixme msgLookup hack doesn't work");
2460 // fixme hack: call the looked-up method
2462 # define CALL_LOOKUP(ret) \
2463 asm volatile ("blr x17 \n mov %x0, x0" : "=r" (ret))
2464 # define CALL_LOOKUP_STRET(ret) \
2465 asm volatile ("mov x8, %x1 \n blr x17 \n" : "=m" (ret) : "r" (&ret))
2468 # define CALL_LOOKUP(ret) \
2469 asm volatile ("blx r12 \n mov %0, r0" : "=r" (ret))
2470 # define CALL_LOOKUP_STRET(ret) \
2471 asm volatile ("mov r0, %1 \n blx r12 \n" : "=m" (ret) : "r" (&ret))
2474 # define CALL_LOOKUP(ret) \
2475 asm volatile ("call *%%r11 \n mov %%rax, %0" : "=r" (ret))
2476 # define CALL_LOOKUP_STRET(ret) \
2477 asm volatile ("mov %1, %%rdi \n call *%%r11 \n" : "=m" (ret) : "r" (&ret))
2480 # define CALL_LOOKUP(ret) \
2481 asm volatile ("call *%%eax \n mov %%eax, %0" : "=r" (ret))
2482 # define CALL_LOOKUP_STRET(ret) \
2483 asm volatile ("add $4, %%esp \n mov %1, (%%esp) \n call *%%eax \n sub $4, %%esp \n" : "=m" (ret) : "d" (&ret))
2486 # error unknown architecture
2489 // msgLookup uncached
2490 // msgLookup uncached super
2491 // msgLookup uncached stret
2492 // msgLookup uncached super stret
2493 // msgLookup uncached fpret
2494 // msgLookup uncached fpret long double
2496 // msgLookup cached stret
2497 // msgLookup cached super
2498 // msgLookup cached super stret
2499 // msgLookup cached fpret
2500 // msgLookup cached fpret long double
2501 // fixme verify that uncached lookup didn't happen the 2nd time?
2503 _objc_flush_caches(object_getClass(sub));
2504 for (int i = 0; i < 5; i++) {
2505 testprintf("objc_msgLookup\n");
2507 idmsg = (typeof(idmsg))objc_msgLookup;
2509 (*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);
2511 testassert(state == 101);
2512 testassert(idval == ID_RESULT);
2514 testprintf("objc_msgLookup_stret\n");
2516 stretmsg = (typeof(stretmsg))objc_msgLookup_stret;
2518 (*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);
2519 CALL_LOOKUP_STRET(stretval);
2520 testassert(state == 103);
2521 testassert(stret_equal(stretval, STRET_RESULT));
2523 testprintf("objc_msgLookupSuper2\n");
2525 sup_st.receiver = sub;
2526 sup_st.super_class = object_getClass(sub);
2527 idmsgsuper = (typeof(idmsgsuper))objc_msgLookupSuper2;
2529 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);
2531 testassert(state == 1);
2532 testassert(idval == ID_RESULT);
2534 testprintf("objc_msgLookupSuper2_stret\n");
2536 sup_st.receiver = sub;
2537 sup_st.super_class = object_getClass(sub);
2538 stretmsgsuper = (typeof(stretmsgsuper))objc_msgLookupSuper2_stret;
2540 (*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);
2541 CALL_LOOKUP_STRET(stretval);
2542 testassert(state == 3);
2543 testassert(stret_equal(stretval, STRET_RESULT));
2546 // fixme fpret, can't test FP stack properly
2549 // fixme fpret, can't test FP stack properly
2550 // fixme fp2ret, can't test FP stack properly
2556 // msgLookup to nil stret
2557 // fixme msgLookup to nil long long
2558 // fixme msgLookup to nil fpret
2559 // fixme msgLookup to nil fp2ret
2561 testprintf("objc_msgLookup to nil\n");
2563 idmsg = (typeof(idmsg))objc_msgLookup;
2565 (*idmsg)(NIL_RECEIVER, @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);
2567 testassert(state == 0);
2568 testassert(idval == nil);
2570 testprintf("objc_msgLookup_stret to nil\n");
2572 stretmsg = (typeof(stretmsg))objc_msgLookup_stret;
2574 (*stretmsg)(NIL_RECEIVER, @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);
2575 CALL_LOOKUP_STRET(stretval);
2576 testassert(state == 0);
2577 // no stret result guarantee
2580 // fixme fpret, can't test FP stack properly
2583 // fixme fpret, can't test FP stack properly
2584 // fixme fp2ret, can't test FP stack properly
2593 testwarn("no unwind tables in this configuration " NO_DWARF_REASON);
2595 // DWARF unwind tables
2596 testprintf("unwind tables\n");
2598 // Clear simulator-related environment variables.
2599 // Disassembly will run llvm-objdump which is not a simulator executable.
2600 unsetenv("DYLD_ROOT_PATH");
2601 unsetenv("DYLD_FALLBACK_LIBRARY_PATH");
2602 unsetenv("DYLD_FALLBACK_FRAMEWORK_PATH");
2604 // Check mprotect() of objc_msgSend.
2605 // It doesn't work when running on a device with no libobjc root.
2606 // In that case we skip this part of the test without failing.
2607 // fixme make this work
2608 // fixme now it doesn't work even with a libobjc root in place?
2609 int err1 = mprotect((void *)((uintptr_t)&objc_msgSend & ~(PAGE_MAX_SIZE-1)),
2610 PAGE_MAX_SIZE, PROT_READ | PROT_WRITE);
2612 int err2 = mprotect((void *)((uintptr_t)&objc_msgSend & ~(PAGE_MAX_SIZE-1)),
2613 PAGE_MAX_SIZE, PROT_READ | PROT_EXEC);
2616 testwarn("can't mprotect() objc_msgSend (%d, %d). "
2617 "Skipping unwind table test.",
2618 err1, errno1, err2, errno2);
2621 // install exception handler
2622 struct sigaction act;
2623 act.sa_sigaction = break_handler;
2625 act.sa_flags = SA_SIGINFO;
2626 sigaction(BREAK_SIGNAL, &act, nil);
2627 #if defined(BREAK_SIGNAL2)
2628 sigaction(BREAK_SIGNAL2, &act, nil);
2631 SubDW *dw = [[SubDW alloc] init];
2633 objc_setForwardHandler((void*)test_dw_forward, (void*)test_dw_forward_stret);
2636 test_dw("objc_msgSend", dw, tagged, exttagged, false, 0);
2637 test_dw("objc_msgSend_stret", dw, tagged, exttagged, true, 0);
2638 test_dw("objc_msgSend_fpret", dw, tagged, exttagged, false, 0);
2639 test_dw("objc_msgSend_fp2ret", dw, tagged, exttagged, false, 0);
2640 test_dw("objc_msgSendSuper", dw, tagged, exttagged, false, 0);
2641 test_dw("objc_msgSendSuper2", dw, tagged, exttagged, false, 0);
2642 test_dw("objc_msgSendSuper_stret", dw, tagged, exttagged, true, 0);
2643 test_dw("objc_msgSendSuper2_stret", dw, tagged, exttagged, true, 0);
2645 test_dw("objc_msgSend", dw, dw, dw, false, 0);
2646 test_dw("objc_msgSend_stret", dw, dw, dw, true, 0);
2647 test_dw("objc_msgSend_fpret", dw, dw, dw, false, 0);
2648 test_dw("objc_msgSendSuper", dw, dw, dw, false, 0);
2649 test_dw("objc_msgSendSuper2", dw, dw, dw, false, 0);
2650 test_dw("objc_msgSendSuper_stret", dw, dw, dw, true, 0);
2651 test_dw("objc_msgSendSuper2_stret", dw, dw, dw, true, 0);
2653 test_dw("objc_msgSend", dw, tagged, exttagged, false, 1);
2654 test_dw("objc_msgSendSuper", dw, tagged, exttagged, false, 1);
2655 test_dw("objc_msgSendSuper2", dw, tagged, exttagged, false, 1);
2657 test_dw("objc_msgSend", dw, dw, dw, false, 0);
2658 test_dw("objc_msgSend_stret", dw, dw, dw, true, 0);
2659 test_dw("objc_msgSendSuper", dw, dw, dw, false, 0);
2660 test_dw("objc_msgSendSuper2", dw, dw, dw, false, 0);
2661 test_dw("objc_msgSendSuper_stret", dw, dw, dw, true, 0);
2662 test_dw("objc_msgSendSuper2_stret", dw, dw, dw, true, 0);
2664 # error unknown architecture
2668 // end DWARF unwind test