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
13 #include <libkern/OSCacheControl.h>
15 #include <objc/objc.h>
16 #include <objc/runtime.h>
17 #include <objc/objc-internal.h>
18 #include <objc/objc-abi.h>
19 #include <simd/simd.h>
20 #include <mach-o/loader.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 objc_msgLookup_stret objc_msgLookup
35 # define objc_msgLookupSuper2_stret objc_msgLookupSuper2
36 # define method_invoke_stret method_invoke
38 # define SUPPORT_STRET 1
46 # define ALIGN_() asm(".align 4");
49 @interface Super : TestRoot @end
51 @interface Sub : Super @end
57 // for typeof() shorthand only
58 id (*idmsg0)(id, SEL) __attribute__((unused));
59 long long (*llmsg0)(id, SEL) __attribute__((unused));
60 // struct stret (*stretmsg0)(id, SEL) __attribute__((unused));
61 double (*fpmsg0)(id, SEL) __attribute__((unused));
62 long double (*lfpmsg0)(id, SEL) __attribute__((unused));
63 vector_ulong2 (*vecmsg0)(id, SEL) __attribute__((unused));
65 #define VEC1 ((vector_ulong2){1, 1})
66 #define VEC2 ((vector_ulong2){2, 2})
67 #define VEC3 ((vector_ulong2){3, 3})
68 #define VEC4 ((vector_ulong2){4, 4})
69 #define VEC5 ((vector_ulong2){5, 5})
70 #define VEC6 ((vector_ulong2){6, 6})
71 #define VEC7 ((vector_ulong2){7, 7})
72 #define VEC8 ((vector_ulong2){8, 8})
74 #define CHECK_ARGS(sel) \
76 testassert(self == SELF); \
77 testassert(_cmd == sel_registerName(#sel "::::::::::::::::::::::::::::::::::::"));\
78 testassert(i1 == 1); \
79 testassert(i2 == 2); \
80 testassert(i3 == 3); \
81 testassert(i4 == 4); \
82 testassert(i5 == 5); \
83 testassert(i6 == 6); \
84 testassert(i7 == 7); \
85 testassert(i8 == 8); \
86 testassert(i9 == 9); \
87 testassert(i10 == 10); \
88 testassert(i11 == 11); \
89 testassert(i12 == 12); \
90 testassert(i13 == 13); \
91 testassert(f1 == 1.0); \
92 testassert(f2 == 2.0); \
93 testassert(f3 == 3.0); \
94 testassert(f4 == 4.0); \
95 testassert(f5 == 5.0); \
96 testassert(f6 == 6.0); \
97 testassert(f7 == 7.0); \
98 testassert(f8 == 8.0); \
99 testassert(f9 == 9.0); \
100 testassert(f10 == 10.0); \
101 testassert(f11 == 11.0); \
102 testassert(f12 == 12.0); \
103 testassert(f13 == 13.0); \
104 testassert(f14 == 14.0); \
105 testassert(f15 == 15.0); \
106 testassert(vector_all(v1 == 1)); \
107 testassert(vector_all(v2 == 2)); \
108 testassert(vector_all(v3 == 3)); \
109 testassert(vector_all(v4 == 4)); \
110 testassert(vector_all(v5 == 5)); \
111 testassert(vector_all(v6 == 6)); \
112 testassert(vector_all(v7 == 7)); \
113 testassert(vector_all(v8 == 8)); \
116 #define CHECK_ARGS_NOARG(sel) \
118 testassert(self == SELF); \
119 testassert(_cmd == sel_registerName(#sel "_noarg"));\
124 long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
125 double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
126 long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
127 vector_ulong2 VEC_RESULT = { 0x1234567890abcdefULL, 0xfedcba0987654321ULL };
128 // STRET_RESULT in test.h
130 static struct stret zero;
257 @interface Super (Prototypes)
259 // Method prototypes to pacify -Wundeclared-selector.
262 (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 (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;
267 -(struct stret)stret:
268 (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 (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;
273 -(long double)lfpret:
274 (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;
276 -(vector_ulong2)vecret:
277 (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;
282 // Zero all volatile registers.
301 "\n xorps %xmm0, %xmm0"
302 "\n xorps %xmm1, %xmm1"
303 "\n xorps %xmm2, %xmm2"
304 "\n xorps %xmm3, %xmm3"
305 "\n xorps %xmm4, %xmm4"
306 "\n xorps %xmm5, %xmm5"
307 "\n xorps %xmm6, %xmm6"
308 "\n xorps %xmm7, %xmm7"
309 "\n xorps %xmm8, %xmm8"
310 "\n xorps %xmm9, %xmm9"
311 "\n xorps %xmm10, %xmm10"
312 "\n xorps %xmm11, %xmm11"
313 "\n xorps %xmm12, %xmm12"
314 "\n xorps %xmm13, %xmm13"
315 "\n xorps %xmm14, %xmm14"
316 "\n xorps %xmm15, %xmm15"
326 "\n xorps %xmm0, %xmm0"
327 "\n xorps %xmm1, %xmm1"
328 "\n xorps %xmm2, %xmm2"
329 "\n xorps %xmm3, %xmm3"
330 "\n xorps %xmm4, %xmm4"
331 "\n xorps %xmm5, %xmm5"
332 "\n xorps %xmm6, %xmm6"
333 "\n xorps %xmm7, %xmm7"
372 "\n .thumb_func _stomp"
386 "\n vmov.i32 q10, #0"
387 "\n vmov.i32 q11, #0"
388 "\n vmov.i32 q12, #0"
389 "\n vmov.i32 q13, #0"
390 "\n vmov.i32 q14, #0"
391 "\n vmov.i32 q15, #0"
396 # error unknown architecture
400 @implementation Super
401 -(struct stret)stret { return STRET_RESULT; }
403 // The IMPL_ methods are not called directly. Instead the non IMPL_ name is
404 // called. The resolver function installs the real method. This allows
405 // the resolver function to stomp on registers to help test register
406 // preservation in the uncached path.
408 +(BOOL) resolveInstanceMethod:(SEL)sel
410 const char *name = sel_getName(sel);
411 if (! strstr(name, "::::::::")) return false;
413 testprintf("resolving %s\n", name);
417 asprintf(&realName, "IMPL_%s", name);
418 SEL realSel = sel_registerName(realName);
421 IMP imp = class_getMethodImplementation(self, realSel);
422 if (imp == &_objc_msgForward) return false;
423 return class_addMethod(self, sel, imp, "");
427 (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
434 -(long long)IMPL_llret:
435 (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
442 -(struct stret)IMPL_stret:
443 (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
451 (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
458 -(long double)IMPL_lfpret:
459 (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
466 -(vector_ulong2)IMPL_vecret:
467 (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
477 CHECK_ARGS_NOARG(idret);
482 -(long long)llret_noarg
484 CHECK_ARGS_NOARG(llret);
489 -(struct stret)stret_noarg
491 CHECK_ARGS_NOARG(stret);
498 CHECK_ARGS_NOARG(fpret);
503 -(long double)lfpret_noarg
505 CHECK_ARGS_NOARG(lfpret);
510 -(vector_ulong2)vecret_noarg
512 CHECK_ARGS_NOARG(vecret);
518 -(struct stret)stret_nop
524 #define STRET_IMP(n) \
525 +(struct stret_##n)stret_##n##_zero \
527 struct stret_##n ret; \
528 bzero(&ret, sizeof(ret)); \
531 +(struct stret_##n)stret_##n##_nonzero \
533 struct stret_##n ret; \
534 memset(&ret, 0xff, sizeof(ret)); \
560 (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
562 fail("+idret called instead of -idret");
567 (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
569 fail("+llret called instead of -llret");
573 +(struct stret)stret:
574 (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
576 fail("+stret called instead of -stret");
581 (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
583 fail("+fpret called instead of -fpret");
587 +(long double)lfpret:
588 (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
590 fail("+lfpret called instead of -lfpret");
596 fail("+idret_noarg called instead of -idret_noarg");
597 CHECK_ARGS_NOARG(idret);
600 +(long long)llret_noarg
602 fail("+llret_noarg called instead of -llret_noarg");
603 CHECK_ARGS_NOARG(llret);
606 +(struct stret)stret_noarg
608 fail("+stret_noarg called instead of -stret_noarg");
609 CHECK_ARGS_NOARG(stret);
614 fail("+fpret_noarg called instead of -fpret_noarg");
615 CHECK_ARGS_NOARG(fpret);
618 +(long double)lfpret_noarg
620 fail("+lfpret_noarg called instead of -lfpret_noarg");
621 CHECK_ARGS_NOARG(lfpret);
624 +(vector_ulong2)vecret_noarg
626 fail("+vecret_noarg called instead of -vecret_noarg");
627 CHECK_ARGS_NOARG(vecret);
636 (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
641 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];
642 testassert(state == 1);
643 testassert(result == ID_RESULT);
648 -(long long)IMPL_llret:
649 (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
654 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];
655 testassert(state == 2);
656 testassert(result == LL_RESULT);
661 -(struct stret)IMPL_stret:
662 (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
667 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];
668 testassert(state == 3);
669 testassert(stret_equal(result, STRET_RESULT));
675 (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
680 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];
681 testassert(state == 4);
682 testassert(result == FP_RESULT);
687 -(long double)IMPL_lfpret:
688 (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
693 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];
694 testassert(state == 5);
695 testassert(result == LFP_RESULT);
700 -(vector_ulong2)IMPL_vecret:
701 (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 vector_ulong2 result;
706 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];
707 testassert(state == 6);
708 testassert(vector_equal(result, VEC_RESULT));
717 CHECK_ARGS_NOARG(idret);
719 result = [super idret_noarg];
720 testassert(state == 11);
721 testassert(result == ID_RESULT);
726 -(long long)llret_noarg
729 CHECK_ARGS_NOARG(llret);
731 result = [super llret_noarg];
732 testassert(state == 12);
733 testassert(result == LL_RESULT);
738 -(struct stret)stret_noarg
741 CHECK_ARGS_NOARG(stret);
743 result = [super stret_noarg];
744 testassert(state == 13);
745 testassert(stret_equal(result, STRET_RESULT));
753 CHECK_ARGS_NOARG(fpret);
755 result = [super fpret_noarg];
756 testassert(state == 14);
757 testassert(result == FP_RESULT);
762 -(long double)lfpret_noarg
765 CHECK_ARGS_NOARG(lfpret);
767 result = [super lfpret_noarg];
768 testassert(state == 15);
769 testassert(result == LFP_RESULT);
774 -(vector_ulong2)vecret_noarg
776 vector_ulong2 result;
777 CHECK_ARGS_NOARG(vecret);
779 result = [super vecret_noarg];
780 testassert(state == 16);
781 testassert(vector_equal(result, VEC_RESULT));
789 #if OBJC_HAVE_TAGGED_POINTERS
791 @interface TaggedSub : Sub @end
793 @implementation TaggedSub : Sub
797 _objc_registerTaggedPointerClass(OBJC_TAG_1, self);
802 @interface ExtTaggedSub : Sub @end
804 @implementation ExtTaggedSub : Sub
808 _objc_registerTaggedPointerClass(OBJC_TAG_First52BitPayload, self);
816 // DWARF checking machinery
819 // unimplemented on this platform
820 #define NO_DWARF_REASON "(windows)"
822 #elif TARGET_OS_WATCH
823 // fixme unimplemented - ucontext not passed to signal handlers
824 #define NO_DWARF_REASON "(watchOS)"
826 #elif __has_feature(objc_arc)
827 // ARC's extra RR calls hit the traps at the wrong times
828 #define NO_DWARF_REASON "(ARC)"
834 // Classes with no implementations and no cache contents from elsewhere.
835 @interface SuperDW : TestRoot @end
836 @implementation SuperDW @end
838 @interface Sub0DW : SuperDW @end
839 @implementation Sub0DW @end
841 @interface SubDW : Sub0DW @end
842 @implementation SubDW @end
846 #include <sys/mman.h>
847 #include <libunwind.h>
853 extern void callit(void *obj, void *sel, void *fn);
854 extern struct stret callit_stret(void *obj, void *sel, void *fn);
859 typedef uint8_t insn_t;
860 typedef insn_t clobbered_insn_t;
861 #define BREAK_INSN ((insn_t)0x06) // undefined
862 #define BREAK_SIGNAL SIGILL
873 void handle_exception(x86_thread_state64_t *state)
880 err = unw_init_local(&curs, (unw_context_t *)state);
883 step = unw_step(&curs);
884 testassert(step > 0);
886 err = unw_get_reg(&curs, UNW_X86_64_R12, ®);
888 testassert(reg == r12);
890 err = unw_get_reg(&curs, UNW_X86_64_R13, ®);
892 testassert(reg == r13);
894 err = unw_get_reg(&curs, UNW_X86_64_R14, ®);
896 testassert(reg == r14);
898 err = unw_get_reg(&curs, UNW_X86_64_R15, ®);
900 testassert(reg == r15);
902 err = unw_get_reg(&curs, UNW_X86_64_RBX, ®);
904 testassert(reg == rbx);
906 err = unw_get_reg(&curs, UNW_X86_64_RBP, ®);
908 testassert(reg == rbp);
910 err = unw_get_reg(&curs, UNW_X86_64_RSP, ®);
912 testassert(reg == rsp);
914 err = unw_get_reg(&curs, UNW_REG_IP, ®);
916 testassert(reg == rip);
919 // set thread state to unwound state
933 void break_handler(int sig, siginfo_t *info, void *cc)
935 ucontext_t *uc = (ucontext_t *)cc;
936 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
938 testprintf(" handled\n");
940 testassert(sig == BREAK_SIGNAL);
941 testassert((uintptr_t)info->si_addr == clobbered);
943 handle_exception(&mc->__ss);
944 // handle_exception changed register state for continuation
951 // save sp and return address to variables
952 "\n movq (%rsp), %r10"
953 "\n movq %r10, _rip(%rip)"
954 "\n movq %rsp, _rsp(%rip)"
955 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
956 // save other non-volatile registers to variables
957 "\n movq %rbx, _rbx(%rip)"
958 "\n movq %rbp, _rbp(%rip)"
959 "\n movq %r12, _r12(%rip)"
960 "\n movq %r13, _r13(%rip)"
961 "\n movq %r14, _r14(%rip)"
962 "\n movq %r15, _r15(%rip)"
968 "\n .globl _callit_stret"
970 // save sp and return address to variables
971 "\n movq (%rsp), %r10"
972 "\n movq %r10, _rip(%rip)"
973 "\n movq %rsp, _rsp(%rip)"
974 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
975 // save other non-volatile registers to variables
976 "\n movq %rbx, _rbx(%rip)"
977 "\n movq %rbp, _rbp(%rip)"
978 "\n movq %r12, _r12(%rip)"
979 "\n movq %r13, _r13(%rip)"
980 "\n movq %r14, _r14(%rip)"
981 "\n movq %r15, _r15(%rip)"
990 typedef uint8_t insn_t;
991 typedef insn_t clobbered_insn_t;
992 #define BREAK_INSN ((insn_t)0xcc) // int3
993 #define BREAK_SIGNAL SIGTRAP
1001 uintptr_t espfix = 0;
1003 void handle_exception(i386_thread_state_t *state)
1010 err = unw_init_local(&curs, (unw_context_t *)state);
1013 step = unw_step(&curs);
1014 testassert(step > 0);
1016 err = unw_get_reg(&curs, UNW_REG_IP, ®);
1018 testassert(reg == eip);
1020 err = unw_get_reg(&curs, UNW_X86_ESP, ®);
1022 testassert(reg == esp);
1024 err = unw_get_reg(&curs, UNW_X86_EBX, ®);
1026 testassert(reg == ebx);
1028 err = unw_get_reg(&curs, UNW_X86_EBP, ®);
1030 testassert(reg == ebp);
1032 err = unw_get_reg(&curs, UNW_X86_EDI, ®);
1034 testassert(reg == edi);
1036 err = unw_get_reg(&curs, UNW_X86_ESI, ®);
1038 testassert(reg == esi);
1041 // set thread state to unwound state
1043 state->__esp = esp + espfix;
1053 void break_handler(int sig, siginfo_t *info, void *cc)
1055 ucontext_t *uc = (ucontext_t *)cc;
1056 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
1058 testprintf(" handled\n");
1060 testassert(sig == BREAK_SIGNAL);
1061 testassert((uintptr_t)info->si_addr-1 == clobbered);
1063 handle_exception(&mc->__ss);
1064 // handle_exception changed register state for continuation
1071 // save sp and return address to variables
1074 "\n movl (%esp), %eax"
1075 "\n movl %eax, _eip-1b(%edx)"
1076 "\n movl %esp, _esp-1b(%edx)"
1077 "\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
1078 "\n movl $0, _espfix-1b(%edx)"
1079 // save other non-volatile registers to variables
1080 "\n movl %ebx, _ebx-1b(%edx)"
1081 "\n movl %ebp, _ebp-1b(%edx)"
1082 "\n movl %edi, _edi-1b(%edx)"
1083 "\n movl %esi, _esi-1b(%edx)"
1089 "\n .globl _callit_stret"
1091 // save sp and return address to variables
1094 "\n movl (%esp), %eax"
1095 "\n movl %eax, _eip-1b(%edx)"
1096 "\n movl %esp, _esp-1b(%edx)"
1097 "\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
1098 "\n movl $4, _espfix-1b(%edx)"
1099 // save other non-volatile registers to variables
1100 "\n movl %ebx, _ebx-1b(%edx)"
1101 "\n movl %ebp, _ebp-1b(%edx)"
1102 "\n movl %edi, _edi-1b(%edx)"
1103 "\n movl %esi, _esi-1b(%edx)"
1111 #include <sys/ucontext.h>
1113 typedef uint32_t insn_t;
1114 typedef insn_t clobbered_insn_t;
1115 #define BREAK_INSN ((insn_t)0xd4200020) // brk #1
1116 #define BREAK_SIGNAL SIGTRAP
1132 void handle_exception(arm_thread_state64_t *state)
1139 // libunwind layout differs from mcontext layout
1140 // GPRs are the same but vector registers are not
1141 unw_context_t unwstate;
1142 unw_getcontext(&unwstate);
1143 memcpy(&unwstate, state, sizeof(*state));
1145 // libunwind and xnu sign some pointers differently
1146 // xnu: not signed (fixme this may change?)
1147 // libunwind: PC and LR both signed with return address key and SP
1148 void **pcp = &((arm_thread_state64_t *)&unwstate)->__opaque_pc;
1149 *pcp = ptrauth_sign_unauthenticated((void*)__darwin_arm_thread_state64_get_pc(*state),
1150 ptrauth_key_return_address,
1151 (ptrauth_extra_data_t)__darwin_arm_thread_state64_get_sp(*state));
1152 void **lrp = &((arm_thread_state64_t *)&unwstate)->__opaque_lr;
1153 *lrp = ptrauth_sign_unauthenticated((void*)__darwin_arm_thread_state64_get_lr(*state),
1154 ptrauth_key_return_address,
1155 (ptrauth_extra_data_t)__darwin_arm_thread_state64_get_sp(*state));
1157 err = unw_init_local(&curs, &unwstate);
1160 step = unw_step(&curs);
1161 testassert(step > 0);
1163 err = unw_get_reg(&curs, UNW_ARM64_X19, ®);
1165 testassert(reg == x19);
1167 err = unw_get_reg(&curs, UNW_ARM64_X20, ®);
1169 testassert(reg == x20);
1171 err = unw_get_reg(&curs, UNW_ARM64_X21, ®);
1173 testassert(reg == x21);
1175 err = unw_get_reg(&curs, UNW_ARM64_X22, ®);
1177 testassert(reg == x22);
1179 err = unw_get_reg(&curs, UNW_ARM64_X23, ®);
1181 testassert(reg == x23);
1183 err = unw_get_reg(&curs, UNW_ARM64_X24, ®);
1185 testassert(reg == x24);
1187 err = unw_get_reg(&curs, UNW_ARM64_X25, ®);
1189 testassert(reg == x25);
1191 err = unw_get_reg(&curs, UNW_ARM64_X26, ®);
1193 testassert(reg == x26);
1195 err = unw_get_reg(&curs, UNW_ARM64_X27, ®);
1197 testassert(reg == x27);
1199 err = unw_get_reg(&curs, UNW_ARM64_X28, ®);
1201 testassert(reg == x28);
1203 err = unw_get_reg(&curs, UNW_ARM64_FP, ®);
1205 testassert(reg == fp);
1207 err = unw_get_reg(&curs, UNW_ARM64_SP, ®);
1209 testassert(reg == sp);
1211 err = unw_get_reg(&curs, UNW_REG_IP, ®);
1213 // libunwind's return is signed but our value is not
1214 reg = (uintptr_t)ptrauth_strip((void *)reg, ptrauth_key_return_address);
1215 testassert(reg == pc);
1217 // libunwind restores PC into LR and doesn't track LR
1218 // err = unw_get_reg(&curs, UNW_ARM64_LR, ®);
1219 // testassert(!err);
1220 // testassert(reg == lr);
1222 // set signal handler's thread state to unwound state
1223 state->__x[19] = x19;
1224 state->__x[20] = x20;
1225 state->__x[21] = x21;
1226 state->__x[22] = x22;
1227 state->__x[23] = x23;
1228 state->__x[24] = x24;
1229 state->__x[25] = x25;
1230 state->__x[26] = x26;
1231 state->__x[27] = x27;
1232 state->__x[28] = x28;
1233 state->__opaque_fp = (void *)fp;
1234 state->__opaque_lr = (void *)pc; // libunwind restores PC into LR
1235 state->__opaque_sp = (void *)sp;
1236 state->__opaque_pc = (void *)pc;
1242 void break_handler(int sig, siginfo_t *info, void *cc)
1244 ucontext_t *uc = (ucontext_t *)cc;
1245 struct __darwin_mcontext64 *mc = (struct __darwin_mcontext64 *)uc->uc_mcontext;
1247 testprintf(" handled\n");
1249 testassert(sig == BREAK_SIGNAL);
1250 testassert((uintptr_t)info->si_addr == clobbered);
1252 handle_exception(&mc->__ss);
1253 // handle_exception changed register state for continuation
1261 // save sp and return address to variables
1263 "\n adrp x17, _sp@PAGE"
1264 "\n str x16, [x17, _sp@PAGEOFF]"
1265 "\n adrp x17, _pc@PAGE"
1266 "\n str lr, [x17, _pc@PAGEOFF]"
1267 // save other non-volatile registers to variables
1268 "\n adrp x17, _x19@PAGE"
1269 "\n str x19, [x17, _x19@PAGEOFF]"
1270 "\n adrp x17, _x19@PAGE"
1271 "\n str x20, [x17, _x20@PAGEOFF]"
1272 "\n adrp x17, _x19@PAGE"
1273 "\n str x21, [x17, _x21@PAGEOFF]"
1274 "\n adrp x17, _x19@PAGE"
1275 "\n str x22, [x17, _x22@PAGEOFF]"
1276 "\n adrp x17, _x19@PAGE"
1277 "\n str x23, [x17, _x23@PAGEOFF]"
1278 "\n adrp x17, _x19@PAGE"
1279 "\n str x24, [x17, _x24@PAGEOFF]"
1280 "\n adrp x17, _x19@PAGE"
1281 "\n str x25, [x17, _x25@PAGEOFF]"
1282 "\n adrp x17, _x19@PAGE"
1283 "\n str x26, [x17, _x26@PAGEOFF]"
1284 "\n adrp x17, _x19@PAGE"
1285 "\n str x27, [x17, _x27@PAGEOFF]"
1286 "\n adrp x17, _x19@PAGE"
1287 "\n str x28, [x17, _x28@PAGEOFF]"
1288 "\n adrp x17, _x19@PAGE"
1289 "\n str fp, [x17, _fp@PAGEOFF]"
1297 #include <sys/ucontext.h>
1299 typedef uint16_t insn_t;
1305 #define BREAK_INSN ((insn_t)0xdefe) // trap
1306 #define BREAK_SIGNAL SIGILL
1307 #define BREAK_SIGNAL2 SIGTRAP
1319 void handle_exception(arm_thread_state_t *state)
1321 // No unwind tables on this architecture so no libunwind checks.
1322 // We run the test anyway to verify instruction-level coverage.
1324 // set thread state to unwound state
1330 state->__r[10] = r10;
1331 state->__r[11] = r11;
1334 // clear IT... bits so caller doesn't act on them
1335 state->__cpsr &= ~0x0600fc00;
1341 void break_handler(int sig, siginfo_t *info, void *cc)
1343 ucontext_t *uc = (ucontext_t *)cc;
1344 struct __darwin_mcontext32 *mc = (struct __darwin_mcontext32 *)uc->uc_mcontext;
1346 testprintf(" handled\n");
1348 testassert(sig == BREAK_SIGNAL || sig == BREAK_SIGNAL2);
1349 testassert((uintptr_t)info->si_addr == clobbered);
1351 handle_exception(&mc->__ss);
1352 // handle_exception changed register state for continuation
1358 "\n .syntax unified"
1364 // save sp and return address to variables
1365 "\n movw r12, :lower16:(_sp-1f-4)"
1366 "\n movt r12, :upper16:(_sp-1f-4)"
1369 "\n movw r12, :lower16:(_pc-1f-4)"
1370 "\n movt r12, :upper16:(_pc-1f-4)"
1373 // save other non-volatile registers to variables
1374 "\n movw r12, :lower16:(_r4-1f-4)"
1375 "\n movt r12, :upper16:(_r4-1f-4)"
1378 "\n movw r12, :lower16:(_r5-1f-4)"
1379 "\n movt r12, :upper16:(_r5-1f-4)"
1382 "\n movw r12, :lower16:(_r6-1f-4)"
1383 "\n movt r12, :upper16:(_r6-1f-4)"
1386 "\n movw r12, :lower16:(_r7-1f-4)"
1387 "\n movt r12, :upper16:(_r7-1f-4)"
1390 "\n movw r12, :lower16:(_r8-1f-4)"
1391 "\n movt r12, :upper16:(_r8-1f-4)"
1394 "\n movw r12, :lower16:(_r10-1f-4)"
1395 "\n movt r12, :upper16:(_r10-1f-4)"
1398 "\n movw r12, :lower16:(_r11-1f-4)"
1399 "\n movt r12, :upper16:(_r11-1f-4)"
1407 "\n .syntax unified"
1410 "\n .globl _callit_stret"
1413 // save sp and return address to variables
1414 "\n movw r12, :lower16:(_sp-1f-4)"
1415 "\n movt r12, :upper16:(_sp-1f-4)"
1418 "\n movw r12, :lower16:(_pc-1f-4)"
1419 "\n movt r12, :upper16:(_pc-1f-4)"
1422 // save other non-volatile registers to variables
1423 "\n movw r12, :lower16:(_r4-1f-4)"
1424 "\n movt r12, :upper16:(_r4-1f-4)"
1427 "\n movw r12, :lower16:(_r5-1f-4)"
1428 "\n movt r12, :upper16:(_r5-1f-4)"
1431 "\n movw r12, :lower16:(_r6-1f-4)"
1432 "\n movt r12, :upper16:(_r6-1f-4)"
1435 "\n movw r12, :lower16:(_r7-1f-4)"
1436 "\n movt r12, :upper16:(_r7-1f-4)"
1439 "\n movw r12, :lower16:(_r8-1f-4)"
1440 "\n movt r12, :upper16:(_r8-1f-4)"
1443 "\n movw r12, :lower16:(_r10-1f-4)"
1444 "\n movt r12, :upper16:(_r10-1f-4)"
1447 "\n movw r12, :lower16:(_r11-1f-4)"
1448 "\n movt r12, :upper16:(_r11-1f-4)"
1458 #error unknown architecture
1464 uintptr_t fnaddr(void *fn) { return (uintptr_t)fn & ~(uintptr_t)1; }
1466 uintptr_t fnaddr(void *fn) { return (uintptr_t)fn; }
1469 void flushICache(uintptr_t addr) {
1470 sys_icache_invalidate((void *)addr, sizeof(insn_t));
1473 insn_t set(uintptr_t dst, insn_t newvalue)
1475 uintptr_t start = dst & ~(PAGE_MAX_SIZE-1);
1476 int err = mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_WRITE);
1477 if (err) fail("mprotect(%p, RW-) failed (%d)", start, errno);
1478 insn_t oldvalue = *(insn_t *)dst;
1479 *(insn_t *)dst = newvalue;
1480 err = mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_EXEC);
1481 if (err) fail("mprotect(%p, R-X) failed (%d)", start, errno);
1486 clobbered_insn_t clobber(void *fn, uintptr_t offset)
1488 clobbered = fnaddr(fn) + offset;
1489 insn_t oldInsn = set(fnaddr(fn) + offset, BREAK_INSN);
1491 // Need to clobber 32-bit Thumb instructions with another 32-bit instruction
1492 // to preserve the behavior of IT... blocks.
1493 clobbered_insn_t result = {oldInsn, 0, false};
1494 if (((oldInsn & 0xf000) == 0xf000) ||
1495 ((oldInsn & 0xf800) == 0xe800))
1497 testprintf("clobbering thumb-32 at offset %zu\n", offset);
1498 // Old insn was 32-bit. Clobber all of it.
1500 set(fnaddr(fn) + offset, oldInsn);
1501 // f7f0 a0f0 is a "permanently undefined" Thumb-2 instruction.
1502 // Clobber the first half last so `clobbered` gets the right value.
1503 result.second = set(fnaddr(fn) + offset + 2, 0xa0f0);
1504 result.first = set(fnaddr(fn) + offset, 0xf7f0);
1505 result.thirty_two = true;
1513 void unclobber(void *fn, uintptr_t offset, clobbered_insn_t oldvalue)
1516 if (oldvalue.thirty_two) {
1517 set(fnaddr(fn) + offset + 2, oldvalue.second);
1519 set(fnaddr(fn) + offset, oldvalue.first);
1521 set(fnaddr(fn) + offset, oldvalue);
1526 // terminator for the list of instruction offsets
1527 #define END_OFFSETS ~0UL
1529 // Disassemble instructions symbol..<symbolEnd.
1530 // Write the offset of each non-NOP instruction start to *offsets..<end.
1531 // Return the incremented offsets pointer.
1532 uintptr_t *disassemble(uintptr_t symbol, uintptr_t symbolEnd,
1533 uintptr_t *offsets, uintptr_t *end)
1536 // 1. Copy asm-placeholder.exe into a temporary file.
1537 // 2. Write the instructions into the temp file.
1538 // 3. Run llvm-objdump on the temp file.
1539 // 4. Parse the llvm-objdump output.
1541 // copy asm-placeholder.exe into a new temporary file and open it.
1542 int placeholder = open("asm-placeholder.exe", O_RDONLY);
1543 if (placeholder < 0) {
1544 fail("couldn't open asm-placeholder.exe (%d)", errno);
1547 size_t tempdirlen = confstr(_CS_DARWIN_USER_TEMP_DIR, nil, 0);
1548 char tempsuffix[] = "objc-test-msgSend-asm-XXXXXX";
1549 char *tempname = (char *)malloc(tempdirlen + strlen(tempsuffix));
1550 confstr(_CS_DARWIN_USER_TEMP_DIR, tempname, tempdirlen);
1551 strcat(tempname, tempsuffix);
1553 int fd = mkstemp(tempname);
1555 fail("couldn't create asm temp file %s (%d)", tempname, errno);
1558 if (fstat(placeholder, &st) < 0) {
1559 fail("couldn't stat asm-placeholder.exe (%d)", errno);
1561 ssize_t sz = (ssize_t)st.st_size;
1562 char *buf = (char *)malloc(sz);
1563 if (pread(placeholder, buf, sz, 0) != sz) {
1564 fail("couldn't read asm-placeholder.exe (%d)", errno);
1566 if (pwrite(fd, buf, sz, 0) != sz) {
1567 fail("couldn't write asm temp file %s (%d)", tempname, errno);
1572 // write code into asm-placeholder.exe
1573 // asm-placeholder.exe may have as little as 1024 bytes of space reserved
1574 testassert(symbolEnd - symbol < 1024);
1575 // text section should be 16KB into asm-placeholder.exe
1576 if (pwrite(fd, (void*)symbol, symbolEnd - symbol, 16384) < 0) {
1577 fail("couldn't write code into asm temp file %s (%d)", tempname, errno);
1581 // run `llvm-objdump -disassemble`
1582 const char *objdump;
1583 if (0 == access("/usr/local/bin/llvm-objdump", F_OK)) {
1584 objdump = "/usr/local/bin/llvm-objdump";
1585 } else if (0 == access("/usr/bin/llvm-objdump", F_OK)) {
1586 objdump = "/usr/bin/llvm-objdump";
1588 fail("couldn't find llvm-objdump");
1591 asprintf(&cmd, "%s -disassemble %s", objdump, tempname);
1592 FILE *disa = popen(cmd, "r");
1594 fail("couldn't popen %s", cmd);
1599 // read past "_main:" line
1602 while ((line = fgetln(disa, &len))) {
1603 testprintf("ASM: %.*s", (int)len, line);
1604 if (0 == strncmp(line, "_main:", strlen("_main:"))) break;
1607 // read instructions and save offsets
1611 uintptr_t *p = offsets;
1612 // disassembly format:
1613 // ADDR:\t ...instruction bytes... \tOPCODE ...etc...\n
1614 while (2 == fscanf(disa, "%lx:\t%*[a-fA-F0-9 ]\t%s%*[^\n]\n", &addr, op)) {
1615 if (base == 0) base = addr;
1616 testprintf("ASM: %lx (+%d) ... %s ...\n", addr, addr - base, op);
1617 // allow longer nops like Intel nopw and nopl
1618 if (0 != strncmp(op, "nop", 3)) {
1619 testassert(offsets < end);
1622 // assume nops are unreached (e.g. alignment padding)
1628 // hack: skip last instruction because libunwind blows up if it's
1629 // one byte long and followed by the next function with no NOPs first
1630 if (p > offsets) *p-- = END_OFFSETS;
1637 uintptr_t *getOffsets(const char *symname, uintptr_t *outBase)
1639 // Find the start of our function.
1640 uintptr_t symbol = (uintptr_t)dlsym(RTLD_NEXT, symname);
1641 if (!symbol) return nil;
1642 #if __has_feature(ptrauth_calls)
1643 symbol = (uintptr_t)
1644 ptrauth_strip((void*)symbol, ptrauth_key_function_pointer);
1647 if (outBase) *outBase = symbol;
1649 // Find the end of our function by finding the start
1650 // of the next symbol after our target symbol.
1652 const int insnIncrement =
1656 2; // in case of thumb or thumb-2
1657 #elif __i386__ || __x86_64__
1660 #error unknown architecture
1663 uintptr_t symbolEnd;
1666 for (symbolEnd = symbol + insnIncrement;
1667 ((ok = dladdr((void*)symbolEnd, &dli))) && dli.dli_saddr == (void*)symbol;
1668 symbolEnd += insnIncrement)
1671 testprintf("found %s at %p..<%p %d %p %s\n",
1672 symname, (void*)symbol, (void*)symbolEnd, ok, dli.dli_saddr, dli.dli_sname);
1674 // Record the offset to each non-NOP instruction.
1675 uintptr_t *result = (uintptr_t *)malloc(1000 * sizeof(uintptr_t));
1676 uintptr_t *end = result + 1000;
1677 uintptr_t *p = result;
1679 p = disassemble(symbol, symbolEnd, p, end);
1681 // Also record the offsets in _objc_msgSend_uncached when present
1682 // (which is the slow path and has a frame to unwind)
1683 if (!strstr(symname, "_uncached")) {
1684 const char *uncached_symname = strstr(symname, "stret")
1685 ? "_objc_msgSend_stret_uncached" : "_objc_msgSend_uncached";
1686 uintptr_t uncached_symbol;
1687 uintptr_t *uncached_offsets =
1688 getOffsets(uncached_symname, &uncached_symbol);
1689 if (uncached_offsets) {
1690 uintptr_t *q = uncached_offsets;
1691 // Skip prologue and epilogue of objc_msgSend_uncached
1692 // because it's imprecisely modeled in compact unwind
1693 int prologueInstructions, epilogueInstructions;
1695 prologueInstructions = 3;
1696 epilogueInstructions = 2;
1697 #elif __arm64__ || __x86_64__ || __i386__ || __arm__
1698 prologueInstructions = 2;
1699 epilogueInstructions = 1;
1701 #error unknown architecture
1703 // skip past prologue
1704 for (int i = 0; i < prologueInstructions; i++) {
1705 testassert(*q != END_OFFSETS);
1709 // copy instructions
1710 while (*q != END_OFFSETS) *p++ = *q++ + uncached_symbol - symbol;
1712 // rewind past epilogue
1713 for (int i = 0; i < epilogueInstructions; i++) {
1714 testassert(p > result);
1718 free(uncached_offsets);
1722 // Terminate the list of offsets and return.
1723 testassert(p > result);
1724 testassert(p < end);
1731 void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret) __attribute__((noinline));
1732 void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret)
1734 uintptr_t message_ref[2];
1737 // copy to a local buffer to keep sel_arg un-fixed-up
1738 memcpy(message_ref, sel_arg, sizeof(message_ref));
1739 sel_arg = message_ref;
1741 if (!stret) callit(o, sel_arg, f);
1743 else callit_stret(o, sel_arg, f);
1745 else fail("stret?");
1749 void test_dw_forward(void)
1754 struct stret test_dw_forward_stret(void)
1759 // sub = ordinary receiver object
1760 // tagged = tagged receiver object
1761 // SEL = selector to send
1762 // sub_arg = arg to pass in receiver register (may be objc_super struct)
1763 // tagged_arg = arg to pass in receiver register (may be objc_super struct)
1764 // sel_arg = arg to pass in sel register (may be message_ref)
1765 // uncaughtAllowed is the number of acceptable unreachable instructions
1766 // (for example, the ones that handle the corrupt-cache-error case)
1767 void test_dw(const char *name, id sub, id tagged, id exttagged, bool stret,
1768 int uncaughtAllowed)
1771 testprintf("DWARF FOR %s%s\n", name, stret ? " (stret)" : "");
1773 // We need 2 SELs of each alignment so we can generate hash collisions.
1774 // sel_registerName() never returns those alignments because they
1775 // differ from malloc's alignment. So we create lots of compiled-in
1776 // SELs here and hope something fits.
1777 #pragma clang diagnostic push
1778 #pragma clang diagnostic ignored "-Wundeclared-selector"
1779 SEL sel = @selector(a);
1780 SEL lotsOfSels[] = {
1781 @selector(a1), @selector(a2), @selector(a3), @selector(a4),
1782 @selector(a5), @selector(a6), @selector(a7), @selector(a8),
1783 @selector(aa), @selector(ab), @selector(ac), @selector(ad),
1784 @selector(ae), @selector(af), @selector(ag), @selector(ah),
1785 @selector(A1), @selector(A2), @selector(A3), @selector(A4),
1786 @selector(A5), @selector(A6), @selector(A7), @selector(A8),
1787 @selector(AA), @selector(Ab), @selector(Ac), @selector(Ad),
1788 @selector(Ae), @selector(Af), @selector(Ag), @selector(Ah),
1789 @selector(bb1), @selector(bb2), @selector(bb3), @selector(bb4),
1790 @selector(bb5), @selector(bb6), @selector(bb7), @selector(bb8),
1791 @selector(bba), @selector(bbb), @selector(bbc), @selector(bbd),
1792 @selector(bbe), @selector(bbf), @selector(bbg), @selector(bbh),
1793 @selector(BB1), @selector(BB2), @selector(BB3), @selector(BB4),
1794 @selector(BB5), @selector(BB6), @selector(BB7), @selector(BB8),
1795 @selector(BBa), @selector(BBb), @selector(BBc), @selector(BBd),
1796 @selector(BBe), @selector(BBf), @selector(BBg), @selector(BBh),
1797 @selector(ccc1), @selector(ccc2), @selector(ccc3), @selector(ccc4),
1798 @selector(ccc5), @selector(ccc6), @selector(ccc7), @selector(ccc8),
1799 @selector(ccca), @selector(cccb), @selector(cccc), @selector(cccd),
1800 @selector(ccce), @selector(cccf), @selector(cccg), @selector(ccch),
1801 @selector(CCC1), @selector(CCC2), @selector(CCC3), @selector(CCC4),
1802 @selector(CCC5), @selector(CCC6), @selector(CCC7), @selector(CCC8),
1803 @selector(CCCa), @selector(CCCb), @selector(CCCc), @selector(CCCd),
1804 @selector(CCCe), @selector(CCCf), @selector(CCCg), @selector(CCCh),
1806 #pragma clang diagnostic pop
1809 IMP imp = stret ? (IMP)test_dw_forward_stret : (IMP)test_dw_forward;
1810 Class cls = object_getClass(sub);
1811 Class tagcls = object_getClass(tagged);
1812 Class exttagcls = object_getClass(exttagged);
1813 class_replaceMethod(cls, sel, imp, "");
1814 class_replaceMethod(tagcls, sel, imp, "");
1815 class_replaceMethod(exttagcls, sel, imp, "");
1816 for (size_t i = 0; i < sizeof(lotsOfSels)/sizeof(lotsOfSels[0]); i++) {
1817 class_replaceMethod(cls, lotsOfSels[i], imp, "");
1818 class_replaceMethod(tagcls, lotsOfSels[i], imp, "");
1819 class_replaceMethod(exttagcls, lotsOfSels[i], imp, "");
1823 #define ALIGNCOUNT 16
1824 SEL sels[ALIGNCOUNT][2] = {{0}};
1825 for (int align = 0; align < ALIGNCOUNT; align++) {
1826 for (size_t i = 0; i < sizeof(lotsOfSels)/sizeof(lotsOfSels[0]); i++) {
1827 if ((uintptr_t)(void*)lotsOfSels[i] % ALIGNCOUNT == align) {
1828 if (sels[align][0]) {
1829 sels[align][1] = lotsOfSels[i];
1831 sels[align][0] = lotsOfSels[i];
1835 if (!sels[align][0]) fail("no SEL with alignment %d", align);
1836 if (!sels[align][1]) fail("only one SEL with alignment %d", align);
1839 void *fn = dlsym(RTLD_DEFAULT, name);
1840 #if __has_feature(ptrauth_calls)
1841 fn = ptrauth_strip(fn, ptrauth_key_function_pointer);
1845 // argument substitutions
1847 void *sub_arg = (__bridge void*)sub;
1848 void *tagged_arg = (__bridge void*)tagged;
1849 void *exttagged_arg = (__bridge void*)exttagged;
1850 void *sel_arg = (void*)sel;
1852 struct objc_super sup_st = { sub, object_getClass(sub) };
1853 struct objc_super tagged_sup_st = { tagged, object_getClass(tagged) };
1854 struct objc_super exttagged_sup_st = { exttagged, object_getClass(exttagged) };
1855 struct { void *imp; SEL sel; } message_ref = { fn, sel };
1857 Class cache_cls = object_getClass(sub);
1858 Class tagged_cache_cls = object_getClass(tagged);
1859 Class exttagged_cache_cls = object_getClass(exttagged);
1861 if (strstr(name, "Super")) {
1862 // super version - replace receiver with objc_super
1863 // clear caches of superclass
1864 cache_cls = class_getSuperclass(cache_cls);
1865 tagged_cache_cls = class_getSuperclass(tagged_cache_cls);
1866 exttagged_cache_cls = class_getSuperclass(exttagged_cache_cls);
1868 tagged_arg = &tagged_sup_st;
1869 exttagged_arg = &exttagged_sup_st;
1872 if (strstr(name, "_fixup")) {
1873 // fixup version - replace sel with message_ref
1874 sel_arg = &message_ref;
1878 uintptr_t *insnOffsets = getOffsets(name, nil);
1879 testassert(insnOffsets);
1881 int uncaughtCount = 0;
1882 for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
1883 offset = insnOffsets[oo];
1884 testprintf("OFFSET %lu\n", offset);
1886 clobbered_insn_t saved_insn = clobber(fn, offset);
1890 if ((__bridge void*)sub == sub_arg) {
1892 testprintf(" nil\n");
1893 CALLIT(nil, sel_arg, sel, fn, stret);
1894 CALLIT(nil, sel_arg, sel, fn, stret);
1899 testprintf(" uncached\n");
1900 _objc_flush_caches(cache_cls);
1901 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1902 _objc_flush_caches(cache_cls);
1903 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1907 testprintf(" cached\n");
1908 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1909 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1913 testprintf(" uncached,tagged\n");
1914 _objc_flush_caches(tagged_cache_cls);
1915 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1916 _objc_flush_caches(tagged_cache_cls);
1917 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1918 _objc_flush_caches(exttagged_cache_cls);
1919 CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
1920 _objc_flush_caches(exttagged_cache_cls);
1921 CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
1925 testprintf(" cached,tagged\n");
1926 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1927 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1928 CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
1929 CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
1931 // multiple SEL alignments, collisions, wraps
1933 for (int a = 0; a < ALIGNCOUNT; a++) {
1934 testprintf(" cached and uncached, SEL alignment %d\n", a);
1936 // Count both up and down to be independent of
1937 // implementation's cache scan direction
1939 _objc_flush_caches(cache_cls);
1940 for (int x2 = 0; x2 < 8; x2++) {
1941 for (int s = 0; s < 4; s++) {
1942 int align = (a+s) % ALIGNCOUNT;
1943 CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
1944 CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
1948 _objc_flush_caches(cache_cls);
1949 for (int x2 = 0; x2 < 8; x2++) {
1950 for (int s = 0; s < 4; s++) {
1951 int align = abs(a-s) % ALIGNCOUNT;
1952 CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
1953 CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
1958 unclobber(fn, offset, saved_insn);
1960 // remember offsets that were caught by none of the above
1962 insnOffsets[oo] = 0;
1965 testprintf("offset %s+%lu not caught (%d/%d)\n",
1966 name, offset, uncaughtCount, uncaughtAllowed);
1970 // Complain if too many offsets went uncaught.
1971 // Acceptably-uncaught offsets include the corrupt-cache-error handler.
1972 if (uncaughtCount != uncaughtAllowed) {
1973 for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
1974 if (insnOffsets[oo]) {
1975 fprintf(stderr, "BAD: offset %s+%lu not caught\n",
1976 name, insnOffsets[oo]);
1979 fail("wrong instructions not reached for %s (missed %d, expected %d)",
1980 name, uncaughtCount, uncaughtAllowed);
1991 void test_basic(id receiver)
1995 struct stret stretval;
1998 vector_ulong2 vecval;
2001 // message uncached long long
2002 // message uncached stret
2003 // message uncached fpret
2004 // message uncached fpret long double
2005 // message uncached noarg (as above)
2007 // message cached long long
2008 // message cached stret
2009 // message cached fpret
2010 // message cached fpret long double
2011 // message cached noarg (as above)
2012 // fixme verify that uncached lookup didn't happen the 2nd time?
2014 _objc_flush_caches(object_getClass(receiver));
2015 for (int i = 0; i < 5; i++) {
2016 testprintf("idret\n");
2019 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];
2020 testassert(state == 101);
2021 testassert(idval == ID_RESULT);
2023 testprintf("llret\n");
2025 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];
2026 testassert(state == 102);
2027 testassert(llval == LL_RESULT);
2029 testprintf("stret\n");
2031 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];
2032 testassert(state == 103);
2033 testassert(stret_equal(stretval, STRET_RESULT));
2035 testprintf("fpret\n");
2037 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];
2038 testassert(state == 104);
2039 testassert(fpval == FP_RESULT);
2041 testprintf("lfpret\n");
2043 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];
2044 testassert(state == 105);
2045 testassert(lfpval == LFP_RESULT);
2047 testprintf("vecret\n");
2049 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];
2050 testassert(state == 106);
2051 testassert(vector_equal(vecval, VEC_RESULT));
2053 // explicitly call noarg messenger, even if compiler doesn't emit it
2055 testprintf("idret noarg\n");
2057 idval = ((typeof(idmsg0))objc_msgSend_noarg)(receiver, @selector(idret_noarg));
2058 testassert(state == 111);
2059 testassert(idval == ID_RESULT);
2061 testprintf("llret noarg\n");
2063 llval = ((typeof(llmsg0))objc_msgSend_noarg)(receiver, @selector(llret_noarg));
2064 testassert(state == 112);
2065 testassert(llval == LL_RESULT);
2067 no objc_msgSend_stret_noarg
2069 stretval = ((typeof(stretmsg0))objc_msgSend_stret_noarg)(receiver, @selector(stret_noarg));
2070 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];
2071 testassert(state == 113);
2072 testassert(stret_equal(stretval, STRET_RESULT));
2075 testprintf("fpret noarg\n");
2077 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(receiver, @selector(fpret_noarg));
2078 testassert(state == 114);
2079 testassert(fpval == FP_RESULT);
2081 testprintf("vecret noarg\n");
2083 vecval = ((typeof(vecmsg0))objc_msgSend_noarg)(receiver, @selector(vecret_noarg));
2084 testassert(state == 116);
2085 testassert(vector_equal(vecval, VEC_RESULT));
2087 #if !__i386__ && !__x86_64__
2088 testprintf("lfpret noarg\n");
2090 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(receiver, @selector(lfpret_noarg));
2091 testassert(state == 115);
2092 testassert(lfpval == LFP_RESULT);
2096 testprintf("basic done\n");
2104 struct stret stretval;
2107 vector_ulong2 vecval;
2110 struct stret *stretptr;
2120 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);
2121 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);
2122 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);
2123 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);
2124 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);
2125 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);
2127 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));
2128 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));
2129 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));
2130 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));
2131 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));
2132 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));
2133 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));
2134 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));
2136 // get +initialize out of the way
2138 #if OBJC_HAVE_TAGGED_POINTERS
2140 [ExtTaggedSub class];
2143 ID_RESULT = [Super new];
2145 Sub *sub = [Sub new];
2146 Super *sup = [Super new];
2147 #if OBJC_HAVE_TAGGED_POINTERS
2148 TaggedSub *tagged = (__bridge id)_objc_makeTaggedPointer(OBJC_TAG_1, 999);
2149 ExtTaggedSub *exttagged = (__bridge id)_objc_makeTaggedPointer(OBJC_TAG_First52BitPayload, 999);
2152 // Basic cached and uncached dispatch.
2153 // Do this first before anything below caches stuff.
2154 testprintf("basic\n");
2156 #if OBJC_HAVE_TAGGED_POINTERS
2157 testprintf("basic tagged\n");
2159 testprintf("basic ext tagged\n");
2160 test_basic(exttagged);
2163 idmethod = class_getInstanceMethod([Super class], @selector(idret::::::::::::::::::::::::::::::::::::));
2164 testassert(idmethod);
2165 llmethod = class_getInstanceMethod([Super class], @selector(llret::::::::::::::::::::::::::::::::::::));
2166 testassert(llmethod);
2167 stretmethod = class_getInstanceMethod([Super class], @selector(stret::::::::::::::::::::::::::::::::::::));
2168 testassert(stretmethod);
2169 fpmethod = class_getInstanceMethod([Super class], @selector(fpret::::::::::::::::::::::::::::::::::::));
2170 testassert(fpmethod);
2171 lfpmethod = class_getInstanceMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::::::::::));
2172 testassert(lfpmethod);
2173 vecmethod = class_getInstanceMethod([Super class], @selector(vecret::::::::::::::::::::::::::::::::::::));
2174 testassert(vecmethod);
2176 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;
2177 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;
2178 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;
2179 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;
2180 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;
2181 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;
2184 // method_invoke long long
2185 // method_invoke_stret stret
2186 // method_invoke_stret fpret
2187 // method_invoke fpret long double
2188 testprintf("method_invoke\n");
2194 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);
2195 testassert(state == 1);
2196 testassert(idval == ID_RESULT);
2199 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);
2200 testassert(state == 2);
2201 testassert(llval == LL_RESULT);
2204 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);
2205 testassert(state == 3);
2206 testassert(stret_equal(stretval, STRET_RESULT));
2209 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);
2210 testassert(state == 4);
2211 testassert(fpval == FP_RESULT);
2214 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);
2215 testassert(state == 5);
2216 testassert(lfpval == LFP_RESULT);
2219 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);
2220 testassert(state == 6);
2221 testassert(vector_equal(vecval, VEC_RESULT));
2225 // message to nil long long
2226 // message to nil stret
2227 // message to nil fpret
2228 // message to nil fpret long double
2229 // Use NIL_RECEIVER to avoid compiler optimizations.
2230 testprintf("message to nil\n");
2234 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];
2235 testassert(state == 0);
2236 testassert(idval == nil);
2240 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];
2241 testassert(state == 0);
2242 testassert(llval == 0LL);
2246 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];
2247 testassert(state == 0);
2248 testassert(0 == memcmp(&stretval, &zero, sizeof(stretval)));
2251 // check stret return register
2254 stretptr = ((struct stret *(*)(struct stret *, id, SEL))objc_msgSend_stret)
2255 (&stretval, nil, @selector(stret_nop));
2256 testassert(stretptr == &stretval);
2257 testassert(state == 0);
2258 // no stret result guarantee for hand-written calls
2262 // check struct-return address stack pop
2263 for (int i = 0; i < 10000000; i++) {
2265 ((struct stret (*)(id, SEL))objc_msgSend_stret)
2266 (nil, @selector(stret_nop));
2272 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];
2273 testassert(state == 0);
2274 testassert(fpval == 0.0);
2277 lfpval = LFP_RESULT;
2278 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];
2279 testassert(state == 0);
2280 testassert(lfpval == 0.0);
2283 vecval = VEC_RESULT;
2284 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];
2285 testassert(state == 0);
2286 testassert(vector_all(vecval == 0));
2288 // message to nil, different struct types
2289 // This verifies that ordinary objc_msgSend() erases enough registers
2290 // for structs that return in registers.
2291 #define TEST_NIL_STRUCT(i,n) \
2293 struct stret_##i##n z; \
2294 bzero(&z, sizeof(z)); \
2295 [Super stret_i##n##_nonzero]; \
2296 [Super stret_d##n##_nonzero]; \
2297 struct stret_##i##n val = [(id)NIL_RECEIVER stret_##i##n##_zero]; \
2298 testassert(0 == memcmp(&z, &val, sizeof(val))); \
2301 TEST_NIL_STRUCT(i,1);
2302 TEST_NIL_STRUCT(i,2);
2303 TEST_NIL_STRUCT(i,3);
2304 TEST_NIL_STRUCT(i,4);
2305 TEST_NIL_STRUCT(i,5);
2306 TEST_NIL_STRUCT(i,6);
2307 TEST_NIL_STRUCT(i,7);
2308 TEST_NIL_STRUCT(i,8);
2309 TEST_NIL_STRUCT(i,9);
2312 testwarn("rdar://16267205 i386 struct{float} and struct{double}");
2314 TEST_NIL_STRUCT(d,1);
2316 TEST_NIL_STRUCT(d,2);
2317 TEST_NIL_STRUCT(d,3);
2318 TEST_NIL_STRUCT(d,4);
2319 TEST_NIL_STRUCT(d,5);
2320 TEST_NIL_STRUCT(d,6);
2321 TEST_NIL_STRUCT(d,7);
2322 TEST_NIL_STRUCT(d,8);
2323 TEST_NIL_STRUCT(d,9);
2326 // message to nil noarg
2327 // explicitly call noarg messenger, even if compiler doesn't emit it
2330 idval = ((typeof(idmsg0))objc_msgSend_noarg)(nil, @selector(idret_noarg));
2331 testassert(state == 0);
2332 testassert(idval == nil);
2336 llval = ((typeof(llmsg0))objc_msgSend_noarg)(nil, @selector(llret_noarg));
2337 testassert(state == 0);
2338 testassert(llval == 0LL);
2340 // no stret_noarg messenger
2345 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(nil, @selector(fpret_noarg));
2346 testassert(state == 0);
2347 testassert(fpval == 0.0);
2350 vecval = VEC_RESULT;
2351 vecval = ((typeof(vecmsg0))objc_msgSend_noarg)(nil, @selector(vecret_noarg));
2352 testassert(state == 0);
2353 testassert(vector_all(vecval == 0));
2355 #if !__i386__ && !__x86_64__
2357 lfpval = LFP_RESULT;
2358 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(nil, @selector(lfpret_noarg));
2359 testassert(state == 0);
2360 testassert(lfpval == 0.0);
2364 // rdar://8271364 objc_msgSendSuper2 must not change objc_super
2365 testprintf("super struct\n");
2366 struct objc_super sup_st = {
2368 object_getClass(sub),
2375 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);
2376 testassert(state == 1);
2377 testassert(idval == ID_RESULT);
2378 testassert(sup_st.receiver == sub);
2379 testassert(sup_st.super_class == object_getClass(sub));
2383 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);
2384 testassert(state == 3);
2385 testassert(stret_equal(stretval, STRET_RESULT));
2386 testassert(sup_st.receiver == sub);
2387 testassert(sup_st.super_class == object_getClass(sub));
2390 // Debug messengers.
2391 testprintf("debug messengers\n");
2394 idmsg = (typeof(idmsg))objc_msgSend_debug;
2396 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);
2397 testassert(state == 101);
2398 testassert(idval == ID_RESULT);
2401 llmsg = (typeof(llmsg))objc_msgSend_debug;
2403 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);
2404 testassert(state == 102);
2405 testassert(llval == LL_RESULT);
2408 stretmsg = (typeof(stretmsg))objc_msgSend_stret_debug;
2410 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);
2411 testassert(state == 103);
2412 testassert(stret_equal(stretval, STRET_RESULT));
2415 sup_st.receiver = sub;
2416 sup_st.super_class = object_getClass(sub);
2417 idmsgsuper = (typeof(idmsgsuper))objc_msgSendSuper2_debug;
2419 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);
2420 testassert(state == 1);
2421 testassert(idval == ID_RESULT);
2424 sup_st.receiver = sub;
2425 sup_st.super_class = object_getClass(sub);
2426 stretmsgsuper = (typeof(stretmsgsuper))objc_msgSendSuper2_stret_debug;
2428 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);
2429 testassert(state == 3);
2430 testassert(stret_equal(stretval, STRET_RESULT));
2434 fpmsg = (typeof(fpmsg))objc_msgSend_fpret_debug;
2436 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);
2437 testassert(state == 104);
2438 testassert(fpval == FP_RESULT);
2442 lfpmsg = (typeof(lfpmsg))objc_msgSend_fpret_debug;
2444 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);
2445 testassert(state == 105);
2446 testassert(lfpval == LFP_RESULT);
2458 // fixme objc_msgLookup test hack stopped working after a compiler update
2460 #elif __has_feature(objc_arc)
2461 // ARC interferes with objc_msgLookup test hacks
2463 #elif __i386__ && TARGET_OS_SIMULATOR
2464 testwarn("fixme msgLookup hack doesn't work");
2467 // fixme hack: call the looked-up method
2469 # define CALL_LOOKUP(ret) \
2470 asm volatile ("blr x17 \n mov %x0, x0" : "=r" (ret))
2471 # define CALL_LOOKUP_STRET(ret) \
2472 asm volatile ("mov x8, %x1 \n blr x17 \n" : "=m" (ret) : "r" (&ret))
2475 # define CALL_LOOKUP(ret) \
2476 asm volatile ("blx r12 \n mov %0, r0" : "=r" (ret))
2477 # define CALL_LOOKUP_STRET(ret) \
2478 asm volatile ("mov r0, %1 \n blx r12 \n" : "=m" (ret) : "r" (&ret))
2481 # define CALL_LOOKUP(ret) \
2482 asm volatile ("call *%%r11 \n mov %%rax, %0" : "=r" (ret))
2483 # define CALL_LOOKUP_STRET(ret) \
2484 asm volatile ("mov %1, %%rdi \n call *%%r11 \n" : "=m" (ret) : "r" (&ret))
2487 # define CALL_LOOKUP(ret) \
2488 asm volatile ("call *%%eax \n mov %%eax, %0" : "=r" (ret))
2489 # define CALL_LOOKUP_STRET(ret) \
2490 asm volatile ("add $4, %%esp \n mov %1, (%%esp) \n call *%%eax \n sub $4, %%esp \n" : "=m" (ret) : "d" (&ret))
2493 # error unknown architecture
2496 // msgLookup uncached
2497 // msgLookup uncached super
2498 // msgLookup uncached stret
2499 // msgLookup uncached super stret
2500 // msgLookup uncached fpret
2501 // msgLookup uncached fpret long double
2503 // msgLookup cached stret
2504 // msgLookup cached super
2505 // msgLookup cached super stret
2506 // msgLookup cached fpret
2507 // msgLookup cached fpret long double
2508 // fixme verify that uncached lookup didn't happen the 2nd time?
2510 _objc_flush_caches(object_getClass(sub));
2511 for (int i = 0; i < 5; i++) {
2512 testprintf("objc_msgLookup\n");
2514 idmsg = (typeof(idmsg))objc_msgLookup;
2516 (*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);
2518 testassert(state == 101);
2519 testassert(idval == ID_RESULT);
2521 testprintf("objc_msgLookup_stret\n");
2523 stretmsg = (typeof(stretmsg))objc_msgLookup_stret;
2525 (*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);
2526 CALL_LOOKUP_STRET(stretval);
2527 testassert(state == 103);
2528 testassert(stret_equal(stretval, STRET_RESULT));
2530 testprintf("objc_msgLookupSuper2\n");
2532 sup_st.receiver = sub;
2533 sup_st.super_class = object_getClass(sub);
2534 idmsgsuper = (typeof(idmsgsuper))objc_msgLookupSuper2;
2536 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);
2538 testassert(state == 1);
2539 testassert(idval == ID_RESULT);
2541 testprintf("objc_msgLookupSuper2_stret\n");
2543 sup_st.receiver = sub;
2544 sup_st.super_class = object_getClass(sub);
2545 stretmsgsuper = (typeof(stretmsgsuper))objc_msgLookupSuper2_stret;
2547 (*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);
2548 CALL_LOOKUP_STRET(stretval);
2549 testassert(state == 3);
2550 testassert(stret_equal(stretval, STRET_RESULT));
2553 // fixme fpret, can't test FP stack properly
2556 // fixme fpret, can't test FP stack properly
2557 // fixme fp2ret, can't test FP stack properly
2563 // msgLookup to nil stret
2564 // fixme msgLookup to nil long long
2565 // fixme msgLookup to nil fpret
2566 // fixme msgLookup to nil fp2ret
2568 testprintf("objc_msgLookup to nil\n");
2570 idmsg = (typeof(idmsg))objc_msgLookup;
2572 (*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);
2574 testassert(state == 0);
2575 testassert(idval == nil);
2577 testprintf("objc_msgLookup_stret to nil\n");
2579 stretmsg = (typeof(stretmsg))objc_msgLookup_stret;
2581 (*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);
2582 CALL_LOOKUP_STRET(stretval);
2583 testassert(state == 0);
2584 // no stret result guarantee
2587 // fixme fpret, can't test FP stack properly
2590 // fixme fpret, can't test FP stack properly
2591 // fixme fp2ret, can't test FP stack properly
2600 testwarn("no unwind tables in this configuration " NO_DWARF_REASON);
2602 // DWARF unwind tables
2603 testprintf("unwind tables\n");
2605 // Clear simulator-related environment variables.
2606 // Disassembly will run llvm-objdump which is not a simulator executable.
2607 unsetenv("DYLD_ROOT_PATH");
2608 unsetenv("DYLD_FALLBACK_LIBRARY_PATH");
2609 unsetenv("DYLD_FALLBACK_FRAMEWORK_PATH");
2611 // Check mprotect() of objc_msgSend.
2612 // It doesn't work when running on a device with no libobjc root.
2613 // In that case we skip this part of the test without failing.
2614 // fixme make this work
2615 // fixme now it doesn't work even with a libobjc root in place?
2616 int err1 = mprotect((void *)((uintptr_t)&objc_msgSend & ~(PAGE_MAX_SIZE-1)),
2617 PAGE_MAX_SIZE, PROT_READ | PROT_WRITE);
2619 int err2 = mprotect((void *)((uintptr_t)&objc_msgSend & ~(PAGE_MAX_SIZE-1)),
2620 PAGE_MAX_SIZE, PROT_READ | PROT_EXEC);
2623 testwarn("can't mprotect() objc_msgSend (%d, %d). "
2624 "Skipping unwind table test.",
2625 err1, errno1, err2, errno2);
2628 // install exception handler
2629 struct sigaction act;
2630 act.sa_sigaction = break_handler;
2632 act.sa_flags = SA_SIGINFO;
2633 sigaction(BREAK_SIGNAL, &act, nil);
2634 #if defined(BREAK_SIGNAL2)
2635 sigaction(BREAK_SIGNAL2, &act, nil);
2638 SubDW *dw = [[SubDW alloc] init];
2640 objc_setForwardHandler((void*)test_dw_forward, (void*)test_dw_forward_stret);
2643 test_dw("objc_msgSend", dw, tagged, exttagged, false, 0);
2644 test_dw("objc_msgSend_stret", dw, tagged, exttagged, true, 0);
2645 test_dw("objc_msgSend_fpret", dw, tagged, exttagged, false, 0);
2646 test_dw("objc_msgSend_fp2ret", dw, tagged, exttagged, false, 0);
2647 test_dw("objc_msgSendSuper", dw, tagged, exttagged, false, 0);
2648 test_dw("objc_msgSendSuper2", dw, tagged, exttagged, false, 0);
2649 test_dw("objc_msgSendSuper_stret", dw, tagged, exttagged, true, 0);
2650 test_dw("objc_msgSendSuper2_stret", dw, tagged, exttagged, true, 0);
2652 test_dw("objc_msgSend", dw, dw, dw, false, 0);
2653 test_dw("objc_msgSend_stret", dw, dw, dw, true, 0);
2654 test_dw("objc_msgSend_fpret", dw, dw, dw, false, 0);
2655 test_dw("objc_msgSendSuper", dw, dw, dw, false, 0);
2656 test_dw("objc_msgSendSuper2", dw, dw, dw, false, 0);
2657 test_dw("objc_msgSendSuper_stret", dw, dw, dw, true, 0);
2658 test_dw("objc_msgSendSuper2_stret", dw, dw, dw, true, 0);
2660 test_dw("objc_msgSend", dw, tagged, exttagged, false, 1);
2661 test_dw("objc_msgSendSuper", dw, tagged, exttagged, false, 1);
2662 test_dw("objc_msgSendSuper2", dw, tagged, exttagged, false, 1);
2664 test_dw("objc_msgSend", dw, dw, dw, false, 0);
2665 test_dw("objc_msgSend_stret", dw, dw, dw, true, 0);
2666 test_dw("objc_msgSendSuper", dw, dw, dw, false, 0);
2667 test_dw("objc_msgSendSuper2", dw, dw, dw, false, 0);
2668 test_dw("objc_msgSendSuper_stret", dw, dw, dw, true, 0);
2669 test_dw("objc_msgSendSuper2_stret", dw, dw, dw, true, 0);
2671 # error unknown architecture
2675 // end DWARF unwind test