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>
25 # define ALIGN_() asm(".align 4");
28 @interface Super : TestRoot @end
30 @interface Sub : Super @end
36 // for typeof() shorthand only
37 id (*idmsg0)(id, SEL) __attribute__((unused));
38 long long (*llmsg0)(id, SEL) __attribute__((unused));
39 // struct stret (*stretmsg0)(id, SEL) __attribute__((unused));
40 double (*fpmsg0)(id, SEL) __attribute__((unused));
41 long double (*lfpmsg0)(id, SEL) __attribute__((unused));
44 #define CHECK_ARGS(sel) \
46 testassert(self == SELF); \
47 testassert(_cmd == sel_registerName(#sel "::::::::::::::::::::::::::::"));\
48 testassert(i1 == 1); \
49 testassert(i2 == 2); \
50 testassert(i3 == 3); \
51 testassert(i4 == 4); \
52 testassert(i5 == 5); \
53 testassert(i6 == 6); \
54 testassert(i7 == 7); \
55 testassert(i8 == 8); \
56 testassert(i9 == 9); \
57 testassert(i10 == 10); \
58 testassert(i11 == 11); \
59 testassert(i12 == 12); \
60 testassert(i13 == 13); \
61 testassert(f1 == 1.0); \
62 testassert(f2 == 2.0); \
63 testassert(f3 == 3.0); \
64 testassert(f4 == 4.0); \
65 testassert(f5 == 5.0); \
66 testassert(f6 == 6.0); \
67 testassert(f7 == 7.0); \
68 testassert(f8 == 8.0); \
69 testassert(f9 == 9.0); \
70 testassert(f10 == 10.0); \
71 testassert(f11 == 11.0); \
72 testassert(f12 == 12.0); \
73 testassert(f13 == 13.0); \
74 testassert(f14 == 14.0); \
75 testassert(f15 == 15.0); \
78 #define CHECK_ARGS_NOARG(sel) \
80 testassert(self == SELF); \
81 testassert(_cmd == sel_registerName(#sel "_noarg"));\
85 long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
86 double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
87 long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
88 // STRET_RESULT in test.h
90 static struct stret zero;
94 -(struct stret)stret { return STRET_RESULT; }
97 (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
105 (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
112 -(struct stret)stret:
113 (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
121 (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
128 -(long double)lfpret:
129 (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
139 CHECK_ARGS_NOARG(idret);
144 -(long long)llret_noarg
146 CHECK_ARGS_NOARG(llret);
151 -(struct stret)stret_noarg
153 CHECK_ARGS_NOARG(stret);
160 CHECK_ARGS_NOARG(fpret);
165 -(long double)lfpret_noarg
167 CHECK_ARGS_NOARG(lfpret);
183 -(long long)llret_nop
188 -(struct stret)stret_nop
198 -(long double)lfpret_nop
206 (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
208 fail("+idret called instead of -idret");
213 (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
215 fail("+llret called instead of -llret");
219 +(struct stret)stret:
220 (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
222 fail("+stret called instead of -stret");
227 (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
229 fail("+fpret called instead of -fpret");
233 +(long double)lfpret:
234 (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
236 fail("+lfpret called instead of -lfpret");
242 fail("+idret_noarg called instead of -idret_noarg");
243 CHECK_ARGS_NOARG(idret);
246 +(long long)llret_noarg
248 fail("+llret_noarg called instead of -llret_noarg");
249 CHECK_ARGS_NOARG(llret);
252 +(struct stret)stret_noarg
254 fail("+stret_noarg called instead of -stret_noarg");
255 CHECK_ARGS_NOARG(stret);
260 fail("+fpret_noarg called instead of -fpret_noarg");
261 CHECK_ARGS_NOARG(fpret);
264 +(long double)lfpret_noarg
266 fail("+lfpret_noarg called instead of -lfpret_noarg");
267 CHECK_ARGS_NOARG(lfpret);
276 (int)i1:(int)i2:(int)i3:(int)i4:(int)i5:(int)i6:(int)i7:(int)i8:(int)i9:(int)i10:(int)i11:(int)i12:(int)i13 :(double)f1:(double)f2:(double)f3:(double)f4:(double)f5:(double)f6:(double)f7:(double)f8:(double)f9:(double)f10:(double)f11:(double)f12:(double)f13:(double)f14:(double)f15
281 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];
282 testassert(state == 1);
283 testassert(result == ID_RESULT);
289 (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
294 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];
295 testassert(state == 2);
296 testassert(result == LL_RESULT);
301 -(struct stret)stret:
302 (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
307 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];
308 testassert(state == 3);
309 testassert(stret_equal(result, STRET_RESULT));
315 (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
320 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];
321 testassert(state == 4);
322 testassert(result == FP_RESULT);
327 -(long double)lfpret:
328 (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
333 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];
334 testassert(state == 5);
335 testassert(result == LFP_RESULT);
344 CHECK_ARGS_NOARG(idret);
346 result = [super idret_noarg];
347 testassert(state == 11);
348 testassert(result == ID_RESULT);
353 -(long long)llret_noarg
356 CHECK_ARGS_NOARG(llret);
358 result = [super llret_noarg];
359 testassert(state == 12);
360 testassert(result == LL_RESULT);
365 -(struct stret)stret_noarg
368 CHECK_ARGS_NOARG(stret);
370 result = [super stret_noarg];
371 testassert(state == 13);
372 testassert(stret_equal(result, STRET_RESULT));
380 CHECK_ARGS_NOARG(fpret);
382 result = [super fpret_noarg];
383 testassert(state == 14);
384 testassert(result == FP_RESULT);
389 -(long double)lfpret_noarg
392 CHECK_ARGS_NOARG(lfpret);
394 result = [super lfpret_noarg];
395 testassert(state == 15);
396 testassert(result == LFP_RESULT);
406 @interface TaggedSub : Sub @end
408 @implementation TaggedSub : Sub
410 #define TAG_VALUE(tagSlot, value) (objc_unretainedObject((void*)(1UL | (((uintptr_t)(tagSlot)) << 1) | (((uintptr_t)(value)) << 4))))
414 _objc_insert_tagged_isa(2, self);
419 // DWARF checking machinery
423 #include <sys/mman.h>
424 #include <libunwind.h>
426 #define UNW_STEP_SUCCESS 1
427 #define UNW_STEP_END 0
441 void handle_exception(x86_thread_state64_t *state)
448 err = unw_init_local(&curs, (unw_context_t *)state);
451 step = unw_step(&curs);
452 testassert(step == UNW_STEP_SUCCESS);
454 err = unw_get_reg(&curs, UNW_X86_64_R12, ®);
456 testassert(reg == r12);
458 err = unw_get_reg(&curs, UNW_X86_64_R13, ®);
460 testassert(reg == r13);
462 err = unw_get_reg(&curs, UNW_X86_64_R14, ®);
464 testassert(reg == r14);
466 err = unw_get_reg(&curs, UNW_X86_64_R15, ®);
468 testassert(reg == r15);
470 err = unw_get_reg(&curs, UNW_X86_64_RBX, ®);
472 testassert(reg == rbx);
474 err = unw_get_reg(&curs, UNW_X86_64_RBP, ®);
476 testassert(reg == rbp);
478 err = unw_get_reg(&curs, UNW_X86_64_RSP, ®);
480 testassert(reg == rsp);
482 err = unw_get_reg(&curs, UNW_REG_IP, ®);
484 testassert(reg == rip);
487 // set thread state to unwound state
501 void sigtrap(int sig, siginfo_t *info, void *cc)
503 ucontext_t *uc = (ucontext_t *)cc;
504 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
506 testprintf(" handled\n");
508 testassert(sig == SIGTRAP);
509 testassert((uintptr_t)info->si_addr-1 == clobbered);
511 handle_exception(&mc->__ss);
512 // handle_exception changed register state for continuation
516 uint8_t set(uintptr_t dst, uint8_t newvalue)
518 uintptr_t start = dst & ~(4096-1);
519 mprotect((void*)start, 4096, PROT_READ|PROT_WRITE);
521 uint8_t oldvalue = *(uint8_t *)dst;
522 *(uint8_t *)dst = newvalue;
523 mprotect((void*)start, 4096, PROT_READ|PROT_EXEC);
527 uint8_t clobber(void *fn, uintptr_t offset)
529 clobbered = (uintptr_t)fn + offset;
530 return set((uintptr_t)fn + offset, 0xcc /*int3*/);
533 void unclobber(void *fn, uintptr_t offset, uint8_t oldvalue)
535 set((uintptr_t)fn + offset, oldvalue);
539 extern void callit(void *obj, void *sel, void *fn);
540 extern struct stret callit_stret(void *obj, void *sel, void *fn);
547 // save rsp and rip registers to variables
548 "\n movq (%rsp), %r10"
549 "\n movq %r10, _rip(%rip)"
550 "\n movq %rsp, _rsp(%rip)"
551 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
552 // save other non-volatile registers to variables
553 "\n movq %rbx, _rbx(%rip)"
554 "\n movq %rbp, _rbp(%rip)"
555 "\n movq %r12, _r12(%rip)"
556 "\n movq %r13, _r13(%rip)"
557 "\n movq %r14, _r14(%rip)"
558 "\n movq %r15, _r15(%rip)"
564 "\n .globl _callit_stret"
566 // save rsp and rip registers to variables
567 "\n movq (%rsp), %r10"
568 "\n movq %r10, _rip(%rip)"
569 "\n movq %rsp, _rsp(%rip)"
570 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
571 // save other non-volatile registers to variables
572 "\n movq %rbx, _rbx(%rip)"
573 "\n movq %rbp, _rbp(%rip)"
574 "\n movq %r12, _r12(%rip)"
575 "\n movq %r13, _r13(%rip)"
576 "\n movq %r14, _r14(%rip)"
577 "\n movq %r15, _r15(%rip)"
581 uintptr_t *getOffsets(void *symbol, const char *symname)
583 uintptr_t *result = (uintptr_t *)malloc(4096 * sizeof(uintptr_t));
584 uintptr_t *end = result + 4096;
585 uintptr_t *p = result;
591 // call `otool` on library
592 unsetenv("DYLD_LIBRARY_PATH");
593 unsetenv("DYLD_ROOT_PATH");
594 unsetenv("DYLD_INSERT_LIBRARIES");
596 asprintf(&cmd, "/usr/bin/xcrun otool -arch x86_64 -tv -p _%s %s",
597 symname, dl.dli_fname);
598 FILE *disa = popen(cmd, "r");
602 // read past "_symname:" line
605 while ((line = fgetln(disa, &len))) {
606 if (0 == strncmp(1+line, symname, MIN(len-1, strlen(symname)))) break;
609 // read instructions and save offsets
613 while (2 == fscanf(disa, "%lx%s%*[^\n]\n", &addr, op)) {
614 if (base == 0) base = addr;
615 if (0 != strncmp(op, "nop", 3)) {
619 // assume nops are unreached (e.g. alignment padding)
624 testassert(p > result);
630 void CALLIT(void *o, void *sel_arg, SEL s, void *f) __attribute__((noinline));
631 void CALLIT(void *o, void *sel_arg, SEL s, void *f)
633 uintptr_t message_ref[2];
636 // copy to a local buffer to keep sel_arg un-fixed-up
637 memcpy(message_ref, sel_arg, sizeof(message_ref));
638 sel_arg = message_ref;
640 if (s == @selector(idret_nop)) callit(o, sel_arg, f);
641 else if (s == @selector(fpret_nop)) callit(o, sel_arg, f);
642 else if (s == @selector(stret_nop)) callit_stret(o, sel_arg, f);
643 else fail("test_dw selector");
646 // sub = ordinary receiver object
647 // tagged = tagged receiver object
648 // SEL = selector to send
649 // sub_arg = arg to pass in receiver register (may be objc_super struct)
650 // tagged_arg = arg to pass in receiver register (may be objc_super struct)
651 // sel_arg = arg to pass in sel register (may be message_ref)
652 void test_dw(const char *name, id sub, id tagged, SEL sel)
654 testprintf("DWARF FOR %s\n", name);
656 void *fn = dlsym(RTLD_DEFAULT, name);
659 // argument substitutions
661 void *sub_arg = (void*)objc_unretainedPointer(sub);
662 void *tagged_arg = (void*)objc_unretainedPointer(tagged);
663 void *sel_arg = (void*)sel;
665 struct objc_super sup_st = { sub, object_getClass(sub) };
666 struct objc_super tagged_sup_st = { tagged, object_getClass(tagged) };
667 struct { void *imp; SEL sel; } message_ref = { fn, sel };
669 if (strstr(name, "Super")) {
670 // super version - replace receiver with objc_super
672 tagged_arg = &tagged_sup_st;
675 if (strstr(name, "_fixup")) {
676 // fixup version - replace sel with message_ref
677 sel_arg = &message_ref;
681 uintptr_t *insnOffsets = getOffsets(fn, name);
682 uintptr_t *offsetp = insnOffsets;
684 while ((offset = *offsetp++) != ~0UL) {
685 testprintf("OFFSET %lu\n", offset);
687 uint8_t insn_byte = clobber(fn, offset);
691 if ((void*)objc_unretainedPointer(sub) == sub_arg) {
693 testprintf(" nil\n");
694 CALLIT(nil, sel_arg, sel, fn);
695 CALLIT(nil, sel_arg, sel, fn);
700 testprintf(" uncached\n");
701 _objc_flush_caches(object_getClass(sub));
702 CALLIT(sub_arg, sel_arg, sel, fn);
703 _objc_flush_caches(object_getClass(sub));
704 CALLIT(sub_arg, sel_arg, sel, fn);
708 testprintf(" cached\n");
709 CALLIT(sub_arg, sel_arg, sel, fn);
710 CALLIT(sub_arg, sel_arg, sel, fn);
714 testprintf(" uncached,tagged\n");
715 _objc_flush_caches(object_getClass(tagged));
716 CALLIT(tagged_arg, sel_arg, sel, fn);
717 _objc_flush_caches(object_getClass(tagged));
718 CALLIT(tagged_arg, sel_arg, sel, fn);
722 testprintf(" cached,tagged\n");
723 CALLIT(tagged_arg, sel_arg, sel, fn);
724 CALLIT(tagged_arg, sel_arg, sel, fn);
726 unclobber(fn, offset, insn_byte);
728 // require at least one path above to trip this offset
729 if (!caught) fprintf(stderr, "OFFSET %lu NOT CAUGHT\n", offset);
738 void test_basic(id receiver)
742 struct stret stretval;
747 // message uncached long long
748 // message uncached stret
749 // message uncached fpret
750 // message uncached fpret long double
751 // message uncached noarg (as above)
753 // message cached long long
754 // message cached stret
755 // message cached fpret
756 // message cached fpret long double
757 // message cached noarg (as above)
758 // fixme verify that uncached lookup didn't happen the 2nd time?
760 for (int i = 0; i < 5; i++) {
763 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];
764 testassert(state == 101);
765 testassert(idval == ID_RESULT);
768 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];
769 testassert(state == 102);
770 testassert(llval == LL_RESULT);
773 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];
774 testassert(state == 103);
775 testassert(stret_equal(stretval, STRET_RESULT));
778 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];
779 testassert(state == 104);
780 testassert(fpval == FP_RESULT);
783 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];
784 testassert(state == 105);
785 testassert(lfpval == LFP_RESULT);
788 // explicitly call noarg messenger, even if compiler doesn't emit it
791 idval = ((typeof(idmsg0))objc_msgSend_noarg)(receiver, @selector(idret_noarg));
792 testassert(state == 111);
793 testassert(idval == ID_RESULT);
796 llval = ((typeof(llmsg0))objc_msgSend_noarg)(receiver, @selector(llret_noarg));
797 testassert(state == 112);
798 testassert(llval == LL_RESULT);
800 no objc_msgSend_stret_noarg
802 stretval = ((typeof(stretmsg0))objc_msgSend_stret_noarg)(receiver, @selector(stret_noarg));
803 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];
804 testassert(state == 113);
805 testassert(stret_equal(stretval, STRET_RESULT));
809 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(receiver, @selector(fpret_noarg));
810 testassert(state == 114);
811 testassert(fpval == FP_RESULT);
813 # if !__i386__ && !__x86_64__
815 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(receiver, @selector(lfpret_noarg));
816 testassert(state == 115);
817 testassert(lfpval == LFP_RESULT);
830 struct stret stretval;
844 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);
845 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);
846 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);
847 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);
848 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);
850 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));
851 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));
852 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));
853 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));
854 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));
855 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));
856 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));
858 // get +initialize out of the way
864 ID_RESULT = [Super new];
866 Sub *sub = [Sub new];
867 Super *sup = [Super new];
869 TaggedSub *tagged = TAG_VALUE(2, 999);
872 // Basic cached and uncached dispatch.
873 // Do this first before anything below caches stuff.
879 idmethod = class_getInstanceMethod([Super class], @selector(idret::::::::::::::::::::::::::::));
880 testassert(idmethod);
881 llmethod = class_getInstanceMethod([Super class], @selector(llret::::::::::::::::::::::::::::));
882 testassert(llmethod);
883 stretmethod = class_getInstanceMethod([Super class], @selector(stret::::::::::::::::::::::::::::));
884 testassert(stretmethod);
885 fpmethod = class_getInstanceMethod([Super class], @selector(fpret::::::::::::::::::::::::::::));
886 testassert(fpmethod);
887 lfpmethod = class_getInstanceMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::));
888 testassert(lfpmethod);
890 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;
891 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;
892 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;
893 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;
894 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;
896 // cached message performance
897 // catches failure to cache or (abi=2) failure to fixup (#5584187)
898 // fixme unless they all fail
899 // `.align 4` matches loop alignment to make -O0 work
918 // Some of these times have high variance on some compilers.
919 // The errors we're trying to catch should be catastrophically slow,
920 // so the margins here are generous to avoid false failures.
922 #define COUNT 1000000
923 startTime = mach_absolute_time();
925 for (i = 0; i < COUNT; i++) {
926 [sub voidret_nop]; // id return is too slow for perf test with ARC
928 totalTime = mach_absolute_time() - startTime;
929 testprintf("time: idret %llu\n", totalTime);
930 targetTime = totalTime;
932 startTime = mach_absolute_time();
934 for (i = 0; i < COUNT; i++) {
935 [sub voidret_nop]; // id return is too slow for perf test with ARC
937 totalTime = mach_absolute_time() - startTime;
938 testprintf("time: idret %llu\n", totalTime);
939 targetTime = totalTime;
941 startTime = mach_absolute_time();
943 for (i = 0; i < COUNT; i++) {
946 totalTime = mach_absolute_time() - startTime;
947 timecheck("llret ", totalTime, targetTime * 0.7, targetTime * 2.0);
949 startTime = mach_absolute_time();
951 for (i = 0; i < COUNT; i++) {
954 totalTime = mach_absolute_time() - startTime;
955 timecheck("stret ", totalTime, targetTime * 0.7, targetTime * 5.0);
957 startTime = mach_absolute_time();
959 for (i = 0; i < COUNT; i++) {
962 totalTime = mach_absolute_time() - startTime;
963 timecheck("fpret ", totalTime, targetTime * 0.7, targetTime * 4.0);
965 startTime = mach_absolute_time();
967 for (i = 0; i < COUNT; i++) {
970 totalTime = mach_absolute_time() - startTime;
971 timecheck("lfpret", totalTime, targetTime * 0.7, targetTime * 4.0);
975 // method_invoke long long
976 // method_invoke_stret stret
977 // method_invoke_stret fpret
978 // method_invoke fpret long double
983 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);
984 testassert(state == 1);
985 testassert(idval == ID_RESULT);
988 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);
989 testassert(state == 2);
990 testassert(llval == LL_RESULT);
993 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);
994 testassert(state == 3);
995 testassert(stret_equal(stretval, STRET_RESULT));
998 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);
999 testassert(state == 4);
1000 testassert(fpval == FP_RESULT);
1003 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);
1004 testassert(state == 5);
1005 testassert(lfpval == LFP_RESULT);
1009 // message to nil long long
1010 // message to nil stret
1011 // message to nil fpret
1012 // message to nil fpret long double
1015 idval = [(id)nil idret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1016 testassert(state == 0);
1017 testassert(idval == nil);
1021 llval = [(id)nil llret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1022 testassert(state == 0);
1023 testassert(llval == 0LL);
1027 stretval = [(id)nil stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1028 testassert(state == 0);
1030 testassert(0 == memcmp(&stretval, &zero, sizeof(stretval)));
1032 // no stret result guarantee
1037 fpval = [(id)nil fpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1038 testassert(state == 0);
1039 testassert(fpval == 0.0);
1042 lfpval = LFP_RESULT;
1043 lfpval = [(id)nil lfpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
1044 testassert(state == 0);
1045 testassert(lfpval == 0.0);
1048 // message to nil noarg
1049 // explicitly call noarg messenger, even if compiler doesn't emit it
1052 idval = ((typeof(idmsg0))objc_msgSend_noarg)(nil, @selector(idret_noarg));
1053 testassert(state == 0);
1054 testassert(idval == nil);
1058 llval = ((typeof(llmsg0))objc_msgSend_noarg)(nil, @selector(llret_noarg));
1059 testassert(state == 0);
1060 testassert(llval == 0LL);
1062 // no stret_noarg messenger
1067 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(nil, @selector(fpret_noarg));
1068 testassert(state == 0);
1069 testassert(fpval == 0.0);
1071 # if !__i386__ && !__x86_64__
1073 lfpval = LFP_RESULT;
1074 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(nil, @selector(lfpret_noarg));
1075 testassert(state == 0);
1076 testassert(lfpval == 0.0);
1080 // message forwarded
1081 // message forwarded long long
1082 // message forwarded stret
1083 // message forwarded fpret
1084 // message forwarded fpret long double
1088 // rdar://8271364 objc_msgSendSuper2 must not change objc_super
1089 struct objc_super sup_st = {
1091 object_getClass(sub),
1098 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);
1099 testassert(state == 1);
1100 testassert(idval == ID_RESULT);
1101 testassert(sup_st.receiver == sub);
1102 testassert(sup_st.super_class == object_getClass(sub));
1106 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);
1107 testassert(state == 3);
1108 testassert(stret_equal(stretval, STRET_RESULT));
1109 testassert(sup_st.receiver == sub);
1110 testassert(sup_st.super_class == object_getClass(sub));
1114 // Debug messengers.
1116 idmsg = (typeof(idmsg))objc_msgSend_debug;
1118 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);
1119 testassert(state == 101);
1120 testassert(idval == ID_RESULT);
1123 llmsg = (typeof(llmsg))objc_msgSend_debug;
1125 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);
1126 testassert(state == 102);
1127 testassert(llval == LL_RESULT);
1130 stretmsg = (typeof(stretmsg))objc_msgSend_stret_debug;
1132 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);
1133 testassert(state == 103);
1134 testassert(stret_equal(stretval, STRET_RESULT));
1137 sup_st.receiver = sub;
1138 sup_st.super_class = object_getClass(sub);
1139 idmsgsuper = (typeof(idmsgsuper))objc_msgSendSuper2_debug;
1141 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);
1142 testassert(state == 1);
1143 testassert(idval == ID_RESULT);
1146 sup_st.receiver = sub;
1147 sup_st.super_class = object_getClass(sub);
1148 stretmsgsuper = (typeof(stretmsgsuper))objc_msgSendSuper2_stret_debug;
1150 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);
1151 testassert(state == 3);
1152 testassert(stret_equal(stretval, STRET_RESULT));
1156 fpmsg = (typeof(fpmsg))objc_msgSend_fpret_debug;
1158 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);
1159 testassert(state == 104);
1160 testassert(fpval == FP_RESULT);
1164 lfpmsg = (typeof(lfpmsg))objc_msgSend_fpret_debug;
1166 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);
1167 testassert(state == 105);
1168 testassert(lfpval == LFP_RESULT);
1177 #if __x86_64__ && !__has_feature(objc_arc)
1178 // DWARF unwind tables
1179 // Not for ARC because the extra RR calls hit the traps at the wrong times
1181 // install exception handler
1182 struct sigaction act;
1183 act.sa_sigaction = sigtrap;
1185 act.sa_flags = SA_SIGINFO;
1186 sigaction(SIGTRAP, &act, NULL);
1188 // use _nop methods because other methods make more calls
1189 // which can die in the trapped messenger
1191 test_dw("objc_msgSend", sub,tagged,@selector(idret_nop));
1192 test_dw("objc_msgSend_fixup", sub,tagged,@selector(idret_nop));
1193 test_dw("objc_msgSend_stret", sub,tagged,@selector(stret_nop));
1194 test_dw("objc_msgSend_stret_fixup", sub,tagged,@selector(stret_nop));
1195 test_dw("objc_msgSend_fpret", sub,tagged,@selector(fpret_nop));
1196 test_dw("objc_msgSend_fpret_fixup", sub,tagged,@selector(fpret_nop));
1198 test_dw("objc_msgSendSuper", sub,tagged,@selector(idret_nop));
1199 test_dw("objc_msgSendSuper2", sub,tagged,@selector(idret_nop));
1200 test_dw("objc_msgSendSuper2_fixup", sub,tagged,@selector(idret_nop));
1201 test_dw("objc_msgSendSuper_stret", sub,tagged,@selector(stret_nop));
1202 test_dw("objc_msgSendSuper2_stret", sub,tagged,@selector(stret_nop));
1203 test_dw("objc_msgSendSuper2_stret_fixup", sub,tagged,@selector(stret_nop));
1205 // DWARF unwind tables