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>
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"));\
86 long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
87 double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
88 long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
89 // STRET_RESULT in test.h
91 static struct stret zero;
95 -(struct stret)stret { return STRET_RESULT; }
98 (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
106 (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
113 -(struct stret)stret:
114 (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
122 (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
129 -(long double)lfpret:
130 (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
140 CHECK_ARGS_NOARG(idret);
145 -(long long)llret_noarg
147 CHECK_ARGS_NOARG(llret);
152 -(struct stret)stret_noarg
154 CHECK_ARGS_NOARG(stret);
161 CHECK_ARGS_NOARG(fpret);
166 -(long double)lfpret_noarg
168 CHECK_ARGS_NOARG(lfpret);
184 -(long long)llret_nop
189 -(struct stret)stret_nop
199 -(long double)lfpret_nop
207 (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
209 fail("+idret called instead of -idret");
214 (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
216 fail("+llret called instead of -llret");
220 +(struct stret)stret:
221 (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
223 fail("+stret called instead of -stret");
228 (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
230 fail("+fpret called instead of -fpret");
234 +(long double)lfpret:
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
237 fail("+lfpret called instead of -lfpret");
243 fail("+idret_noarg called instead of -idret_noarg");
244 CHECK_ARGS_NOARG(idret);
247 +(long long)llret_noarg
249 fail("+llret_noarg called instead of -llret_noarg");
250 CHECK_ARGS_NOARG(llret);
253 +(struct stret)stret_noarg
255 fail("+stret_noarg called instead of -stret_noarg");
256 CHECK_ARGS_NOARG(stret);
261 fail("+fpret_noarg called instead of -fpret_noarg");
262 CHECK_ARGS_NOARG(fpret);
265 +(long double)lfpret_noarg
267 fail("+lfpret_noarg called instead of -lfpret_noarg");
268 CHECK_ARGS_NOARG(lfpret);
277 (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 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];
283 testassert(state == 1);
284 testassert(result == ID_RESULT);
290 (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
295 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];
296 testassert(state == 2);
297 testassert(result == LL_RESULT);
302 -(struct stret)stret:
303 (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
308 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];
309 testassert(state == 3);
310 testassert(stret_equal(result, STRET_RESULT));
316 (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
321 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];
322 testassert(state == 4);
323 testassert(result == FP_RESULT);
328 -(long double)lfpret:
329 (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
334 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];
335 testassert(state == 5);
336 testassert(result == LFP_RESULT);
345 CHECK_ARGS_NOARG(idret);
347 result = [super idret_noarg];
348 testassert(state == 11);
349 testassert(result == ID_RESULT);
354 -(long long)llret_noarg
357 CHECK_ARGS_NOARG(llret);
359 result = [super llret_noarg];
360 testassert(state == 12);
361 testassert(result == LL_RESULT);
366 -(struct stret)stret_noarg
369 CHECK_ARGS_NOARG(stret);
371 result = [super stret_noarg];
372 testassert(state == 13);
373 testassert(stret_equal(result, STRET_RESULT));
381 CHECK_ARGS_NOARG(fpret);
383 result = [super fpret_noarg];
384 testassert(state == 14);
385 testassert(result == FP_RESULT);
390 -(long double)lfpret_noarg
393 CHECK_ARGS_NOARG(lfpret);
395 result = [super lfpret_noarg];
396 testassert(state == 15);
397 testassert(result == LFP_RESULT);
405 #if OBJC_HAVE_TAGGED_POINTERS
407 @interface TaggedSub : Sub @end
409 @implementation TaggedSub : Sub
413 _objc_registerTaggedPointerClass(OBJC_TAG_7, self);
418 // DWARF checking machinery
422 #include <sys/mman.h>
423 #include <libunwind.h>
425 #define UNW_STEP_SUCCESS 1
426 #define UNW_STEP_END 0
440 void handle_exception(x86_thread_state64_t *state)
447 err = unw_init_local(&curs, (unw_context_t *)state);
450 step = unw_step(&curs);
451 testassert(step == UNW_STEP_SUCCESS);
453 err = unw_get_reg(&curs, UNW_X86_64_R12, ®);
455 testassert(reg == r12);
457 err = unw_get_reg(&curs, UNW_X86_64_R13, ®);
459 testassert(reg == r13);
461 err = unw_get_reg(&curs, UNW_X86_64_R14, ®);
463 testassert(reg == r14);
465 err = unw_get_reg(&curs, UNW_X86_64_R15, ®);
467 testassert(reg == r15);
469 err = unw_get_reg(&curs, UNW_X86_64_RBX, ®);
471 testassert(reg == rbx);
473 err = unw_get_reg(&curs, UNW_X86_64_RBP, ®);
475 testassert(reg == rbp);
477 err = unw_get_reg(&curs, UNW_X86_64_RSP, ®);
479 testassert(reg == rsp);
481 err = unw_get_reg(&curs, UNW_REG_IP, ®);
483 testassert(reg == rip);
486 // set thread state to unwound state
500 void sigtrap(int sig, siginfo_t *info, void *cc)
502 ucontext_t *uc = (ucontext_t *)cc;
503 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
505 testprintf(" handled\n");
507 testassert(sig == SIGTRAP);
508 testassert((uintptr_t)info->si_addr-1 == clobbered);
510 handle_exception(&mc->__ss);
511 // handle_exception changed register state for continuation
515 uint8_t set(uintptr_t dst, uint8_t newvalue)
517 uintptr_t start = dst & ~(PAGE_SIZE-1);
518 mprotect((void*)start, PAGE_SIZE, PROT_READ|PROT_WRITE);
520 uint8_t oldvalue = *(uint8_t *)dst;
521 *(uint8_t *)dst = newvalue;
522 mprotect((void*)start, PAGE_SIZE, PROT_READ|PROT_EXEC);
526 uint8_t clobber(void *fn, uintptr_t offset)
528 clobbered = (uintptr_t)fn + offset;
529 return set((uintptr_t)fn + offset, 0xcc /*int3*/);
532 void unclobber(void *fn, uintptr_t offset, uint8_t oldvalue)
534 set((uintptr_t)fn + offset, oldvalue);
538 extern void callit(void *obj, void *sel, void *fn);
539 extern struct stret callit_stret(void *obj, void *sel, void *fn);
546 // save rsp and rip registers to variables
547 "\n movq (%rsp), %r10"
548 "\n movq %r10, _rip(%rip)"
549 "\n movq %rsp, _rsp(%rip)"
550 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
551 // save other non-volatile registers to variables
552 "\n movq %rbx, _rbx(%rip)"
553 "\n movq %rbp, _rbp(%rip)"
554 "\n movq %r12, _r12(%rip)"
555 "\n movq %r13, _r13(%rip)"
556 "\n movq %r14, _r14(%rip)"
557 "\n movq %r15, _r15(%rip)"
563 "\n .globl _callit_stret"
565 // save rsp and rip registers to variables
566 "\n movq (%rsp), %r10"
567 "\n movq %r10, _rip(%rip)"
568 "\n movq %rsp, _rsp(%rip)"
569 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
570 // save other non-volatile registers to variables
571 "\n movq %rbx, _rbx(%rip)"
572 "\n movq %rbp, _rbp(%rip)"
573 "\n movq %r12, _r12(%rip)"
574 "\n movq %r13, _r13(%rip)"
575 "\n movq %r14, _r14(%rip)"
576 "\n movq %r15, _r15(%rip)"
580 uintptr_t *getOffsets(void *symbol, const char *symname)
582 uintptr_t *result = (uintptr_t *)malloc(PAGE_SIZE * sizeof(uintptr_t));
583 uintptr_t *end = result + PAGE_SIZE;
584 uintptr_t *p = result;
590 // call `otool` on library
591 unsetenv("DYLD_LIBRARY_PATH");
592 unsetenv("DYLD_ROOT_PATH");
593 unsetenv("DYLD_INSERT_LIBRARIES");
595 asprintf(&cmd, "/usr/bin/xcrun otool -arch x86_64 -tv -p _%s %s",
596 symname, dl.dli_fname);
597 testprintf("%s\n", cmd);
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);
627 // hack: skip last instruction because libunwind blows up if it's
628 // one byte long and followed by the next function with no NOPs first
629 if (p > result) p[-1] = ~0UL;
633 void CALLIT(void *o, void *sel_arg, SEL s, void *f) __attribute__((noinline));
634 void CALLIT(void *o, void *sel_arg, SEL s, void *f)
636 uintptr_t message_ref[2];
639 // copy to a local buffer to keep sel_arg un-fixed-up
640 memcpy(message_ref, sel_arg, sizeof(message_ref));
641 sel_arg = message_ref;
643 if (s == @selector(idret_nop)) callit(o, sel_arg, f);
644 else if (s == @selector(fpret_nop)) callit(o, sel_arg, f);
645 else if (s == @selector(stret_nop)) callit_stret(o, sel_arg, f);
646 else fail("test_dw selector");
649 // sub = ordinary receiver object
650 // tagged = tagged receiver object
651 // SEL = selector to send
652 // sub_arg = arg to pass in receiver register (may be objc_super struct)
653 // tagged_arg = arg to pass in receiver register (may be objc_super struct)
654 // sel_arg = arg to pass in sel register (may be message_ref)
655 void test_dw(const char *name, id sub, id tagged, SEL sel)
657 testprintf("DWARF FOR %s\n", name);
659 void *fn = dlsym(RTLD_DEFAULT, name);
662 // argument substitutions
664 void *sub_arg = (void*)objc_unretainedPointer(sub);
665 void *tagged_arg = (void*)objc_unretainedPointer(tagged);
666 void *sel_arg = (void*)sel;
668 struct objc_super sup_st = { sub, object_getClass(sub) };
669 struct objc_super tagged_sup_st = { tagged, object_getClass(tagged) };
670 struct { void *imp; SEL sel; } message_ref = { fn, sel };
672 if (strstr(name, "Super")) {
673 // super version - replace receiver with objc_super
675 tagged_arg = &tagged_sup_st;
678 if (strstr(name, "_fixup")) {
679 // fixup version - replace sel with message_ref
680 sel_arg = &message_ref;
684 uintptr_t *insnOffsets = getOffsets(fn, name);
685 uintptr_t *offsetp = insnOffsets;
687 while ((offset = *offsetp++) != ~0UL) {
688 testprintf("OFFSET %lu\n", offset);
690 uint8_t insn_byte = clobber(fn, offset);
694 if ((void*)objc_unretainedPointer(sub) == sub_arg) {
696 testprintf(" nil\n");
697 CALLIT(nil, sel_arg, sel, fn);
698 CALLIT(nil, sel_arg, sel, fn);
703 testprintf(" uncached\n");
704 _objc_flush_caches(object_getClass(sub));
705 CALLIT(sub_arg, sel_arg, sel, fn);
706 _objc_flush_caches(object_getClass(sub));
707 CALLIT(sub_arg, sel_arg, sel, fn);
711 testprintf(" cached\n");
712 CALLIT(sub_arg, sel_arg, sel, fn);
713 CALLIT(sub_arg, sel_arg, sel, fn);
717 testprintf(" uncached,tagged\n");
718 _objc_flush_caches(object_getClass(tagged));
719 CALLIT(tagged_arg, sel_arg, sel, fn);
720 _objc_flush_caches(object_getClass(tagged));
721 CALLIT(tagged_arg, sel_arg, sel, fn);
725 testprintf(" cached,tagged\n");
726 CALLIT(tagged_arg, sel_arg, sel, fn);
727 CALLIT(tagged_arg, sel_arg, sel, fn);
729 unclobber(fn, offset, insn_byte);
731 // require at least one path above to trip this offset
732 if (!caught) fprintf(stderr, "OFFSET %s+%lu NOT CAUGHT\n", name, offset);
741 void test_basic(id receiver)
745 struct stret stretval;
750 // message uncached long long
751 // message uncached stret
752 // message uncached fpret
753 // message uncached fpret long double
754 // message uncached noarg (as above)
756 // message cached long long
757 // message cached stret
758 // message cached fpret
759 // message cached fpret long double
760 // message cached noarg (as above)
761 // fixme verify that uncached lookup didn't happen the 2nd time?
763 for (int i = 0; i < 5; i++) {
766 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];
767 testassert(state == 101);
768 testassert(idval == ID_RESULT);
771 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];
772 testassert(state == 102);
773 testassert(llval == LL_RESULT);
776 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];
777 testassert(state == 103);
778 testassert(stret_equal(stretval, STRET_RESULT));
781 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];
782 testassert(state == 104);
783 testassert(fpval == FP_RESULT);
786 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];
787 testassert(state == 105);
788 testassert(lfpval == LFP_RESULT);
791 // explicitly call noarg messenger, even if compiler doesn't emit it
794 idval = ((typeof(idmsg0))objc_msgSend_noarg)(receiver, @selector(idret_noarg));
795 testassert(state == 111);
796 testassert(idval == ID_RESULT);
799 llval = ((typeof(llmsg0))objc_msgSend_noarg)(receiver, @selector(llret_noarg));
800 testassert(state == 112);
801 testassert(llval == LL_RESULT);
803 no objc_msgSend_stret_noarg
805 stretval = ((typeof(stretmsg0))objc_msgSend_stret_noarg)(receiver, @selector(stret_noarg));
806 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];
807 testassert(state == 113);
808 testassert(stret_equal(stretval, STRET_RESULT));
812 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(receiver, @selector(fpret_noarg));
813 testassert(state == 114);
814 testassert(fpval == FP_RESULT);
816 # if !__i386__ && !__x86_64__
818 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(receiver, @selector(lfpret_noarg));
819 testassert(state == 115);
820 testassert(lfpval == LFP_RESULT);
833 struct stret stretval;
838 struct stret *stretptr;
851 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);
852 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);
853 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);
854 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);
855 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);
857 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));
858 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));
859 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));
860 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));
861 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));
862 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));
863 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));
865 // get +initialize out of the way
867 #if OBJC_HAVE_TAGGED_POINTERS
871 ID_RESULT = [Super new];
873 Sub *sub = [Sub new];
874 Super *sup = [Super new];
875 #if OBJC_HAVE_TAGGED_POINTERS
876 TaggedSub *tagged = objc_unretainedObject(_objc_makeTaggedPointer(OBJC_TAG_7, 999));
879 // Basic cached and uncached dispatch.
880 // Do this first before anything below caches stuff.
881 testprintf("basic\n");
883 #if OBJC_HAVE_TAGGED_POINTERS
884 testprintf("basic tagged\n");
888 idmethod = class_getInstanceMethod([Super class], @selector(idret::::::::::::::::::::::::::::));
889 testassert(idmethod);
890 llmethod = class_getInstanceMethod([Super class], @selector(llret::::::::::::::::::::::::::::));
891 testassert(llmethod);
892 stretmethod = class_getInstanceMethod([Super class], @selector(stret::::::::::::::::::::::::::::));
893 testassert(stretmethod);
894 fpmethod = class_getInstanceMethod([Super class], @selector(fpret::::::::::::::::::::::::::::));
895 testassert(fpmethod);
896 lfpmethod = class_getInstanceMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::));
897 testassert(lfpmethod);
899 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;
900 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;
901 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;
902 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;
903 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;
905 // cached message performance
906 // catches failure to cache or (abi=2) failure to fixup (#5584187)
907 // fixme unless they all fail
908 // `.align 4` matches loop alignment to make -O0 work
910 testprintf("time checks\n");
929 // Some of these times have high variance on some compilers.
930 // The errors we're trying to catch should be catastrophically slow,
931 // so the margins here are generous to avoid false failures.
933 #define COUNT 1000000
934 startTime = mach_absolute_time();
936 for (i = 0; i < COUNT; i++) {
937 [sub voidret_nop]; // id return is too slow for perf test with ARC
939 totalTime = mach_absolute_time() - startTime;
940 testprintf("time: idret %llu\n", totalTime);
941 targetTime = totalTime;
943 startTime = mach_absolute_time();
945 for (i = 0; i < COUNT; i++) {
946 [sub voidret_nop]; // id return is too slow for perf test with ARC
948 totalTime = mach_absolute_time() - startTime;
949 testprintf("time: idret %llu\n", totalTime);
950 targetTime = totalTime;
952 startTime = mach_absolute_time();
954 for (i = 0; i < COUNT; i++) {
957 totalTime = mach_absolute_time() - startTime;
958 timecheck("llret ", totalTime, targetTime * 0.7, targetTime * 2.0);
960 startTime = mach_absolute_time();
962 for (i = 0; i < COUNT; i++) {
965 totalTime = mach_absolute_time() - startTime;
966 timecheck("stret ", totalTime, targetTime * 0.7, targetTime * 5.0);
968 startTime = mach_absolute_time();
970 for (i = 0; i < COUNT; i++) {
973 totalTime = mach_absolute_time() - startTime;
974 timecheck("fpret ", totalTime, targetTime * 0.7, targetTime * 4.0);
976 startTime = mach_absolute_time();
978 for (i = 0; i < COUNT; i++) {
981 totalTime = mach_absolute_time() - startTime;
982 timecheck("lfpret", totalTime, targetTime * 0.7, targetTime * 4.0);
986 // method_invoke long long
987 // method_invoke_stret stret
988 // method_invoke_stret fpret
989 // method_invoke fpret long double
990 testprintf("method_invoke\n");
996 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);
997 testassert(state == 1);
998 testassert(idval == ID_RESULT);
1001 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);
1002 testassert(state == 2);
1003 testassert(llval == LL_RESULT);
1006 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);
1007 testassert(state == 3);
1008 testassert(stret_equal(stretval, STRET_RESULT));
1011 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);
1012 testassert(state == 4);
1013 testassert(fpval == FP_RESULT);
1016 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);
1017 testassert(state == 5);
1018 testassert(lfpval == LFP_RESULT);
1022 // message to nil long long
1023 // message to nil stret
1024 // message to nil fpret
1025 // message to nil fpret long double
1026 // Use NIL_RECEIVER to avoid compiler optimizations.
1027 testprintf("message to nil\n");
1031 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];
1032 testassert(state == 0);
1033 testassert(idval == nil);
1037 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];
1038 testassert(state == 0);
1039 testassert(llval == 0LL);
1043 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];
1044 testassert(state == 0);
1046 testassert(0 == memcmp(&stretval, &zero, sizeof(stretval)));
1048 // no stret result guarantee
1052 // check stret return register
1055 stretptr = ((struct stret *(*)(struct stret *, id, SEL))objc_msgSend_stret)
1056 (&stretval, nil, @selector(stret_nop));
1057 testassert(stretptr == &stretval);
1058 testassert(state == 0);
1059 // no stret result guarantee for hand-written calls, even with clang
1064 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];
1065 testassert(state == 0);
1066 testassert(fpval == 0.0);
1069 lfpval = LFP_RESULT;
1070 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];
1071 testassert(state == 0);
1072 testassert(lfpval == 0.0);
1075 // message to nil noarg
1076 // explicitly call noarg messenger, even if compiler doesn't emit it
1079 idval = ((typeof(idmsg0))objc_msgSend_noarg)(nil, @selector(idret_noarg));
1080 testassert(state == 0);
1081 testassert(idval == nil);
1085 llval = ((typeof(llmsg0))objc_msgSend_noarg)(nil, @selector(llret_noarg));
1086 testassert(state == 0);
1087 testassert(llval == 0LL);
1089 // no stret_noarg messenger
1094 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(nil, @selector(fpret_noarg));
1095 testassert(state == 0);
1096 testassert(fpval == 0.0);
1098 # if !__i386__ && !__x86_64__
1100 lfpval = LFP_RESULT;
1101 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(nil, @selector(lfpret_noarg));
1102 testassert(state == 0);
1103 testassert(lfpval == 0.0);
1109 // rdar://8271364 objc_msgSendSuper2 must not change objc_super
1110 testprintf("super struct\n");
1111 struct objc_super sup_st = {
1113 object_getClass(sub),
1120 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);
1121 testassert(state == 1);
1122 testassert(idval == ID_RESULT);
1123 testassert(sup_st.receiver == sub);
1124 testassert(sup_st.super_class == object_getClass(sub));
1128 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);
1129 testassert(state == 3);
1130 testassert(stret_equal(stretval, STRET_RESULT));
1131 testassert(sup_st.receiver == sub);
1132 testassert(sup_st.super_class == object_getClass(sub));
1136 // Debug messengers.
1137 testprintf("debug messengers\n");
1140 idmsg = (typeof(idmsg))objc_msgSend_debug;
1142 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);
1143 testassert(state == 101);
1144 testassert(idval == ID_RESULT);
1147 llmsg = (typeof(llmsg))objc_msgSend_debug;
1149 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);
1150 testassert(state == 102);
1151 testassert(llval == LL_RESULT);
1154 stretmsg = (typeof(stretmsg))objc_msgSend_stret_debug;
1156 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);
1157 testassert(state == 103);
1158 testassert(stret_equal(stretval, STRET_RESULT));
1161 sup_st.receiver = sub;
1162 sup_st.super_class = object_getClass(sub);
1163 idmsgsuper = (typeof(idmsgsuper))objc_msgSendSuper2_debug;
1165 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);
1166 testassert(state == 1);
1167 testassert(idval == ID_RESULT);
1170 sup_st.receiver = sub;
1171 sup_st.super_class = object_getClass(sub);
1172 stretmsgsuper = (typeof(stretmsgsuper))objc_msgSendSuper2_stret_debug;
1174 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);
1175 testassert(state == 3);
1176 testassert(stret_equal(stretval, STRET_RESULT));
1180 fpmsg = (typeof(fpmsg))objc_msgSend_fpret_debug;
1182 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);
1183 testassert(state == 104);
1184 testassert(fpval == FP_RESULT);
1188 lfpmsg = (typeof(lfpmsg))objc_msgSend_fpret_debug;
1190 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);
1191 testassert(state == 105);
1192 testassert(lfpval == LFP_RESULT);
1201 #if __x86_64__ && !__has_feature(objc_arc)
1202 // DWARF unwind tables
1203 // Not for ARC because the extra RR calls hit the traps at the wrong times
1204 testprintf("unwind tables\n");
1206 // install exception handler
1207 struct sigaction act;
1208 act.sa_sigaction = sigtrap;
1210 act.sa_flags = SA_SIGINFO;
1211 sigaction(SIGTRAP, &act, NULL);
1213 // use _nop methods because other methods make more calls
1214 // which can die in the trapped messenger
1216 test_dw("objc_msgSend", sub,tagged,@selector(idret_nop));
1217 test_dw("objc_msgSend_stret", sub,tagged,@selector(stret_nop));
1218 test_dw("objc_msgSend_fpret", sub,tagged,@selector(fpret_nop));
1220 test_dw("objc_msgSendSuper", sub,tagged,@selector(idret_nop));
1221 test_dw("objc_msgSendSuper2", sub,tagged,@selector(idret_nop));
1222 test_dw("objc_msgSendSuper_stret", sub,tagged,@selector(stret_nop));
1223 test_dw("objc_msgSendSuper2_stret", sub,tagged,@selector(stret_nop));
1225 // DWARF unwind tables