1 // TEST_CFLAGS -Wno-unused-parameter
6 #if __cplusplus && !__clang__
10 // llvm-g++ is confused by @selector(foo::) and will never be fixed
16 #include <objc/objc.h>
17 #include <objc/runtime.h>
18 #include <objc/objc-internal.h>
19 #include <objc/objc-abi.h>
22 // no stret dispatchers
23 # define SUPPORT_STRET 0
24 # define objc_msgSend_stret objc_msgSend
25 # define objc_msgSendSuper2_stret objc_msgSendSuper2
26 # define objc_msgSend_stret_debug objc_msgSend_debug
27 # define objc_msgSendSuper2_stret_debug objc_msgSendSuper2_debug
28 # define method_invoke_stret method_invoke
30 # define SUPPORT_STRET 1
38 # define ALIGN_() asm(".align 4");
41 @interface Super : TestRoot @end
43 @interface Sub : Super @end
49 // for typeof() shorthand only
50 id (*idmsg0)(id, SEL) __attribute__((unused));
51 long long (*llmsg0)(id, SEL) __attribute__((unused));
52 // struct stret (*stretmsg0)(id, SEL) __attribute__((unused));
53 double (*fpmsg0)(id, SEL) __attribute__((unused));
54 long double (*lfpmsg0)(id, SEL) __attribute__((unused));
57 #define CHECK_ARGS(sel) \
59 testassert(self == SELF); \
60 testassert(_cmd == sel_registerName(#sel "::::::::::::::::::::::::::::"));\
61 testassert(i1 == 1); \
62 testassert(i2 == 2); \
63 testassert(i3 == 3); \
64 testassert(i4 == 4); \
65 testassert(i5 == 5); \
66 testassert(i6 == 6); \
67 testassert(i7 == 7); \
68 testassert(i8 == 8); \
69 testassert(i9 == 9); \
70 testassert(i10 == 10); \
71 testassert(i11 == 11); \
72 testassert(i12 == 12); \
73 testassert(i13 == 13); \
74 testassert(f1 == 1.0); \
75 testassert(f2 == 2.0); \
76 testassert(f3 == 3.0); \
77 testassert(f4 == 4.0); \
78 testassert(f5 == 5.0); \
79 testassert(f6 == 6.0); \
80 testassert(f7 == 7.0); \
81 testassert(f8 == 8.0); \
82 testassert(f9 == 9.0); \
83 testassert(f10 == 10.0); \
84 testassert(f11 == 11.0); \
85 testassert(f12 == 12.0); \
86 testassert(f13 == 13.0); \
87 testassert(f14 == 14.0); \
88 testassert(f15 == 15.0); \
91 #define CHECK_ARGS_NOARG(sel) \
93 testassert(self == SELF); \
94 testassert(_cmd == sel_registerName(#sel "_noarg"));\
99 long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
100 double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
101 long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
102 // STRET_RESULT in test.h
104 static struct stret zero;
231 @implementation Super
232 -(struct stret)stret { return STRET_RESULT; }
235 (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
243 (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
250 -(struct stret)stret:
251 (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
259 (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 -(long double)lfpret:
267 (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
277 CHECK_ARGS_NOARG(idret);
282 -(long long)llret_noarg
284 CHECK_ARGS_NOARG(llret);
289 -(struct stret)stret_noarg
291 CHECK_ARGS_NOARG(stret);
298 CHECK_ARGS_NOARG(fpret);
303 -(long double)lfpret_noarg
305 CHECK_ARGS_NOARG(lfpret);
326 -(long long)llret_nop
331 -(struct stret)stret_nop
341 -(long double)lfpret_nop
346 #define STRET_IMP(n) \
347 +(struct stret_##n)stret_##n##_zero \
349 struct stret_##n ret; \
350 bzero(&ret, sizeof(ret)); \
353 +(struct stret_##n)stret_##n##_nonzero \
355 struct stret_##n ret; \
356 memset(&ret, 0xff, sizeof(ret)); \
382 (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
384 fail("+idret called instead of -idret");
389 (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
391 fail("+llret called instead of -llret");
395 +(struct stret)stret:
396 (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
398 fail("+stret called instead of -stret");
403 (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
405 fail("+fpret called instead of -fpret");
409 +(long double)lfpret:
410 (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
412 fail("+lfpret called instead of -lfpret");
418 fail("+idret_noarg called instead of -idret_noarg");
419 CHECK_ARGS_NOARG(idret);
422 +(long long)llret_noarg
424 fail("+llret_noarg called instead of -llret_noarg");
425 CHECK_ARGS_NOARG(llret);
428 +(struct stret)stret_noarg
430 fail("+stret_noarg called instead of -stret_noarg");
431 CHECK_ARGS_NOARG(stret);
436 fail("+fpret_noarg called instead of -fpret_noarg");
437 CHECK_ARGS_NOARG(fpret);
440 +(long double)lfpret_noarg
442 fail("+lfpret_noarg called instead of -lfpret_noarg");
443 CHECK_ARGS_NOARG(lfpret);
452 (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 result = [super idret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
458 testassert(state == 1);
459 testassert(result == ID_RESULT);
465 (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
470 result = [super llret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
471 testassert(state == 2);
472 testassert(result == LL_RESULT);
477 -(struct stret)stret:
478 (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
483 result = [super stret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
484 testassert(state == 3);
485 testassert(stret_equal(result, STRET_RESULT));
491 (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
496 result = [super fpret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
497 testassert(state == 4);
498 testassert(result == FP_RESULT);
503 -(long double)lfpret:
504 (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
509 result = [super lfpret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
510 testassert(state == 5);
511 testassert(result == LFP_RESULT);
520 CHECK_ARGS_NOARG(idret);
522 result = [super idret_noarg];
523 testassert(state == 11);
524 testassert(result == ID_RESULT);
529 -(long long)llret_noarg
532 CHECK_ARGS_NOARG(llret);
534 result = [super llret_noarg];
535 testassert(state == 12);
536 testassert(result == LL_RESULT);
541 -(struct stret)stret_noarg
544 CHECK_ARGS_NOARG(stret);
546 result = [super stret_noarg];
547 testassert(state == 13);
548 testassert(stret_equal(result, STRET_RESULT));
556 CHECK_ARGS_NOARG(fpret);
558 result = [super fpret_noarg];
559 testassert(state == 14);
560 testassert(result == FP_RESULT);
565 -(long double)lfpret_noarg
568 CHECK_ARGS_NOARG(lfpret);
570 result = [super lfpret_noarg];
571 testassert(state == 15);
572 testassert(result == LFP_RESULT);
580 #if OBJC_HAVE_TAGGED_POINTERS
582 @interface TaggedSub : Sub @end
584 @implementation TaggedSub : Sub
588 _objc_registerTaggedPointerClass(OBJC_TAG_7, self);
596 // DWARF checking machinery
599 // unimplemented on this platform
601 // 32-bit Mac doesn't use DWARF unwind
602 #elif TARGET_OS_IPHONE && __arm__
603 // 32-bit iOS device doesn't use DWARF unwind
604 #elif __has_feature(objc_arc)
605 // ARC's extra RR calls hit the traps at the wrong times
610 // Classes with no implementations and no cache contents from elsewhere.
611 @interface SuperDW : TestRoot @end
612 @implementation SuperDW @end
614 @interface Sub0DW : SuperDW @end
615 @implementation Sub0DW @end
617 @interface SubDW : Sub0DW @end
618 @implementation SubDW @end
622 #include <sys/mman.h>
623 #include <libunwind.h>
625 #define UNW_STEP_SUCCESS 1
626 #define UNW_STEP_END 0
632 extern void callit(void *obj, void *sel, void *fn);
633 extern struct stret callit_stret(void *obj, void *sel, void *fn);
638 #define OTOOL "/usr/bin/xcrun otool -arch x86_64 "
640 typedef uint8_t insn_t;
641 #define BREAK_INSN ((insn_t)0xcc) // int3
652 void handle_exception(x86_thread_state64_t *state)
659 err = unw_init_local(&curs, (unw_context_t *)state);
662 step = unw_step(&curs);
663 testassert(step == UNW_STEP_SUCCESS);
665 err = unw_get_reg(&curs, UNW_X86_64_R12, ®);
667 testassert(reg == r12);
669 err = unw_get_reg(&curs, UNW_X86_64_R13, ®);
671 testassert(reg == r13);
673 err = unw_get_reg(&curs, UNW_X86_64_R14, ®);
675 testassert(reg == r14);
677 err = unw_get_reg(&curs, UNW_X86_64_R15, ®);
679 testassert(reg == r15);
681 err = unw_get_reg(&curs, UNW_X86_64_RBX, ®);
683 testassert(reg == rbx);
685 err = unw_get_reg(&curs, UNW_X86_64_RBP, ®);
687 testassert(reg == rbp);
689 err = unw_get_reg(&curs, UNW_X86_64_RSP, ®);
691 testassert(reg == rsp);
693 err = unw_get_reg(&curs, UNW_REG_IP, ®);
695 testassert(reg == rip);
698 // set thread state to unwound state
712 void sigtrap(int sig, siginfo_t *info, void *cc)
714 ucontext_t *uc = (ucontext_t *)cc;
715 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
717 testprintf(" handled\n");
719 testassert(sig == SIGTRAP);
720 testassert((uintptr_t)info->si_addr-1 == clobbered);
722 handle_exception(&mc->__ss);
723 // handle_exception changed register state for continuation
730 // save sp and return address to variables
731 "\n movq (%rsp), %r10"
732 "\n movq %r10, _rip(%rip)"
733 "\n movq %rsp, _rsp(%rip)"
734 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
735 // save other non-volatile registers to variables
736 "\n movq %rbx, _rbx(%rip)"
737 "\n movq %rbp, _rbp(%rip)"
738 "\n movq %r12, _r12(%rip)"
739 "\n movq %r13, _r13(%rip)"
740 "\n movq %r14, _r14(%rip)"
741 "\n movq %r15, _r15(%rip)"
747 "\n .globl _callit_stret"
749 // save sp and return address to variables
750 "\n movq (%rsp), %r10"
751 "\n movq %r10, _rip(%rip)"
752 "\n movq %rsp, _rsp(%rip)"
753 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
754 // save other non-volatile registers to variables
755 "\n movq %rbx, _rbx(%rip)"
756 "\n movq %rbp, _rbp(%rip)"
757 "\n movq %r12, _r12(%rip)"
758 "\n movq %r13, _r13(%rip)"
759 "\n movq %r14, _r14(%rip)"
760 "\n movq %r15, _r15(%rip)"
769 #define OTOOL "/usr/bin/xcrun otool -arch i386 "
771 typedef uint8_t insn_t;
772 #define BREAK_INSN ((insn_t)0xcc) // int3
780 uintptr_t espfix = 0;
782 void handle_exception(i386_thread_state_t *state)
789 err = unw_init_local(&curs, (unw_context_t *)state);
792 step = unw_step(&curs);
793 testassert(step == UNW_STEP_SUCCESS);
795 err = unw_get_reg(&curs, UNW_REG_IP, ®);
797 testassert(reg == eip);
799 err = unw_get_reg(&curs, UNW_X86_ESP, ®);
801 testassert(reg == esp);
803 err = unw_get_reg(&curs, UNW_X86_EBX, ®);
805 testassert(reg == ebx);
807 err = unw_get_reg(&curs, UNW_X86_EBP, ®);
809 testassert(reg == ebp);
811 err = unw_get_reg(&curs, UNW_X86_EDI, ®);
813 testassert(reg == edi);
815 err = unw_get_reg(&curs, UNW_X86_ESI, ®);
817 testassert(reg == esi);
820 // set thread state to unwound state
822 state->__esp = esp + espfix;
832 void sigtrap(int sig, siginfo_t *info, void *cc)
834 ucontext_t *uc = (ucontext_t *)cc;
835 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
837 testprintf(" handled\n");
839 testassert(sig == SIGTRAP);
840 testassert((uintptr_t)info->si_addr-1 == clobbered);
842 handle_exception(&mc->__ss);
843 // handle_exception changed register state for continuation
850 // save sp and return address to variables
853 "\n movl (%esp), %eax"
854 "\n movl %eax, _eip-1b(%edx)"
855 "\n movl %esp, _esp-1b(%edx)"
856 "\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
857 "\n movl $0, _espfix-1b(%edx)"
858 // save other non-volatile registers to variables
859 "\n movl %ebx, _ebx-1b(%edx)"
860 "\n movl %ebp, _ebp-1b(%edx)"
861 "\n movl %edi, _edi-1b(%edx)"
862 "\n movl %esi, _esi-1b(%edx)"
868 "\n .globl _callit_stret"
870 // save sp and return address to variables
873 "\n movl (%esp), %eax"
874 "\n movl %eax, _eip-1b(%edx)"
875 "\n movl %esp, _esp-1b(%edx)"
876 "\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
877 "\n movl $4, _espfix-1b(%edx)"
878 // save other non-volatile registers to variables
879 "\n movl %ebx, _ebx-1b(%edx)"
880 "\n movl %ebp, _ebp-1b(%edx)"
881 "\n movl %edi, _edi-1b(%edx)"
882 "\n movl %esi, _esi-1b(%edx)"
890 #include <sys/ucontext.h>
892 // runs on iOS device, no xcrun command present
893 #define OTOOL "/usr/bin/otool -arch arm64 "
895 typedef uint32_t insn_t;
896 #define BREAK_INSN ((insn_t)0xd4200020) // brk #1
912 void handle_exception(arm_thread_state64_t *state)
919 err = unw_init_local(&curs, (unw_context_t *)state);
922 step = unw_step(&curs);
923 testassert(step == UNW_STEP_SUCCESS);
925 err = unw_get_reg(&curs, UNW_ARM64_X19, ®);
927 testassert(reg == x19);
929 err = unw_get_reg(&curs, UNW_ARM64_X20, ®);
931 testassert(reg == x20);
933 err = unw_get_reg(&curs, UNW_ARM64_X21, ®);
935 testassert(reg == x21);
937 err = unw_get_reg(&curs, UNW_ARM64_X22, ®);
939 testassert(reg == x22);
941 err = unw_get_reg(&curs, UNW_ARM64_X23, ®);
943 testassert(reg == x23);
945 err = unw_get_reg(&curs, UNW_ARM64_X24, ®);
947 testassert(reg == x24);
949 err = unw_get_reg(&curs, UNW_ARM64_X25, ®);
951 testassert(reg == x25);
953 err = unw_get_reg(&curs, UNW_ARM64_X26, ®);
955 testassert(reg == x26);
957 err = unw_get_reg(&curs, UNW_ARM64_X27, ®);
959 testassert(reg == x27);
961 err = unw_get_reg(&curs, UNW_ARM64_X28, ®);
963 testassert(reg == x28);
965 err = unw_get_reg(&curs, UNW_ARM64_FP, ®);
967 testassert(reg == fp);
969 err = unw_get_reg(&curs, UNW_ARM64_SP, ®);
971 testassert(reg == sp);
973 err = unw_get_reg(&curs, UNW_REG_IP, ®);
975 testassert(reg == pc);
977 // libunwind restores PC into LR and doesn't track LR
978 // err = unw_get_reg(&curs, UNW_ARM64_LR, ®);
980 // testassert(reg == lr);
982 // set thread state to unwound state
983 state->__x[19] = x19;
984 state->__x[20] = x20;
985 state->__x[20] = x21;
986 state->__x[22] = x22;
987 state->__x[23] = x23;
988 state->__x[24] = x24;
989 state->__x[25] = x25;
990 state->__x[26] = x26;
991 state->__x[27] = x27;
992 state->__x[28] = x28;
994 state->__lr = pc; // libunwind restores PC into LR
1002 void sigtrap(int sig, siginfo_t *info, void *cc)
1004 ucontext_t *uc = (ucontext_t *)cc;
1005 struct __darwin_mcontext64 *mc = (struct __darwin_mcontext64 *)uc->uc_mcontext;
1007 testprintf(" handled\n");
1009 testassert(sig == SIGTRAP);
1010 testassert((uintptr_t)info->si_addr == clobbered);
1012 handle_exception(&mc->__ss);
1013 // handle_exception changed register state for continuation
1021 // save sp and return address to variables
1023 "\n adrp x17, _sp@PAGE"
1024 "\n str x16, [x17, _sp@PAGEOFF]"
1025 "\n adrp x17, _pc@PAGE"
1026 "\n str lr, [x17, _pc@PAGEOFF]"
1027 // save other non-volatile registers to variables
1028 "\n adrp x17, _x19@PAGE"
1029 "\n str x19, [x17, _x19@PAGEOFF]"
1030 "\n adrp x17, _x19@PAGE"
1031 "\n str x20, [x17, _x20@PAGEOFF]"
1032 "\n adrp x17, _x19@PAGE"
1033 "\n str x21, [x17, _x21@PAGEOFF]"
1034 "\n adrp x17, _x19@PAGE"
1035 "\n str x22, [x17, _x22@PAGEOFF]"
1036 "\n adrp x17, _x19@PAGE"
1037 "\n str x23, [x17, _x23@PAGEOFF]"
1038 "\n adrp x17, _x19@PAGE"
1039 "\n str x24, [x17, _x24@PAGEOFF]"
1040 "\n adrp x17, _x19@PAGE"
1041 "\n str x25, [x17, _x25@PAGEOFF]"
1042 "\n adrp x17, _x19@PAGE"
1043 "\n str x26, [x17, _x26@PAGEOFF]"
1044 "\n adrp x17, _x19@PAGE"
1045 "\n str x27, [x17, _x27@PAGEOFF]"
1046 "\n adrp x17, _x19@PAGE"
1047 "\n str x28, [x17, _x28@PAGEOFF]"
1048 "\n adrp x17, _x19@PAGE"
1049 "\n str fp, [x17, _fp@PAGEOFF]"
1057 #error unknown architecture
1062 insn_t set(uintptr_t dst, insn_t newvalue)
1064 uintptr_t start = dst & ~(PAGE_MAX_SIZE-1);
1065 mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_WRITE);
1066 insn_t oldvalue = *(insn_t *)dst;
1067 *(insn_t *)dst = newvalue;
1068 mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_EXEC);
1072 insn_t clobber(void *fn, uintptr_t offset)
1074 clobbered = (uintptr_t)fn + offset;
1075 return set((uintptr_t)fn + offset, BREAK_INSN);
1078 void unclobber(void *fn, uintptr_t offset, insn_t oldvalue)
1080 set((uintptr_t)fn + offset, oldvalue);
1084 uintptr_t *getOffsets(void *symbol, const char *symname, uintptr_t *outBase)
1086 uintptr_t *result = (uintptr_t *)malloc(1000 * sizeof(uintptr_t));
1087 uintptr_t *end = result + 1000;
1088 uintptr_t *p = result;
1092 dladdr(symbol, &dl);
1094 // call `otool` on library
1095 unsetenv("DYLD_LIBRARY_PATH");
1096 unsetenv("DYLD_ROOT_PATH");
1097 unsetenv("DYLD_INSERT_LIBRARIES");
1098 unsetenv("DYLD_SHARED_REGION");
1099 unsetenv("DYLD_SHARED_CACHE_DIR");
1100 unsetenv("DYLD_SHARED_CACHE_DONT_VALIDATE");
1102 asprintf(&cmd, OTOOL "-tv -p _%s %s",
1103 symname, dl.dli_fname);
1104 testprintf("%s\n", cmd);
1105 FILE *disa = popen(cmd, "r");
1109 // read past "_symname:" line
1112 while ((line = fgetln(disa, &len))) {
1113 if (0 == strncmp(1+line, symname, MIN(len-1, strlen(symname)))) break;
1116 // read instructions and save offsets
1120 while (2 == fscanf(disa, "%lx%s%*[^\n]\n", &addr, op)) {
1121 if (base == 0) base = addr;
1122 if (0 != strncmp(op, "nop", 3)) {
1123 testassert(p < end);
1126 // assume nops are unreached (e.g. alignment padding)
1132 // Also add breakpoints in _objc_msgSend_uncached_impcache
1133 // (which is the slow path and has a frame to unwind)
1134 if (0 != strcmp(symname, "_objc_msgSend_uncached_impcache")) {
1136 uintptr_t *more_offsets = getOffsets(symbol, "_objc_msgSend_uncached_impcache", &base2);
1137 uintptr_t *q = more_offsets;
1138 // Skip prologue because it's imprecisely modeled in compact unwind
1139 testassert(*q != ~0UL);
1141 testassert(*q != ~0UL);
1143 while (*q != ~0UL) *p++ = *q++ + base2 - base;
1144 // Skip return because it's imprecisely modeled in compact unwind
1150 testassert(p > result);
1151 testassert(p < end);
1154 // hack: skip last instruction because libunwind blows up if it's
1155 // one byte long and followed by the next function with no NOPs first
1158 if (outBase) *outBase = base;
1162 void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret) __attribute__((noinline));
1163 void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret)
1165 uintptr_t message_ref[2];
1168 // copy to a local buffer to keep sel_arg un-fixed-up
1169 memcpy(message_ref, sel_arg, sizeof(message_ref));
1170 sel_arg = message_ref;
1172 if (!stret) callit(o, sel_arg, f);
1174 else callit_stret(o, sel_arg, f);
1176 else fail("stret?");
1180 void test_dw_forward(void)
1185 struct stret test_dw_forward_stret(void)
1190 // sub = ordinary receiver object
1191 // tagged = tagged receiver object
1192 // SEL = selector to send
1193 // sub_arg = arg to pass in receiver register (may be objc_super struct)
1194 // tagged_arg = arg to pass in receiver register (may be objc_super struct)
1195 // sel_arg = arg to pass in sel register (may be message_ref)
1196 // uncaughtAllowed is the number of acceptable unreachable instructions
1197 // (for example, the ones that handle the corrupt-cache-error case)
1198 void test_dw(const char *name, id sub, id tagged, bool stret,
1199 int uncaughtAllowed)
1201 SEL sel = @selector(a);
1203 testprintf("DWARF FOR %s%s\n", name, stret ? " (stret)" : "");
1205 // We need 2 SELs of each alignment so we can generate hash collisions.
1206 // sel_registerName() never returns those alignments because they
1207 // differ from malloc's alignment. So we create lots of compiled-in
1208 // SELs here and hope something fits.
1209 SEL lotsOfSels[] = {
1210 @selector(a1), @selector(a2), @selector(a3), @selector(a4),
1211 @selector(a5), @selector(a6), @selector(a7), @selector(a8),
1212 @selector(aa), @selector(ab), @selector(ac), @selector(ad),
1213 @selector(ae), @selector(af), @selector(ag), @selector(ah),
1214 @selector(A1), @selector(A2), @selector(A3), @selector(A4),
1215 @selector(A5), @selector(A6), @selector(A7), @selector(A8),
1216 @selector(AA), @selector(Ab), @selector(Ac), @selector(Ad),
1217 @selector(Ae), @selector(Af), @selector(Ag), @selector(Ah),
1218 @selector(bb1), @selector(bb2), @selector(bb3), @selector(bb4),
1219 @selector(bb5), @selector(bb6), @selector(bb7), @selector(bb8),
1220 @selector(bba), @selector(bbb), @selector(bbc), @selector(bbd),
1221 @selector(bbe), @selector(bbf), @selector(bbg), @selector(bbh),
1222 @selector(BB1), @selector(BB2), @selector(BB3), @selector(BB4),
1223 @selector(BB5), @selector(BB6), @selector(BB7), @selector(BB8),
1224 @selector(BBa), @selector(BBb), @selector(BBc), @selector(BBd),
1225 @selector(BBe), @selector(BBf), @selector(BBg), @selector(BBh),
1226 @selector(ccc1), @selector(ccc2), @selector(ccc3), @selector(ccc4),
1227 @selector(ccc5), @selector(ccc6), @selector(ccc7), @selector(ccc8),
1228 @selector(ccca), @selector(cccb), @selector(cccc), @selector(cccd),
1229 @selector(ccce), @selector(cccf), @selector(cccg), @selector(ccch),
1230 @selector(CCC1), @selector(CCC2), @selector(CCC3), @selector(CCC4),
1231 @selector(CCC5), @selector(CCC6), @selector(CCC7), @selector(CCC8),
1232 @selector(CCCa), @selector(CCCb), @selector(CCCc), @selector(CCCd),
1233 @selector(CCCe), @selector(CCCf), @selector(CCCg), @selector(CCCh),
1235 #define ALIGNCOUNT 16
1236 SEL sels[ALIGNCOUNT][2] = {{0}};
1237 for (int align = 0; align < ALIGNCOUNT; align++) {
1238 for (size_t i = 0; i < sizeof(lotsOfSels)/sizeof(lotsOfSels[0]); i++) {
1239 if ((uintptr_t)(void*)lotsOfSels[i] % ALIGNCOUNT == align) {
1240 if (sels[align][0]) {
1241 sels[align][1] = lotsOfSels[i];
1243 sels[align][0] = lotsOfSels[i];
1247 if (!sels[align][0]) fail("no SEL with alignment %d", align);
1248 if (!sels[align][1]) fail("only one SEL with alignment %d", align);
1251 void *fn = dlsym(RTLD_DEFAULT, name);
1254 // argument substitutions
1256 void *sub_arg = (void*)objc_unretainedPointer(sub);
1257 void *tagged_arg = (void*)objc_unretainedPointer(tagged);
1258 void *sel_arg = (void*)sel;
1260 struct objc_super sup_st = { sub, object_getClass(sub) };
1261 struct objc_super tagged_sup_st = { tagged, object_getClass(tagged) };
1262 struct { void *imp; SEL sel; } message_ref = { fn, sel };
1264 Class cache_cls = object_getClass(sub);
1266 if (strstr(name, "Super")) {
1267 // super version - replace receiver with objc_super
1268 // clear caches of superclass
1269 cache_cls = class_getSuperclass(cache_cls);
1271 tagged_arg = &tagged_sup_st;
1274 if (strstr(name, "_fixup")) {
1275 // fixup version - replace sel with message_ref
1276 sel_arg = &message_ref;
1280 uintptr_t *insnOffsets = getOffsets(fn, name, nil);
1282 int uncaughtCount = 0;
1283 for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
1284 offset = insnOffsets[oo];
1285 testprintf("OFFSET %lu\n", offset);
1287 insn_t saved_insn = clobber(fn, offset);
1291 if ((void*)objc_unretainedPointer(sub) == sub_arg) {
1293 testprintf(" nil\n");
1294 CALLIT(nil, sel_arg, sel, fn, stret);
1295 CALLIT(nil, sel_arg, sel, fn, stret);
1300 testprintf(" uncached\n");
1301 _objc_flush_caches(cache_cls);
1302 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1303 _objc_flush_caches(cache_cls);
1304 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1308 testprintf(" cached\n");
1309 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1310 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1314 testprintf(" uncached,tagged\n");
1315 _objc_flush_caches(cache_cls);
1316 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1317 _objc_flush_caches(cache_cls);
1318 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1322 testprintf(" cached,tagged\n");
1323 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1324 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1326 // multiple SEL alignments, collisions, wraps
1328 for (int a = 0; a < ALIGNCOUNT; a++) {
1329 testprintf(" cached, SEL alignment %d\n", a);
1331 // Count both up and down to be independent of
1332 // implementation's cache scan direction
1334 _objc_flush_caches(cache_cls);
1335 for (int x2 = 0; x2 < 1; x2++) {
1336 for (int s = 0; s < 4; s++) {
1337 int align = (a+s) % ALIGNCOUNT;
1338 CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
1339 CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
1343 _objc_flush_caches(cache_cls);
1344 for (int x2 = 0; x2 < 1; x2++) {
1345 for (int s = 0; s < 4; s++) {
1346 int align = abs(a-s) % ALIGNCOUNT;
1347 CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
1348 CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
1353 unclobber(fn, offset, saved_insn);
1355 // remember offsets that were caught by none of the above
1357 insnOffsets[oo] = 0;
1360 testprintf("offset %s+%lu not caught (%d/%d)\n",
1361 name, offset, uncaughtCount, uncaughtAllowed);
1365 // Complain if too many offsets went uncaught.
1366 // Acceptably-uncaught offsets include the corrupt-cache-error handler.
1367 if (uncaughtCount != uncaughtAllowed) {
1368 for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
1369 if (insnOffsets[oo]) {
1370 fprintf(stderr, "BAD: offset %s+%lu not caught\n",
1371 name, insnOffsets[oo]);
1374 fail("wrong instructions not reached for %s (missed %d, expected %d)",
1375 name, uncaughtCount, uncaughtAllowed);
1386 void test_basic(id receiver)
1390 struct stret stretval;
1395 // message uncached long long
1396 // message uncached stret
1397 // message uncached fpret
1398 // message uncached fpret long double
1399 // message uncached noarg (as above)
1401 // message cached long long
1402 // message cached stret
1403 // message cached fpret
1404 // message cached fpret long double
1405 // message cached noarg (as above)
1406 // fixme verify that uncached lookup didn't happen the 2nd time?
1408 for (int i = 0; i < 5; i++) {
1409 testprintf("idret\n");
1412 idval = [receiver idret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1413 testassert(state == 101);
1414 testassert(idval == ID_RESULT);
1416 testprintf("llret\n");
1418 llval = [receiver llret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1419 testassert(state == 102);
1420 testassert(llval == LL_RESULT);
1422 testprintf("stret\n");
1424 stretval = [receiver stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1425 testassert(state == 103);
1426 testassert(stret_equal(stretval, STRET_RESULT));
1428 testprintf("fpret\n");
1430 fpval = [receiver fpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1431 testassert(state == 104);
1432 testassert(fpval == FP_RESULT);
1434 testprintf("lfpret\n");
1436 lfpval = [receiver lfpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1437 testassert(state == 105);
1438 testassert(lfpval == LFP_RESULT);
1441 // explicitly call noarg messenger, even if compiler doesn't emit it
1443 testprintf("idret noarg\n");
1445 idval = ((typeof(idmsg0))objc_msgSend_noarg)(receiver, @selector(idret_noarg));
1446 testassert(state == 111);
1447 testassert(idval == ID_RESULT);
1450 testprintf("llret noarg\n");
1451 llval = ((typeof(llmsg0))objc_msgSend_noarg)(receiver, @selector(llret_noarg));
1452 testassert(state == 112);
1453 testassert(llval == LL_RESULT);
1455 no objc_msgSend_stret_noarg
1457 stretval = ((typeof(stretmsg0))objc_msgSend_stret_noarg)(receiver, @selector(stret_noarg));
1458 stretval = [receiver stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1459 testassert(state == 113);
1460 testassert(stret_equal(stretval, STRET_RESULT));
1463 testprintf("fpret noarg\n");
1465 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(receiver, @selector(fpret_noarg));
1466 testassert(state == 114);
1467 testassert(fpval == FP_RESULT);
1469 # if !__i386__ && !__x86_64__
1470 testprintf("lfpret noarg\n");
1472 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(receiver, @selector(lfpret_noarg));
1473 testassert(state == 115);
1474 testassert(lfpval == LFP_RESULT);
1479 testprintf("basic done\n");
1489 struct stret stretval;
1494 struct stret *stretptr;
1499 uint64_t targetTime;
1507 id (*idfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
1508 long long (*llfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
1509 struct stret (*stretfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
1510 double (*fpfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
1511 long double (*lfpfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
1513 id (*idmsg)(id, SEL, 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));
1514 id (*idmsgsuper)(struct objc_super *, SEL, 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));
1515 long long (*llmsg)(id, SEL, 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));
1516 struct stret (*stretmsg)(id, SEL, 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));
1517 struct stret (*stretmsgsuper)(struct objc_super *, SEL, 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));
1518 double (*fpmsg)(id, SEL, 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));
1519 long double (*lfpmsg)(id, SEL, 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));
1521 // get +initialize out of the way
1523 #if OBJC_HAVE_TAGGED_POINTERS
1527 ID_RESULT = [Super new];
1529 Sub *sub = [Sub new];
1530 Super *sup = [Super new];
1531 #if OBJC_HAVE_TAGGED_POINTERS
1532 TaggedSub *tagged = objc_unretainedObject(_objc_makeTaggedPointer(OBJC_TAG_7, 999));
1535 // Basic cached and uncached dispatch.
1536 // Do this first before anything below caches stuff.
1537 testprintf("basic\n");
1539 #if OBJC_HAVE_TAGGED_POINTERS
1540 testprintf("basic tagged\n");
1544 idmethod = class_getInstanceMethod([Super class], @selector(idret::::::::::::::::::::::::::::));
1545 testassert(idmethod);
1546 llmethod = class_getInstanceMethod([Super class], @selector(llret::::::::::::::::::::::::::::));
1547 testassert(llmethod);
1548 stretmethod = class_getInstanceMethod([Super class], @selector(stret::::::::::::::::::::::::::::));
1549 testassert(stretmethod);
1550 fpmethod = class_getInstanceMethod([Super class], @selector(fpret::::::::::::::::::::::::::::));
1551 testassert(fpmethod);
1552 lfpmethod = class_getInstanceMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::));
1553 testassert(lfpmethod);
1555 idfn = (id (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
1556 llfn = (long long (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
1557 stretfn = (struct stret (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke_stret;
1558 fpfn = (double (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
1559 lfpfn = (long double (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
1561 // cached message performance
1562 // catches failure to cache or (abi=2) failure to fixup (#5584187)
1563 // fixme unless they all fail
1564 // `.align 4` matches loop alignment to make -O0 work
1566 testprintf("time checks\n");
1588 // Some of these times have high variance on some compilers.
1589 // The errors we're trying to catch should be catastrophically slow,
1590 // so the margins here are generous to avoid false failures.
1592 // Use voidret because id return is too slow for perf test with ARC.
1594 // Pick smallest of voidret_nop and voidret_nop2 time
1595 // in the hopes that one of them didn't collide in the method cache.
1597 #define COUNT 1000000
1599 startTime = mach_absolute_time();
1601 for (i = 0; i < COUNT; i++) {
1604 totalTime = mach_absolute_time() - startTime;
1605 testprintf("time: voidret %llu\n", totalTime);
1606 targetTime = totalTime;
1608 startTime = mach_absolute_time();
1610 for (i = 0; i < COUNT; i++) {
1613 totalTime = mach_absolute_time() - startTime;
1614 testprintf("time: voidret2 %llu\n", totalTime);
1615 if (totalTime < targetTime) targetTime = totalTime;
1617 startTime = mach_absolute_time();
1619 for (i = 0; i < COUNT; i++) {
1622 totalTime = mach_absolute_time() - startTime;
1623 timecheck("llret ", totalTime, targetTime * 0.7, targetTime * 2.0);
1625 startTime = mach_absolute_time();
1627 for (i = 0; i < COUNT; i++) {
1630 totalTime = mach_absolute_time() - startTime;
1631 timecheck("stret ", totalTime, targetTime * 0.7, targetTime * 5.0);
1633 startTime = mach_absolute_time();
1635 for (i = 0; i < COUNT; i++) {
1638 totalTime = mach_absolute_time() - startTime;
1639 timecheck("fpret ", totalTime, targetTime * 0.7, targetTime * 4.0);
1641 startTime = mach_absolute_time();
1643 for (i = 0; i < COUNT; i++) {
1646 totalTime = mach_absolute_time() - startTime;
1647 timecheck("lfpret", totalTime, targetTime * 0.7, targetTime * 4.0);
1650 // Removing this testwarn(), or changing voidret_nop to nop;ret,
1651 // changes the voidret_nop and stret_nop times above by a factor of 2.
1652 testwarn("rdar://13896922 nop;ret is faster than ret?");
1658 // method_invoke long long
1659 // method_invoke_stret stret
1660 // method_invoke_stret fpret
1661 // method_invoke fpret long double
1662 testprintf("method_invoke\n");
1668 idval = (*idfn)(sup, idmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1669 testassert(state == 1);
1670 testassert(idval == ID_RESULT);
1673 llval = (*llfn)(sup, llmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1674 testassert(state == 2);
1675 testassert(llval == LL_RESULT);
1678 stretval = (*stretfn)(sup, stretmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1679 testassert(state == 3);
1680 testassert(stret_equal(stretval, STRET_RESULT));
1683 fpval = (*fpfn)(sup, fpmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1684 testassert(state == 4);
1685 testassert(fpval == FP_RESULT);
1688 lfpval = (*lfpfn)(sup, lfpmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1689 testassert(state == 5);
1690 testassert(lfpval == LFP_RESULT);
1694 // message to nil long long
1695 // message to nil stret
1696 // message to nil fpret
1697 // message to nil fpret long double
1698 // Use NIL_RECEIVER to avoid compiler optimizations.
1699 testprintf("message to nil\n");
1703 idval = [(id)NIL_RECEIVER idret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1704 testassert(state == 0);
1705 testassert(idval == nil);
1709 llval = [(id)NIL_RECEIVER llret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1710 testassert(state == 0);
1711 testassert(llval == 0LL);
1715 stretval = [(id)NIL_RECEIVER stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1716 testassert(state == 0);
1718 testassert(0 == memcmp(&stretval, &zero, sizeof(stretval)));
1720 // no stret result guarantee
1724 // check stret return register
1727 stretptr = ((struct stret *(*)(struct stret *, id, SEL))objc_msgSend_stret)
1728 (&stretval, nil, @selector(stret_nop));
1729 testassert(stretptr == &stretval);
1730 testassert(state == 0);
1731 // no stret result guarantee for hand-written calls, even with clang
1735 // check struct-return address stack pop
1736 for (int i = 0; i < 10000000; i++) {
1738 ((struct stret (*)(id, SEL))objc_msgSend_stret)
1739 (nil, @selector(stret_nop));
1745 fpval = [(id)NIL_RECEIVER fpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1746 testassert(state == 0);
1747 testassert(fpval == 0.0);
1750 lfpval = LFP_RESULT;
1751 lfpval = [(id)NIL_RECEIVER lfpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1752 testassert(state == 0);
1753 testassert(lfpval == 0.0);
1755 // message to nil, different struct types
1756 // This verifies that ordinary objc_msgSend() erases enough registers
1757 // for structs that return in registers.
1758 #define TEST_NIL_STRUCT(i,n) \
1760 struct stret_##i##n z; \
1761 bzero(&z, sizeof(z)); \
1762 [Super stret_i##n##_nonzero]; \
1763 [Super stret_d##n##_nonzero]; \
1764 struct stret_##i##n val = [(id)NIL_RECEIVER stret_##i##n##_zero]; \
1765 testassert(0 == memcmp(&z, &val, sizeof(val))); \
1768 TEST_NIL_STRUCT(i,1);
1769 TEST_NIL_STRUCT(i,2);
1770 TEST_NIL_STRUCT(i,3);
1771 TEST_NIL_STRUCT(i,4);
1772 TEST_NIL_STRUCT(i,5);
1773 TEST_NIL_STRUCT(i,6);
1774 TEST_NIL_STRUCT(i,7);
1775 TEST_NIL_STRUCT(i,8);
1776 TEST_NIL_STRUCT(i,9);
1779 testwarn("rdar://16267205 i386 struct{float} and struct{double}");
1781 TEST_NIL_STRUCT(d,1);
1783 TEST_NIL_STRUCT(d,2);
1784 TEST_NIL_STRUCT(d,3);
1785 TEST_NIL_STRUCT(d,4);
1786 TEST_NIL_STRUCT(d,5);
1787 TEST_NIL_STRUCT(d,6);
1788 TEST_NIL_STRUCT(d,7);
1789 TEST_NIL_STRUCT(d,8);
1790 TEST_NIL_STRUCT(d,9);
1794 // message to nil noarg
1795 // explicitly call noarg messenger, even if compiler doesn't emit it
1798 idval = ((typeof(idmsg0))objc_msgSend_noarg)(nil, @selector(idret_noarg));
1799 testassert(state == 0);
1800 testassert(idval == nil);
1804 llval = ((typeof(llmsg0))objc_msgSend_noarg)(nil, @selector(llret_noarg));
1805 testassert(state == 0);
1806 testassert(llval == 0LL);
1808 // no stret_noarg messenger
1813 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(nil, @selector(fpret_noarg));
1814 testassert(state == 0);
1815 testassert(fpval == 0.0);
1817 # if !__i386__ && !__x86_64__
1819 lfpval = LFP_RESULT;
1820 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(nil, @selector(lfpret_noarg));
1821 testassert(state == 0);
1822 testassert(lfpval == 0.0);
1828 // rdar://8271364 objc_msgSendSuper2 must not change objc_super
1829 testprintf("super struct\n");
1830 struct objc_super sup_st = {
1832 object_getClass(sub),
1839 idval = ((id(*)(struct objc_super *, SEL, 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::::::::::::::::::::::::::::), 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);
1840 testassert(state == 1);
1841 testassert(idval == ID_RESULT);
1842 testassert(sup_st.receiver == sub);
1843 testassert(sup_st.super_class == object_getClass(sub));
1847 stretval = ((struct stret(*)(struct objc_super *, SEL, 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::::::::::::::::::::::::::::), 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);
1848 testassert(state == 3);
1849 testassert(stret_equal(stretval, STRET_RESULT));
1850 testassert(sup_st.receiver == sub);
1851 testassert(sup_st.super_class == object_getClass(sub));
1854 #if __OBJC2__ && !__arm64__
1855 // Debug messengers.
1856 testprintf("debug messengers\n");
1859 idmsg = (typeof(idmsg))objc_msgSend_debug;
1861 idval = (*idmsg)(sub, @selector(idret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1862 testassert(state == 101);
1863 testassert(idval == ID_RESULT);
1866 llmsg = (typeof(llmsg))objc_msgSend_debug;
1868 llval = (*llmsg)(sub, @selector(llret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1869 testassert(state == 102);
1870 testassert(llval == LL_RESULT);
1873 stretmsg = (typeof(stretmsg))objc_msgSend_stret_debug;
1875 stretval = (*stretmsg)(sub, @selector(stret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1876 testassert(state == 103);
1877 testassert(stret_equal(stretval, STRET_RESULT));
1880 sup_st.receiver = sub;
1881 sup_st.super_class = object_getClass(sub);
1882 idmsgsuper = (typeof(idmsgsuper))objc_msgSendSuper2_debug;
1884 idval = (*idmsgsuper)(&sup_st, @selector(idret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1885 testassert(state == 1);
1886 testassert(idval == ID_RESULT);
1889 sup_st.receiver = sub;
1890 sup_st.super_class = object_getClass(sub);
1891 stretmsgsuper = (typeof(stretmsgsuper))objc_msgSendSuper2_stret_debug;
1893 stretval = (*stretmsgsuper)(&sup_st, @selector(stret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1894 testassert(state == 3);
1895 testassert(stret_equal(stretval, STRET_RESULT));
1899 fpmsg = (typeof(fpmsg))objc_msgSend_fpret_debug;
1901 fpval = (*fpmsg)(sub, @selector(fpret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1902 testassert(state == 104);
1903 testassert(fpval == FP_RESULT);
1907 lfpmsg = (typeof(lfpmsg))objc_msgSend_fpret_debug;
1909 lfpval = (*lfpmsg)(sub, @selector(lfpret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
1910 testassert(state == 105);
1911 testassert(lfpval == LFP_RESULT);
1921 testwarn("no unwind tables in this configuration");
1923 // DWARF unwind tables
1924 testprintf("unwind tables\n");
1926 // install exception handler
1927 struct sigaction act;
1928 act.sa_sigaction = sigtrap;
1930 act.sa_flags = SA_SIGINFO;
1931 sigaction(SIGTRAP, &act, NULL);
1933 SubDW *dw = [[SubDW alloc] init];
1935 objc_setForwardHandler((void*)test_dw_forward, (void*)test_dw_forward_stret);
1938 test_dw("objc_msgSend", dw, tagged, false, 2);
1939 test_dw("objc_msgSend_stret", dw, tagged, true, 4);
1940 test_dw("objc_msgSend_fpret", dw, tagged, false, 2);
1941 test_dw("objc_msgSend_fp2ret", dw, tagged, false, 2);
1942 test_dw("objc_msgSendSuper", dw, tagged, false, 2);
1943 test_dw("objc_msgSendSuper2", dw, tagged, false, 2);
1944 test_dw("objc_msgSendSuper_stret", dw, tagged, true, 4);
1945 test_dw("objc_msgSendSuper2_stret", dw, tagged, true, 4);
1947 test_dw("objc_msgSend", dw, dw, false, 10);
1948 test_dw("objc_msgSend_stret", dw, dw, true, 10);
1949 test_dw("objc_msgSend_fpret", dw, dw, false, 10);
1950 test_dw("objc_msgSendSuper", dw, dw, false, 10);
1951 test_dw("objc_msgSendSuper2", dw, dw, false, 10);
1952 test_dw("objc_msgSendSuper_stret", dw, dw, true, 10);
1953 test_dw("objc_msgSendSuper2_stret", dw, dw, true, 10);
1955 test_dw("objc_msgSend", dw, tagged, false, 2);
1956 test_dw("objc_msgSendSuper", dw, tagged, false, 2);
1957 test_dw("objc_msgSendSuper2", dw, tagged, false, 2);
1959 # error unknown architecture
1962 // DWARF unwind tables